Está en la página 1de 161

Andrés Zarabozo

Métodos Numéricos. Apuntes

Ingeniería Aeronáutica
ETSEIAT
2012
Andrés Zarabozo Martínez Métodos numéricos

Acerca de estos apuntes

Estos apuntes se han realizado para cubrir el temario de la asignatura “métodos numéricos”,
que se imparte en el quinto curso de Ingeniería Aeronáutica en la Escola Tècnica Superior
d’Enginyeries Industrial i Aeronàutica de Terrassa, de la Universitat Politècnica de Catalunya
(ETSEIAT – UPC).

Licencia

Esta obra está bajo una licencia Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) de
Creative Commons. Para ver una copia de esta licencia, visite:

http://creativecommons.org/licenses/by-sa/3.0/deed.es_ES

En líneas generales:

Es libre de:

 Compartir – Copiar, distribuir y comunicar públicamente la obra.


 Transformar la obra y crear obras derivadas.
 Hacer un uso comercial de esta obra.

Bajo las condiciones siguientes:

 Reconocimiento — Debe reconocer al autor de la obra original (pero no de una


manera que sugiera que tiene su apoyo o apoya el uso que hace de su obra).
 Compartir bajo la Misma Licencia — Si altera o transforma esta obra, o genera una
obra derivada, sólo puede distribuir la obra generada bajo una licencia idéntica a ésta.

-2-
Andrés Zarabozo Martínez Métodos numéricos

Índice
1. Programación en Fortran
1.1. Tipos de variables .......................................................................................................... 7
1.2. Expresiones aritméticas ................................................................................................ 7
1.3. Bucles y condiciones ..................................................................................................... 8
1.4. Vectores y matrices ....................................................................................................... 9
1.5. Subrutinas ................................................................................................................... 11
1.6. Lectura y escritura de datos ........................................................................................ 12
1.7. Programas ................................................................................................................... 13
Programa 1. Mínimo error de un tipo de variable .............................................................. 13
Programa 2. Cálculo del número π...................................................................................... 15
2. Interpolación
2.1. SPLINE.......................................................................................................................... 17
2.2. Interpolación cúbica en un solo intervalo ................................................................... 18
2.3. Programa ..................................................................................................................... 20
Programa 3. Entrada de datos e interpolación ................................................................... 20
3. Integración
3.1. Fórmula de Newton-Cotes .......................................................................................... 23
3.2. Regla del punto medio ................................................................................................ 25
3.3. Regla del trapecio ........................................................................................................ 25
3.4. Regla de Simpson ........................................................................................................ 27
3.5. Extrapolación de Richardson ....................................................................................... 28
3.6. Programas ................................................................................................................... 30
Programa 4. Obtención de la serie de Fourier .................................................................... 30
Programa 5. Iteraciones y extrapolación ............................................................................ 33
4. Resolución numérica de ecuaciones no lineales
4.1. Método de la bisección ............................................................................................... 36
4.2. Método de Newton - Raphson .................................................................................... 36
4.3. Método de la secante.................................................................................................. 37
4.4. Método de regula falsi ................................................................................................ 38
4.5. Teorema del punto fijo................................................................................................ 39
4.6. Programas ................................................................................................................... 41

-3-
Andrés Zarabozo Martínez Métodos numéricos

Programa 6. Deflexión de un cable ..................................................................................... 41


Programa 7. Resolución mediante Newton-Raphson ......................................................... 44
5. Resolución numérica de sistemas lineales
5.1. Método de eliminación de Gauss................................................................................ 45
5.2. Matrices mal condicionadas........................................................................................ 46
5.3. Descomposición LU ..................................................................................................... 47
5.4. Doolittle ....................................................................................................................... 47
5.5. Crout ............................................................................................................................ 48
5.6. Matrices dispersas....................................................................................................... 49
5.7. Método del gradiente conjugado................................................................................ 51
5.8. Ejemplo de aplicación del método del gradiente conjugado ...................................... 56
5.9. Programas ................................................................................................................... 58
Programa 1. Resolución de un sistema mediante Gauss .................................................... 58
Programa 2. Sistema con matriz mal condicionada ............................................................ 61
Programa 3. Doolitle ........................................................................................................... 64
Programa 4. Crout ............................................................................................................... 66
Programa 5. Matriz banda................................................................................................... 69
6. Resolución numérica de sistemas no lineales
6.1. Método de Newton para sistemas no lineales............................................................ 72
7. Ecuaciones diferenciales, problemas de valor inicial
7.1. Tipos de ecuaciones diferenciales ............................................................................... 74
7.2. Método de Euler.......................................................................................................... 74
7.3. Ejemplo de resolución mediante el método de Euler. ................................................ 75
7.4. Método implícito de Euler........................................................................................... 75
7.5. Método de Heun ......................................................................................................... 76
7.6. Método de Runge-Kutta de segundo orden ............................................................... 77
7.7. Método de Runge-Kutta de órdenes superiores......................................................... 78
7.8. Método adaptativo de Runge-Kutta ........................................................................... 80
7.9. Esquema de Crank-Nicolson........................................................................................ 81
7.10. Método de Runge-Kutta para EDOs de grados superiores ......................................... 81
8. Método de diferencias finitas
8.1. Diferencias finitas en una dimensión. ......................................................................... 82
8.2. Diferencias finitas en dos dimensiones ....................................................................... 83

-4-
Andrés Zarabozo Martínez Métodos numéricos

8.3. Ejemplo de problema mecánico.................................................................................. 84


8.4. Programas ................................................................................................................... 90
Programa 6. Ejemplo de problema mecánico ..................................................................... 90
9. Método de elementos finitos
9.1. Forma fuerte del problema ......................................................................................... 96
9.2. Método de Rayleigh-Ritz y método de Galerkin ......................................................... 96
9.3. Ejemplo de formulación fuerte para problema estructural ........................................ 97
9.4. Funciones de forma ................................................................................................... 100
9.5. Cuadratura de Gauss ................................................................................................. 101
9.6. Tipos de elementos en 2D ......................................................................................... 101
9.7. Ejemplo de problema térmico................................................................................... 105
9.8. Programa ................................................................................................................... 111
Programa 7. Radiador espacial .......................................................................................... 111
10. Apéndice
10.1. Programación en Fortran .......................................................................................... 123
Programa 1. Mínimo error de un tipo de variable ............................................................ 123
Programa 2. Cálculo del número π.................................................................................... 124
10.2. Interpolación ............................................................................................................. 125
Programa 3. Entrada de datos e interpolación ................................................................. 125
10.3. Integración ................................................................................................................ 127
Programa 4. Obtención de la serie de Fourier .................................................................. 127
Programa 5. Iteraciones y extrapolación .......................................................................... 129
10.4. Resolución numérica de ecuaciones no lineales ....................................................... 131
Programa 6. Deflexión de un cable ................................................................................... 131
Programa 7. Resolución mediante Newton-Raphson ....................................................... 132
10.5. Resolución numérica de ecuaciones lineales ............................................................ 133
Programa 8. Resolución de un sistema mediante Gauss .................................................. 133
Programa 9. Sistema con matriz mal condicionada .......................................................... 134
Programa 10. Doolittle ...................................................................................................... 136
Programa 11. Crout ........................................................................................................... 138
Programa 12. Matriz Banda .............................................................................................. 140
10.6. Método de diferencias finitas ................................................................................... 142
Programa 13. Ejemplo de problema mecánico ................................................................. 142

-5-
Andrés Zarabozo Martínez Métodos numéricos

10.7. Método de elementos finitos.................................................................................... 145


Programa 15. Radiador especial........................................................................................ 145
10.8. Datos de entrada del Programa 13, radiador espacial .............................................. 154

-6-
Andrés Zarabozo Martínez Métodos numéricos

1. Programación en Fortran
1.1. Tipos de variables
En Fortran se suelen usar cinco tipos básicos de variables:

 Boolean:
Es una variable de un solo bit y por lo tanto solo puede tener dos posibles valores
(.true. o .false.).
 Integer:
Solo permite tener un valor enteros, en general ocupa bits. El primer bit contiene el
signo y por lo tanto el módulo del número ocupa los restantes bits. El valor máximo
es igual a .
 Real:
Es similar al Double usado en otros lenguajes de programación como C. Permite
números en decimales y en general ocupa bits. De forma similar al Integer el primer
bit contiene el signo del número.
 Complex:
Son números complejos compuestos de dos números Real separados por una coma y
entre paréntesis. El primer número representa el valor real y el segundo el valor
complejo.
 Character:
Se utiliza para escribir letras. Se suele generar un vector donde cada posición es un
caracter.

Para definir una variable se debe declarar primero el tipo y luego el nombre de la variable. Las
variables tienen que tener un nombre entre y letras o números siendo la primera siempre
una letra. En Fortran no hay diferencia entre mayúsculas y minúsculas.

real x
integer i

También se puede definir el tamaño en memoria de las distintas variables como por ejemplo:

real*8 x
integer*8 i

1.2. Expresiones aritméticas


Las cinco operaciones aritméticas básicas son: la suma (+), la resta (-), la multiplicación (*), la
división (/) y el exponente (**). Fortran también reconoce otro tipo de funciones como por
ejemplo funciones trigonométricas, logaritmos… Las operaciones aritméticas devuelven un
resultado (que puede ser un Real o Integer) y debe ser almacenado en una variable.

-7-
Andrés Zarabozo Martínez Métodos numéricos

x = 1. + 3. 25 * 5. / 3.
x = cos(1.25) + y**2.

El orden de las operaciones es:

 Primero:
Todas las operaciones exponenciales y se desarrollan de derecha a izquierda.
 Segundo:
Todas las multiplicaciones y divisiones, el orden es de izquierda a derecha.
 Tercero:
Todas las operaciones de suma y resta, el orden es de izquierda a derecha.

En este libro se va a centrar el estudio del uso de Fortran para aplicación en métodos
numéricos. Los programas se deben escribir de forma óptima para el cálculo. La latencia es el
tiempo que se consume en una operación. Las operaciones básicas (menos los exponentes)
tienen latencias muy bajas, en especial la suma, la resta y la multiplicación. La división tiene
una latencia un poco más alta aunque en los nuevos procesadores como por ejemplo los Intel
i7 la diferencia en latencia es despreciable, en ordenadores antiguos la latencia puede ser
hasta cinco veces más lenta. Las operaciones exponenciales, trigonométricas, logarítmicas…
son demasiado lentas y deben ser evitadas en la medida de lo posible. Por ejemplo si se quiere
calcular la siguiente ecuación:

( ) ∑ (1.1)

Se debería evitar hacer la operación exponente y se podría escribir de la siguiente forma (la
terminología de los bucles en Fortran se explica más adelante).

p = a(n)
do i .eq. n, 1, -1
p = p * x + a (n - 1)
end do

1.3. Bucles y condiciones


El bucle estándar en Fortran es do. Se le da un valor inicial a una variable Integer y se le
define el valor final. El código que se ejecuta en el bucle se debe finalizar con end do.

do i .eq. 1, 10, 2
x=x+i
end do

-8-
Andrés Zarabozo Martínez Métodos numéricos

Por defecto cada vez que se ejecuta el bucle se le suma uno a la variable (en el ejemplo i) pero
se puede cambiar el valor que se añade poniendo después del valor final una coma y el
sumando.

La función if ejecuta solo el código si se cumple la condición impuesta. Para poner condiciones
en Fortran se utiliza la siguiente sintaxis (abreviaciones del inglés):

- Mayor que: .gt.


- Menor que: .lt.
- Mayor o igual a: .ge.
- Menor o igual a: .le.
- Igual a: .eq.
- Diferente de: .ne.

Se puede complementar la función if utilizando las funciones else (si la condición del if no se
cumple se ejecuta el código que sigue al else) o elseif (parecido al else pero se le añade una
condición más para que se ejecute el código). Se pueden poner tantos elseif como se quieran
en un mismo conjunto de if. Se debe finalizar el código de esta función con endif.

if (a .gt. 2) then
b=1
else
b=0
end if

La función do while ejecuta repite el código hasta que la condición deje de cumplirse. El
código dentro del do while se ejecuta hasta que se finaliza (con end do) y vuelve a la línea del
principio para comprobar si se cumple aún la condición. Si se desea salir del bucle en algún
punto intermedio se puede utilizar la función exit.

do while (a .lt. 5)
a=a+1
end do

1.4. Vectores y matrices


Se usan los vectores y matrices para utilizar un solo nombre que refiera a un conjunto de
direcciones de memoria. Todos los datos almacenados en un vector o una matriz deben ser del
mismo tipo.

Para usar un vector o matriz (a partir de ahora solo se referirán a matrices ya que el
funcionamiento es casi el mismo) se debe primero decláralo. Se puede declarar de forma
estática o de forma dinámica. Si se declara de forma dinámica no se define la dimensión de la
matriz, mientras que si se define de forma estática si que se define la dimensión.

-9-
Andrés Zarabozo Martínez Métodos numéricos

Para declarar una matriz de forma estática se pone el tipo de las variables que almacena
seguido del nombre de la matriz y en paréntesis sus dimensiones, se utiliza una coma para
definir las distintas columnas de la matriz (el valor de la dimensión de cada columna debe ser
un integro).

real a(4,9)
integer b(2,n)

Para declarar una matriz de forma dinámica se debe utilizar el parámetro allocatable y utilizar
dos puntos para las columnas que no se quiere definir la dimensión. Una vez se decide dar un
valor a la dimensión se utiliza la función allocate.

real, allocatable : : a(4, :)


integer n

print*,"Dimensions of the matrix?"


read(*,*) n

allocate(a(:,n))

Una matriz creada de forma dinámica puede ser eliminada (para liberar espacio en la
memoria) con la función dellocate. Para saber si una matriz dinámica está creada o no en un
momento dado se puede usar la función intrínseca allocatable (la función devuelve un valor
booleano).

Las tablas se puede utilizar globalmente, referenciando un conjunto de elementos seguidos o


de forma individual. Si solo se indica el nombre de la matriz se referencia todos los elementos.

Para referenciar un valor específico se debe introducir la posición del valor de la matriz. Si se
quiere referenciar un rango se utiliza el doble punto para delimitar el rango.

real M(2,4), V(3)

V(2) = 1.
M(2,2:4) = V(2)

En el ejemplo anterior se introduce el valor de V(2) (es decir ) en los tres valores de la matriz
M (M(2,2), M(2,3), M(2,4)).

Las operaciones que se pueden hacer con matrices son:

 x * M: Multiplicación de cada elemento de una matriz M y un escalar x.


 x + M: Suma de cada elemento de una matriz M y un escalar x.
 M * M: Multiplicación de cada elemento por su homologo elemento entre dos
matrices de misma dimensión.

- 10 -
Andrés Zarabozo Martínez Métodos numéricos

 traspose(M): Transpuesta de una matriz.


 matmul(M,M): Multiplicación matricial entre dos matrices.
 dot_product(V,V): Producto escalar entre dos vectores.

Las matrices se almacenan en direcciones consecutivas de memoria. En el caso de un vector


los valores se almacena secuencialmente, empezando por el primero del vector V(1) hasta el
último valor V(n).

V(1) V(2) V(3) … V(n-1) V(n)

Figura 1.1. Orden de los valores de un vector en la memoria.

En el caso de matrices, los valores se almacenan por columnas. Por ejemplo si se tiene una
matriz M(2,2,2) el orden en la memoria es:

M(1,1,1) M(2,1,1) M(1,2,1) M(2,2,1) M(1,1,2) M(2,1,2) M(1,2,2) M(2,2,2)

Figura 1.2. Orden de los valores de una matriz en la memoria.

1.5. Subrutinas
Las subrutinas o subroutine son como funciones en otros lenguajes de programación. Se crea
una subrutina de la misma forma que el programa principal, con la única diferencia que se
deben poner las variables de referencia que se le quieren pasar a la subrutina.

Es recomendable definir al principio de la rutina si la variable es de entrada o de salida. De esta


forma el compilador puede informar de errores en el programa, si por ejemplo se le intenta
dar un valor a una variable de entrada.

En las subrutinas las variables se envían como referencia, es decir, se envía la dirección de
memoria de la variable. Si la variable es una matriz se envía la dirección del primer valor de la
matriz.

subroutine areaCircle(A, r)
implicit none
real, intent (in) :: r
real, intent (out) :: A

real, parameter :: pi = acos(-1)

A = pi * r * r
end subroutine

La subrutina de ejemplo calcula el área de un círculo. El valor de entrada es el radio y devuelve


el área. Para llamar a la subrutina se utiliza la función call.

real A1, r1
r1 = 3.
call areaCircle(A1, r1)

- 11 -
Andrés Zarabozo Martínez Métodos numéricos

1.6. Lectura y escritura de datos


Cuando se quiere trabajar con un archivo para leer o escribir datos se debe usar la función
open. Se le asigna un número de unidad al archivo abierto que es el identificador. Dentro de la
función se debe definir el archivo y el acceso. El acceso se puede definir por ejemplo como
secuencial, es decir, que cada vez que se escriba o se lea pasa a la siguiente línea. Para el
archivo se debe introducir la ruta completa o bien si el archivo está en la misma carpeta se
puede simplemente poner el nombre.

Para leer un archivo se debe utilizar la función read, seguido de una variable o matriz en
donde se quiera almacenar los datos de lectura. Para escribir se usa write seguido de las
variables o los datos que se quieren introducir.

Una vez se termina de usar el archivo es conveniente cerrarlo usando close.

open(unit = 1, file='fileData', access='SEQUENTIAL')


read(1,*) n
write(1,*) 2 * n
close(1)

- 12 -
Andrés Zarabozo Martínez Métodos numéricos

1.7. Programas

Programa 1. Mínimo error de un tipo de variable


El primer programa sirve de ejemplo para poder ver un poco como funcionan los programas
escritos en Fortran.

El objetivo es calcular el mínimo valor para un tipo de variable. Se utilizan variables real ya que
no tiene sentido hacerlo con integer (el error sería ). Se busca el menor número tal que
. En Fortran existe una función intrínseca que calcula lo mismo y que se llama
epsilon().

Como todo programa se debe empezar declarando el programa y las variables que se van a
utilizar. Se necesita al menos una variable donde se pueda almacenar el resultado deseado
(dándole un valor inicial) y también se necesita una variable para el bucle que se va a realizar.

program program1
implicit none
integer i

Small = 1.

end program

El bucle que se quiere realizar consiste en ir dividiendo por dos el valor de la variable small e ir
comprobando que se cumpla la ecuación . Se elige en este ejemplo un bucle tipo do
pese a que sería más lógico utilizar un bucle while, de esta forma se puede ver como funciona
también la condición if.

Dentro de cada iteración se debe comprobar que se cumpla la ecuación descrita, y si se cumple
se debe dividir el valor del resultado por dos. En caso de que no se cumpla la condición hay
que salir de bucle utilizando exit.

do i = 1, 1000
if (1. + small .gt. 1.) then
small = 0.5 * small
else
exit
end if
end do

El resultado aún no es exactamente el valor almacenado en small, el valor bueno es el


resultado multiplicado por dos. Para poder ver el valor en pantalla se usa la función print*,. Se
puede también utilizar la función epsilon(small) para poder comparar el resultado.

- 13 -
Andrés Zarabozo Martínez Métodos numéricos

small = 2 * small

print*, small
print*, epsilon(small)

Se puede cambiar el tipo de variable cuando se define esa, pudiendo probar con variables con
más precisión.

real*8 small8
real*16 small16

- 14 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 2. Cálculo del número π


Utilizando solo una cuerda de y un cuadrado de se puede calcular el número . Se
dibuja un cuarto de círculo de radio un metro dentro del cuadrado y se van lanzando bolas
sobre el cuadrado. Estadísticamente el número de bolas dentro de cada zona es proporcional
al área. El área de un cuarto de círculo es:

(1.2)

Siendo el número de bolas totales lanzadas y el número de bolas que caen en el cuarto de
círculo, la relación entre y es:


(1.3)

Por lo tanto el número es igual a:

(1.4)

Para obtener un número aleatorio se utiliza la función random_number(). De esta forma se


simboliza que se lanza una bola y aleatoriamente cae en una posición concreta del cuadrado.

Como en todos los programas lo primero que se hace es declarar el programa y las variables.
Para obtener mayor precisión se utilizan variables con double precision. Se necesitan cuatro
variables. Dos variables e para definir la posición donde cae la bola, se podría también
utilizar un vector. Y luego dos variables que definan el número de bolas totales y las que han
caído dentro de cuarto de círculo.

program program2
implicit none
real*8 x, y
integer*8 total, inside

total = 0
inside = 0

Se debe empezar el proceso iterativo mediante un bucle. Se muestra a continuación otra


forma de hacer bucles. Se utiliza la función continue y la función go to. La segunda debe
tener un número integro para que el compilador sepa a donde tiene que ir.

El primer paso del bucle es generar la posición aleatoria y sumarle un valor al número total de
bolas lanzadas.

Una vez se lanza la bola se debe comprobar si cae dentro del cuarto de círculo. Como el centro
del eje de coordenadas se define en el centro del circulo se debe cumplir que .

- 15 -
Andrés Zarabozo Martínez Métodos numéricos

Lo siguiente ya es calcular el valor de . Como las iteraciones se hacen muy rápido se puede
marcar que muestre el valor de cada cierto número de iteraciones. La función mod(x,y)
devuelve el resto de la división de íntegros.

Hay que acordarse de que siempre que se hace un cálculo con variables de diferentes tipos se
deben convertir al tipo de la variable que se está calculando. Esto puede evitar errores de
cálculos que no son detectados por el compilador. En este problema, como se han calculado
las variables con double precision se deben convertir con la función dble().

10 continue

!Ball thrown
call random_number(x)
call random_number(y)
total = total + 1

!Looks where the ball fell


if(x*x + y*y .lt. 1.) inside = inside + 1

!Shows the result every 1000 iterations


if (mod(total, 1000) .eq. 0) then
print*, total, 4. * dble(inside) / dble(total)
end if

go to 10

end program

Este programa tiene un bucle que nunca finaliza, hay que tener cuidado con este tipo de
bucles ya que, pese a que en este programa esto no afecta al resultado, en otro programa más
complicado puede meterse en un bucle infinito y no calcular nada. Con este tipo de bucles se
puede salir utilizando la función exit normalmente dentro de un if.

- 16 -
Andrés Zarabozo Martínez Métodos numéricos

2. Interpolación
2.1. SPLINE
En análisis numérico, un spline es una curva diferenciable definida en porciones mediante
polinomios. Esto es útil para poder generar curvas en funciones donde se tienen una serie de
puntos definidos o también para simplificar la función mediante tramos definidos como
polinomios.

El caso más sencillo de spline es el polinomio de primer orden, es decir, rectas que unan los
puntos. Éste genera curvas con puntas donde la pendiente no está definida en los puntos.
Cuanto mayor es el orden del polinomio de la aproximación, aparecen más oscilaciones,
generando curvas de peor calidad.

Figura 2.1. Aproximación de primer orden (recta)


y aproximación de un orden muy superior.

Se suelen usar polinomios de ordenes bajos, normalmente suelen ser de segundo o tercer
orden. En general se busca una curva que pase por los puntos definidos y que lo haga con la
misma pendiente que la función en los puntos. Esto se consigue con polinomios de tercer
orden.

Si lo único que se tiene es la distribución de puntos de la función se debe hacer una estimación
de la pendiente utilizando puntos de alrededor. Si la separación entre los puntos es uniforme
la pendiente de un punto se puede igualar a la pendiente de la recta entre los dos puntos
adyacentes.

𝑥𝑖− 𝑥𝑖 𝑥𝑖+

Figura 2.2. Aproximación de la pendiente mediante dos puntos adyacentes.

- 17 -
Andrés Zarabozo Martínez Métodos numéricos

Siendo la pendiente:

+ −
| ( ) (2.1)
+ −

Donde el error es ( ) y decrece de forma cuadrática con la disminución del intervalo entre
los puntos.

En el caso de estar en los puntos extremos, al faltar uno de los puntos, se aproxima la
pendiente con el propio punto. Por ejemplo si se está en el último punto no se tendría un
punto a la derecha y por lo tanto la pendiente sería:


| ( ) (2.2)

Se puede ver que el error ( ) ha aumentado considerablemente con esta aproximación.

2.2. Interpolación cúbica en un solo intervalo


Para encontrar la función interpolada de tercer orden en un intervalo, se hace primero un
cambio de variable. Teniendo una variable [ ] se transforma a una variable definida en
un intervalo unitario [ ]. El cambio de variable es simplemente:

(2.3)

Se usan polinomios de Hermite para encontrar la función interpolada. Se tienen cuatro


funciones básicas de Hermite, siendo la función interpolada una combinación lineal de estas
cuatro funciones.

Las funciones solo pueden empezar en o y deben acabar en o . Las en y


solo pueden ser o .

𝐻
𝐻
𝐻
𝐻4

Figura 2.3. Las cuatro funciones básicas de Hermite.

Se busca un polinomio que pase por dos puntos conocidos ( y ) y que además la pendiente
también coincida ( y ).

- 18 -
Andrés Zarabozo Martínez Métodos numéricos

El polinomio es por lo tanto:

( ) ( ) ( ) 4( ) (2.4)

El valor de las funciones básicas de Hermite se pueden calcular fácilmente ya que son
polinomios de tercer orden. Se calcula como ejemplo la cuarta función 4 . Esta función tiene
doble raíz en (ya que la pendiente en ese punto es ) y la tercera raíz en . A parte
se sabe que la pendiente en es . Por lo tanto la función tiene la siguiente forma, donde
es una constante que se debe calcular.

4 ( ) (2.5)

Como la pendiente en es , se puede obtener el valor de la constante.

4
| ( )| (2.6)

Por lo tanto el cuarto polinomio es:

4 ( ) (2.7)

Las demás funciones se obtienen de forma similar y son:

( )( ) ( ) ( ) (2.8)

Para el valor de la pendiente también se tiene que hacer el cambio de variable.

(2.9)

Sabiendo del cambio de variable que:

(2.10)

Por lo tanto:

( ) (2.11)

Finalmente la función interpolada es:

( )( ) ( ) ( )
(2.12)
( ) ( ) ( )

- 19 -
Andrés Zarabozo Martínez Métodos numéricos

2.3. Programa

Programa 3. Entrada de datos e interpolación


En este programa se ve un ejemplo de programa que puede leer y escribir en un archivo.
Además se utiliza en el programa una subrutina para hacer la interpolación.

El programa debe de ser capaz de leer un archivo con una serie de puntos de una función.
Pregunta cuantos puntos se quieren tener de salida y genera unos puntos utilizando la
interpolación cúbica. Los nuevos puntos calculados se escriben en un fichero de salida para
poder comparar la función de entrada y la de salida.

Se empieza escribiendo la subrutina. Se debe empezar definiendo las variables que se van a
usar. Esta subrutina calcula un valor de ( ) (yx) para una posición de (x). Para calcular la
función interpolada se necesitan los valores de la función en los extremos del tramo ( y ) y
las pendientes en esos puntos ( y ), se utiliza un vector de cuatro posiciones para guardar
estos valores (v1(4)). Además se necesita saber el valor del tramo y , se guardan también
en un vector (v2(2)).

subroutine hermite (v1, v2, x, yx)


implicit none
real, intent(in) :: v1(4), v2(2), x
real, intent(out) :: yx

Se tiene que hacer el cambio de variable de a definido por la ecuación (2.3).

real :: chi, span

span =v2(2) - v2(1)


chi = (x - v2(1)) / span

Se calcula ahora el valor ( ) con la formula de la interpolación descrita en la ecuación (2.12).


Se puede utilizar el carácter & al final de una línea para indicar que el código sigue como si no
hubiese un salto de línea, esto facilita la lectura del código y no afecta al programa.

yx = v1(1) * (1. + 2. * chi) * (1. - chi) * (1. - chi) + &


v1(2) * span * chi * (1. - chi) * (1. - chi) + &
v1(3) * chi * chi * (3. - 2. * chi) + &
v1(4) * span * chi * chi * (chi - 1.)

end subroutine

Se debe hacer ahora el programa principal que es el que lea los datos de entrada calcule los
nuevos valores y los escriba en un fichero.

- 20 -
Andrés Zarabozo Martínez Métodos numéricos

Lo primero que se debe hacer es definir las variables. Se usan vectores y matrices para guardar
los datos de entrada. Se define una matriz para guardar el valor de la función y el valor de su
derivada, y un vector para almacenar la posición en el eje . Como el programa no sabe aún
cuantos valores de la función se tienen (los debe leer del archivo) se deben definir estas
matrices como allocatable.

Como variables adicionales se definen el número de valores de entrada (n) y el número de


valores de salida (nExit). Además de estas variables se definen otras que ayudarán a la hora de
programar.

program program3
implicit none
real, allocatable :: ydy(:,:), x(:)
real xInt, yInt, step
integer n, i, nExit, last

Se debe leer el archive con los datos para saber la dimensión de las matrices. Se pone como
primer dato el número de valores de la función, y luego, en cada línea los valores de la función.

Se utiliza la función allocate para dar las dimensiones a las matrices.

open(unit = 1, file='initialData', access='SEQUENTIAL')


read(1,*) n
allocate(ydy(2,n), x(n))

do i = 1, n
read(1,*) x(i), ydy(1,i)
end do

close(1)

Como solo se tiene la información de los puntos y de la función en los puntos se debe
aproximar la derivada. Se utiliza la ecuación (2.2) para los puntos externos y la ecuación (3.1)
para el resto.

Una vez calculadas las derivadas se pide el número de puntos de salida.

ydy(2,1) = (ydy(1,2) - ydy(1,1)) / (x(2) - x(1))


do i = 2, n - 1
ydy(2,i) = (ydy(1, i+1) - ydy (1, i-1)) / (x(i+1) - x(i-1))
end do
ydy(2,n) = (ydy(1,n) - ydy(1,n-1)) / (x(n) - x(n-1))

print *, 'Introduce number of points:'


read(*,*) nExit

- 21 -
Andrés Zarabozo Martínez Métodos numéricos

Se iguala la variable xInt a x(1). La variable xInt es la posición de la función interpolada. Se


Calcula también el paso entre los puntos interpolados.

(2.13)

Como se va a empezar a escribir resultados se abre el archivo de resultados. El parámetro que


se le ha puesto en status genera un nuevo documento cada vez que se ejecuta el programa.
En caso de que el documento ya exista, borra el anterior y crea uno nuevo.

xInt = x(1)
step = (x(n) - x(1)) / real(nExit - 1)
open(unit=2, file='dataExit', access='SEQUENTIAL', status='REPLACE')

Se empieza ahora el bucle de cálculo. Cada vez que se hace una iteración se calcular los puntos
que forman el intervalo en el que xInt está.

last = 1

do i = 1, nExit
!Find interval
do while (xInt .gt. x(last+1))
last = last + 1
end do

Se llama a la subrutina para obtener el valor de yInt para el punto xInt. Una vez se obtiene el
valor, se escribe el resultado en el archivo. Finalmente antes de terminar el bucle se toma un
nuevo valor de xInt y se asegura que todos los valores iniciales de se han tomado.

call hermite(ydy(:,last:last+1), x(last:last+1), xInt, yInt)

write(2,*) xInt, yInt


xInt = xInt + step
xInt = min(xInt, x(n))
end do
close(2)

end program

Debido a que Fortran únicamente envía del vector la dirección de memoria del primer valor
asignado, se puede escribir la llamada de la subrutina de la siguiente manera.

call hermite(ydy(1,last), x(last), xInt, yInt)

- 22 -
Andrés Zarabozo Martínez Métodos numéricos

3. Integración
3.1. Fórmula de Newton-Cotes
Si se tiene una función ( ) con [ ], la integral se define según:

 Sean los elementos de área por debajo de la función donde


 Si es suficientemente grande tal que | | y la partición de los elementos es
regular, la integral entre y de ( ) es igual a un sumatorio de los elementos.

∫ ( ) ∑( − ) ( ) [ − ] (3.1)

Si la función está definida en un rango de valores de , podría haber problemas para obtener
los valores de ( ).

Una primera forma de calcular la integral es a través de la formula de Newton Cotes. Se puede
muestrear la función en una serie de puntos y extrapolar los puntos a funciones que se puedan
integrar como polinomios. Finalmente se hace la integral de los polinomios.

Como convenio, cuando se escogen los puntos de los intervalos para integrar, se escogen los
dos extremos y el resto se suelen coger de forma que el intervalo entre puntos es regular
(siendo muy cómodo que el intervalo sea igual).

Se considera una función como la que se ve en la Figura 3.1.

𝑓(𝑥)

𝑎 𝑏

𝑥 𝑥 𝑥 . 𝑥𝑛− 𝑥𝑛 𝑥

Figura 3.1. Función aleatoria dividida en intervalos.

Si los intervalos son iguales éste se puede calcular fácilmente con la posición de los extremos.

(3.2)

Teniendo el valor de ( ) para todos los puntos ( ) se calculan las funciones


polinómicas que aproximan a ( ) para cada intervalo. Esta aproximación polinómica puede

- 23 -
Andrés Zarabozo Martínez Métodos numéricos

ser del orden que se desee, pudiendo aproximar con rectas, parábola u otros.La integral es
entonces la integral de los polinomios (el conjunto se define como ).

∫ ( ) ∫ ( ) (3.3)

El polinomio se calcula mediante la interpolación polinómica de Lagrange. Para un intervalo


que empieza en , el polinomio interpolado en la forma de Lagrange es la siguiente
combinación lineal.

( ) (3.4)

Donde es la delta de Kronecker.

{ (3.5)

Por lo tanto el polinomio interpolado queda:

( )( ) ( − )( + ) ( )
( ) (3.6)
( )( ) ( − )( + ) ( )

Si es muy grande, el polinomio tiene muchas oscilaciones y puede variar mucho respecto a la
función inicial. Los valores típicos de son y . Al tener un pequeño, el polinomio de
Lagrange queda muy simplificado.

El error es la diferencia entre la integral que se quiere obtener y el valor obtenido.

∫ ( ) (3.7)

+
En general el error al interpolar una función en un polinomio de orden es del orden de .
Por lo tanto el error al integral es del orden de:

+ +
∫ (3.8)

Este error se denomina error simple ya que es el error de un solo intervalo. El error producido
por todos los intervalos se denomina el error compuesto.

+
∑∫ ( ) (3.9)
+( − )

+ +
∑ (3.10)

Como además se sabe que ( )⁄ , el error compuesto es por lo tanto del orden de:

( ) + (3.11)

- 24 -
Andrés Zarabozo Martínez Métodos numéricos

3.2. Regla del punto medio


La regla del punto medio establece que la función en los intervalos es constante, tomando solo
un punto del intervalo. Los intervalos se normalizan para que quede una función comprendida
entre y .

𝑓(𝑥)
𝑔(𝜉)

𝑥 𝜉
𝑎 𝑏

Figura 3.2. Normalización de la función.

Siendo:

∫ ( ) ∫ ( ) (3.12)

Se aproxima ( ) a una recta cuyo valor es ( ). La integral de esta función es por lo tanto:

∫ ( ) ∫ ( ) ( ) (3.13)
− −

Pese a que este caso sería el caso en que el error simple no es . Según el teorema de
Taylor, una función se puede aproximar como un polinomio de la siguiente forma:

( ) ( ) ( ) ( ) (3.14)

La aproximación que se usa en este caso es de orden ( ( ) ( )). Pero el segundo


término (que en teoría tendría que definir el error) es cero al integrarse, ya que es una función
antisimétrica entre y . Por lo tanto el error viene definido por el tercer término y es:

(3.15)

3.3. Regla del trapecio


Se aumenta el orden y ahora se toman dos puntos del intervalo en vez de uno. El polinomio
que aproxima el intervalo es por lo tanto una recta que pasa por los dos límites del intervalo.
Se vuelve a normalizar la función para que esté contenida entre y .

𝑔(𝜉)

𝑃(𝜉)
𝜉

Figura 3.3. Polinomio normalizado produciendo un trapecio en el intervalo.

- 25 -
Andrés Zarabozo Martínez Métodos numéricos

La integral del polinomio es igual al área del trapecio.

( ) ( )
( ) ( ) (3.16)

La integral completa es la suma de las integrales de los distintos intervalos.

( ) ( ) ( ) ( ) ( − ) ( )
(3.17)

Agrupando términos iguales se puede simplificar la expresión.



( ) ( )
∑ ( ) (3.18)

Se define el primer término de la ecuación anterior como .

( ) ( ) ( ) ( )
(3.19)

Al estar aproximando de forma lineal el error simple es un término de segundo orden que al
integrar se convierte en tercer orden. El error compuesto es de segundo orden. Los errores son
del mismo orden de magnitud que los de la regla del punto medio, pero no son iguales.

(3.20)

En general no basta con calcular una vez la integral para obtener un resultado válido. Se deben
probar distintos valores de intervalos para comprobar si el resultado converge. Para no tener
que calcular desde el principio cada vez. Es recomendable aprovechar los resultados obtenidos
en las anteriores integraciones y una forma de hacerlo es dividir por dos el valor del
intervalo , es decir poner un punto más en el centro de cada intervalo. De esta forma solo se
tienen que calcular la mitad de puntos.

Si se hace con este método se empezaría calculando la integral con un intervalo . El


resultado saldría de hacer el siguiente cálculo:

( ∑ ( )) (3.21)

Nunca se debe dar por válido el resultado de la primera integración y por lo tanto hay que
hacer una segunda. Se tiene ⁄ y por lo tanto , y además se define el
resultado del sumatorio de la primera integración.

− −

( ∑ ( )) ( ∑ ( )) (3.22)

Se ve fácilmente que solo es necesario hacer la mitad de los cálculos al solo tener que calcular
los intervalos con subíndice impar. De forma similar se pueden ir haciendo iteración y el
trabajo de cada iteración es el mismo.

- 26 -
Andrés Zarabozo Martínez Métodos numéricos

3.4. Regla de Simpson


En la regla de Simpson se extrapolan los intervalos en parábolas. Se toman tres puntos de cada
intervalo ( ), los puntos son los extremos y el punto central del intervalo. De forma similar
se centra a los estudios anteriores, se centra el intervalo en [ ].

𝑔(𝜉)

𝑃(𝜉)

Figura 3.4. Extrapolación parabólica utilizando tres puntos.

Para obtener el valor de la integral por del intervalo se puede usar el polinomio interpolante
de la ecuación (3.6), como se ha dicho antes el orden es .

( )( ) ( )( ) ( )( )
( ) ( ) ( )
( )( ) ( )( ) ( )( )

( ) ( ) ( ) (3.23)

Se integra el polinomio entre y .

∫ ( ) ( ) ( ) (3.24)

Para calcular la integral completa se deben sumar las integrales de todos los intervalos. En este
caso se toman grupos de tres puntos, y por el número de puntos (Figura 3.5) debe ser un
número par.

𝑓(𝑥)

𝑎 𝑏

𝑥 𝑥 𝑥 . 𝑥𝑛− 𝑥𝑛 𝑥

Figura 3.5. Límites de los intervalos de integración.

- 27 -
Andrés Zarabozo Martínez Métodos numéricos

La integral completa es por lo tanto (siendo como antes ( )⁄ ):

[ ( ) ( ) ( )] [ ( − ) ( − ) ( )] (3.25)

Si se agrupan los términos similares se obtiene:

[ ( ) ( ) ( ) ( − ) ( − ) ( )]

( ) ( )
( ∑ ( ) ∑ ( )) (3.26)

El cálculo del error es similar al de la regla del punto medio. Como es una regla cuadrática se
4
podría pensar que el error seria que viene de integrar . Pero es una función
antisimétrica y al integrarla entre y da cero. El error simple es por lo tanto y
4
el error compuesto es .

3.5. Extrapolación de Richardson


Se puede acelerar el cálculo numérico (aumentando por lo tanto el orden de convergencia)
con métodos como la extrapolación de Richardson. Permite a partir de un orden de
convergencia , tener una aproximación . Es preferible que sea .

Supongase que ( ) es una estimación de orden para:

( ) (3.27)

Al no poder hacer el límite infinito, se hace una aproximación de utilizando ( ).

( ) (3.28)

Donde son constantes desconocidas reales y son constantes conocidas tal que
.

Si solo se toma el primer término, la aproximación queda:

( ) +
( ) (3.29)

Dividiendo el paso por dos se escribe como función de ⁄ .

+ (3.30)
( ) ( ) ( )

Utilizando las ecuaciones (3.29) y (3.30) se elimina la constante desconocida .

( ) +
( ) ( ) ( ) (3.31)

( ) ( ) (3.32)
+
( )

- 28 -
Andrés Zarabozo Martínez Métodos numéricos

Con este proceso, se obtiene una mejor aproximación de eliminando el mayor término de
error que es ( ). Este proceso se puede repetir para eliminar términos de error para
obtener una mejor aproximación.

El problema es que no se suele saber el valor de . Se suele usar igual al orden de cuadratura
del método usado o hacer una aproximación del valor haciendo algunas iteraciones.

Se calcula la aproximación de para el intervalo ⁄ .

+ (3.33)
( ) ( ) ( )

Se elimina la constante desconocida utilizando la ecuación (3.30).

+
( ) ( ) ( ) ( ) (3.34)

Si está a punto de converger se podría decir que el hecho de dividir el intervalo por la mitad no
afecta al resultado.

( ) ( ) ( ) ( ) (3.35)

Pudiendo aislar :

( ( ) ( )) ( ) ( )

( ) ( )
( ) (3.36)
( ) ( )

- 29 -
Andrés Zarabozo Martínez Métodos numéricos

3.6. Programas

Programa 4. Obtención de la serie de Fourier


En este programa se quiere calcular los coeficientes de una serie de Fourier. Los coeficientes
de la serie de cosenos se obtienen utilizando la fórmula integral.

∫ ( ) ∫ ( ) ( ) (3.37)
− −

De forma similar se pueden obtener los coeficientes de la serie de senos.

∫ ( ) ( ) (3.38)

Una vez se tienen los coeficientes de la serie de cosenos y los coeficientes de la serie de senos
se pueden calcular la amplitud y el desfase.

√ ( ) (3.39)

Las integrales se hacen utilizando el método del trapecio. Se crea una subrutina que calcule la
integral de una función. A esta subrutina se le debe dar un vector y(n) donde se almacenen los
valores de la función.

subroutine trapice(y, b, z, n)
implicit none
integer, intent (in) :: n
real, intent (in) :: y(n), b
real, intent (out) :: z

z = 0.5 * (y(1) + y(n))+ sum(y(2:n-1))


z = z * b / (real(n) - 1.)

end subroutine

La subrutina fourier debe calcular las fases y las amplitudes. Debe ir llamando a la subrutina
trapice para calcular los coeficientes de la serie de cosenos y senos.

Los valores de las amplitudes y de las fases se almacenan en una matriz llamada
modes(2,0:m). Se le asigna un rango definido a la matriz (0:m) para mantener el convenio de
subíndices.

La variable n es el número de puntos seleccionados de la función para hacer las integrales. La


variable m es el número de términos de la serie de Fourier que se quieren calcular.

Se añaden además una serie de parámetros como pi o su inversa invPi. Como se sabe que se
va a dividir por bastantes veces es recomendable tener una variable que guarde su inversa y
así solo tener que hacer multiplicaciones.

- 30 -
Andrés Zarabozo Martínez Métodos numéricos

subroutine fourier (y, modes, n, m)


implicit none
integer, intent (in) :: n, m
real, intent (in) :: y(n)
real, intent (out) :: modes(2, 0:m)

integer i
real z(n), x(n), dx, invPi, a, b
real, parameter :: pi = acos(-1.)

invPi = 1. / pi

Se inicializa el vector de los puntos .

dx = 2. * pi / (real(n) - 1.)
x(1) = -pi

do i = 2, n
x(i) = x(i-1) + dx
end do

Se calculan ahora los coeficientes de las series y luego finalmente las amplitudes y fases. El
primer coeficiente se calcula fuera del bucle, este valor es ya la amplitud y no hay fase
porque no multiplica una función trigonométrica.

!First coeficient
call trapice(y, 2.*pi, a, n)
modes(1,0) = a * 0.5 * invPi

do i = 1, m
!Cos coeficients
z = y * cos(real(i) * x)
call trapice(z, 2.*pi, a, n)
a = a * invPi

!Sin coeficients
z = y * sin(real(i) * x)
call trapice(z, 2.*pi, b, n)
b = b * invPi

!Amplitudes and phases


modes(1,i) = sqrt(a*a + b*b)
modes(2,i) = -atan(b / a)
end do

end subroutine

- 31 -
Andrés Zarabozo Martínez Métodos numéricos

Finalmente se escribe la funcion principal del programa. Se utiliza una función de ejemplo que
ya está escrita con sus amplitudes y fases para poder comprobar si el programa funciona bien.
La función escogida es:

. ( . ) ( . ) (3.40)

El programa debe primero seleccionar una serie de puntos y calcular el valor de la función
almacenándolos en el vector y(n). El programa llama a la subrutina fourier que es la que se
encarga de devolver las amplitudes y fases.

program program4
implicit none
integer, parameter :: n = 300
integer i
real, parameter :: pi = acos(-1.)

real y(n), step, x, modes(2, 0:8)

x = -pi
step = 2. * pi / (real(n) - 1.)

!Discretization
do i = 1,n
y(i) = 0.5 + 3. * cos(2. * x + 0.75) + 1. * cos(6. * x + 0.25)
x = x + step
end do

!Amplitudes and phases


call fourier (y, modes, n, 8)
!Print results
do i = 0, 8
print* , modes(1,i), modes(2,i)
end do

end program

- 32 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 5. Iteraciones y extrapolación


En este programa se calcula la integral de una función mediante el método del trapecio pero
disminuyendo en cada iteración el tamaño del intervalo entre dos puntos.

Como ya se ha explicado en el tema 3.3, si se divide el intervalo en dos, en los puntos donde ya
se ha evaluado la función no hace falta volver a calcularlos y por lo tanto solo hay que hacer la
mitad de cálculos para cada iteración.

Para este programa se utilizan variables con double precision. Para ello las funciones
trigonométricas que se deben usar son dsin y dcos. En ambas se debe introducir una variable
de double precision. Para transformar el tipo de variable se usa la función dble.

Se crea una subrutina que calcula la función. La función de ejemplo es:

( ) (3.41)

subroutine evaluateFunction(x, y)
implicit none
real* 8, intent(in) :: x
real* 8, intent(out) :: y

y = dcos(5. * x) + 3. * x * x
end subroutine

El programa principal se encarga de ir evaluando la función y sumando esos valores a la


variable suma. Con ésta se puede calcular la integral en función del valor del intervalo de la
iteración.

Se inicializan los valores de las distintas variables y se evalúa la suma de los puntos extremos,
que si además se divide por dos se obtiene el coeficiente de la ecuación (3.19). El número de
intervalos viene definido por la variable n.

program program5
implicit none
integer :: i, j, n
real*8, parameter :: a = 0., b = 1.
real*8 suma, prevInteg, integ, h, sumEnds, aux, x

n = 10
h = (b - a) / dble(n)
suma = 0.

!Sum of limits divided by two


call evaluateFunction(a, aux)
sumEnds = aux
call evaluateFunction(b, aux)
sumEnds = (sumEnds + aux) * 0.5

- 33 -
Andrés Zarabozo Martínez Métodos numéricos

Lo siguiente es hacer el bucle iterativo. En cada iteración simplemente hay que sumar los
valores de la función a la variable suma. Se debe diferenciar la primera iteración de las demás
ya que en la primera hay que evaluar la función en todos los puntos y en las demás
simplemente hay que evaluarla cuando j (subíndice del punto ) sea impar.

do i = 1, 10
!Sum of the values of the function
if(i .eq. 1) then
x=a+h
do j = 1, (n - 1)
call evaluateFunction (x, aux)
suma = suma + aux
x=x+h
end do

else
x=a+h
do j = 1, (n - 1), 2
call evaluateFunction (x, aux)
suma = suma + aux
x=x+2*h
end do
end if

La integral se obtiene multiplicando la suma de todos los puntos (dividiendo por dos los
límites) y multiplicándolo por el intervalo, ecuación (3.18). Una vez obtenido el valor de la
integral se calcula el tamaño del intervalo y el número de intervalos para la próxima iteración.

!Integral
integ = h * (sumEnds + suma)

!Number of intervals and size of interval


n=2*n
h = 0.5 * h

Se sabe que el resultado analítico de la integral es:

∫ ( ( ) ) . (3.42)

El resultado que se imprime es la comparación del resultado calculado y el resultado analítico.

!Results
print*, integ - (.2 * dsin(dble(5.)) + 1.)

end program

- 34 -
Andrés Zarabozo Martínez Métodos numéricos

El programa ya está acabado. Si se ejecuta se puede ver como el error va disminuyendo a


medida que se van haciendo iteraciones. Si se aumenta el número de iteraciones (en este
programa se tiene que cambiar el último valor del bucle do) se puede ver que llega un punto
en el que el error vuelve a aumentar. Esto es debido a los errores de redondeo. En este
programa se necesita aumentar mucho el número de iteraciones porque se han utilizado
variables de mucha precisión justamente para evitar este problema.

Se puede extrapolar el resultado de la integral utilizando el método e extrapolación de


Richardson. El valor de la integral extrapolada se calcula utilizando la ecuación (3.32). Como se
usa el método del trapecio, el orden de convergencia es .

( ) ( ) ( ) ( ) (3.43)

El resultado de cada iteración se puede mostrar junto al resultado utilizando la extrapolación


de Richardson.

!Richardson extrapolation
if(i .eq. 1) then
print*,"No extrapolation", " With extrapolation"
analitical = .2 * dsin(dble(5.)) - 1.
else
aux = (4. * integ - prevInteg) / 3.
print*, integ - analitical, aux - analitical
end if
prevInteg = integ
end do

end program

- 35 -
Andrés Zarabozo Martínez Métodos numéricos

4. Resolución numérica de ecuaciones no lineales


4.1. Método de la bisección
Los métodos de resolución numérica de ecuaciones no lineales permiten la obtención de
resultados de para una función tal que ( ) . A la solución se le llama raíz o cero de la
función.

El primer método se basa en el teorema de Bolzano. Sea una función real continua en un
intervalo cerrado [ ] con ( ) y ( ) de signos contrarios. Entonces existe al menos un
punto del intervalo abierto ( ), con ( ) .

El teorema como tal no especifica el número de puntos, pero afirma que al menos existe uno.

El método consiste en ir tomando el punto medio ( ( )⁄ ) de un intervalo [ ] tal


que ( ) y ( ) de signos contrarios. Se forman dos tramos y se escoge el tramo tal que la
función en los límites sea de signo contrario. Si por ejemplo ( ) y ( ) se tienen
dos opciones:

( ) [ ]
{ (4.1)
( ) [ ]

El proceso se repite en cada iteración. La solución es:

(4.2)

Si no hubiese errores de redondeo al hacer infinitas iteraciones se obtendría el resultado.

̃ (4.3)

La velocidad con la cual la sucesión de iteraciones converge se llama orden de convergencia. Si


se tiene una secuencia ̃ que converge a un valor , se dice que la sucesión converge con
orden a .

|̃ + |
(4.4)
|̃ |

El número es llamado orden de convergencia, y en el caso del método de Bolzano . Es


por lo tanto un método muy lento.

En general no se puede calcular el orden de convergencia exacto, pero utilizando unas cuantas
iteraciones se puede estimar, aunque siempre considerando que a función converge.

4.2. Método de Newton - Raphson


El método de Newton - Raphson es un método con un orden de convergencia mucho mayor,
en general su orden de convergencia es .

- 36 -
Andrés Zarabozo Martínez Métodos numéricos

Para éste método se debe escoger un punto que se aproxime a la solución. La cercanía del
punto a la solución es importante para que el resultado converja. Se puede aproximar la
función en una recta en ese punto utilizando la serie de Taylor.

( ) ( ) ( ) ( ) ( ) (4.5)

Se busca el punto en el cual ( ) .

( ) ( ) ( ) (4.6)

( )
(4.7)
( )

𝑓(𝑥 )

𝑓(𝑥 )

𝑥 𝑥

Figura 4.1. Primera iteración del método de Newton-Raphson.

Se obtiene una regla de recurrencia y por lo tanto se pueden ir haciendo iteraciones hasta
obtener el resultado deseado. Además es una regla cuadrática ( ). Pero tiene algunos
problemas:

 Contiene la derivada de la función, y en ocasiones no es posible obtenerla si por


ejemplo no se tiene una expresión analítica de la función.
 Es un método abierto, la convergencia no está garantizada por un teorema de
convergencia global. El resultado depende del primer valor que se estima. Se pueden
por ejemplo tener problemas con máximos y mínimos.

4.3. Método de la secante


Con este método se evita el primer problema que tiene el método de Newton-Raphson. Se
aproxima la tangente mediante la secante que pasa por dos puntos. En este método se
necesitan dos puntos iniciales. La aproximación de la derivada es:

( ) ( )
( ) (4.8)

Y por lo tanto:

( ) (4.9)
( ) ( )

- 37 -
Andrés Zarabozo Martínez Métodos numéricos

𝑓(𝑥 )

𝑓(𝑥 )
𝑥
𝑥 𝑥 𝑥

𝑓(𝑥 )

Figura 4.2. Dos primeras iteraciones del método de la secante.

En este caso se gana en simplicidad y flexibilidad de ejecución pero se pierde en orden de


convergencia. Este método no es cuadrático pero su orden de convergencia suele ser entre .
y . , y por lo tanto no es tan rápido como el método de Newton-Raphson.

Este método tiene el mismo problema que el método de Newton-Raphson por lo que no se
puede asegurar la convergencia y ésta depende de los valores iniciales.

4.4. Método de regula falsi


El método de regula falsi o falsa posición es una combinación del método de la secante y el
método de la bisección. El orden de convergencia ronda la unidad (convergiendo más
lentamente que el método de la secante) pero éste método asegura la convergencia a
diferencia de por ejemplo el método de la secante.

Se debe empezar con dos valores iniciales tal que los signos de la función es esos puntos son
opuestos, garantizando que hay al menos una raíz en el interior del intervalo (teorema de
Bolzano). Se traza una recta entre los dos puntos y se calcula el cero de esta recta.

𝑓(𝑥 )

𝑓(𝑥 )

𝑥 𝑥
𝑥 𝑥

𝑓(𝑥 )
Figura 4.3. Dos primeras iteraciones del método regula falsi.

- 38 -
Andrés Zarabozo Martínez Métodos numéricos

Se calcula el punto a partir de los puntos y .

( ) ( )
(4.10)
( ) ( )

Una vez se obtiene el nuevo punto se calcula ( ) y se elige un nuevo intervalo que cumpla
que la raíz esté dentro de él. En el caso del ejemplo de la Figura 4.3 se toman los números y
, ya que ( ) ( ) . Se repite el proceso de forma iterativa.

Éste método puede resultar lento si por ejemplo se tiene una función como el de la Figura 4.4
y además no se puede asegurar que el resultado haya convergido correctamente (no se puede
asegurar que el error sea mayor de lo estimado). Esto es debido a que en esta función las
iteraciones avanzan solo en una dirección.

𝑓(𝑥 )
𝑓(𝑥 )

𝑥 𝑥
𝑥 𝑥

𝑓(𝑥 )

Figura 4.4. Dos primeras iteraciones.

4.5. Teorema del punto fijo


El último método de estudio consiste en obtener una ecuación del tipo ( ). Se resuelve
de forma iterativa utilizando un valor inicial + ( ).

Gráficamente este método consiste en encontrar el punto donde se cruza una función
y otra función ( ). Para ello se empieza con un valor , se calcula el valor de ( ) y se
busca del valor de que sea igual.

𝑓(𝑥 )

𝑓(𝑥 )

𝑥 𝑥 𝑥

Figura 4.5. Dos primeras iteraciones, convergiendo.

- 39 -
Andrés Zarabozo Martínez Métodos numéricos

Este método puede no converger. Para que converja se debe cumplir que en la solución
| ( )| . Si no se cumple la condición, la solución diverge alejándose en cada iteración de
la solución, como se puede ver en la Figura 4.6.

𝑥 𝑥 𝑥 𝑥

Figura 4.6. Tres primeras iteraciones, divergiendo.

- 40 -
Andrés Zarabozo Martínez Métodos numéricos

4.6. Programas

Programa 6. Deflexión de un cable


En muchas películas de superagentes como por ejemplo James Bond se suelen ver como
atraviesan una calle entre edificios solamente con un cable. Considerando que realmente
pueden clavar el cable en el edificio de en frente y que se mantiene sujeto, se quiere estudiar
si realmente el cable se mantiene rígido como muestran normalmente.

Se tiene una cable sujeto en los extremos entre dos paredes y aguantando un peso en el
centro, como muestra la Figura 4.7. El cable está caracterizado por sus propiedades y . En
general las cuerdas que se usan para estos casos se llaman cuerdas de piano y son bastante
rígidas. Está claro que en ningún caso estas cuerdas se pueden enrollar en un reloj o en el
cinturón.

𝐴 𝐵

𝑇 𝑇
𝑃

Figura 4.7. Diagrama del cable con un peso en el medio.

La tensión se relaciona con el peso del superagente utilizando el equilibrio de fuerzas


verticales, siendo el ángulo que forma el cable deflectado con la horizontal.

(4.11)

Suponiendo que la deformación es lineal la tensión del cable genera una pequeña
deformación .

(4.12)

La longitud del cable estirado se puede relacionar con la longitud inicial del cable .

(4.13)

Por lo tanto la deformación es:

(4.14)

Se juntan las ecuaciones (4.11), (4.12) y (4.14) se obtiene una relación entre el peso del
superagente y el ángulo .

( ) (4.15)

- 41 -
Andrés Zarabozo Martínez Métodos numéricos

Simplificando la ecuación un poco se obtiene la ecuación que se quiere resolver


numéricamente. En muchos problemas de física es bueno adimensionalizar las ecuaciones ya
que estas muestran en un parámetro la relación entre propiedades importantes del problema.
En este caso se relaciona el peso del superagente con la rigidez del cable.

(4.16)

Se debe hacer una aproximación del resultado para tener un valor inicial. Se puede considerar
que el ángulo es pequeño | | . Esto no implica que y ya que la
ecuación ⁄ no tiene sentido. El problema está en el coseno de la ecuación (4.15). Se
aproxima con un orden superior:

(4.17)

Además se puede incluso hacer otra aproximación para facilitar la resolución de la ecuación.

(4.18)

Por lo tanto la solución aproximada es:

√ (4.19)

Se utiliza el método de la secante para resolver la ecuación. Se puede aproximar el resultado


utilizando un número cercano de la aproximación obtenida, por ejemplo . .

Se toman los siguientes valores de las propiedades del cable y del superagente:
− (4.20)

Lo primero que hay que hacer en este programa es calcular los valores iniciales. Además se
⁄ −
crea una variable . .

program Program6
implicit none
integer i, j, n
integer, parameter :: itMax = 7
real, parameter :: k = 0.25E-3
real x1, x2, x3, fx1, fx2, slope

x1 = (2. * k)**(1./3.)
x2 = 1.1 * x1

Se empieza ahora el bucle iterativo. En este se debe evaluar la función en el último valor
calculado de (para el código es x2). Como el primer valor (el primer x1) solo se tiene que
calcular una vez éste se calcula justo antes de iniciar el bucle.

- 42 -
Andrés Zarabozo Martínez Métodos numéricos

Como protección se pone una salida del bucle en caso de que x1 sea igual a x2. Este caso
significaría que ya se tiene la solución y se evita además hacer cálculos con divisiones por cero.

fx1 = k + sin(x1) - tan(x1)


print*, 'x= ', x1, 'f(x) = ', fx1

do i = 1, itMax
if (x1.eq.x2) exit

fx2 = k + sin(x2) - tan (x2)

print*, 'x = ', x2, 'f(x) = ',fx2

Para hacer la nueva iteración se calcula la pendiente utilizando los dos resultados anteriores y
se usa la ecuación (4.9) para calcular el nuevo valor x3. Una vez calculado se vuelven a
establecer las variables x1 y x2.

slope = (fx2 - fx1) / (x2 - x1)


x3 = x2 - fx2 / slope

x1 = x2
x2 = x3

fx1 = fx2
end do

end program

- 43 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 7. Resolución mediante Newton-Raphson


Se resuelve la misma ecuación mediante el método de Newton-Raphson. En este caso no se
necesitan tener dos valores iniciales pero sí que se necesita la derivada de la función.

( ) (4.21)

Como se utilizan varias veces las funciones trigonométricas se puede optimizar el programa
creando dos variables cosx y sinx que calculen solo una vez por iteración la función
trigonométrica.

program Program7
implicit none
integer i, j, n
integer, parameter :: itMax = 7
real, parameter :: k = 0.25E-3
real x1, x2, fx1, slope, cosx, sinx

x1 = (2. * k)**(1./3.)

do i = 1, itMax

cosx = cos(x1)
sinx = sin(x1)

fx1 = k + sinx - sinx / cosx


slope = cosx - 1. / (cosx * cosx)

print*, 'x = ', x1, 'f(x) = ', fx1

if (fx1 .eq. 0) exit

x2 = x1 - fx1 / slope

x1 = x2
end do

end program

- 44 -
Andrés Zarabozo Martínez Métodos numéricos

5. Resolución numérica de sistemas lineales


5.1. Método de eliminación de Gauss
El método de eliminación de Gauss es un algoritmo de álgebra lineal para determinar
soluciones de un sistema de ecuaciones lineales.

Se obtienen las soluciones del sistema lineal mediante la reducción del sistema dado a otro
equivalente en el que cada ecuación tiene una incógnita menos que la anterior.

Se transforma la matriz del sistema de ecuaciones en una matriz triangular superior.


Obteniendo la solución de la última incógnita y pudiendo ir hacia atrás resolviendo las demás
incógnitas del sistema.

(5.1)

( ){ } { }

A un sistema de ecuaciones lineal se le pueden hacer una serie de operaciones llamadas


elementales.

a. Multiplicar una ecuación por un escalar no nulo.


b. Intercambiar de posición dos ecuaciones.
c. Sumar a una ecuación un múltiplo de otra.

En el caso del sistema matricial, estás se traducen en:

a. Multiplicar una fila de la matriz y la fila del vector solución ( ) por un escalar.
b. Intercambiar dos columnas de la matriz y dos filas del vector incógnitas.
c. Sumar los términos de una fila a otra de la matriz y del vector solución.

Para poder obtener la matriz triangular se debe, para cada fila:

 Se debe ir a la columna que empiece a partir de la diagonal .


 Si éste valor es nulo se debe cambiar la columna por otra que esté a la derecha y que
tenga un valor no nulo. Si coincide que se está en la última fila con todos los valores
nulos, el sistema es indeterminado.
 Se deben obtener ceros por debajo de sumando múltiplos adecuados de la fila
superior a las filas de debajo.

Una vez obtenida la matriz triangular se pueden ir obteniendo los calores de las resultados
partiendo del último.

El buen resultado de este método depende de la calidad de la matriz, que está relacionado con
el radio espectral de la matriz, definido por el supremo de entre los valores absolutos de los
elementos de su espectro.

- 45 -
Andrés Zarabozo Martínez Métodos numéricos

5.2. Matrices mal condicionadas


Existen varias formas de definir una matriz mal condicionada. Una matriz de un sistema de
ecuaciones lineales ( ) está mal condicionada si, por ejemplo, pequeños errores o
variaciones en los elementos de o tienen un gran efecto en la solución exacta de .

Otra forma de definirlo de forma sencilla es que una matriz está mal condiciona si el
determinante es anormalmente pequeño. Se puede comparar con la norma de la matriz ‖ ‖,
estando mal condicionada si | | ‖ ‖. La norma de la matriz (RMS) se puede calcular como:

‖ ‖ √∑ ∑ (5.2)

Como ejemplo se define el siguiente sistema de ecuaciones siguiente, donde :

{ (5.3)
( )
No se puede despreciar ya que si se hiciese el sistema no tendría solución (el determinante
es nulo). Se utiliza el método de eliminación de Gauss.

{ (5.4)

La solución del sistema es por lo tanto:

( ) (5.5)

Se puede ver que tanto la solución de como la de depende mucho del valor de . Un
problema de redondeo del programa podría arruinar el resultado. Se puede comprobar que el
determinante es mucho más pequeño que la norma.

| | ‖ ‖ √ ( ) √ (5.6)

Cuando se tiene una matriz mal condicionada se debe evitar que los valores problemáticos
(números muy pequeños) estén en la diagonal. Se debe por lo tanto reordenar la matriz en
caso de tener ese problema. Si se quiere ser riguroso en la reordenación de la matriz se debe
conseguir una matriz lo más parecido a una matriz diagonal dominante.

Se debe calcular un parámetro de calidad en todas las filas (desde la fila del pívot hasta la
fila n). Éste es el cociente entre el valor de la columna y los elementos de la fila.

| | (5.7)
(| |)

Donde viene dado por el elemento de la columna ( [ ] donde es la posición del pívot)
y viene dado por [ ].

- 46 -
Andrés Zarabozo Martínez Métodos numéricos

Para garantizar que la matriz esté bien condicionada se cambia la fila del pívot por aquella fila
que tenga mayor.

Otro método menos riguroso consiste en buscar el máximo valor de los elementos de la
columna por debajo del pívot y cambiar la fila por la del pívot. Aunque de esta forma no se
garantiza que no haya números muy grandes en el resto de la fila.

5.3. Descomposición LU
La descomposición LU (donde LU viene de las siglas inglesas Lower-Upper) es una forma de
factorización de una matriz como el producto de una matriz triangular inferior y una superior.
Esto puede ser útil cuando se debe resolver varios sistemas de ecuaciones donde la matriz
no varía y lo que varía es el vector . Un ejemplo sería tener una estructura y se deben calcular
varios estados de carga distintos.

(5.8)

( ) ( )

En este libro se estudian dos métodos de descomposición LU. Ambos dependen de qué matriz
( o ) tenga unos en su diagonal. El método Doolittle introduce unos en la matriz ( )
y el método Crout tiene los unos en la matriz ( ).

Una vez se tienen las matrices y se resuelve el sistema y luego . Como y


son diagonales, no hace falta hacer el método de Gauss para obtener la solución.

( ) (5.9)

5.4. Doolittle
En el siguiente ejemplo se puede ver como haciendo el método Doolittle es análogo a hacer el
método de Gauss. Se empieza con las dos matrices y de ejemplo.

4
(5.10)
4

( 4 4 4 ) ( 44 )

4 4
(5.11)
4 4 4

( 4 4 4 4 4 4 4 4 4 4 4 4 44 )

En los elementos de la matriz aparecen las operaciones que se hacen al utilizar el método de
eliminación de Gauss.

- 47 -
Andrés Zarabozo Martínez Métodos numéricos

Para obtener las matrices con el método Doolittle se hacen las operaciones similares a la
triangulación de Gauss. Se triangula la matriz dejando en los ceros el multiplicador.

Como ejemplo se parte de la siguiente matriz :

( ) (5.12)

Se empieza con el pívot de la primera columna. En los elementos y se deja el valor del
multiplicador (valores encuadrados).

( ) (5.13)

Se hace lo mismo para el siguiente pívot.

( ) (5.14)

Por lo tanto las matrices y son:

( ) ( ) (5.15)

5.5. Crout
De forma similar al método Doolittle se multiplican dos matrices y genéricas para ver la
forma de la matriz .

( ) ( 4) (5.16)
4
4 4 4 44

4 4
(5.17)
4 4 4

( 4 4 4 4 4 4 4 4 4 4 4 4 4 44 )

De la primera columna se pueden sacar las variables y utilizando la primera fila se pueden
obtener las variables . Se reduce el tamaño de la matriz para obtener los demás valores.

4 4

( 4 4 4 ) (5.18)
4 4 4 4 4 4 4 4 4 4 4 4 44

- 48 -
Andrés Zarabozo Martínez Métodos numéricos

De forma similar en la primera columna se pueden obtener las variables , ya que los
productos a los que suman estas variables contienen valores conocidos. De la primera fila se
resuelven las variables utilizando los valores conocidos. Se vuelve a reducir la matriz.

4 4 4
( ) (5.19)
4 4 4 4 4 4 4 4 4 4 44

Se pueden resolver y 4 y luego 4 . Este proceso se va repitiendo con cada submatriz


utilizando la primera columna para obtener las variables y la primera fila para obtener las
variables .

De forma general si se tiene la siguiente matriz modificada para ir obteniendo los valores de
y de (hasta el pívot ):

(5.20)

( )

Los valores (donde son los elementos de la columna a partir de ) se obtienen de la


siguiente forma:

∑ (5.21)

Los valores de (donde son los elementos de la fila por detrás de ) se obtienen de la
siguiente forma:

( ∑ ) (5.22)

5.6. Matrices dispersas


Una matriz dispersa es una matriz donde la mayor parte de los elementos son ceros. Existen
métodos para agilizar la resolución de sistemas de ecuaciones disminuyendo la carga
computacional y el tamaño consumido en memoria para almacenar todos los valores.

 Almacenamiento Skyline

Se generan vectores en cada fila de la matriz dispersa tomando desde el primero hasta el
último elemento no nulo de cada fila. Es posible que hayan ceros entre los elementos
seleccionados. Por ejemplo, se quiere almacenar la siguiente matriz:

(5.23)

( )

- 49 -
Andrés Zarabozo Martínez Métodos numéricos

Los cuatro vectores que se forman son:

{ } { } { } { } { } (5.24)

Se escriben todos estos valores en un vector contiguo. De esta forma se almacenan solo
elementos de los que tiene la matriz.

Para saber como están ordenados los valores del vector se necesitan dos vectores punteros. El
vector indica la posición del primer valor no nulo de la fila y el vector indica la cantidad de
valores que hay en esa fila.

(5.25)

{ } { }

Alternativamente en vez del vector se puede utilizar otro vector donde se define a partir de
que posición del vector empieza la siguiente fila.

(5.26)

{ }

Si por ejemplo que se quiere recuperar la tercera fila se va al vector o . Estos vectores
indican que se tienen tres elementos y que empiezan a partir de la quinta posición del vector
de valores. Además gracias al vector se sabe que los valores empiezan a partir de la tercera
columna. Por lo tanto:

( ) (5.27)

 Compress Space Row

En este método solo se almacenan los elementos no nulos. En el caso de tener algún cero en la
diagonal también se tendría que almacenar. De forma similar al método anterior se utilizan
tres vectores donde el primero es para almacenar los valores de las matrices. Además se utiliza
un vector que indica la posición de la columna del elemento y un vector que indica en que
posición del vector de valores se encuentra el salto de línea.

Utilizando la matriz de ejemplo de la ecuación (5.23) se definen los tres vectores:

( )
( ) (5.28)
( )

En el vector puntero se puede introducir un valor adicional que define la posición de la fila
siguiente del valor que ya no existiría en . No es necesario pero se hace por comodidad.

- 50 -
Andrés Zarabozo Martínez Métodos numéricos

Si por ejemplo se quiere recuperar la tercera fila de se iría primero al vector puntero que
indica que en la tercera fila aparecen los valores y del vector ( y ). Utilizando el
vector se sabe que estos valores están en las columnas y respectivamente. Por lo tanto:

( ) (5.29)

 Matriz banda

Una matriz banda es una matriz donde los valores no nulos son confinados en un entorno de la
diagonal principal. Se forma una banda de valores no nulos que completan la diagonal
principal y algunas diagonales en cada uno de sus costados.

El ancho de banda de la matriz es el número de columnas de elementos no nulos en las filas


centrales. Por ejemplo una matriz con un ancho de banda de sería:

4
(5.30)
4 44 4

4
( )

No es necesario almacenar todos los ceros de la matriz, se pueden guardar, por ejemplo, los
datos de la matriz anterior en una matriz reducida .

(5.31)

4
( )

El ancho de la matriz reducida es igual al ancho de banda y la columna central contiene los
elementos de la diagonal principal.

5.7. Método del gradiente conjugado


El método del gradiente conjugado es un algoritmo para resolver numéricamente sistemas de
ecuaciones lineales cuyas matrices son simétricas y definidas positivas.

Una matriz definida positiva es una matriz tal que para cualquier vector de elementos no
nulos cumpla .

Se utiliza ̃ para definir la aproximación de la solución real . Si se cumplen las condiciones de


la ecuación (5.32) entonces también se cumple la ecuación (5.33).

̃ (5.32)

- 51 -
Andrés Zarabozo Martínez Métodos numéricos

( ̃) ̃ ̃ ̃ (5.33)

Por lo tanto ( ) es el mínimo de esa función, es decir:

( ̃) ( ) ̃ (5.34)

Utilizando notación indicial se puede demostrar la afirmación anterior.

( ̃) ̃ ̃ ̃ (5.35)

Derivando la expresión respecto a ̃ .

( ̃ ̃ ) (5.36)
̃

Debido a que la matriz es simétrica los términos dentro de los paréntesis son iguales.

̃ (5.37)
̃

El extremo coincide con la solución del sistema .

La aproximación ̃ es igual a la solución del sistema más un error:

̃ (5.38)

Por lo tanto y recordando que ( ) :

( ) ( ) ( ) ( )

( ) ( ) (5.39)


⏟ ⏟
( − )
( )

Se llega a la conclusión que siempre que se introduzca la solución aproximada el valor de es


mayor, por lo que la solución real coincide con el mínimo.

Por lo tanto encontrando el mínimo se obtiene la solución real. El método del descenso
máximo elige la dirección más rápida de descenso para aproximarse a la solución. Si se hace
eso en cada iteración al final se llega al mínimo.

Se llama al error de la iteración . También se define el residuo . El


objetivo es que tanto como sean cero. Según la ecuación (5.37) se puede ver que el
gradiente de la función es el residuo.

(5.40)

- 52 -
Andrés Zarabozo Martínez Métodos numéricos

Se puede también relacionar el residuo con el error.

(5.41)

La matriz representa la matriz de transformación lineal entre el error y el residuo .

Empezando con una aproximación lineal la siguiente aproximación + se obtiende


moviéndose en dirección del gradiente y en sentido opuesto.

+ (5.42)

Se debe obtener el mínimo siguiendo la dirección del movimiento.

+
(5.43)

Utilizando la regla de la cadena queda:

+ + +
+ + (5.44)
+

Se busca que el residuo de la siguiente iteración sea cero, por lo tanto:

( + )

[ ( )]

( ) ( )

(5.45)

Para reducir el número de operaciones se deben evitar los productos de matriz por vector. A
partir de la ecuación (5.42) se tiene:

+ ( )

+ (5.46)

El nuevo residuo se puede obtener a partir del anterior y la operación no se tiene que
repetir. El proceso iterativo básico se puede ver esquematizado en la Figura 5.1.

𝑟𝑖𝑇 𝑟𝑖 𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑟𝑖
𝑥𝑖 𝑟𝑖 𝛼𝑖
𝑟𝑖𝑇 𝐴𝑟𝑖 𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖

Figura 5.1. Esquema iterativo básico del método.

- 53 -
Andrés Zarabozo Martínez Métodos numéricos

Este esquema permite obtener una solución rápida si las curvas de nivel son más o menos
circulares. Si tienen forma de elipses alargadas, el esquema puede tardar mucho en obtener la
solución del sistema.

Para aproximarse mejor a la solución se debe buscar una dirección ortogonal a todas las
direcciones anteriores, asegurándose así que solo se pasa una vez por la misma dirección.
Estando por ejemplo en la primera iteración, la nueva aproximación es:

(5.47)

El error en la dirección de ortogonalidad es nulo ( ). Si esto se cumple en todas las


iteraciones:

+ ( + )

( )

( ) (5.48)

Pudiendo obtener la constante .

(5.49)

El problema es que el error depende de la solución pero esta no se conoce. Se debe por lo
tanto utilizar el residuo en vez del error. Se debe aplicar la transformación del error por el
residuo en un espacio cuya métrica sea:

⃗ ⃗ (5.50)

También hay que asegurarse de que las direcciones son ortogonales entre sí.

(5.51)

El número de direcciones que se pueden tener es igual a la dimensión del sistema. ). De esta
forma se asegura que un sistema de ecuaciones se obtiene la solución exacta en
iteraciones (sin tener en cuenta errores de redondeo).

Se puede obtener la constante para la primera iteración de la siguiente forma:

( )

(5.52)

Siendo la nueva aproximación .

La secuencia de los vectores ( ̅ ̅ ̅ ) no se calcula desde el principio si no que se van


calculando a medida que se hacen las iteración. En el caso de la primera iteración este vector
es simplemente:

(5.53)

- 54 -
Andrés Zarabozo Martínez Métodos numéricos

Para la siguiente iteración se debe conseguir que sea ortogonal a . Se elimina la


componente en la dirección para asegurarlo.

(5.54)

Donde es una constante y se obtiene utilizando la condición de ortogonalidad.

( )

(5.55)

Por lo tanto es:

(5.56)

Para las siguientes direcciones se debe asegurar que son ortogonales a las anteriores es decir:

− − (5.57)

Pero mediante una demostración que no se va a realizar en este libro se puede llegar a la
conclusión que todos las constantes son cero para . Pudiendo utilizar la
ecuación (5.56) para obtener el valor de .

El esquema iterativo se presenta en la Figura 5.2.

𝑟𝑖𝑇 𝐴𝑑𝑖− 𝑑𝑖𝑇 𝑟𝑖


𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑇 𝑑𝑖 𝑟𝑖 𝛽𝑖 𝑑𝑖− 𝛼𝑖
𝑑𝑖− 𝐴𝑑𝑖− 𝑑𝑖𝑇 𝐴𝑑𝑖

𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑑𝑖
𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖

Figura 5.2. Esquema iterativo del método.

Aprovechando la ortogonalidad de las derivadas de búsqueda se puede reescribir el esquema


anterior de forma que solo sea necesario un producto de matriz por vector. El siguiente
esquema es el más utilizado ya que se reducen el número de productos de matriz necesarios.

𝑟𝑖𝑇 𝑟𝑖 𝑟𝑖𝑇 𝑟𝑖
𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑇 𝑑𝑖 𝑟𝑖 𝛽𝑖 𝑑𝑖− 𝛼𝑖
𝑟𝑖− 𝑟𝑖− 𝑑𝑖𝑇 𝐴𝑑𝑖

𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑑𝑖
𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑑𝑖

Figura 5.3. Esquema iterativo más utilizado del método.

- 55 -
Andrés Zarabozo Martínez Métodos numéricos

5.8. Ejemplo de aplicación del método del gradiente conjugado


Como ejemplo se considera el siguiente sistema:

[ ]{ } { } (5.58)

Se toma como aproximación inicial:

{ } (5.59)

Lo primero que se tiene que calcular es el residuo inicial.

{ } [ ]{ } { } (5.60)

Al ser los valores iniciales el residuo es igual a .

{ } (5.61)

Lo siguiente que se calcula es la dirección de la primera iteración .

{ }{ }
(5.62)
{ }[ ]{ }

Por lo tanto la solución al hacer una iteración es:

{ } { } { } (5.63)

Y se calcula el nuevo residuo.

{ } [ ]{ } { } (5.64)

Al hacer la nueva iteración se calcula la constante .

{ }{ }
(5.65)
− − { }{ }

Se calcula y .

{ } { } { } (5.66)

- 56 -
Andrés Zarabozo Martínez Métodos numéricos

{ }{ }
(5.67)
4{ }[ ]{ }

Finalmente se calcula , como la dimensión del sistema es dos y esta es la segunda iteración,
el resultado es el exacto (ya que no se ha redondeado ningún resultado anterior).

{ } { } { } (5.68)

- 57 -
Andrés Zarabozo Martínez Métodos numéricos

5.9. Programas

Programa 1. Resolución de un sistema mediante Gauss


El programa debe resolver un sistema lineal, considerando que la matriz está bien
condicionada. Se crea una subrutina que resuelve el sistema.

Se deben crear dos variables integer para los bucles do. Como convenio el elemento de la
diagonal a la que se le quiere hacer ceros por debajo se llama pívot. Se crea otra variable mult
donde se almacena el multiplicador de cada fila.

subroutine solver(a, b, n)
implicit none

integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult

Se debe crear ahora la matriz diagonal. El primer bucle se encarga de ir cambiando la posición
del pívot y va desde la primera posición hasta la penúltima. El segundo bucle se encarga de ir
cambiando los valores de las filas de por debajo del pívot en ceros, por lo tanto éste bucle
empieza en la siguiente fila del pívot y acaba en la última fila.

!Triangulate the matrix


do pivot = 1, n-1
do row = pivot+1, n

Una vez dentro del segundo bucle se deben ir convirtiendo los elementos de la columna en
ceros. Primero se calcula el multiplicador que es igual al elemento de la fila dividido por
elemento de la diagonal.

Para utilizar el convenio de numeración que sigue Fortran se utiliza al nombrar elementos de la
matriz se utiliza el primer valor para la columna y el segundo para la fila, siendo el contrario de
lo que se suele usar, por lo que se deberá enviar a la subrutina la función transpuesta.

Seguido, a la fila dada se le resta la fila del pívot multiplicada por el multiplicador. Esto solo se
hace para los elementos que estén una columna por detrás de la del pívot, no es necesario
modificar los elementos por debajo del pívot ya que se sabe que esa operación da cero (y no
es necesario poner esos ceros). Se hace la misma operación para el vector .

do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot)
a(pivot+1:n,row) = a(pivot+1:n,row) - mult * a(pivot+1:n,pivot)
b(row) = b(row) - mult * b(pivot)
end do

- 58 -
Andrés Zarabozo Martínez Métodos numéricos

Una vez se tiene la matriz triangular se pueden obtener las soluciones. La primera solución es
trivial de obtener. En este programa el propio vector se va modificando para ir introduciendo
las soluciones.

!Obtain solutions
b(n) = b(n) / a(n,n)

Se debe hacer un bucle para obtener las demás soluciones. Se parte de la penúltima fila y se
llega hasta la primera (restando uno al valor de la fila en cada iteración). En cada iteración del
bucle se obtiene un nuevo resultado.

Una vez triangulada la matriz, el sistema queda de la siguiente forma:

( − ) ( − )

( − )( − ) ( − )( − ) ( − ) − − (5.69)
( − )( − ) ( − ) − −
( ){ } { }

Si por ejemplo se quiere obtener la antepenúltima solución lo primero que se hace es aislar la
variable que se quiere encontrar ( ( − )( − ) − ). Para ello se pasa del otro lado los
términos de la matriz multiplicando a las soluciones ya conocidas (en este caso − y ).
Por lo tanto la ecuación queda:

( − )( − ) − − ( − )( − ) − ( − ) (5.70)

La operación ( − )( − ) − ( − ) equivale a hacer el producto escalar de los


elementos de la fila que estén por detrás del pívot y de los elementos del vector solución por
debajo de la fila del pívot.

Una vez se obtiene el resultado de la parte de la derecha de la ecuación (5.70) simplemente se


divide por ( − )( − ) para obtener la solución.

do row=n-1,1,-1
b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n))
b(row) = b(row) / a(row,row)
end do
end subroutine

El programa principal debe inicializar la matriz y el vector y comprobar que la subrutina


funciona correctamente.

La subrutina solo funciona correctamente si la matriz está bien condicionada. Tanto la matriz
como el vector se generan con números aleatorios. Los valores que no estén en la diagonal
que se generen estarán comprendidos entre . y . y los elementos de la diagonal siempre

- 59 -
Andrés Zarabozo Martínez Métodos numéricos

serán como mínimo igual al número de filas de la matriz por lo que la suma de los elementos
fuera de la diagonal siempre serán menor que los de la diagonal (en cada fila).

program program8
implicit none
integer, parameter :: n = 20
integer i, j
real :: a(n,n), aTrans(n,n), b(n), x(n), rand

!Initialize matrix and vector


do i = 1, n
do j = 1, n
call random_number(rand)
a(i,j) = 0.5 - rand
end do
a(i,i) = (1. + rand) * real(n)
call random_number(rand)
b(i) = rand
end do

Se resuelve ahora el sistema. Como ya se dijo antes, en la subrutina se utiliza el convenio de


estructura del fortran por lo que se debe hacer la transpuesta de la matriz para que coincida
que el primer índice de la matriz sea la columna.

Como la solución del sistema en la subrutina se escribe directamente en se debe enviar el


vector pero con los valores del vector b.

!Solve system
aTrans = transpose(a)
x=b
call solver(aTrans, x, n)

Para comprobar que el programa funciona bien se calcula . Esto en teoría tiene que dar
un vector nulo. Se imprime el máximo valor absoluto de ese vector (dando el error más
grande) y se comprueba que el valor sea prácticamente cero.

La función Matmul multiplica las matrices según el convenio matemático, primer índice filas y
segundo índice columnas.

!Errors
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number: ', maxval(abs(x))
end program

Nota, la subrutina modifica tanto la matriz como el vector que se envía. El vector es ya la
solución (que se ha almacenado en ) pero la matriz queda triangulada. Por suerte en vez de
enviar la matriz se ha enviado la matriz aTrans.

- 60 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 2. Sistema con matriz mal condicionada


En este programa se trabaja con una matriz mal condicionada. Se debe por lo tanto
reorganizar los elementos de la matriz para obtener un buen resultado. En modificar las filas
de la matriz y del vector se utiliza un vector llamado puntero donde se almacena la
posición de las filas. Por ejemplo, se tiene una matriz y un vector de puntero que
inicialmente son:

( ) { } (5.71)

Si se quiere cambiar la primera fila por la tercera simplemente hay que cambiar el valor del
vector puntero, dejando la matriz y el vector de la siguiente forma:

( ) { } (5.72)

Así se sabe que en la primera fila de la matriz están situados los elementos de la tercera fila
de la matriz , aunque la matriz no exista.

De forma similar al programa anterior se crea una subrutina que resuelve el sistema. En este
caso se crea además un vector puntero (point) y lo primero es inicializar los valores.

subroutine solveMatrix(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot, point(n), i, pos_row, posPiv
real :: mult, x(n)

!Initialize point vector


do row=1,n
point(row)=row
end do

Para reorganizar la matriz se utiliza un método menos riguroso que consiste en poner el
número más grande que haya por debajo del pívot. Esto no garantiza que la matriz esté
perfectamente condicionada pero es más rápido.

do pivot = 1, n-1
!Organize matrix
mult = 0.
do row = pivot,
if (abs(a(pivot,point(row))) .GT. mult) then
i = row
mult = abs(a(pivot,point(row)))
end if
end do

- 61 -
Andrés Zarabozo Martínez Métodos numéricos

Se tiene ahora la posición de la fila que se quiere cambiar por la del pívot. Se debe por lo
tanto intercambiar en el puntero el valor de estas dos filas.

row = point(pivot)
point(pivot) = point(i)
point(i) = row

Se utiliza la variable posPiv sirve para guardar la posición del pívot y no tener que utilizar
todo el rato point(pivot).

posPiv = point(pivot)

La parte del código que triangula la matriz es similar a la del programa anterior. Hay que tener
cuidado en seleccionar bien la fila ya que ésta puede haber sido cambiada por otra.

!Make zeros under Pivot


do row = pivot+1, n
posRow = point(row)
mult = a(pivot, posRow) / a(pivot,posPiv)
a(pivot+1:n,posRow) = a(pivot+1:n,posRow) - mult * a(pivot+1:n,posPiv)
b(posRow) = b(posRow) - mult * b(posPiv)
end do

end do

De forma similar, el código que obtiene los resultados se tiene que modificar para que
seleccione bien las filas que se deben usar.

!Obtain Results
x(n) = b(point(n)) / a(n,point(n))
do row = n-1,1,-1
posRow = point(row)
x(row) = b(posRow) - dot_product(a(row+1:n,posRow), x(row+1:n))
x(row) = x(row) / a(row,posRow)
end do

b=x

end subroutine

Se crea ahora el codigo del programa principal. El codigo es similar al del programa anterior. Se
tiene un generador de matrices que genera una matriz mal condicionada. Los valores de la
matriz fuera de la diagonal principal varían entre -0.5 y 0.5 y los de la diagonal son del orden

de .

- 62 -
Andrés Zarabozo Martínez Métodos numéricos

program program9
implicit none
integer, parameter :: size = 20
integer i, j
real :: a(size,size), aTrans(size,size), b(size), x(size), rand

!Generate matrix
do i = 1, size
do j = 1, size
call random_number(rand)
a(i,j) = 0.5 - rand !Number between -0.5 and 0.5
end do
a(i,i) = rand * 1.E-5 !Very small number for the diagonal
call random_number(rand)
b(i) = rand !Number between 0. and 1.
end do

El sistema resuelve las matrices con el convenio de numeración de matrices de Fortran (como
en el programa anterior). Se debe por lo tanto enviar la transpuesta de la matriz a la subrutina.

!Solve system
aTrans = transpose(a)
x=b
call solveMatrix(aTrans, x, size)

Se comprueba el resultado haciendo la operación y buscando el máximo valor


absoluto, que indica el mayor error.

!Check results
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

- 63 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 3. Doolitle
Para resolver un sistema utilizando el método Doolitle (con unos en la diagonal de la matriz )
el programa tiene que descomponer primero la matriz . El programa se escribe para poder
resolver una matriz bien condicionada.

Tanto la matriz como la matriz se pueden guardar en la misma matriz (en este caso
modificando la propia matriz . El código que consigue las dos matrices es muy similar al que
triangula la matriz en el Programa 1. La diferencia es que se introducen los valores de los
multiplicadores en los elementos que son nulos.

subroutine luDecomposition(a, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: a(n,n)
integer :: row, pivot
real :: mult
do pivot = 1, n-1
do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot
a(pivot+1:n,row) = a(pivot+1:n,row) &
- mult * a(pivot+1:n,pivot)
a(pivot,row) = mult
end do
end do
end subroutine

Se crea ahora una subrutina que resuelva el sistema utilizando las matrices y (almacenadas
en la matriz ). Se resuelve primer seguido de

subroutine luSustitution(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n)
real, intent(in) :: a(n,n)
integer :: row, i

!Ly = b
do row = 1, n
b(row) = b(row) &
- dot_product(a(1:row-1,row),b(1:row-1))
end do

!Ux = y
do row = n, 1, -1
b(row) = b(row) &
- dot_product(a(row+1:n,row),b(row+1:n))
b(row) = b(row) / a(row,row)
end do
end subroutine

- 64 -
Andrés Zarabozo Martínez Métodos numéricos

El programa principal es parecido a los anteriores programas que resuelven sistemas de


ecuaciones lineales. La matriz que se genera está bien condicionada. En este programa se debe
llamar primero a la subrutina que se encarga de generar las matrices y y luego se obtiene
el resultado del sistema.

program program10
implicit none
integer, parameter :: n = 50
integer i, j
real :: a(n,n), aTrans(n,n), b(n), x(n), rand

!Generate matrix
do i = 1, n
do j = 1, n
call random_number(rand)
a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5
end do
a(i,i) = 0.1 * (1. + rand) * real(n) ! Good matrix
call random_number(rand)
b(i) = rand ! A number between 0. and 1.
end do

!Solve system
aTrans = transpose(a)
x=b
call luDecomposition(aTrans, n)
call luSustitution(aTrans, x, n)

!Check results
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

- 65 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 4. Crout
En este programa se resuelve un sistema de ecuaciones lineales utilizando el método de
descomposición de Crout. De forma similar al programa anterior, primero se descompone la
matriz del sistema y luego se usa esa matriz para resolver el sistema.

La primera subrutina descompone la matriz. Se considera que la matriz está bien condicionada.
Se usa un bucle para ir moviendo el pivot e ir obteniendo los valores de las matrices y .

subroutine croutDescomp(a, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: a(n,n)
integer :: row, column, i

do i = 1, n

De forma general si se tiene la siguiente matriz modificada para ir obteniendo los valores de
y de (hasta el pívot ):

(5.73)

( )

Los valores (donde son los elementos de la columna a partir de ) se obtienen de la


siguiente forma:

∑ (5.74)

El sumatorio es análogo a hacer el producto escalar entre el vector que contiene los elementos
de de la fila a la izquierda del elemento en y el vector que contiene los elementos de por
encima del pívot.

!Obtain L
do row = i, n
a(row,i) = a(row,i) - dot_product(a(row,1:i-1),a(1:i-1,i))
end do

Los valores de (donde son los elementos de la fila por detrás de ) se obtienen de la
siguiente forma:

( ∑ ) (5.75)

- 66 -
Andrés Zarabozo Martínez Métodos numéricos

De forma similar, el sumatorio se traduce en el código en un producto escalar entre los


elementos a la izquierda del pívot y los elementos por encima del elemento en .

!Obtain U
do column = i + 1, n
a(i, column) = a(i, column) – dot_product(a(i,1:i-1),a(1:i-1,column))
a(i, column) = a(i, column) / a(i,i)
end do
end do
end subroutine

La segunda subrutina calcula la solución del sistema utilizando la matriz descompuesta de


Crout. Esta subrutina es muy parecida a la utilizada en el programa anterior. La diferencia con
Doolitle es que la matriz ya no tiene unos en la diagonal por lo que la división por los
elementos de la diagonal se hace en el primer sistema y en cambio la matriz sí que
tiene unos en la diagonal.

subroutine croutSust(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n)
real, intent(in) :: a(n,n)
integer :: row, i

!Ly = b
do row = 1, n
b(row) = b(row) - dot_product(a(row,1:row-1), b(1:row-1))
b(row) = b(row) / a(row,row)
end do

!Ux = y
do row = n, 1, -1
b(row) = b(row) - dot_product(a(row,row+1:n),b(row+1:n))
end do
end subroutine

El programa principal es parecido a los programas anteriores. Primero genera una matriz bien
condicionada, luego llama a las subrutinas que resuelven el sistema y finalmente calcula el
error.

La diferencia entre éste programa y los demás es que en éste no se hace la transpuesta de la
matriz. Se hace una copia de la matriz para poder luego calcular el error.

program program11
implicit none
integer, parameter :: size = 50
integer i, j
real :: a(size,size), aCopy(size,size), b(size), x(size), rand

- 67 -
Andrés Zarabozo Martínez Métodos numéricos

do i = 1, size
do j = 1, size
call random_number(rand)
a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5
end do
a(i,i) = 0.1 * (1. + rand) * real(size) ! Good matrix
call random_number(rand)
b(i) = rand ! A number between 0. and 1.
end do

aCopy = a
x=b

call croutDescomp(aCopy,size)
call croutSust(aCopy, x, size)

x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

- 68 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 5. Matriz banda


El objetivo del programa es implementar el método de eliminación de Gauss a una matriz
Banda, reduciendo el número de operaciones en los elementos que se saben que son nulos.

Se define la matriz del sistema como una matriz reducida a(-d:d,size). Siguiendo el convenio
de Fortran el primer índice indica las columnas y el segundo las filas. Los elementos de la
diagonal están situados en la columna y el ancho de banda de la matriz es .

La subrutina que resuelve el sistema es parecida a la del Programa 1, primero se triangula la


matriz del sistema y luego se obtienen los resultados.

Se tiene que tener mucho cuidado con las primeras y últimas filas, ya que éstas no tienen
tantos valores como el ancho de banda. Cada vez que se escribe un bucle o se define un vector
de fila se tiene que utilizar la función min() para que devuelva como mucho el número de
elementos del ancho de banda o si hay menos, el número de elementos disponibles.

Se toma por ejemplo una matriz con un ancho de banda de e un punto intermedio. El
subíndice indica la columna y el superíndice indica la fila, en el ejemplo se mira la matriz a
partir de la fila . Los elementos de la diagonal principal tienen como subíndice .


𝐴 𝐴 𝐴
𝑑 𝐴7− 𝐴7
𝐴7 𝐴7 (5.76)
𝐴8− 𝐴8− 𝐴8 𝐴8 𝐴8
𝐴− 𝐴− 𝐴 𝐴 𝐴
(⬚ )

Se puede ver que solo se necesitan modificar las filas que hay por debajo del pívot. Además
solo se pueden restar elementos de la fila del pívot a las demás filas.

subroutine gaussBand(a, b, d, n)
implicit none
integer, intent(in) :: d, n
real, intent(inout) :: a(-d:d,n), b(n)
integer pivot, row, disp
real mult

!Triangulate matrix
do pivot = 1, n - 1
do row = pivot + 1, min(pivot + d, n)

Como ya se ha dicho antes la función min(pivot + d, n) se utiliza para asegurarse de que el


programa no busca valores que están fuera de la matriz.

- 69 -
Andrés Zarabozo Martínez Métodos numéricos

Para triangular la matriz se tiene que tener cuidado en definir bien los rangos de los vectores.
La matriz reducida no está escrita en el programa como la matriz de la ecuación (5.76). Está
escrita de la siguiente forma:

7 7 7 7 (5.77)

8 8 8 8 8
− −
( )

A diferencia del Programa 1 los elementos que se eliminan no están debajo del pívot. En el
caso del ejemplo se deben eliminar los elementos 7− y 8− . Para ello se define la variable
disp que indica el número de filas que hay entre la fila y el pívot. Éste valor no puede superar
por lo que también es útil para poder definir rangos de columnas.

disp = row - pivot

mult = a(-disp,row) / a(0, pivot)


a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - &
mult * a(1:d,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

De forma similar, para resolver las variables, se tiene que tener cuidado de no salirse de los
rangos de la matriz (utilizando disp = min(d, n - row)) y de definir bien los rangos de los
vectores.

Una vez triangulada la matriz, se obtiene una matriz reducida donde se tienen ceros a la
izquierda de la columna central (que contiene los elementos de la diagonal principal).

7 7 7

8 8 8
(5.78)

− − −

− −

( )

Por lo tanto el producto escalar como mucho se hace utilizando un vector de dimensión que
siempre empieza a partir de la columna . En el caso de las últimas filas se debe tener cuidado
de no utilizar elementos que no existen.

Se utiliza la variable disp para obtener el número máximo de columnas que se tienen a la
derecha del pívot.

- 70 -
Andrés Zarabozo Martínez Métodos numéricos

!Solve x
do row = n, 1, -1
disp = min(d, n - row)
b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp))
b(row) = b(row) / a(0,row)
end do
end subroutine

El programa principal es parecido a los otros programas. Se define la matriz de forma


distinta ya que ésta no es una matriz cuadrada. Se genera la matriz de forma que esté bien
condicionada.

Program program12
implicit none
integer, parameter :: size = 50, d = 5
integer i, j, left, right
real :: a(-d:d,size), aCopy(-d:d,size), b(size), bCopy(size), x(size), rand

do i = 1, size
do j = -d, d
call random_number(rand)
a(j,i) = 0.5 - rand ! A number between -0.5 and 0.5
end do

a(0,i) = (1. + rand) * real(size) !Good matrix

call random_number(rand)
b(i) = rand !A number between 0. and 1.
end do

aCopy = a
x=b

!Solve
call gaussBand(aCopy, b, d, size)
bCopy = b

Como la matriz que se ha generado es la matriz reducida no se puede hacer directamente la


operación . Se debe hacer la operación para cada fila de la matriz .

!Check results
bCopy = b
do i = 1, size
left = min(d, i - 1)
right = min(d, size - i)
x(i) = dot_product(a(-left:right, i),bCopy(i-left:i+right)) - x(i)
end do
print *, 'If the code is correct this is a small number:', maxval(abs(x))
end program

- 71 -
Andrés Zarabozo Martínez Métodos numéricos

6. Resolución numérica de sistemas no lineales


6.1. Método de Newton para sistemas no lineales
Utilizando sistemas de elementos finitos se obtiene un sistema de ecuaciones que no tienen
por qué ser lineales. Se puede extender el método de Newton para resolver sistemas
multivariables.

Para que se pueda resolver el problema se necesitan tantas ecuaciones como incógnitas, que
cumplan que ⃗ ( ) donde ⃗ , y además unos valores iniciales .

( )
( )
( ) (6.1)

( )

El residuo es el valor que se obtiene al poner las soluciones en las funciones ⃗ ( ). Si es


la solución del sistema entonces es nulo.

De forma similar al método de Newton-Raphson, se utiliza una aproximación mediante series


de Taylor para aproximar linealmente ⃗ a .

⃗( ) ⃗( ) ⃗( ) ( ) (6.2)

La matriz de derivadas ⃗ ( ) se suele escribir como matriz . Por ejemplo en los problemas
de elementos finitos estructurales esta matriz es la matriz de rigidez. Los elementos de la
matriz son:

( ) ( ) ( )

( ) ( ) ( )
( ) | (6.3)
̅

( ) ( ) ( )
( )

Para calcularla se necesitan hacer muchas derivadas parciales y este es un proceso caro por lo
que existen métodos que buscan reducir al máximo el cálculo de esa matriz, por ejemplo, el
método de cuasi Newton.

El objetivo del método es encontrar la solución tal que ⃗ ( ) sea cero. Por lo tanto, volviendo
a la ecuación (6.2), se elige tal que:

( ) ( ) (6.4)

- 72 -
Andrés Zarabozo Martínez Métodos numéricos

Como la matriz es cuadrada se puede resolver el sistema, siempre que la matriz tenga
inversa.

− ⃗ (6.5)

En la práctica no se debe usar la inversa de la matriz ya que el cálculo es extremadamente


costoso. Se puede resolver la ecuación resolviendo primero un sistema de ecuaciones lineales.
Se define como . El sistema lineal que se resuelve es el siguiente:

(6.6)

Al obtener se puede resolver fácilmente la nueva iteración.

(6.7)

- 73 -
Andrés Zarabozo Martínez Métodos numéricos

7. Ecuaciones diferenciales, problemas de valor inicial


7.1. Tipos de ecuaciones diferenciales
Una ecuación diferencial es una ecuación en la que intervienen derivadas de una o más
funciones desconocidas. Resolviendo la ecuación diferencial se obtiene la función desconocida.

Dependiendo del número de variables independientes respecto de las que se deriva, las
ecuaciones diferenciales pueden ser:

 Ordinarias: aquellas que contienen derivadas respecto a una sola variable


independiente.
 Parciales: aquellas que contienen derivadas respecto a dos o más variables.

El orden de la derivada más alta en una ecuación diferencial se denomina orden de la


ecuación. En cambio el grado de la ecuación es la potencia de la derivada de mayor orden que
aparece en la ecuación, siempre y cuando la ecuación esté en forma polinómica, de no ser así
se considera que no tiene grado.

Las ecuaciones diferenciales que se estudian en este tema son problemas de valor inicial. Se
busca la solución numérica de una ecuación diferencial ordinaria de primer orden de la forma
( ) con una condición inicial ( ). Ecuaciones de órdenes superiores se pueden
transformar en sistemas de ecuaciones diferenciales de primer orden.

Un ejemplo típico de mecánica es la ecuación diferencial ̈ ( ), siendo una ecuación


diferencial ordinaria de segundo orden. Se busca la solución ( ), es decir, utilizando la
expresión de las fuerzas sobre una masa se busca la posición que va teniendo a lo largo del
tiempo.

7.2. Método de Euler


El método de Euler es un método para resolver ecuaciones diferenciales ordinarias a partir de
un valor inicial. Es el método más básico y explicito para resolver problemas de valor inicial.

Suponiendo que se quiere aproximar la solución del siguiente problema con un valor inicial:

( ) ( ( )) ( ) (7.1)

Se puede tomar un valor constante de cada intervalo .

+ (7.2)

Utilizando la aproximación de primer orden de la serie de Taylor, se puede obtener la


aproximación de un punto separado por .

̃+ ( ̃) ( ) (7.3)

Los valores ̃ son aproximaciones de la función en los puntos . El método de Euler es un


método explícito, es decir, la solución ̃ + es una función explícita de para .

- 74 -
Andrés Zarabozo Martínez Métodos numéricos

El error se propaga con cada intervalo y el error acumulado es del orden .

(7.4)

El error es por lo tanto de primer orden por lo que el método no es recomendable.

7.3. Ejemplo de resolución mediante el método de Euler.


Como ejemplo de resolución con este método se toman los siguientes valores:

( ) (7.5)

Se busca la aproximación utilizando el método de Euler para obtener ( ). Para empezar se


utiliza un intervalo igual uno.

El método se resuelve utilizando la ecuación (7.3). Por lo tanto para el tramo de inicio se debe
calcular ( ), en este caso ( ) .

( ) ( ) (7.6)

Con este paso se ha calculado la pendiente de la recta que pasa por el punto inicial y va hasta
el primer punto. El primer punto es por lo tanto:

( ) (7.7)

Se hace lo mismo para los siguientes tres puntos

(7.8)

{ 4

La solución exacta de esta EDO es . En la siguiente figura se comparan la solución real


(gris) con la aproximada (negro).

50
40
30
20
10
0
0 0.5 1 1.5 2 2.5 3 3.5 4

Figura 7.1. Solución real (gris) y solución aproximada (negro).

7.4. Método implícito de Euler


El método implícito de Euler o método hacia atrás de Euler es muy parecido al método de
Euler (que también se le llama método hacia adelante) pero difiere en que es un método

- 75 -
Andrés Zarabozo Martínez Métodos numéricos

implícito. Éste método es más estable que el anterior y permite utilizar intervalos mayores,
aunque como siempre, hay que tener cuidado con que no afecte a la calidad de la solución.

La diferencia ente los dos métodos es en aproximación de la pendiente ( ( ).

̃+ ( + ̃+ ) ( ) (7.9)

La nueva aproximación de ̃ + aparece en ambos lados de la ecuación y por lo tanto se tiene


que resolver una ecuación algebraica. Se puede por ejemplo el teorema del punto fijo para
resolverlo.

Se puede desarrollar la función en serie de Taylor pero hacer derivadas de la función es muy
costosos.

Este método también es de orden uno y el error es similar al del método de Euler.

7.5. Método de Heun


El método de Heun también es conocido como el método modificado de Euler. También es
similar al método de Runge-Kutta de dos pasos.

Se calcula primero el valor intermedio de ̃ + y luego el valor aproximado + en el siguiente


punto de integración. En este método se cambia la terminología ya que ̃ deja de ser el
resultado y pasa a ser una primera aproximación para luego calcular el resultado

̃+ ( ) + ( ( ) ( + ̃ + )) (7.10)

Este método utiliza el método de Euler para calcular una estimación de las coordenadas del
siguiente punto y, con este dato, se corrige la estimación original. Considerando que el valor
de ( ̃) en la parte derecha de la ecuación es la pendiente de la solución en el punto ( ),
esto se puede combinar con la estimación de Euler en el siguiente punto para dar la pendiente
de la línea tangente en el punto de la derecha ( ( ̃)). La solución es el punto intermedio
entre las dos soluciones.

𝑦
𝑦̃𝑖+ 𝑓(𝑥 𝑦𝑖 )

𝑓(𝑥𝑖+ 𝑦̃𝑖+ )

𝑥𝑖 𝑥𝑖 𝑥
Figura 7.2. Método de Heun de forma gráfica.

- 76 -
Andrés Zarabozo Martínez Métodos numéricos

7.6. Método de Runge-Kutta de segundo orden


El método de Runge-Kutta de segundo orden se basa en la aproximación de la serie de Taylor
de segundo orden.

( ) ( ) ( ) ( ) ( ) (7.11)

La primera derivada se sustituye por la ecuación diferencial ( ) ( ). La segunda


derivada se obtiene haciendo la derivada de la ecuación diferencial.

( ) ( ) ( ) ( )
( ) ( ) (7.12)

La expansión de Taylor se convierte en:

( ) ( )
( ) ( ) ( ( ) ) ( )
(7.13)
( ) ( )
( ) [( ) ( ) ] ( )

La expansión de Taylor para dos variables es:

( ) ( )
( ) ( ) (7.14)

Se puede ver que la expresión entre corchetes de la ecuación (7.12) se puede interpretar
como:

( ) ( )
( ( )) ( ) ( ) ( ) (7.15)

Obteniendo:

( ) ( ) ( ) ( ( )) ( ) (7.16)

Se puede escribir con la connotación numérica.

+ ( ) (7.17)

Donde

( ) ( ( )) (7.18)

Se puede ver que para el caso del método de Euler se tiene y .

La forma explícita general del método de segundo orden de Runge-Kutta asumiendo:

( ) ( ) [ ̅ ̅ ] ( ) (7.19)

Donde ̅ ( )y ̅ ( ( )).

- 77 -
Andrés Zarabozo Martínez Métodos numéricos

Está claro que esto es una generalización del método clásico de Runge-Kutta ya que los
coeficientes ⁄ y cumplen la ecuación (7.17). Estos coeficientes se
suelen ordenar en una tabla conocida como Butcher tableau, donde se ponen los vectores y
y la matriz de la siguiente forma.

Figura 7.3. Butcher tableau.

Para el método de Runge-Kutta de segundo orden la tabla queda de la siguiente forma.

Figura 7.4. Runge-Kutta de segundo orden.

7.7. Método de Runge-Kutta de órdenes superiores


Se puede aumentar el orden del método de Runge-Kutta aumentando los pasos que se hacen.

De forma similar a la ecuación (7.17) la solución general para orden viene dada por:

+ ∑ ( ) (7.20)

Donde

( )

( )

( ) (7.21)

( − −

Para cada método particular, se debe proveer con el íntegro (número de pasos) y los
coeficientes (para ), b (para ) y (para ). La
matriz se llama la matriz de Runge-Kutta, mientras que los vectores y son los pesos y los
nodos. Los valores se suelen escribir en el Butcher tableau.


Figura 7.5. Butcher tableau.

- 78 -
Andrés Zarabozo Martínez Métodos numéricos

Para que el método de Runge-Kutta sea consistente se debe cumplir que:


∑ (7.22)

El siguiente valor ( + ) se determina con el valor actual ( ) más la media ponderada de los
incrementos, donde cada incremento es el producto del tamaño del intervalo ( ) y una
pendiente estimada por la función en la parte derecha de la ecuación diferencial.

Pese que aumentar el orden del método de Runge-Kutta aumenta la precisión del resultado,
estimar la función suele ser muy caro, y un problema con un orden debe evaluar veces la
función. En general se suelen utilizar órdenes cercanos a o como compromiso entre
precisión y carga computacional.

Como ejemplo el problema de Runge-Kutta de orden viene dado por la siguiente ecuación:

+ ( 4) + (7.23)

Para que se cumpla que sea un valor promedio de la derivada se debe cumplir que la suma de
los valores que multiplican a los coeficientes sea igual a , en este caso se cumple.

Los coeficientes son:

( )

( )
(7.24)
( )

4 ( )

En este caso se tiene que:

 es el incremento basado en la pendiente al principio del intervalo, usando


(método de Euler).
 es el incremento basado en la pendiente en el punto medio del intervalo, usando
. .
 es también el incremento basado en la pendiente en el punto medio del intervalo,
usando . .
 4 es el incremento basado en la pendiente al final del intervalo usando .

Haciendo la media ponderada de estos cuatro incrementos se le da más importancia a los


incrementos en el punto medio del intervalo. Los pesos se escogen de manera que si es
independiente de , por lo que la ecuación diferencial es equivalente a una simple integral, el
método de cuarto orden es similar a la regla de Simpson.

Como su nombre lo indica este método es de cuarto orden por lo que el error entre intervalos
es del orden de y el error acumulado es del orden de 4 .

- 79 -
Andrés Zarabozo Martínez Métodos numéricos

7.8. Método adaptativo de Runge-Kutta


Este método es capaz de ir ajustando el intervalo . Zonas de la solución que tienen una forma
suave (la pendiente no cambia mucho) no requieren intervalos pequeños mientras que
zonas donde la pendiente cambia rápidamente sí que requieren intervalos pequeños ya que si
no la solución no sería buena.

Implementando este método en un programa se puede automatizar el proceso de selección


del intervalo y así agilizar el programa si necesidad de estropear la solución. Siempre se debe
mantener el error local dentro de unos márgenes.

Para avaluar el cambio de intervalo se calcula una estimación del error de truncamiento local
del método de Runge-Kutta de dos órdenes distintos.

Se pueden introducir los dos métodos en el Butcher tableau, uno de orden y otro de orden
. La tabla se representa de la siguiente manera.



Figura 7.6. Butcher tableau para el método adaptativo.

El paso de menor orden viene dado por:

+ ∑ (7.25)

Donde son los mismos que para el paso de mayor orden. Se comparan las soluciones dadas
por los dos pasos para calcular el error.

+ + + ∑( ) (7.26)

Este error es del orden ( ). Si el error está dentro de unos márgenes de precisión significa
que la solución del orden inferior es suficientemente buena (comparada con la de orden
superior) por lo que la curva es suave en ese punto, pudiendo incrementar el intervalo.

Como ejemplo, el método de Runge-Kutta adaptativo más simple es el que combina el método
de Heun (segundo orden) con el método de Euler (primer orden). La tabla extendida queda:

⁄ ⁄

Figura 7.7. Runge-Kutta adaptativo de menor orden.

- 80 -
Andrés Zarabozo Martínez Métodos numéricos

7.9. Esquema de Crank-Nicolson


El esquema de Crank-Nicolson es un método implícito. Viene dado por la siguiente ecuación:

( ) ( + )
+ (7.27)

Es un método muy estable pero también es muy sensible a perturbaciones

El esquema de Crank-Nicolson es un caso particular de la familia de esquemas que se obtienen


ponderando mediante un parámetro [ ] el peso dado a ( ) frente al dado a
( + + ) en la fórmula de integración numérica.

+ [( ) ( ) ( + )] (7.28)

En el caso del esquema de Crank-Nicolson dado por la ecuación (7.27) . . . Si se le da


más peso al segundo término se parece más el método de Euler hacia atrás y se vuelve más
estable. Por lo general estos métodos suelen tener [ . ].

7.10. Método de Runge-Kutta para EDOs de grados superiores


Cuando el orden de la ecuación diferencial es mayor que uno, se debe convertir la ecuación
diferencial en un sistema de ecuaciones diferenciales de primer orden. Si se tiene una ecuación
diferencial de la forma:

( ) (7.29)

Se debe escribir un sistema de ecuaciones diferenciales de la forma:


− (7.30)

Por ejemplo, si se quiere resolver un sistema de segundo orden de la forma:

( ) (7.31)

Se debe convertir la ecuación en un sistema de dos ecuaciones tal que:

(7.32)

El sistema de ecuaciones diferenciales queda:

( ) (7.33)

Para cada intervalo se calculan de forma separada el siguiente valor de la solución ( y ). Para
cada EDO se obtienen sus respectivos coeficientes .

Al ser una ecuación diferencial de segundo orden se deben tener dos condiciones iniciales:

( ) ( ) ( ) ( ) (7.34)

- 81 -
Andrés Zarabozo Martínez Métodos numéricos

8. Método de diferencias finitas


8.1. Diferencias finitas en una dimensión.
Una diferencia finita es una expresión matemática de la forma ( ) ( ). Si se
divide la diferencia finita por se obtiene el cociente diferencial.

Se puede discretizar un dominio en diferencias finitas, buscando en esos puntos las soluciones
aproximadas ( ) de un sistema de ecuaciones diferenciales. Se define una malla de una
dimensión como la de la Figura 8.1

𝜙𝑖− 𝜙𝑖− 𝜙𝑖 𝜙𝑖+ 𝜙𝑖+

Figura 8.1. Discretización del dominio en una dimensión.

La solución ( ) debe cumplir ( ) para .

Aunque la malla no sea uniforme normalmente se pueden hacer transformaciones. En el caso


de tener un dominio sin un orden definido y al que no se le puede aplicar una transformación,
las diferencias finitas no tienen sentido.

Se busca cambiar las ecuaciones diferenciales por un sistema de ecuaciones lineales donde
solo aparecen las soluciones aproximadas en los nodos. Para ello se deben obtener
aproximaciones de las derivadas en los nodos.

Se utiliza la serie de Taylor para aproximar la función en una zona dividida por diferencias
finitas. Se aproximan primero el punto y el punto .

( 4) (8.1)
+

( 4) (8.2)

Se resta la ecuación (8.2) a la ecuación (3.1) pero aproximadas hasta el segundo orden.

+ − ( ) (8.3)

Pudiendo obtener la aproximación de segundo orden de la derivada primera.

+ −
( ) (8.4)

Se puede obtener la segunda derivada de la función sumando las ecuaciones (3.1) y (8.2).

( 4)
+ −

+ −
( ) (8.5)

- 82 -
Andrés Zarabozo Martínez Métodos numéricos

En el caso de estar situados en los nodos extremos no se pueden aplicar estas ecuaciones. Se
podría utilizar la aproximación de primer orden de la primera derivada:

+
( ) (8.6)

Pero ésta no es una buena solución. La aproximación de un orden superior requiere tomar el
siguiente nodo. Utilizar el nodo puede provocar la necesidad de aumentar el ancho de
banda del sistema aumentando el número de operaciones. La aproximación de un punto más a
la derecha es:

+ ( ) (8.7)

Se utiliza multiplica la ecuación (3.1) por cuatro y se le resta la ecuación (8.7).

+ + ( )

+ +
( ) (8.8)

Para el caso de la derivada por la izquierda la metodología es la misma.

− −
( ) (8.9)

En general los valores de las derivadas por la izquierda son los mismos que los de la derecha
pero si la derivada es impar se deben cambiar los signos (como en el caso de la primera
derivada en las ecuaciones (8.8) y (8.9)).

Se puede aumentar el orden de aproximación Taylor para obtener expresiones para derivadas
de mayor orden. El problema de aumentar el orden de aproximación de Taylor es que se
necesitan funciones muy suaves. Si por ejemplo se resuelven las ecuaciones de Euler, que
admiten discontinuidades (ondas de choque), y se utiliza un esquema de alto orden, la
solución muestra unas oscilaciones en la presión y densidad que no reflejan la realidad.

Para problemas térmicos donde las funciones suelen ser suaves se puede usar un orden alto.
Existen métodos llamados espectrales que cada nodo toma información de todo el dominio.
Pero si la geometría es complicada tampoco se pueden usar órdenes altos.

8.2. Diferencias finitas en dos dimensiones


El caso bidimensional es parecido al anterior pero esta vez el mallado se hace en dos
direcciones. En general se suele definir un mallado uniforme, con forma rectangular, como el
de la Figura 8.2. El intervalo en las dos direcciones puede ser diferente.

Aunque la geometría del problema no sea rectangular se pueden hacer transformaciones del
mallado. Para geometrías complejas se utilizan volúmenes estructurados para dividir el
dominio en distintos bloques donde aplicar diferencias finitas. El código escrito por Onera para
problemas aerodinámicos (ELSA) utiliza volúmenes finitos estructurados.

- 83 -
Andrés Zarabozo Martínez Métodos numéricos

𝑦
( 𝑚) ( 𝑚) (𝑛 𝑚)

( ) ( ) (𝑛 )

𝑦
( ) ( ) (𝑛 )
𝑥
𝑥

Figura 8.2. Discretización en dos dimensiones.

Las derivadas parciales que solo sean en una dirección son las obtenidas para el caso
unidimensional. Por ejemplo la derivada primera en la dirección es:

+ −
( ) (8.10)

La derivada cruzada de segundo orden se obtiene utilizando las series de Taylor. Se hace la
derivada en dos pasos:

( ) ( )
+ −
| ( ) (8.11)

[ ]
Se hace ahora la derivada en la dirección .

| [ + + + − − + − − ] ( ) (8.12)

En general se suelen guardar todos los nodos en un solo vector en vez de una matriz ya que se
necesita resolver un sistema de ecuaciones del tipo . El valor de la posición en el
vector es:

( ) (8.13)

8.3. Ejemplo de problema mecánico


En una película llamada “Total Recall” se muestra un innovativo método de transporte para ir
desde Inglaterra hasta Australia. El método consiste en hacer caer un ascensor por un túnel a
través del centro de la tierra aprovechándose únicamente de la gravedad. Empezando sin
ningún tipo de velocidad ni de empuje adicional más que la gravedad, el viaje dura 17 minutos.

Para comprobar si lo que se muestra la película es correcto se hacen las siguientes


suposiciones:

- La masa de la tierra se distribuye de forma uniforme dentro de una esfera de


. El parámetro gravitacional de la tierra es ⁄ .
- El túnel es una línea recta que pasa por el centro de la tierra.

- 84 -
Andrés Zarabozo Martínez Métodos numéricos

- La única fuerza externa actuando en el cuerpo a parte de la gravedad es la fricción


aerodinámica. Se puede computar como . . Se podría incluso asumir
que la densidad del aire en el túnel se mantiene constante e igual a la densidad del
aire a nivel del mar.
- Se ignoran las fuerzas centrífugas debidas a la rotación de la tierra y la aceleración de
Coriolis.

Visto que por lógica la única forma que el ascensor llegue al otro lado en el caso de haber
fricción aerodinámica se debe tener una velocidad inicial nula. Este problema se puede
resolver analíticamente si se considera que no hay fuerzas externas aparte de la gravedad,
pudiendo llegar de un lado al otro de la tierra empezando con velocidad nula.

Utilizando la formulación adimensional explicada más adelante se puede obtener la solución


analítica para el caso de empezar con velocidad nula y sin fricción:

̃( ̃ ) ( ̃) (8.14)

Siendo esta solución el caso más favorable, el tiempo que tardaría en recorrer toda la tierra
sería de unos minutos. Se empieza a ver que los guionistas no se han molestado por
investigar un poco de física antes de inventar sus mundos de ficción.

Debido a que los minutos de caída libre no pueden conseguirse empezando sin velocidad
inicial, el objetivo del problema es calcular la velocidad inicial que se necesitaría para poder
llegar en 17 minutos al otro lado de la tierra.

 Ecuación del movimiento

Lo primero que se debe hacer es obtener la ecuación que gobierna el problema. La ecuación
del movimiento se basa en la segunda ley de Newton.

∑ (8.15)

Hay dos fuerzas presentes en el ascensor: la gravedad y la fricción aerodinámica.

(8.16)

La fricción se puede simplificar utilizando la siguiente expresión:

( ) (8.17)

Considerando la densidad de la tierra constante en todo el túnel. La masa que ejerce una
fuerza sobre el ascensor, en una posición desde el centro de la tierra es:

(8.18)

- 85 -
Andrés Zarabozo Martínez Métodos numéricos

La fuerza de gravedad en esa posición es:

(8.19)

El origen se ha puesto en el centro de la tierra y el inicio del movimiento en . La


ecuación diferencial que gobierna el movimiento es finalmente:

[ ] ( ) [ ] (8.20)

 Ecuación adimensional

En general es recomendable adimensionar las ecuaciones antes de resolverlas. En la ecuación


anterior hay dos parámetros que se deben adimensionalizar: la posición y el tiempo .

La posición se adimensionaliza con el radio de la tierra y para el tiempo se define un tiempo de


referencia el cual se le puede dar un valor más tarde.

̃ ̃ (8.21)

(̃ ) (̃ )
[ ] [ ] [ ] (̃ ) (8.22)
(̃ ) (̃ )

La ecuación anterior se divide por ⁄ para que todos los sumandos sean
adimensionales.

̃ ̃
[ ] ( ) [ ] ̃ (8.23)
̃ ̃

Para simplifica la ecuación anterior se puede elegir un valor de de forma que ̃ no esté
multiplicado por ningún coeficiente.

(8.24)

La ecuación adimensionalizada queda:

̃ ̃
[ ] ( ) ̃ (8.25)
̃ ̃

 Discretización

La ecuación diferencial se discretiza utilizando diferencias finitas. Para el caso de la derivada


segunda, ésta se discretiza para los nodos desde hasta de la siguiente forma:

̃ ̃+ ̃ ̃−
( ) (8.26)
̃

- 86 -
Andrés Zarabozo Martínez Métodos numéricos

Para el caso de la primera derivada, la discretización queda:

̃ ̃+ ̃−
( ) (8.27)
̃

Introduciendo estas dos ecuaciones en la ecuación (8.25) se obtiene la ecuación del problema
discretizada.

̃+ ̃ ̃− ̃+ ̃−
[ ] ( ) ̃ (8.28)

Para simplificar la ecuación anterior se nombra el término constante de la fricción como un


coeficiente .

(8.29)

̃+ ̃ ̃− ̃+ ̃−
( ) ̃ (8.30)

Las condiciones de contorno son la posición conocida en los extremos.

̃ ̃ (8.31)

El sistema de ecuaciones se puede expresar mediante un vector de ecuaciones.

̃
̃ ̃ ̃ ̃ ̃
( ) ̃

( ̃) ̃+ ̃ ̃− ̃+ ̃− (8.32)
( ) ̃

[ ̃ ]

El sistema de ecuaciones anterior no es lineal por lo se debe utilizar el método de Newton para
sistemas no lineales para resolverlo. La matriz de derivadas para este sistema es:

(̃ ̃ ) (̃ ̃ )

(8.33)
(̃ + ̃− ) (̃ + ̃− )

[ ]

Para obtener el resultado de cada iteración se debe resolver un sistema lineal y una suma
vectorial.
+
̃ ̃ (8.34)

- 87 -
Andrés Zarabozo Martínez Métodos numéricos

El residuo inicial se obtiene introduciendo los valores iniciales en el sistema de ecuaciones.


Para el primer y último nodo el residuo es cero puesto que la solución es conocida.

̃ ̃ ̃ ̃ ̃
( ) ̃

(8.35)
̃+ ̃ ̃− ̃+ ̃−
( ) ̃

[ ]

Los valores iniciales se pueden calcular obteniendo la solución analítica en el caso que no haya
fricción aerodinámica. La ecuación diferencial es una simple de segundo grado.

̃
̃ (8.36)
̃

La solución es de la siguiente forma, siendo y constantes.

̃( ̃ ) ̃ ̃ (8.37)

Como condiciones iniciales se puede utilizar la posición inicial y la posición final.

̃( ) (8.38)

̃
̃( ̃ ) (8.39)
̃

Siendo el tiempo final:

̃ ⁄ . (8.40)

El tiempo transcurrido entre cada nodo se define utilizando el tiempo total ( minutos) y el
número de nodos utilizados para la simulación

⁄ .
(8.41)

Por lo tanto los valores iniciales se estiman como:

̃
̃ ̃ ̃ ̃ ( ) (8.42)
̃

 Estimación del coeficiente de fricción

La contribución de la fricción aerodinámica viene dada por un coeficiente (definido en la


ecuación (8.29)) multiplicado por la velocidad al cuadrado. El parámetro se puede dividir el
coeficiente de fricción del aire (que se puede considerar del orden de magnitud 1) y el ratio
entre la masa de aire dentro del túnel y la masa del ascensor ⁄ . Si el aire es “respirable”
este número no puede ser pequeño conociendo el tamaño del túnel. En la película el ascensor

- 88 -
Andrés Zarabozo Martínez Métodos numéricos

parecía muy grande y para dar un poco de credibilidad a la película se podría considerar que
ese ratio es de orden de magnitud 1. Por lo tanto se define . .

 Velocidad inicial

La velocidad inicial se puede calcular utilizando la aproximación de segundo orden por la


derecha.

̃ ̃ ̃
̃ (8.43)

El programa escrito para resolver este problema se detalla en el siguiente apartado.

- 89 -
Andrés Zarabozo Martínez Métodos numéricos

8.4. Programas

Programa 6. Ejemplo de problema mecánico


El programa debe resolver un problema de diferencias finitas con un sistema no lineal. Al ser
un sistema no lineal se debe tener un bucle iterativo para ese sistema. Se puede también
poner un bucle mayor para hacer un estudio de convergencia de malla, cambiando el tamaño
de malla cada vez que obtenga una solución. La estructura del programa es la siguiente:

Iniciar variables

Generar matrices:
𝐾y𝑅

Resolver sistema lineal


𝐾 𝛿𝑥 𝑅

Obtener nueva solución


𝑥 𝑖+ 𝑥 𝑖 𝛿𝑥

Calcular velocidad inicial

¿Nueva iteración del


sistema no lineal?

Imprimir resultados

¿Nuevo tamaño
de malla?

Fin

Figura 8.3. Estructura del programa.

Para este programa se crean tres subrutinas: una para iniciar variables, otra para generar las
matrices y y la tercera para resolver el sistema lineal. Se describen primero las subrutinas.

- 90 -
Andrés Zarabozo Martínez Métodos numéricos

La primera subrutina genera el vector ̃ . Debido a que esta variable depende del tamaño de la
malla se tiene que hacer cada vez que se cambie el tamaño de ésta. Se utiliza la ecuación
(8.42) para obtener estos valores.

subroutine initialValues(x0, n, tref, h)


implicit none
integer, intent (in) :: n
real*8, intent(in) :: tref, h
real*8, intent (out) :: x0(n)

integer i
real*8 t, tn, kn

tn = 1020. / tref

kn = (1. + dcos(tn)) / dsin(tn)

x0(1) = -1.
do i = 2, n - 1
t = dble(i - 1) * h
x0(i) = - dcos(t) + kn * dsin(t)
end do
x0(n) = 1.
end subroutine

La segunda subrutina genera las matrices y . Se utilizan las ecuaciones (8.33) y (8.35) para
calcular las matrices.

subroutine writeSystem(K, R, x, n, tref, h, ka)


implicit none
integer, intent (in) :: n
real*8, intent (in) :: x(n), tref, h, ka
real*8, intent (out) :: K(3,n), R(n)

integer i
real*8 h2

h2 = 1. / (h * h)

!Write matrix K
K(2,1) = 1.
K(3,1) = 0.

do i = 2, n - 1
K(1,i) = h2 - ka * 2. * (x(i+1) - x(i-1)) * h2
K(2,i) = 1. - 2. * h2
K(3,i) = h2 + ka * 2. * (x(i+1) - x(i-1)) * h2
end do

K(1,n) = 0.
K(2,n) = 1.

- 91 -
Andrés Zarabozo Martínez Métodos numéricos

!Write vector R
R(1) = 0.
do i = 2, n - 1
R(i) = x(i) + (x(i+1) - 2. * x(i) + x(i-1)) * h2 + &
ka * (x(i+1) - x(i-1)) * (x(i+1) - x(i-
1)) * h2
end do
R(n) = 0.

end subroutine

La tercera subrutina es la que resuelve el sistema lineal. El sistema está compuesta por una
matriz banda de solo tres columnas por lo que es recomendable utilizar un solver que se
aproveche de esta condición.

subroutine gaussBand(a, b, d, n)
implicit none
integer, intent(in) :: d, n
real*8, intent(inout) :: a(-d:d,n), b(n)
integer pivot, row, disp
real*8 mult

!Triangulate matrix
do pivot = 1, n - 1
do row = pivot + 1, min(pivot + d, n)
disp = row - pivot
!Gauss
mult = a(-disp,row) / a(0, pivot)
a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - &
mult * a(1:d,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

!Solve x
do row = n, 1, -1

disp = min(d, n - row)


b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp))
b(row) = b(row) / a(0,row)
end do

end subroutine

La rutina principal se encarga de seguir el esquema de la Figura 8.3, llamando a las 3


subrutinas descritas.

Lo primero que debe hacer es definir las variables que se utilizaran. Se crean una serie de
variables de configuración del programa.

- 92 -
Andrés Zarabozo Martínez Métodos numéricos

- es la constante del termino de fricción, equivale a la k


- es el número de nodos de la primera malla
- es el número de veces que se cambia la malla
- es el número máximo de iteraciones para resolver cada malla
- es el valor máximo aceptable en el vector R

program finiteDifferences
implicit none
integer n, i, j, maxIt, maxLoop, kas
real*8, allocatable :: K(:,:), R(:), x(:)
real*8 v, v1, h, tref, ka, error

!Program configuration
ka = 0.5 !Constant in drag
n = 1000 !Initial number of nodes
maxLoop = 10 !Maximum number of times the program is runned
maxIt = 100 !Maximum iteration in Newton's method
error = 0.00001 !Maximum Error

tref = 6.371E6 * 6.371E6 * 6.371E6 / 3.986E14


tref = tref ** 0.5

El primer bucle es el que se encara de regenerar las mallas. Debe primero crear las matrices K,
R y x. Una vez ha generado esas matrices en memoria se llama a la subrutina que se encarga
de asignar los valores iniciales.

!Loop for number of nodes


do j = 1, maxLoop
allocate (K(3,n), R(n), x(n))

!Initial values for x


h = (1020. / tref) / dble(n - 1)
call initialValues(x, n, tref, h)
v = 0.

Seguidamente, se empiezan las iteraciones que resuelven el problema para la malla dada. El
bucle se termina o bien cuando llega al máximo de iteraciones o cuando el error menor que el
marcado en la variable .

!Loop for number of iterations


do i = 1, maxIt
!Generate matrix K and vector R
call writeSystem (K, R, x, n, tref, h, ka)

!Solve K·dx = -R
R=-R
call gaussBand(K, R, 1, n)

- 93 -
Andrés Zarabozo Martínez Métodos numéricos

!Solve x1 = x0 + dx
x=x+R
!Initial velocity
v1 = v
v = (4. * x(2) - 3. * x(1) - x(3)) / (2. * h)

!Print results
if(maxval(abs(R)) .lt. error) then
print*, "Number of nodes: ", n
print*, "Error in R: ", maxval(abs(R))
print*, "Iterations needed: ", i
print*, "Initial velocity: ", " ", v
print*, " "
exit
elseif (i .eq. maxIt) then
print*, "Number of nodes: ", n
print*, "No solution found. "
print*, " "
end if
end do

Una vez se acaba el cálculo se le da un nuevo valor a la malla si es necesario borrando antes las
matrices K, R y x.

!Renew discretization
deallocate(K, R, x)
n = 1000 + n
end do
end program

Los resultados generados por el programa anterior son los siguientes:

Number of nodes: 1000


Error in R: 4.05833953591406877E-010
Iterations needed: 6
Initial velocity: 33.901530208195759
Number of nodes: 2000
Error in R: 3.99446362148938426E-010
Iterations needed: 6
Initial velocity: 33.988404464699350

Number of nodes: 3000


Error in R: 3.98089342760615747E-010
Iterations needed: 6
Initial velocity: 34.006278684062110
Number of nodes: 4000
Error in R: 3.97452197374683662E-010
Iterations needed: 6
Initial velocity: 34.012788837112836

- 94 -
Andrés Zarabozo Martínez Métodos numéricos

Number of nodes: 5000


Error in R: 3.97345468277236172E-010
Iterations needed: 6
Initial velocity: 34.015867125092669

Number of nodes: 6000


Error in R: 3.97189273253109707E-010
Iterations needed: 6
Initial velocity: 34.017561828242137
Number of nodes: 7000
Error in R: 3.97116818907919676E-010
Iterations needed: 6
Initial velocity: 34.018593137328239
Number of nodes: 8000
Error in R: 3.97085218660822430E-010
Iterations needed: 6
Initial velocity: 34.019267018567149

Number of nodes: 9000


Error in R: 3.97022337062319620E-010
Iterations needed: 6
Initial velocity: 34.019731410085285
Number of nodes: 10000
Error in R: 3.97022961043059028E-010
Iterations needed: 6
Initial velocity: 34.020064936000409

Se puede ver que la velocidad inicial converge hacia unos 34.02. Hay que recordar que el error
es el valor absoluto máximo de la matriz R pero para el cálculo de la velocidad inicial se debe
hacer una operación matemática que incluye la longitud de malla por lo que el error de la
velocidad es distinto.

La velocidad dada está en unidades adimensionales por lo que para pasarla a unidades
internacionales se debe multiplicar por la longitud de referencia dividida por el tiempo de
referencia.

̃ ⁄ (8.44)

Se puede ver que la velocidad inicial para que se cumplan los minutos es desorbitada.

- 95 -
Andrés Zarabozo Martínez Métodos numéricos

9. Método de elementos finitos


9.1. Forma fuerte del problema
El método de elementos finitos (MEF) es un método numérico general para la aproximación de
soluciones de ecuaciones diferenciales parciales, como por ejemplo la ecuación de Laplace.

( ̅ ) (9.1)

El MEF permite obtener una solución numérica aproximada sobre un dominio (medio
continuo) dividido en un número elevado de subdominios no intersectantes entre sí
denominados elementos finitos. Dentro de cada elemento se distinguen una serie de puntos
representativos llamados nodos. Dos nodos son adyacentes si pertenecen al mismo elemento.

La solución obtenida para el sistema es ( ) . Además de la ecuación diferencial se


deben tener condiciones de contorno . Estas condiciones pueden ser:

 Condición de contorno de Dirichlet, especifica el valor de la solución en los puntos del


contorno del dominio.

̅ (9.2)

 Condición de contorno de Neumann, especifica el valor de la derivada de la solución


en el contorno del dominio.

̅ (9.3)

Las condiciones de contorno del problema completo son una combinación de los dos tipos
anteriores.

(9.4)

La definición del problema es lo que se llama la forma fuerte del problema, esto incluye la
ecuación diferencial y las condiciones de contorno. Hasta este punto no se ha hecho ninguna
discretización ni ninguna aproximación.

9.2. Método de Rayleigh-Ritz y método de Galerkin


El objetivo del método es resolver la ecuación diferencial definida en la ecuación (3.1). Una
forma de resolver la ecuación bajando un orden a la ecuación diferencial es integrando la
función en todo el dominio. Si la función es cero en todo el dominio entonces la integral debe
ser cero.

∫ (9.5)

Pero esto no asegura que , para ello se introduce una función de peso ( ).

∫ ( ) ( ̅ ) ( ) (9.6)

- 96 -
Andrés Zarabozo Martínez Métodos numéricos

A parte de transformar la ecuación diferencial se deben también transformar las condiciones


de contorno.

∫ ( )( ̅) ∫ ( )( ⃗ ) (9.7)

El método integral consiste en introducir una aproximación de ̃ en cada nodo.

̃
∫ ( ) ( ̅ ̃) ∫ ( )( ̅ ) ̃( ) ̅ (9.8)

Con esta ecuación se obtiene la solución del método de Rayleigh-Ritz. En general este método
no se usa mucho.

El método de Galerkin utiliza la siguiente aproximación para la función.

̃ ∑ ( ) (9.9)

Siendo una combinación lineal de . Si además la ecuación integral es lineal, lo que queda
es un sistema de ecuaciones lineales.

El problema con este método es que en general estas funciones están definidas en todo el
dominio y es muy complicado concentrar la combinación de que cumplan todas las
condiciones de contorno.

9.3. Ejemplo de formulación fuerte para problema estructural


Un ejemplo clásico de aplicación del método de elementos finitos es en problemas
estructurales. Se desarrolla a modo de ejemplo en este apartado la formulación débil de un
problema estructural de vigas.

En una viga se pueden tener tres tipos de cargas: cargas concentradas, cargas distribuidas y
momentos. Aislando una porción de la viga se obtienen las ecuaciones diferenciales para los
distintos esfuerzos. Se denomina al esfuerzo cortante vertical y al momento flector.

 Carga concentrada

𝑀
𝑀 𝑀

𝑉 𝑉 𝑉
Δ𝑥

Figura 9.1. Carga concentrada.

(9.10)

- 97 -
Andrés Zarabozo Martínez Métodos numéricos

 Carga distribuida

𝑀
𝑀 𝑀

𝑉 𝑉 𝑉
Δ𝑥

Figura 9.2. Carga concentrada.

( ) ( ) (9.11)

 Carga concentrada

𝑀
𝑀 𝑀

𝑉 𝑉 𝑉
Δ𝑥

Figura 9.3. Carga concentrada.

(9.12)

Se estudia el problema de flexión en la viga. Siendo la inversa del radio de curvatura del
elemento de la viga se tiene:

( )
( ) (9.13)

Siendo la dirección de la fibra neutra el ángulo de curvatura. La derivada del ángulo se


puede aproximar y dejarlo en función del desplazamiento vertical .

( ) ⁄
(9.14)
( )

También se puede relacionar el momento flector con el desplazamiento vertical:

( ) (9.15)

Se reescribe la ecuación anterior utilizando las ecuaciones diferenciales obtenidas para el caso
de carga distribuida (ecuación (9.11)).

( ) ( ) (9.16)

- 98 -
Andrés Zarabozo Martínez Métodos numéricos

Se le tienen que añadir las condiciones de frontera para terminar de definir la forma fuerte del
problema. Las condiciones de contorno pueden ser:

 Desplazamiento vertical

( ) ̅ (9.17)

 Rotación

( )
̅ (9.18)

 Cortante

( )
( ) ̅ (9.19)

 Momento

( )
̅ (9.20)

Para este ejemplo se consideran las siguientes condiciones de frontera:

( ) () ()
( ) ̅ ̅ ( ) ̅ ̅ (9.21)

Se empieza ahora definiendo la forma débil del problema. Se utiliza la ecuación integral
definida en la ecuación (9.6). En este problema se podría considerar que la función es el
desplazamiento virtual.

∫ ( ) ∫ (9.22)

Se integra la parte de la izquierda por partes.

( ) ( )
∫ ( ) [ ( )] ∫ ( ) (9.23)

La parte de la izquierda está definido para los dos extremos de la barra introduciendo ahí las
condiciones de contorno, en este caso es el cortante.

( )
∫ ( ) () ̅ ∫ (9.24)

Se vuelve a integrar por partes.

( ) ( ) ( )
∫ ( ) [ ] ∫ (9.25)

- 99 -
Andrés Zarabozo Martínez Métodos numéricos

En este caso la condición de contorno que se aplica es el momento.

( ) ()
∫ ̅ () ̅ ∫ (9.26)

Para que se cumpla la ecuación anterior se ha impuesto que:

( )
( ) (9.27)

Además para que la integral de la izquierda se pueda integrar el desplazamiento virtual debe
tener segunda derivada.

9.4. Funciones de forma


Para resolver la ecuación diferencial utilizando MEF se debe crear un dominio de elementos
finitos. Éste se compone de elementos y nodos. Los elementos pueden tener múltiples
formas, aunque se suelen emplear elementos triangulares o cuadriláteros (en el caso 2D).

También se necesita una forma de caracterizar las propiedades físicas de los elementos. Los
vínculos entre los nodos de un elemento se caracterizan por las funciones de forma.

La función de forma asociada al nodo y el elemento debe satisfacer que sea la unidad en
el nodo y cero en los demás.

(9.28)

Por ejemplo, considerando una viga, la distribución de los desplazamientos a lo largo del
elemento (con un nodo en cada extremo) sería:

{ }{ } (9.29)

Siendo y los desplazamientos en los nodos. Las funciones de forma en este caso serían
rectas que deben satisfacer la ecuación (9.28).

(9.30)

𝑁 𝑁

Figura 9.4. Funciones de forma para un elemento de una dimensión.

Una vez obtenida la distribución de las funciones ya se puede integrar. Introduciendo las
funciones de forma que suelen ser lineales se pueden integrar fácilmente las expresiones
obtenidas en la forma débil.

- 100 -
Andrés Zarabozo Martínez Métodos numéricos

9.5. Cuadratura de Gauss


En general no es necesario integrar analíticamente todas las expresiones de la forma débil una
vez introducidas las funciones de forma. Se puede, por ejemplo, utilizar la cuadratura de gauss
para obtener el resultado numérico de la integral.

A diferencia de otros métodos de integración numérica, los puntos de evaluación de la función


están definidos. El resultado obtenido en la cuadratura de Gauss de puntos es el de integrar
un polinomio de orden o menos. El dominio de la cuadratura por regla es de [ ].

∫ ( ) ∑ ( ) (9.31)

Donde es el peso para el punto de integración .

En la siguiente tabla se pueden ver una lista de puntos de integración y de pesos para los tres
primeros valores de .

Núm. de puntos Puntos de integración Pesos

√ √

√ √

Tabla 9.1. Puntos de integración y pesos.

Como normalmente las funciones de formas son lineales, se suelen tener que integrar
polinomios, obteniendo resultados exactos con la cuadratura de Gauss.

9.6. Tipos de elementos en 2D


En el apartado 9.5 se puede ver un elemento para el caso unidimensional con dos nodos y sus
funciones de forma. Los siguientes elementos son los que más se utilizan en el caso
bidimensional.

Las funciones de forma se definen en coordenadas locales y .

 Elementos triangulares

Los elementos triangulares más básicos se componen de tres nodos en los vértices del
elemento. Se utilizan coordenadas locales para para obtener las funciones de forma.

Para pasar de unas coordenadas a otras se utiliza el siguiente cambio:

{ } [ ]{ } { } (9.32)

- 101 -
Andrés Zarabozo Martínez Métodos numéricos

𝜂 𝑥
(𝑏 𝑏 )
(𝑐 𝑐 )

(𝑎 𝑎 )
𝜉 𝑥

Figura 9.5. Transformación entre coordenadas locales y coordenadas globales.

El área del elemento es:

( )( ) ( )( ) (9.33)

La función inversa es:

( ) ( )
{ } [ ]{ } { } (9.34)
( ) ( )

Las funciones de forma en coordenadas locales son:

(9.35)

(9.36)

(9.37)

Las tres funciones de forma suman la unidad. Las derivadas de las funciones de forma respecto
a las dos variables son:

(9.38)

(9.39)

(9.40)

Utilizando la transformación las funciones de forma en las coordenadas globales queda:

( ) [( ) ( ) ( ) ] (9.41)

( ) [( ) ( ) ( ) ] (9.42)

( ) [( ) ( ) ( ) ] (9.43)

- 102 -
Andrés Zarabozo Martínez Métodos numéricos

( ) ( ) (9.44)

( ) ( ) (9.45)

( ) ( ) (9.46)

 Elementos cuadriláteros

Los elementos cuadriláteros más básicos se componen de cuatro nodos en los vértices del
elemento.

𝜂 𝑥

𝜉 𝑥

Figura 9.6. Transformación de coordenadas de un elemento rectangular.

Las funciones de formas para este elemento genérico son:

( )( ) (9.47)

( )( ) (9.48)

( )( ) (9.49)

4 ( )( ) (9.50)

Se cumple que la suma de todas las funciones es igual a la unidad. Las derivadas de estos
elementos respecto a las diferentes variables son:

( ) ( ) (9.51)

( ) ( ) (9.52)

( ) ( ) (9.53)

4 4
( ) ( ) (9.54)

- 103 -
Andrés Zarabozo Martínez Métodos numéricos

La matriz de derivadas de las funciones de forma es

4 4

(9.55)

[ ] [ ]

Para pasar de las coordenadas locales a las globales se utiliza el Jacobino.


− (9.56)

Donde éste se calcula como:

(9.57)

Donde es la posición en donde se quiere evaluar el Jacobino.

También existen otros tipos de elementos cuadriláteros utilizando más nodos. El


procedimiento de obtención de las funciones de forma y sus derivadas es igual que en el caso
de tener solo cuatro nodos.

 Elemento cuadrilátero de elementos

Se pueden aumentar el orden de los elementos introduciendo más nodos por elemento.

Figura 9.7. Elemento rectangular con nodos.

Se han introducido nueve nodos en el nodo. Las funciones de forma son por lo tanto más
complicadas. La función de forma del nodo debe anularse en los nuevos puntos, por ejemplo
en el punto ( ).

( ) ( )
(9.58)

Se tienen tres tipos diferentes de nodos en este elemento, se tienen: nodos de las esquinas
que tienen funciones de forma similares a la mostrada para , nodos laterales y el nodo
central.

( )( ) ( )
(9.59)

( )( ) (9.60)

- 104 -
Andrés Zarabozo Martínez Métodos numéricos

 Elemento cuadrilátero de nodos Serendipity

Eliminando el nodo central se obtiene un elemento de nodos que tiene las ventajas de
reducir el orden de las funciones de forma. En este caso se tienen dos tipos de nodos: los de
las esquinas y los de los laterales.

( )( )( )
(9.61)

( )( )
(9.62)

A parte de eliminar un grado de la ecuación (eliminando el nodo central) los elementos del
lateral son más simples (pierden los términos de orden ).

9.7. Ejemplo de problema térmico


El ejemplo que se desarrolla aquí es un problema térmico con radiación. En este apartado se
desarrolla el ejemplo y el programa descrito en este tema es el que resuelve este ejemplo.

La siguiente figura muestra la sección de un radiador para uso en el espacio profundo. Debido
a su doble simetría solo se muestra una cuarta parte de la sección.

𝑇 𝑞𝑟 𝜎𝑇 4

𝑅
𝑘
𝑅 𝑇𝑝 𝑅

𝜆𝑅 (𝜆 ≫ )

Figura 9.8. Sección del radiador espacial.

La carga de pago del radiador situada en la zona central debe mantenerse a conocida. El
radiador actúa como un cuerpo negro según la ley de Stefan-Boltzmann. La temperatura
ambiente equivalente es tan baja que se puede despreciar.

Para este ejemplo se utilizará como connotación de matrices las letras sin cursiva y en negrita.

 Forma débil

La ecuación que gobierna la distribución de temperaturas es la ley de Fourier.

(9.63)

Donde es el flujo de calor por unidad de longitud, es la conductividad térmica y es el


gradiente local de temperaturas.

- 105 -
Andrés Zarabozo Martínez Métodos numéricos

Debido a la falta de fuentes de calor y que el problema es estacionario, la ley de Fourier se


simplifica a la ecuación de Laplace.

(9.64)

Se tienen dos tipos de condiciones de contorno. La condición de contorno de Dirichlet está


presente en el centro donde la temperatura es conocida. La condición de contorno de
Neumann está en la pared exterior del radiador, siendo el flujo de calor de radiación.
4
⃗ (9.65)

Es recomendable adimensionar el problema para simplificar el problema y reducir las


dependencias. Se define la temperatura de referencia como la temperatura de la carga de
pago y la longitud de referencia como . La ecuación de Laplace adimensionalizada queda:

̂ ̂
(9.66)
̂ ̂

Las condiciones de contorno quedan:

̂ ̂
̂ ( ̂ 4) ⃗ (9.67)
̂ ̂

El término constante en la condición de contorno de Neumann puede expresarse como un


coeficiente .

(9.68)

Este parámetro es una relación entre el flujo de calor a través del radiador y el calor de
radiación que se puede emitir, siempre que la diferencia de temperaturas entre el interior y la
superficie como la temperatura superficial son del mismo orden.

(9.69)
4

La potencial adimensional del radiador se puede definir como:

̇
4 (9.70)

Se pueden obtener analíticamente los valores de la potencia para los casos extremos. Si
la conductividad es muy baja y el radiador se comporta como un aislante, por lo tanto la
temperatura de la superficie exterior es muy baja y la potencia emitida muy baja también
( ). Si en cambio ≫ la temperatura en todo el radiador es casi igual a la temperatura
de la carga de pago. En un cuarto de la sección la potencia radiada sería:
4 4
̇ ( ) (9.71)

- 106 -
Andrés Zarabozo Martínez Métodos numéricos

Por lo tanto el orden de magnitud de la potencia adimensional es ( ) para ≫ .

A partir de este momento todas las variables que se utilicen son adimensionales por lo que la
notación con acento circunflejo ya no se utiliza. Se tienen que tener en cuenta las siguientes
expresiones:

- Regla de la derivada de un producto

( ) (9.72)

- Teorema de la divergencia

∫ ( ) ∫ ̂ (9.73)

La forma débil se obtiene integrando la ecuación de Laplace multiplicada por una función
arbitraria .

∫ (9.74)

Se integra esta expresión por partes:

∫ ∫ ∫ ̂ (9.75)

La integral de línea se hace donde se tienen condiciones de contorno ( ). Se elige


una función tal que en la condición de contorno de Dirichlet sea cero.

∫ ( ̂) ∫ ⏟( ̂) ∫ (⏟) ̂ (9.76)

Siendo la forma débil del problema:

∫ ∫ ( ̂) (9.77)

( ) ( ) (9.78)

 Discretización

La temperatura ( ) se interpola a partir de las temperaturas las correspondientes


funciones de forma ( ) para cada nodo contenido en el elemento.

Se utilizan elementos cuadriláteros. La temperatura ( ) de un punto dentro de un elemento


puede escribirse como:

( ) [ ( ) ( ) ( ) 4( )] ( ) (9.79)

[ 4]

- 107 -
Andrés Zarabozo Martínez Métodos numéricos

El gradiente de temperatura es:

(9.80)

[ ] [ ] [ 4]

Se utilizan las mismas funciones de forma para interpolar la función de peso del elemento.

( ) ( ) ( ) ( ) (9.81)

Aplicando la ecuación (9.77) a cada elemento se obtiene:

∫ ∫ ( ̂) (9.82)

Se introducen las expresiones que contienen las funciones de forma.

∫ ∫ ( ̂) (9.83)

Y ésta se puede reescribir como:

(9.84)

Donde:

∫ (9.85)

∫ ( ̂) (9.86)

 Ensamblaje

El sistema global se obtiene añadiendo la contribución de cada elemento.

∑ ∑ (9.87)

Esto se debe hacer usando la numeración global de nodos y elementos. La ecuación queda:

(9.88)

Esta ecuación debe cumplirse para cualquier que es lo mismo que decir que se cumple para
cualquier .

(9.89)

Debido a la no linealidad del problema (causada por el flujo de radiación) el sistema se tiene
que resolver de forma iterativa.

- 108 -
Andrés Zarabozo Martínez Métodos numéricos

El calor de radiación se linealiza de la siguiente forma:

| ( ) (9.90)

El vector puede reescribirse como:

(9.91)

El subíndice indica que está evaluado con las temperaturas de la iteración anterior. La
ecuación (9.89) se escribe finalmente como un sistema lineal.

( ) (9.92)

Donde y deben ser evaluadas para cada iteración.

 Integración

Los elementos que se usan son cuadriláteros de cuatro nodos. Las integrales de volumen son
del orden (de segundo orden) y de área ( dimensiones) por lo que se necesitan cuatro
puntos de integración para la cuadratura de Gauss, dos en cada dimensión.

𝜂
: I 𝑥

𝜉
𝑥

Figura 9.9. Elemento cuadrilátero de nodos en coordenadas locales (izq.) y globales (der.).

La integral de la ecuación (9.85) se calcula de la siguiente forma:


4

∫ ∫ || ∑( | |) (9.93)

Donde es el peso (siendo igual a en todos los casos). El Jacobino y las funciones de
forma derivadas en un cierto punto se obtiene como:

(9.94)

El flujo de calor se considera lineal en el elemento y puede integrarse fácilmente


(analíticamente) en el contorno de Neumann. La integral en un lado del elemento (de longitud
) es:

∫ ( ) ∫ ( ) (9.95)

[ ]

- 109 -
Andrés Zarabozo Martínez Métodos numéricos

Utilizando las funciones de forma en una dimensión de la ecuación (9.30). Se linealiza ahora
esta ecuación.

| ( ) | ( )

| ( ) | ( )

[ ]

4
4
( ) ( )

4
4
( ) ( )
[ ]

4
4

[ ] (9.96)
4
4
[ ] [ ]

 Potencia del radiada

Una vez calculada la distribución de temperaturas en todo el dominio se puede calcular la


potencia del radiador. Se calcula como la integral de todo el flujo de calor en el contorno de
Neumann.

Para un elemento la potencia adimensional se calcula utilizando un único punto de integración


de Gauss ya que es del orden de .

4 ( 4 4)
∫ ∫ (9.97)

Para obtener la potencia total se suman las contribuciones de todos los elementos.

- 110 -
Andrés Zarabozo Martínez Métodos numéricos

9.8. Programa

Programa 7. Radiador espacial


Se presenta ahora el código que resuelve el ejemplo descrito en la sección 9.7. Para poder
visualizar la solución, el siguiente código está adaptado para que la distribución de
temperaturas la lea un programa llamado GID de la empresa CIMNE La versión gratuita del
programa se puede descargar desde la página de la empresa. Tiene limitados el número de
nodos que se pueden utilizar pero para este ejemplo es suficiente.

Al programa se le debe introducir la malla (con los elementos y los nodos) y los contornos con
condiciones de contorno, incluida en el apéndice de este libro, sección 10.8.

El programa se estructura mediante un módulo que incluye todas las variables y subrutinas. El
programa principal solo tiene las variables que se pueden configurar y se dedica a ir llamando
a las distintas subrutinas para que vayan haciendo el cálculo.

El error es la diferencia máxima entre temperaturas de iteraciones consecutivas. La secuencia


del programa es:

- Cargar la malla del archivo “imput_mesh.txt”


- Inicializar las variables, crear las coordenadas locales de los elementos cuadriláteros y
las matrices de las funciones de forma y de sus derivadas
- Se ensambla la matriz , ésta es la que no cambia entre iteraciones
- El solver es la subrutina que tiene el bucle iterativo que va calculando las nuevas
temperaturas y con esas las matrices y y resuelve el sistema lineal.
- Una vez se tiene la distribución de temperaturas se calcula la potencia radiada
- Las dos últimas dos subrutinas sirven para escribir los archivos necesarios para que los
pueda leer el programa GID.

program spaceRadiator
use subroutines
implicit none
integer i

!Program configurator
alpha = 100.
maxIterations = 30
error = 0.0001

!Program sequence
call readMesh(); print*, "Read Mesh Done!"
call init(); print*, "Init Done!"
call assembleK(); print*, "Assemble K Done!"; print*," "
call solver(); print*, "Solver Done!"
call getW(); Print*, "Get W Done!"
call writeGidMesh();
call writeTemperature();
end program spaceRadiator

- 111 -
Andrés Zarabozo Martínez Métodos numéricos

El módulo subroutines incluye todas las variables y subrutinas. Las variables se utilizan de
forma global, es decir que cada subrutina puede cambiar sus valores.

module subroutines

implicit none

!Variables: Local means element coordinates. X: coordinates of node;


!N: shape function; DN: deriv.N; IP: Integ. points
real, save :: localX(4,2), localN(4,4), localDN(4,2,4), localIP(4,2), alpha
real, allocatable, save :: node(:,:), K(:,:), T(:), q0(:), T0(:), Kr(:,:), Ktot(:,:), Tit(:,:)
integer, allocatable, save :: elemNode(:,:), boundIn(:), boundExt(:,:)
integer, save :: nNode, nElem, nIn, nExt, nIP, nX
integer, save :: maxIterations, endIT
real, save :: error

contains

La primera subrutina Se encarga de abrir el archivo “imput_mesh.txt” y obtener los datos del
mallado.

subroutine readMesh()

implicit none

integer i
real aux, aux2

open(UNIT = 5, FILE = 'input_mesh.txt', ACCESS = 'SEQUENTIAL')

!Read nodal coordinates


read(5,*) nNode
allocate (node(nNode,2))
do i = 1, nNode
read(5,*) aux, node(i,:), aux2 !First and last numbers not needed
end do

!Read Elements
read(5,*) nElem
allocate(elemNode(nElem,4))
do i = 1, nElem
read(5,*) aux, elemNode(i,:)
end do

!Read Boundary nodes that Radiate


read(5,*) nExt
allocate(boundExt(nExt,2))
do i = 1, nExt
read(5,*) aux, boundExt(i,:)
end do

- 112 -
Andrés Zarabozo Martínez Métodos numéricos

!Read Boundary nodes with constant Temperature


read(5,*) nIn
allocate(boundIn(nIn))
do i = 1, nIn
read(5,*) aux, boundIn(i)
end do

close(5)

end subroutine readMesh

La subrutina init() se encarga de inicializar variables y de crear las coordenadas locales de los
elementos y de los puntos de integración y las matrices de funciones de formas y de sus
derivadas.

subroutine init()

implicit none
real aux
integer i

allocate(K(nNode, nNode), Kr(nNode, nNode), KTot(nNode,nNode), &


T(nNode), T0(nNode), q0(nNode))
allocate(Tit(nNode,maxIterations))

K = 0.; Kr = 0.; KTot = 0.; T = 0.; T0 = 0.; q0 = 0.; nIP = 4; nX = 4; Tit = 0.

!Initial temperature
if (alpha .ge. 1) then
T0 = 0.9
else
T0 = alpha
end if

!Node positions localX(node, xi-eta)


localX(1,1) = -1.; localX(1,2) = -1.
localX(2,1) = 1.; localX(2,2) = -1.
localX(3,1) = 1.; localX(3,2) = 1.
localX(4,1) = -1.; localX(4,2) = 1.

!Integration points position localIP(IP, xi-eta)


aux = 1. / sqrt(3.)
localIP = localX * aux

do i = 1, 4

!Shape functions localN(IP, shape function)


localN(i,1) = (1. - localIP(i,1)) * (1. - localIP(i,2))
localN(i,2) = (1. + localIP(i,1)) * (1. - localIP(i,2))
localN(i,3) = (1. + localIP(i,1)) * (1. + localIP(i,2))
localN(i,4) = (1. - localIP(i,1)) * (1. + localIP(i,2))

- 113 -
Andrés Zarabozo Martínez Métodos numéricos

!Derivative localDN(IP, dxi - deta, shape function)


localDN(i,1,1) = - 1. + localIP(i,2); localDN(i,2,1) = - 1. + localIP(i,1)
localDN(i,1,2) = 1. - localIP(i,2); localDN(i,2,2) = - 1. - localIP(i,1)
localDN(i,1,3) = 1. + localIP(i,2); localDN(i,2,3) = 1. + localIP(i,1)
localDN(i,1,4) = - 1. - localIP(i,2); localDN(i,2,4) = 1. - localIP(i,1)
end do

localDN = 0.25 * localDN; localN = 0.25 * localN

end subroutine init

La subrutina assembleK se encarga de calcular y ensamblar . Ésta es la matriz de rigidez que


no cambia entre iteraciones. La subrutina calcula las matrices (ecuación (9.93)) y luego las
ensambla (en la matriz global) para cada elemento.

Para poder calcular se debe llamar a la subrutina isoTransform que devuelve la matriz de
derivadas de las funciones de forma y el Jacobiano para cada punto de integración, utilizando
la ecuación (9.94).

subroutine isoTransform (x, dN, detJ) !Returns dN and detJ


implicit none

real, intent(in) :: x(nX,2)


real, intent(out) :: dN(nIP,2,nX), detJ(nIP)

integer i
real J(nIP,2,2), invJ(nIP,2,2)

do i = 1, nIP

!Obtain Jacobian and determinant. J = D x


J(i,:,:) = matmul(localDN(i,:,:),x)
detJ(i) = abs(J(i,1,1) * J(i,2,2) - J(i,2,1) * J(i,1,2))

!Obtain the inverse of a 2x2 matrix


invJ(i,1,1) = J(i,2,2); invJ(i,1,2) = -J(i,1,2)
invJ(i,2,1) = -J(i,2,1); invJ(i,2,2) = J(i,1,1)
invJ(i,:,:) = (1. / detJ(i)) * invJ(i,:,:)

!Obtain dN = invJ * localDN


dN(i,:,:) = matmul(invJ(i,:,:), localDN(i,:,:))
end do

end subroutine isoTransform

subroutine assembleK()
implicit none

integer i, j, l, eN(nX) !Remember nX is number of nodes per element


real x(nX,2), dN(nIP,2,nX), detJ(nIP)
real localK(nX,nX)

- 114 -
Andrés Zarabozo Martínez Métodos numéricos

do i = 1, nElem
!Saves, in eN(4), the number of the nodes in the element
eN = elemNode(i,:)

!Saves, in x(4,2), the positions of the nodes


!in global coordinates of the element
do j = 1, nX
x(j,:) = node(eN(j),:)
end do

localK = 0.
call isoTransform(x, dN, detJ)

!K = sum(|J| Dt D)
do j = 1, nIP
localK = localK + detJ(j) * matmul(transpose(dN(j,:,:)),dN(j,:,:))
end do

!Introduces the values in the global matrix K


do j = 1, nX
do l = 1, nX
K(eN(j), eN(l)) = K(eN(j), eN(l)) + localK(j,l)
end do
end do

end do
end subroutine assembleK

La siguiente subrutina es muy parecida a la subrutina assembleK pero ésta se encarga de


ensamblar las matrices y . Éstas matrices se deben calcular en cada iteración.

subroutine assembleQ()
implicit none

integer i, j, k, x(2)
real localQ(2), localT(2), localKr(2,2), L
real aux

!Restarts q0 and Kr
q0 = 0.; Kr = 0.

do i = 1, nExt
!Pointer to node number
x = boundExt(i,:)

!Length
L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1))
L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2))
L = sqrt(L)

!Temperatures at the nodes


localT(1) = T0(x(1)); localT(2) = T0(x(2))

- 115 -
Andrés Zarabozo Martínez Métodos numéricos

!Matrix q0
!Heat on the nodes
localQ(1) = localT(1)*localT(1)*localT(1)*localT(1) + 0.5 * &
localT(2)*localT(2)*localT(2)*localT(2)
localQ(2) = localT(2)*localT(2)*localT(2)*localT(2) + 0.5 * &
localT(1)*localT(1)*localT(1)*localT(1)
aux = L / alpha
localQ = localQ * aux

!Introduce values in global q


q0(x(1)) = q0(x(1)) + localQ(1)
q0(x(2)) = q0(x(2)) + localQ(2)

!Matrix Kr
!Local Kr
aux = 4./6.
localKr(1,1) = 2. * aux * localT(1)*localT(1)*localT(1)
localKr(2,1) = aux * localT(1)*localT(1)*localT(1)
localKr(1,2) = aux * localT(2)*localT(2)*localT(2)
localKr(2,2) = 2. * aux * localT(2)*localT(2)*localT(2)
aux = - L / alpha
localKr = localKr * aux

!Introduce values in global Kr


do j = 1, 2
do k = 1, 2
Kr(x(j),x(k)) = Kr(x(j),x(k)) + localKr(j,k)
end do
end do

end do
endsubroutine assembleQ

La subrutina innerBoundary introduce las condiciones de contorno de Dirichlet. Simplemente,


para todos los nodos donde la ecuación es conocida, borra la ecuación e introduce una nueva
ecuación .

subroutine innerBoundary()
implicit none

integer i, n

do i = 1, nIn
n = boundIn(i)
KTot(n,:) = 0.; KTot(n,n) = 1.
T(n) = 1. !Boundary temperature is 1
end do

end subroutine innerBoundary

- 116 -
Andrés Zarabozo Martínez Métodos numéricos

La subrutina solveSystem es un simple código de resolución de sistemas lineales mediante el


método de Gauss. De forma similar a los programas escritos en el tema de resolución de
sistemas lineales, la matriz de entrada debe estar transpuesta para gestionar de forma más
eficiente la memoria.

subroutine solveSystem(a, b, n) !Matrix needs to be transposed


implicit none

integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult

!Triangulate the matrix


do pivot = 1, n-1
do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot)
a(pivot+1:n,row) = a(pivot+1:n,row) - mult * &
a(pivot+1:n,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

!Obtain solutions
b(n) = b(n) / a(n,n)
do row=n-1,1,-1
b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n))
b(row) = b(row) / a(row,row)
end do

end subroutine

Finalmente la subrutina solver es la que se encarda del bucle iterativo y calcula la distribución
de las temperaturas en los nodos. Para cada iteración calcula los vectores y llamando a
la subrutina assembleQ. Luego construye un sistema lineal (ecuación (9.92)) y le introduce las
condiciones de contorno llamando a la subrutina innerBoundary. Finalmente resuelve el
sistema, escribe los resultados y los verifica para saber si el bucle debe finalizarse.

subroutine solver()
implicit none
integer i, j
real a(nNode, nNode)
logical bool

bool = .true.

do i = 1, maxIterations !bucle iterativo

!Obteins matrix Kr and vector q0


call assembleQ();

- 117 -
Andrés Zarabozo Martínez Métodos numéricos

!Builds linear system Ax=b Where A=KTot and b=T


KTot = K - Kr
T = q0

!Introduces Dirichlett boundary conditions


call innerBoundary()

!Solves system
a = transpose(KTot)
call solveSystem(a, T, nNode)

!Writtes result
Tit(:,i) = T
!End loop
if(maxval(abs(T - T0)).lt. error) then
print*, " "
print*, "Final iteration: ", i
print*, " "
bool = .false.
exit
end if

!New iteration
T0 = T

print*, "Iteration ", i,"Done!"

end do

endIT = i
if (bool) endIT = i - 1

end subroutine

Una vez ya se tiene la distribución de temperaturas, se puede calcular la potencia


adimensional. Se calcula la potencia radiada en cada elemento (ecuación (9.97)) y ésta se va
sumando a la global.

subroutine getW()

implicit none

real L, W, localW, aux, localT(2)


integer i, x(2)

aux = 0.5
W = 0.

do i = 1, nExt
!Pointer to node number
x = boundExt(i,:)

- 118 -
Andrés Zarabozo Martínez Métodos numéricos

!Length
L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1))
L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2))
L = sqrt(L)

!Temperatures at the nodes


localT(1) = T0(x(1))*T0(x(1))*T0(x(1))*T0(x(1))
localT(2) = T0(x(2))*T0(x(2))*T0(x(2))*T0(x(2))

!Emitted power
localW = L * aux * (localT(1) + localT(2))

!Global power
W = W + localW
end do

print*, " "


print*, "Alpha:", alpha
print*, "Non-dim. power:", W
print*, " "

end subroutine getW

Las siguientes dos subrutinas son una adaptación de un código para que el GiD pueda leer el
resultado de la distribución de nodos, elementos y temperaturas.

subroutine writeGidMesh()

implicit none
! x : Nodal Coordinates
! conec : Conectivity (Nodes of elements)
! n_nod : Number of Nodes
! n_el : Number of Elements

integer n_nod, n_el, conec(4,nElem), i


real x(2,nNode)

!Convert the variables to R.F. variables


n_nod = nNode; n_el = nElem
x(1,:) = node(:,1); x(2,:) = node(:,2)
conec = transpose(elemNode)

open(UNIT=6,FILE='radiation_analysis.post.msh',ACCESS='SEQUENTIAL',&
STATUS='REPLACE') ! Create File
write(6,*) '# postprocess mesh for GiD' ! File Header
write(6,*) 'MESH "RADIATION_FEA" dimension 2 ElemType Quadrilateral Nnode 4'
! Write Nodal Coordinates
write(6,*) 'Coordinates'
write(6,*) '# node number coordinate_x coordinate_y'

- 119 -
Andrés Zarabozo Martínez Métodos numéricos

do i = 1, n_nod
write(6,*) i, x(:, i)
end do ! i

write(6,*) 'end coordinates'

! Write Surface Elements


write(6,*) 'Elements'
write(6,*) '# element node_1 node_2 node_3 node_4'

do i = 1, n_el
write(6,*) i, conec(:, i)
end do ! i

write(6,*) 'end elements'


close(6) ! Close File
end subroutine writeGidMesh

!**************************************************************

subroutine writeTemperature()

implicit none

integer n_nod, n_ite


real temperature(nNode, endIT)

integer nodeF, iter


character*(*) temp_h, scalar, endvalues, values
character*(*) header, filename
parameter (temp_h = 'Result "TEMPERATURE" "ITERATION=" ')
parameter (scalar = ' Scalar OnNodes')
parameter (endvalues = 'End Values', values = 'Values')
parameter (header = 'GiD Post Results File 1.0')
parameter (filename = 'radiation_analysis.post.res')

!Convert the variables to R.F. variables


n_nod = nNode; n_ite = endIT; temperature(:,:) = Tit(:,1:endIT)

! Format specs
10 format (A) ! Single character field
20 format (A, I0, A) ! Use to write iteration number
! Open Output File & Overwrite
open(UNIT=6, FILE=filename, ACCESS='SEQUENTIAL', &
STATUS='REPLACE')

! Write Header
write(6,10) header

! Write Temperature Distribution for Each Iteration


do iter = 1, n_ite
write(6,20) temp_h, iter, scalar
write(6,10) values

- 120 -
Andrés Zarabozo Martínez Métodos numéricos

do nodeF = 1, n_nod
write(6,*) nodeF, temperature(nodeF, iter)
end do ! nodeF

write(6,10) endvalues
end do ! iter

! Close file
close(6)

end subroutine writeTemperature


end module subroutines

Los siguientes resultados corresponden a las temperaturas adimensionales en un cuarto de


radiador con . El radiador se ha mallado con 288 nodos. El programa finaliza cuando el
error es menor que . .

Las primeras dos soluciones mostradas en las siguientes figuras corresponden para valores de
muy pequeño y muy grande.

Figura 9.10. Temperaturas adimensionales para . .

Figura 9.11.Temperaturas adimensionales para .

La Figura 9.10 muestra el resultado cuando la conductividad es muy baja. Como ya se suponía,
la temperatura en el interior es alta mientras que en el exterior la temperatura es muy baja.

Como caso opuesto, la Figura 9.11 muestra el resultado cuando la conductividad es muy alta.
La temperatura en todo el dominio es muy alta.

Los valores de la potencia adimensional para distintos valores del parámetro se pueden
ver en la Tabla 9.2 y en la Figura 9.12.

- 121 -
Andrés Zarabozo Martínez Métodos numéricos

. − . .
.
. − . .
.
. − . .
.
. . . .
. . . .
. . . .
. . . .
. . .

Tabla 9.2. Potencia adimensional para distintos valores de .

12

10

θ 6

0
1.E-03 1.E-02 1.E-01 1.E+00 1.E+01 1.E+02 1.E+03 1.E+04 1.E+05
α

Figura 9.12. Potencia adimensional para distintos valores de .

Como se había predicho en el tema 9.7, cuando la conductividad es muy baja ( ) la


potencia adimensional tiende a ser muy baja también (del orden de magnitud de ). Mientras
que si la conductividad es alta ( ≫ ) la solución converge hacia ( ) .

- 122 -
Andrés Zarabozo Martínez Métodos numéricos

10. Apéndice
10.1. Programación en Fortran

Programa 1. Mínimo error de un tipo de variable

program program1
implicit none
real small = 1.
integer i

do i = 1, 1000
if (1. + small .gt. 1.) then
small = 0.5 * small
else
exit
end if
end do

small = 2. * small

print*, small
print*, epsilon(small)

end program

- 123 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 2. Cálculo del número π

program program2
implicit none
real*8 x, y
integer*8 total, inside

total = 0
inside = 0

10 continue
!Ball thrown
call random_number(x)
call random_number(y)
total = total + 1

!Looks where the ball fell


if(x*x + y*y .lt. 1.) inside = inside + 1

!Shows the result every 1000 iterations


if (mod(total, 1000) .eq. 0) then
print*, total, 4. * dble(inside) / dble(total)
end if
go to 10

end program

- 124 -
Andrés Zarabozo Martínez Métodos numéricos

10.2. Interpolación

Programa 3. Entrada de datos e interpolación

program program3
implicit none
real, allocatable :: ydy(:,:), x(:)
real xInt, yInt, step
integer n, i, nExit, last

!Reading Data
open(unit = 1, file='initialData', access='SEQUENTIAL')
read(1,*) n
allocate(ydy(2,n), x(n))

do i = 1, n
read(1,*) x(i), ydy(1,i)
end do

close(1)

!Obtaining Slopes
ydy(2,1) = (ydy(1,2) - ydy(1,1)) / (x(2) - x(1))
do i = 2, n - 1
ydy(2,i) = (ydy(1, i+1) - ydy (1, i-1)) / (x(i+1) - x(i-1))
end do
ydy(2,n) = (ydy(1,n) - ydy(1,n-1)) / (x(n) - x(n-1))

print *, 'Introduce number of points:'


read(*,*) nExit

xInt = x(1)
step = (x(n) - x(1)) / real(nExit - 1)

open(unit=2, file='dataExit', access='SEQUENTIAL', status='REPLACE')


last = 1

do i = 1, nExit
!Find interval
do while (xInt .gt. x(last+1))
last = last + 1
end do

!Obtain results
call hermite(ydy(:,last:last+1), x(last:last+1), xInt, yInt)
write(2,*) xInt, yInt

!New step
xInt = xInt + step
xInt = min(xInt, x(n))
end do
close(2)
end program

- 125 -
Andrés Zarabozo Martínez Métodos numéricos

!***************************************************

subroutine hermite (v1, v2, x, yx)


implicit none
real, intent(in) :: v1(4), v2(2), x
real, intent(out) :: yx
real :: chi, span

span =v2(2) - v2(1)


chi = (x - v2(1)) / span

yx = v1(1) * (1. + 2. * chi) * (1. - chi) * (1. - chi) + &


v1(2) * span * chi * (1. - chi) * (1. - chi) + &
v1(3) * chi * chi * (3. - 2. * chi) + &
v1(4) * span * chi * chi * (chi - 1.)

end subroutine

- 126 -
Andrés Zarabozo Martínez Métodos numéricos

10.3. Integración

Programa 4. Obtención de la serie de Fourier

program program4
implicit none
integer, parameter :: n = 300
integer i
real, parameter :: pi = acos(-1.)

real y(n), step, x, modes(2, 0:8)

x = -pi
step = 2. * pi / (real(n) - 1.)

!Discretization
do i = 1,n
y(i) = 0.5 + 3. * cos(2. * x + 0.75) + 1. * cos(6. * x + 0.25)
x = x + step
end do

!Amplitudes and phases


call fourier (y, modes, n, 8)

!Print results
do i = 0, 8
print* , modes(1,i), modes(2,i)
end do

end program

!***************************************************

subroutine trapice(y, b, z, n)
implicit none
integer, intent (in) :: n
real, intent (in) :: y(n), b
real, intent (out) :: z

z = 0.5 * (y(1) + y(n))+ sum(y(2:n-1))


z = z * b / (real(n) - 1.)

end subroutine

!***************************************************

subroutine fourier (y, modes, n, m)


implicit none
integer, intent (in) :: n, m
real, intent (in) :: y(n)
real, intent (out) :: modes(2, 0:m)

integer i
real z(n), x(n), dx, invPi, a, b

- 127 -
Andrés Zarabozo Martínez Métodos numéricos

real, parameter :: pi = acos(-1.)


invPi = 1. / pi

dx = 2. * pi / (real(n) - 1.)
x(1) = -pi

do i = 2, n
x(i) = x(i-1) + dx
end do

!First coeficient
call trapice(y, 2.*pi, a, n)
modes(1,0) = a * 0.5 * invPi

do i = 1, m
!Cos coeficients
z = y * cos(real(i) * x)
call trapice(z, 2.*pi, a, n)
a = a * invPi

!Sin coeficients
z = y * sin(real(i) * x)
call trapice(z, 2.*pi, b, n)
b = b * invPi

!Amplitudes and phases


modes(2,i) = -atan(b / a)
modes(1,i) = sqrt(a*a + b*b)
end do

end subroutine

- 128 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 5. Iteraciones y extrapolación

program program5
implicit none
integer :: i, j, n
real*8, parameter :: a = 0., b = 1.
real*8 suma, prevInteg, integ, h, sumEnds, aux, x, analitical
n = 10
h = (b - a) / dble(n)
suma = 0.

!Sum of limits divided by two


call evaluateFunction(a, aux)
sumEnds = aux
call evaluateFunction(b, aux)
sumEnds = (sumEnds + aux) * 0.5

do i = 1, 10
!Sum of the values of the function
if(i .eq. 1) then
x=a+h
do j = 1, (n - 1)
call evaluateFunction (x, aux)
suma = suma + aux
x=x+h
end do

else
x=a+h
do j = 1, (n - 1), 2
call evaluateFunction (x, aux)
suma = suma + aux
x=x+2*h
end do
end if

!Integral
integ = h * (sumEnds + suma)

!Number of intervals and size of interval


n=2*n
h = h * 0.5

!Richardson extrapolation
if(i .eq. 1) then
print*,"No extrapolation", " With extrapolation"
analitical = .2 * dsin(dble(5.)) - 1.
else
aux = (4. * integ - prevInteg) / 3.
print*, integ - analitical, aux - analitical
end if
prevInteg = integ
end do
end program

- 129 -
Andrés Zarabozo Martínez Métodos numéricos

!***************************************************

subroutine evaluateFunction(x, y)
implicit none
real* 8, intent(in) :: x
real* 8, intent(out) :: y

y = dcos(5. * x) + 3. * x * x
end subroutine

- 130 -
Andrés Zarabozo Martínez Métodos numéricos

10.4. Resolución numérica de ecuaciones no lineales

Programa 6. Deflexión de un cable

program Program6
implicit none
integer i, j, n
integer, parameter :: itMax = 7
real, parameter :: k = 0.25E-3
real x1, x2, x3, fx1, fx2, slope

x1 = (2. * k)**(1./3.)
x2 = 1.1 * x1

fx1 = k + sin(x1) - tan(x1)


print*, 'x= ', x1, 'f(x) = ', fx1

do i = 1, itMax
if (x1.eq.x2) exit

fx2 = k + sin(x2) - tan (x2)


print*, 'x = ', x2, 'f(x) = ',fx2

slope = (fx2 - fx1) / (x2 - x1)

x3 = x2 - fx2 / slope

x1 = x2
x2 = x3

fx1 = fx2
end do

end program

- 131 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 7. Resolución mediante Newton-Raphson

program Program7
implicit none
integer i, j, n
integer, parameter :: itMax = 7
real, parameter :: k = 0.25E-3
real x1, x2, fx1, slope, cosx, sinx

x1 = (2. * k)**(1./3.)

do i = 1, itMax

cosx = cos(x1)
sinx = sin(x1)

fx1 = k + sinx - sinx / cosx


slope = cosx - 1. / (cosx * cosx)

print*, 'x = ', x1, 'f(x) = ', fx1

if (fx1 .eq. 0) exit

x2 = x1 - fx1 / slope

x1 = x2
end do

end program

- 132 -
Andrés Zarabozo Martínez Métodos numéricos

10.5. Resolución numérica de ecuaciones lineales

Programa 8. Resolución de un sistema mediante Gauss

program program8
implicit none
integer, parameter :: n = 20
integer i, j
real :: a(n,n), aTrans(n,n), b(n), x(n), rand
!Initialize matrix and vector
do i = 1, n
do j = 1, n
call random_number(rand)
a(i,j) = 0.5 - rand
end do
a(i,i) = (1. + rand) * real(n)
call random_number(rand)
b(i) = rand
end do
!Solve system
aTrans = transpose(a)
x=b
call solver(aTrans, x, n)
!Errors
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number: ', maxval(abs(x))
end program

!****************************************************************************
subroutine solver(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult

!Triangulate the matrix


do pivot = 1, n-1
do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot)
a(pivot+1:n,row) = a(pivot+1:n,row) - mult &
* a(pivot+1:n,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

!Obtain solutions
b(n) = b(n) / a(n,n)
do row=n-1,1,-1
b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n))
b(row) = b(row) / a(row,row)
end do
end subroutine

- 133 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 9. Sistema con matriz mal condicionada

program program9
implicit none
integer, parameter :: size = 20
integer i, j
real :: a(size,size), aTrans(size,size), b(size), x(size), rand

!Generate matrix
do i = 1, size
do j = 1, size
call random_number(rand)
a(i,j) = 0.5 - rand !Number between -0.5 and 0.5
end do

a(i,i) = rand * 1.E-5 !Very small number for the diagonal


call random_number(rand)
b(i) = rand !Number between 0. and 1.
end do

!Solve system
aTrans = transpose(a)
x=b
call solveMatrix(aTrans, x, size)

!Check results
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

!****************************************************************************

subroutine solveMatrix(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot, point(n), i, posRow, posPiv
real :: mult, x(n)

!Initialize pointer vector


do row = 1,n
point(row) = row
end do

do pivot = 1, n-1
!Organize matrix
mult = 0.
do row = pivot, n !Searches biggest number under Pivot
if (abs(a(pivot,point(row))) .GT. mult) then
i = row
mult = abs(a(pivot,point(row)))
end if
end do

- 134 -
Andrés Zarabozo Martínez Métodos numéricos

row = point(pivot)
point(pivot) = point(i)
point(i) = row

posPiv = point(pivot)

!Make zeros under Pivot


do row = pivot+1, n
posRow = point(row)
mult = a(pivot, posRow) / a(pivot,posPiv)
a(pivot+1:n,posRow) = a(pivot+1:n,posRow) - mult &
* a(pivot+1:n,posPiv)
b(posRow) = b(posRow) - mult * b(posPiv)
end do
end do

!Obtain Results
x(n) = b(point(n)) / a(n,point(n))
do row = n-1,1,-1
posRow = point(row)
x(row) = b(posRow) - &
dot_product(a(row+1:n,posRow), x(row+1:n))
x(row) = x(row) / a(row,posRow)
end do
b=x

end subroutine

- 135 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 10. Doolittle

program program10
implicit none
integer, parameter :: n = 50
integer i, j
real :: a(n,n), aTrans(n,n), b(n), x(n), rand

!Generate matrix
do i = 1, n
do j = 1, n
call random_number(rand)
a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5
end do

a(i,i) = 0.1 * (1. + rand) * real(n) ! Good matrix

call random_number(rand)
b(i) = rand ! A number between 0. and 1.
end do

!Solve system
aTrans = transpose(a)
x=b
call luDecomposition(aTrans, n)
call luSustitution(aTrans, x, n)

!Check results
x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

!****************************************************************************

subroutine luDecomposition(a, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: a(n,n)
integer :: row, pivot
real :: mult

do pivot = 1, n-1
do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot)
a(pivot+1:n,row) = a(pivot+1:n,row) &
- mult * a(pivot+1:n,pivot)
a(pivot,row) = mult
end do
end do

end subroutine

!****************************************************************************

- 136 -
Andrés Zarabozo Martínez Métodos numéricos

subroutine luSustitution(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n)
real, intent(in) :: a(n,n)
integer :: row, i

!Ly = b
do row = 1, n
b(row) = b(row) - dot_product(a(1:row-1,row),b(1:row-1))
end do

!Ux = y
do row = n, 1, -1
b(row) = b(row) - dot_product(a(row+1:n,row),b(row+1:n))
b(row) = b(row) / a(row,row)
end do

end subroutine

- 137 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 11. Crout

program program11
implicit none
integer, parameter :: size = 50
integer i, j
real :: a(size,size), aCopy(size,size), b(size), x(size), rand

do i = 1, size
do j = 1, size
call random_number(rand)
a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5
end do
a(i,i) = 0.1 * (1. + rand) * real(size) ! Good matrix
call random_number(rand)
b(i) = rand ! A number between 0. and 1.
end do

aCopy = a
x=b

call croutDescomp(aCopy,size)
call croutSust(aCopy, x, size)

x = matmul(a, x) - b
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

!****************************************************************************

subroutine croutDescomp(a, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: a(n,n)
integer :: row, column, i

do i = 1, n
!Obtain L
do row = i, n
a(row,i) = a(row,i) - dot_product(a(row,1:i-1),a(1:i-1,i))
end do

!Obtain U
do column = i + 1, n
a(i, column) = a(i, column) - &
dot_product(a(i,1:i-1),a(1:i-1,column))
a(i, column) = a(i, column) / a(i,i)
end do
end do

end subroutine

!****************************************************************************

- 138 -
Andrés Zarabozo Martínez Métodos numéricos

subroutine croutSust(a, b, n)
implicit none
integer, intent(in) :: n
real, intent(inout) :: b (n)
real, intent(in) :: a(n,n)
integer :: row, i

!Ly = b
do row = 1, n
b(row) = b(row) - dot_product(a(row,1:row-1), b(1:row-1))
b(row) = b(row) / a(row,row)
end do

!Ux = y
do row = n, 1, -1
b(row) = b(row) - dot_product(a(row,row+1:n),b(row+1:n))
end do

end subroutine

- 139 -
Andrés Zarabozo Martínez Métodos numéricos

Programa 12. Matriz Banda

Program program12
implicit none
integer, parameter :: size = 50, d = 5
integer i, j, left, right
real :: a(-d:d,size), aCopy(-d:d,size), b(size), bCopy(size), x(size), rand

do i = 1, size
do j = -d, d
call random_number(rand)
a(j,i) = 0.5 - rand !A number between -0.5 and 0.5
end do
a(0,i) = (1. + rand) * real(size) !Good matrix
call random_number(rand)
b(i) = rand !A number between 0. and 1.
end do
aCopy = a
x=b

!Solve
call gaussBand(aCopy, b, d, size)

!Check results
bCopy = b
do i = 1, size
left = min(d, i - 1)
right = min(d, size - i)
x(i) = dot_product(a(-left:right, i),bCopy(i-left:i+right)) - x(i)
end do
print *, 'If the code is correct this is a small number:', maxval(abs(x))

end program

!****************************************************************************

subroutine gaussBand(a, b, d, n)
implicit none
integer, intent(in) :: d, n
real, intent(inout) :: a(-d:d,n), b(n)
integer pivot, row, disp
real mult

!Triangulate matrix
do pivot = 1, n - 1
do row = pivot + 1, min(pivot + d, n)
disp = row - pivot
!Gauss
mult = a(-disp,row) / a(0, pivot)
a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - &
mult * a(1:d,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

- 140 -
Andrés Zarabozo Martínez Métodos numéricos

!Solve x
do row = n, 1, -1

disp = min(d, n - row)


b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp))
b(row) = b(row) / a(0,row)
end do

end subroutine

- 141 -
Andrés Zarabozo Martínez Métodos numéricos

10.6. Método de diferencias finitas

Programa 13. Ejemplo de problema mecánico

program finiteDifferences
implicit none
integer n, i, j, maxIt, maxLoop, kas
real*8, allocatable :: K(:,:), R(:), x(:)
real*8 v, v1, h, tref, ka, error

!Program configuration
ka = 0.5 !Constant in drag
n = 1000 !Initial number of nodes
maxLoop = 10 !Maximum number of times the program is runned
maxIt = 100 !Maximum iteration in Newton's method
error = 0.00001 !Maximum Error
tref = 6.371E6 * 6.371E6 * 6.371E6 / 3.986E14
tref = tref ** 0.5

!Loop for number of nodes


do j = 1, maxLoop
allocate (K(3,n), R(n), x(n))

!Initial values for x


h = (1020. / tref) / dble(n - 1)
call initialValues(x, n, tref, h)
v = 0.

!Loop for number of iterations


do i = 1, maxIt

!Generate matrix K and vector R


call writeSystem (K, R, x, n, tref, h, ka)

!Solve K·dx = -R
R=-R
call gaussBand(K, R, 1, n)

!Solve x1 = x0 + dx
x=x+R

!Initial velocity
v1 = v
v = (4. * x(2) - 3. * x(1) - x(3)) / (2. * h)

!Print results
if(maxval(abs(R)) .lt. error) then
print*, "Number of nodes: ", n
print*, "Error in R: ", maxval(abs(R))
print*, "Iterations needed: ", i
print*, "Initial velocity: ", " ", v
print*, " "
exit

- 142 -
Andrés Zarabozo Martínez Métodos numéricos

elseif (i .eq. maxIt) then


print*, "Number of nodes: ", n
print*, "No solution found. "
print*, " "
end if
end do
!Renew discretization
deallocate(K, R, x)
n = 1000 + n
end do

end program

!******************************************************************

subroutine writeSystem(K, R, x, n, tref, h, ka)


implicit none
integer, intent (in) :: n
real*8, intent (in) :: x(n), tref, h, ka
real*8, intent (out) :: K(3,n), R(n)

integer i
real*8 h2

h2 = 1. / (h * h)

!Write matrix K
K(2,1) = 1.
K(3,1) = 0.
do i = 2, n - 1
K(1,i) = h2 - ka * 2. * (x(i+1) - x(i-1)) * h2
K(2,i) = 1. - 2. * h2
K(3,i) = h2 + ka * 2. * (x(i+1) - x(i-1)) * h2
end do
K(1,n) = 0.
K(2,n) = 1.

!Write vector R
R(1) = 0.
do i = 2, n - 1
R(i) = x(i) + (x(i+1) - 2. * x(i) + x(i-1)) * h2 + &
ka * (x(i+1) - x(i-1)) * (x(i+1) - x(i-1)) * h2
end do
R(n) = 0.

end subroutine

!******************************************************************

subroutine initialValues(x0, n, tref, h)


implicit none
integer, intent (in) :: n
real*8, intent(in) :: tref, h
real*8, intent (out) :: x0(n)

- 143 -
Andrés Zarabozo Martínez Métodos numéricos

integer i
real*8 t, tn, kn

tn = 1020. / tref

kn = (1. + dcos(tn)) / dsin(tn)

x0(1) = -1.
do i = 2, n - 1
t = dble(i - 1) * h
x0(i) = - dcos(t) + kn * dsin(t)
end do
x0(n) = 1.
end subroutine

!******************************************************************

subroutine gaussBand(a, b, d, n)
implicit none
integer, intent(in) :: d, n
real*8, intent(inout) :: a(-d:d,n), b(n)
integer pivot, row, disp
real*8 mult

!Triangulate matrix
do pivot = 1, n - 1
do row = pivot + 1, min(pivot + d, n)
disp = row - pivot
!Gauss
mult = a(-disp,row) / a(0, pivot)
a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - &
mult * a(1:d,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

!Solve x
do row = n, 1, -1
disp = min(d, n - row)
b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp))
b(row) = b(row) / a(0,row)
end do

end subroutine

- 144 -
Andrés Zarabozo Martínez Métodos numéricos

10.7. Método de elementos finitos

Programa 15. Radiador especial

module subroutines

implicit none

!Variables: Local means element coordinates. X: coordinates of node;


!N: shape function; DN: deriv.N; IP: Integ. points
real, save :: localX(4,2), localN(4,4), localDN(4,2,4), localIP(4,2), alpha
real, allocatable, save :: node(:,:), K(:,:), T(:), q0(:), T0(:), Kr(:,:), Ktot(:,:), Tit(:,:)
integer, allocatable, save :: elemNode(:,:), boundIn(:), boundExt(:,:)
integer, save :: nNode, nElem, nIn, nExt, nIP, nX
integer, save :: maxIterations, endIT
real, save :: error

contains

!**************************************************************

subroutine readMesh()

implicit none

integer i
real aux, aux2

open(UNIT = 5, FILE = 'input_mesh.txt', ACCESS = 'SEQUENTIAL')

!Read nodal coordinates


read(5,*) nNode
allocate (node(nNode,2))
do i = 1, nNode
read(5,*) aux, node(i,:), aux2 !First and last numbers not needed
end do

!Read Elements
read(5,*) nElem
allocate(elemNode(nElem,4))
do i = 1, nElem
read(5,*) aux, elemNode(i,:)
end do

!Read Boundary nodes that Radiate


read(5,*) nExt
allocate(boundExt(nExt,2))
do i = 1, nExt
read(5,*) aux, boundExt(i,:)
end do

- 145 -
Andrés Zarabozo Martínez Métodos numéricos

!Read Boundary nodes with constant Temperature


read(5,*) nIn
allocate(boundIn(nIn))
do i = 1, nIn
read(5,*) aux, boundIn(i)
end do

close(5)

end subroutine readMesh

!**************************************************************

subroutine init()
implicit none
real aux
integer i

allocate(K(nNode, nNode), Kr(nNode, nNode), KTot(nNode,nNode), &


T(nNode), T0(nNode), q0(nNode))
allocate(Tit(nNode,maxIterations))

K = 0.; Kr = 0.; KTot = 0.; T = 0.; T0 = 0.; q0 = 0.; nIP = 4; nX = 4; Tit = 0.

!Initial temperature
if (alpha .ge. 1) then
T0 = 0.9
else
T0 = alpha
end if

!Node positions localX(node, xi-eta)


localX(1,1) = -1.; localX(1,2) = -1.
localX(2,1) = 1.; localX(2,2) = -1.
localX(3,1) = 1.; localX(3,2) = 1.
localX(4,1) = -1.; localX(4,2) = 1.

!Integration points position localIP(IP, xi-eta)


aux = 1. / sqrt(3.)
localIP = localX * aux

do i = 1, 4
!Shape functions localN(IP, shape function)
localN(i,1) = (1. - localIP(i,1)) * (1. - localIP(i,2))
localN(i,2) = (1. + localIP(i,1)) * (1. - localIP(i,2))
localN(i,3) = (1. + localIP(i,1)) * (1. + localIP(i,2))
localN(i,4) = (1. - localIP(i,1)) * (1. + localIP(i,2))

!Derivative localDN(IP, dxi - deta, shape function)


localDN(i,1,1) = - 1. + localIP(i,2); localDN(i,2,1) = - 1. + localIP(i,1)
localDN(i,1,2) = 1. - localIP(i,2); localDN(i,2,2) = - 1. - localIP(i,1)
localDN(i,1,3) = 1. + localIP(i,2); localDN(i,2,3) = 1. + localIP(i,1)
localDN(i,1,4) = - 1. - localIP(i,2); localDN(i,2,4) = 1. - localIP(i,1)
end do

- 146 -
Andrés Zarabozo Martínez Métodos numéricos

localDN = 0.25 * localDN; localN = 0.25 * localN

end subroutine init

!**************************************************************

subroutine isoTransform (x, dN, detJ) !Returns dN and detJ


implicit none

real, intent(in) :: x(nX,2)


real, intent(out) :: dN(nIP,2,nX), detJ(nIP)

integer i
real J(nIP,2,2), invJ(nIP,2,2)

do i = 1, nIP

!Obtain Jacobian and determinant. J = D x


J(i,:,:) = matmul(localDN(i,:,:),x)
detJ(i) = abs(J(i,1,1) * J(i,2,2) - J(i,2,1) * J(i,1,2))

!Obtain the inverse of a 2x2 matrix


invJ(i,1,1) = J(i,2,2); invJ(i,1,2) = -J(i,1,2)
invJ(i,2,1) = -J(i,2,1); invJ(i,2,2) = J(i,1,1)
invJ(i,:,:) = (1. / detJ(i)) * invJ(i,:,:)

!Obtain dN = invJ * localDN


dN(i,:,:) = matmul(invJ(i,:,:), localDN(i,:,:))
end do

end subroutine isoTransform

!**************************************************************

subroutine assembleK()
implicit none

integer i, j, l, eN(nX) !Remember nX is number of nodes per element


real x(nX,2), dN(nIP,2,nX), detJ(nIP)
real localK(nX,nX)

do i = 1, nElem
!Saves, in eN(4), the number of the nodes in the element
eN = elemNode(i,:)

!Saves, in x(4,2), the positions of the nodes


!in global coordinates of the element
do j = 1, nX
x(j,:) = node(eN(j),:)
end do

localK = 0.
call isoTransform(x, dN, detJ)

- 147 -
Andrés Zarabozo Martínez Métodos numéricos

!K = sum(|J| Dt D)
do j = 1, nIP
localK = localK + detJ(j) * matmul(transpose(dN(j,:,:)),dN(j,:,:))
end do

!Introduces the values in the global matrix K


do j = 1, nX
do l = 1, nX
K(eN(j), eN(l)) = K(eN(j), eN(l)) + localK(j,l)
end do
end do

end do
end subroutine assembleK

!**************************************************************

subroutine assembleQ()

implicit none

integer i, j, k, x(2)
real localQ(2), localT(2), localKr(2,2), L
real aux

!Restarts q0 and Kr
q0 = 0.; Kr = 0.

do i = 1, nExt
!Pointer to node number
x = boundExt(i,:)

!Length
L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1))
L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2))
L = sqrt(L)

!Temperatures at the nodes


localT(1) = T0(x(1)); localT(2) = T0(x(2))

!Matrix q0
!Heat on the nodes
localQ(1) = localT(1)*localT(1)*localT(1)*localT(1) + 0.5 * &
localT(2)*localT(2)*localT(2)*localT(2)
localQ(2) = localT(2)*localT(2)*localT(2)*localT(2) + 0.5 * &
localT(1)*localT(1)*localT(1)*localT(1)
aux = L / alpha
localQ = localQ * aux

!Introduce values in global q


q0(x(1)) = q0(x(1)) + localQ(1)
q0(x(2)) = q0(x(2)) + localQ(2)

- 148 -
Andrés Zarabozo Martínez Métodos numéricos

!Matrix Kr
!Local Kr
aux = 4./6.
localKr(1,1) = 2. * aux * localT(1)*localT(1)*localT(1)
localKr(2,1) = aux * localT(1)*localT(1)*localT(1)
localKr(1,2) = aux * localT(2)*localT(2)*localT(2)
localKr(2,2) = 2. * aux * localT(2)*localT(2)*localT(2)
aux = - L / alpha
localKr = localKr * aux

!Introduce values in global Kr


do j = 1, 2
do k = 1, 2
Kr(x(j),x(k)) = Kr(x(j),x(k)) + localKr(j,k)
end do
end do

end do
endsubroutine assembleQ

!**************************************************************

subroutine innerBoundary()
implicit none
integer i, n

do i = 1, nIn
n = boundIn(i)
KTot(n,:) = 0.; KTot(n,n) = 1.
T(n) = 1. !Boundary temperature is 1
end do

end subroutine innerBoundary

!**************************************************************

subroutine solveSystem(a, b, n) !Matrix needs to be transposed


implicit none

integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult

!Triangulate the matrix


do pivot = 1, n-1
do row = pivot+1, n
mult = a(pivot, row) / a(pivot,pivot)
a(pivot+1:n,row) = a(pivot+1:n,row) - mult * &
a(pivot+1:n,pivot)
b(row) = b(row) - mult * b(pivot)
end do
end do

- 149 -
Andrés Zarabozo Martínez Métodos numéricos

!Obtain solutions
b(n) = b(n) / a(n,n)
do row=n-1,1,-1
b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n))
b(row) = b(row) / a(row,row)
end do

end subroutine

!**************************************************************

subroutine solver()
implicit none

integer i, j
real a(nNode, nNode)
logical bool

bool = .true.

do i = 1, maxIterations !bucle iterativo

!Obteins matrix Kr and vector q0


call assembleQ();

!Builds linear system Ax=b Where A=KTot and b=T


KTot = K - Kr
T = q0

!Introduces Dirichlett boundary conditions


call innerBoundary()

!Solves system
a = transpose(KTot)
call solveSystem(a, T, nNode)

!Writtes result
Tit(:,i) = T
!End loop
if(maxval(abs(T - T0)).lt. error) then
print*, " "
print*, "Final iteration: ", i
print*, " "
bool = .false.
exit
end if

!New iteration
T0 = T

print*, "Iteration ", i,"Done!"

end do

- 150 -
Andrés Zarabozo Martínez Métodos numéricos

endIT = i
if (bool) endIT = i - 1

end subroutine

!**************************************************************

subroutine getW()

implicit none

real L, W, localW, aux, localT(2)


integer i, x(2)

aux = 0.5
W = 0.

do i = 1, nExt
!Pointer to node number
x = boundExt(i,:)

!Length
L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1))
L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2))
L = sqrt(L)

!Temperatures at the nodes


localT(1) = T0(x(1))*T0(x(1))*T0(x(1))*T0(x(1))
localT(2) = T0(x(2))*T0(x(2))*T0(x(2))*T0(x(2))

!Emitted power
localW = L * aux * (localT(1) + localT(2))

!Global power
W = W + localW
end do

print*, " "


print*, "Alpha:", alpha
print*, "Non-dim. power:", W
print*, " "

end subroutine getW

!**************************************************************
!**************************************************************

subroutine writeGidMesh()

implicit none
! x : Nodal Coordinates
! conec : Conectivity (Nodes of elements)
! n_nod : Number of Nodes
! n_el : Number of Elements

- 151 -
Andrés Zarabozo Martínez Métodos numéricos

integer n_nod, n_el, conec(4,nElem), i


real x(2,nNode)

!Convert the variables to R.F. variables


n_nod = nNode; n_el = nElem
x(1,:) = node(:,1); x(2,:) = node(:,2)
conec = transpose(elemNode)

open(UNIT=6,FILE='radiation_analysis.post.msh',ACCESS='SEQUENTIAL',&
STATUS='REPLACE') ! Create File
write(6,*) '# postprocess mesh for GiD' ! File Header
write(6,*) 'MESH "RADIATION_FEA" dimension 2 ElemType Quadrilateral Nnode 4'
! Write Nodal Coordinates
write(6,*) 'Coordinates'
write(6,*) '# node number coordinate_x coordinate_y'

do i = 1, n_nod
write(6,*) i, x(:, i)
end do ! i

write(6,*) 'end coordinates'

! Write Surface Elements


write(6,*) 'Elements'
write(6,*) '# element node_1 node_2 node_3 node_4'

do i = 1, n_el
write(6,*) i, conec(:, i)
end do ! i

write(6,*) 'end elements'


close(6) ! Close File
end subroutine writeGidMesh

!**************************************************************

subroutine writeTemperature()

implicit none

integer n_nod, n_ite


real temperature(nNode, endIT)

integer nodeF, iter


character*(*) temp_h, scalar, endvalues, values
character*(*) header, filename
parameter (temp_h = 'Result "TEMPERATURE" "ITERATION=" ')
parameter (scalar = ' Scalar OnNodes')
parameter (endvalues = 'End Values', values = 'Values')
parameter (header = 'GiD Post Results File 1.0')
parameter (filename = 'radiation_analysis.post.res')

!Convert the variables to R.F. variables


n_nod = nNode; n_ite = endIT; temperature(:,:) = Tit(:,1:endIT)

- 152 -
Andrés Zarabozo Martínez Métodos numéricos

! Format specs
10 format (A) ! Single character field
20 format (A, I0, A) ! Use to write iteration number
! Open Output File & Overwrite
open(UNIT=6, FILE=filename, ACCESS='SEQUENTIAL', &
STATUS='REPLACE')

! Write Header
write(6,10) header

! Write Temperature Distribution for Each Iteration


do iter = 1, n_ite
write(6,20) temp_h, iter, scalar
write(6,10) values

do nodeF = 1, n_nod
write(6,*) nodeF, temperature(nodeF, iter)
end do ! nodeF

write(6,10) endvalues
end do ! iter

! Close file
close(6)

end subroutine writeTemperature


end module subroutines

!**************************************************************
! Main Program
!**************************************************************

program spaceRadiator
use subroutines
implicit none
integer i

!Program configurator
alpha = 100.
maxIterations = 30
error = 0.0001

!Program sequence
call readMesh(); print*, "Read Mesh Done!"
call init(); print*, "Init Done!"
call assembleK(); print*, "Assemble K Done!"; print*," "
call solver(); print*, "Solver Done!"
call getW(); Print*, "Get W Done!"
call writeGidMesh();
call writeTemperature();

end program spaceRadiator

- 153 -
Andrés Zarabozo Martínez Métodos numéricos

10.8. Datos de entrada del Programa 15, radiador espacial


Los siguientes datos se utilizan como datos de entrada para el programa del radiador espacial.
Debe ser nombrado “imput_mesh.txt”. Consiste en una malla con nodos para .

288 ! Number of nodes


1, 10.000000, 0.000000, 0.000000
2, 10.000000, 0.100000, 0.000000
3, 10.000000, 0.200000, 0.000000
4, 10.000000, 0.300000, 0.000000
5, 10.000000, 0.400000, 0.000000
6, 10.000000, 0.500000, 0.000000
7, 10.000000, 0.600000, 0.000000
8, 10.000000, 0.700000, 0.000000
9, 9.208628, 0.000000, 0.000000
10, 9.208628, 0.103795, 0.000000
11, 10.000000, 0.800000, 0.000000
12, 9.208628, 0.210336, 0.000000
13, 9.208628, 0.318936, 0.000000
14, 10.000000, 0.900000, 0.000000
15, 9.208628, 0.428909, 0.000000
16, 9.208628, 0.539569, 0.000000
17, 10.000000, 1.000000, 0.000000
18, 9.208628, 0.650228, 0.000000
19, 9.208628, 0.760201, 0.000000
20, 9.208628, 0.868801, 0.000000
21, 9.208628, 0.975342, 0.000000
22, 9.208628, 1.079137, 0.000000
23, 8.427669, 0.000000, 0.000000
24, 8.427669, 0.110203, 0.000000
25, 8.427669, 0.224086, 0.000000
26, 8.427669, 0.340729, 0.000000
27, 8.427669, 0.459213, 0.000000
28, 8.427669, 0.578617, 0.000000
29, 8.427669, 0.698020, 0.000000
30, 8.427669, 0.816504, 0.000000
31, 8.427669, 0.933147, 0.000000
32, 8.427669, 1.047030, 0.000000
33, 8.427669, 1.157233, 0.000000
34, 7.666995, 0.000000, 0.000000
35, 7.666995, 0.118371, 0.000000
36, 7.666995, 0.240048, 0.000000
37, 7.666995, 0.364205, 0.000000
38, 7.666995, 0.490014, 0.000000
39, 7.666995, 0.616650, 0.000000
40, 7.666995, 0.743286, 0.000000
41, 7.666995, 0.869096, 0.000000
42, 7.666995, 0.993252, 0.000000
43, 7.666995, 1.114929, 0.000000
44, 7.666995, 1.233300, 0.000000
45, 6.935578, 0.000000, 0.000000
46, 6.935578, 0.127460, 0.000000
47, 6.935578, 0.257043, 0.000000
48, 6.935578, 0.388218, 0.000000
49, 6.935578, 0.520454, 0.000000
50, 6.935578, 0.653221, 0.000000
51, 6.935578, 0.785988, 0.000000
52, 6.935578, 0.918224, 0.000000
53, 6.935578, 1.049399, 0.000000
54, 6.935578, 1.178982, 0.000000
55, 6.935578, 1.306442, 0.000000
56, 6.241194, 0.000000, 0.000000
57, 6.241194, 0.136723, 0.000000
58, 6.241194, 0.274023, 0.000000
59, 6.241194, 0.411755, 0.000000
60, 6.241194, 0.549775, 0.000000
61, 6.241194, 0.687940, 0.000000
62, 6.241194, 0.826105, 0.000000
63, 6.241194, 0.964126, 0.000000
64, 6.241194, 1.101858, 0.000000
65, 6.241194, 1.239158, 0.000000
66, 6.241194, 1.375881, 0.000000
67, 5.590209, 0.000000, 0.000000
68, 5.590209, 0.145558, 0.000000

- 154 -
Andrés Zarabozo Martínez Métodos numéricos

69, 5.590209, 0.290142, 0.000000


70, 5.590209, 0.433997, 0.000000
71, 5.590209, 0.577365, 0.000000
72, 5.590209, 0.720490, 0.000000
73, 5.590209, 0.863614, 0.000000
74, 5.590209, 1.006982, 0.000000
75, 5.590209, 1.150837, 0.000000
76, 5.590209, 1.295421, 0.000000
77, 5.590209, 1.440979, 0.000000
78, 4.987445, 0.000000, 0.000000
79, 4.987445, 0.153537, 0.000000
80, 4.987445, 0.304800, 0.000000
81, 4.987445, 0.454357, 0.000000
82, 4.987445, 0.602777, 0.000000
83, 4.987445, 0.750628, 0.000000
84, 4.987445, 0.898479, 0.000000
85, 4.987445, 1.046899, 0.000000
86, 4.987445, 1.196456, 0.000000
87, 4.987445, 1.347718, 0.000000
88, 4.987445, 1.501255, 0.000000
89, 4.436137, 0.000000, 0.000000
90, 4.436137, 0.160408, 0.000000
91, 4.436137, 0.317636, 0.000000
92, 4.436137, 0.472480, 0.000000
93, 4.436137, 0.625734, 0.000000
94, 4.436137, 0.778193, 0.000000
95, 4.436137, 0.930652, 0.000000
96, 4.436137, 1.083906, 0.000000
97, 4.436137, 1.238750, 0.000000
98, 4.436137, 1.395978, 0.000000
99, 4.436137, 1.556386, 0.000000
100, 3.937967, 0.000000, 0.000000
101, 3.937967, 0.166071, 0.000000
102, 3.937967, 0.328508, 0.000000
103, 3.937967, 0.488220, 0.000000
104, 3.937967, 0.646115, 0.000000
105, 3.937967, 0.803102, 0.000000
106, 3.937967, 0.960088, 0.000000
107, 3.937967, 1.117983, 0.000000
108, 3.937967, 1.277695, 0.000000
109, 3.937967, 1.440132, 0.000000
110, 3.937967, 1.606203, 0.000000
111, 3.493172, 0.000000, 0.000000
112, 3.493172, 0.170548, 0.000000
113, 3.493172, 0.337443, 0.000000
114, 3.493172, 0.501598, 0.000000
115, 3.493172, 0.663926, 0.000000
116, 3.493172, 0.825341, 0.000000
117, 3.493172, 0.986756, 0.000000
118, 3.493172, 1.149085, 0.000000
119, 3.493172, 1.313239, 0.000000
120, 3.493172, 1.480134, 0.000000
121, 3.493172, 1.650683, 0.000000
122, 3.100706, 0.000000, 0.000000
123, 3.100706, 0.173947, 0.000000
124, 3.100706, 0.344591, 0.000000
125, 3.100706, 0.512758, 0.000000
126, 3.100706, 0.679274, 0.000000
127, 3.100706, 0.844965, 0.000000
128, 3.100706, 1.010655, 0.000000
129, 3.100706, 1.177171, 0.000000
130, 3.100706, 1.345338, 0.000000
131, 3.100706, 1.515982, 0.000000
132, 3.100706, 1.689929, 0.000000
133, 2.758440, 0.000000, 0.000000
134, 2.758440, 0.176421, 0.000000
135, 2.758440, 0.350172, 0.000000
136, 2.758440, 0.521920, 0.000000
137, 2.758440, 0.692333, 0.000000
138, 2.758440, 0.862078, 0.000000
139, 2.758440, 1.031823, 0.000000
140, 2.758440, 1.202236, 0.000000
141, 2.758440, 1.373984, 0.000000
142, 2.758440, 1.547735, 0.000000
143, 2.758440, 1.724156, 0.000000
144, 2.463382, 0.000000, 0.000000
145, 2.463382, 0.178145, 0.000000

- 155 -
Andrés Zarabozo Martínez Métodos numéricos

146, 2.463382, 0.354438, 0.000000


147, 2.463382, 0.529341, 0.000000
148, 2.463382, 0.703317, 0.000000
149, 2.463382, 0.876831, 0.000000
150, 2.463382, 1.050344, 0.000000
151, 2.463382, 1.224321, 0.000000
152, 2.463382, 1.399224, 0.000000
153, 2.463382, 1.575517, 0.000000
154, 2.463382, 1.753662, 0.000000
155, 2.211913, 0.000000, 0.000000
156, 2.211913, 0.179288, 0.000000
157, 2.211913, 0.357637, 0.000000
158, 2.211913, 0.535284, 0.000000
159, 2.211913, 0.712461, 0.000000
160, 2.211913, 0.889404, 0.000000
161, 2.211913, 1.066347, 0.000000
162, 2.211913, 1.243525, 0.000000
163, 2.211913, 1.421171, 0.000000
164, 2.211913, 1.599521, 0.000000
165, 2.211913, 1.778809, 0.000000
166, 2.000000, 0.000000, 0.000000
167, 2.000000, 0.180000, 0.000000
168, 2.000000, 0.360000, 0.000000
169, 2.000000, 0.540000, 0.000000
170, 2.000000, 0.720000, 0.000000
171, 2.000000, 0.900000, 0.000000
172, 2.000000, 1.080000, 0.000000
173, 2.000000, 1.260000, 0.000000
174, 2.000000, 1.440000, 0.000000
175, 2.000000, 1.620000, 0.000000
176, 1.821629, 0.000000, 0.000000
177, 1.815673, 0.180872, 0.000000
178, 1.815169, 0.361012, 0.000000
179, 2.000000, 1.800000, 0.000000
180, 1.815784, 0.541894, 0.000000
181, 1.812997, 0.719583, 0.000000
182, 1.811110, 0.898145, 0.000000
183, 1.808492, 1.079273, 0.000000
184, 1.806234, 1.266466, 0.000000
185, 1.804310, 1.455508, 0.000000
186, 1.808224, 1.637391, 0.000000
187, 1.636086, 0.000000, 0.000000
188, 1.630681, 0.176823, 0.000000
189, 1.630370, 0.353756, 0.000000
190, 1.813192, 1.818681, 0.000000
191, 1.625911, 0.528767, 0.000000
192, 1.619998, 0.705203, 0.000000
193, 1.619546, 0.888848, 0.000000
194, 1.616625, 1.072482, 0.000000
195, 1.608731, 1.266208, 0.000000
196, 1.606702, 1.463877, 0.000000
197, 1.615396, 1.655375, 0.000000
198, 1.446553, 0.167221, 0.000000
199, 1.443569, 0.000000, 0.000000
200, 1.441455, 0.338019, 0.000000
201, 1.622146, 1.837785, 0.000000
202, 1.432886, 0.508613, 0.000000
203, 1.421536, 0.683612, 0.000000
204, 1.424186, 0.865111, 0.000000
205, 1.405719, 1.052398, 0.000000
206, 1.400527, 1.256977, 0.000000
207, 1.400477, 1.462519, 0.000000
208, 1.275691, 0.151792, 0.000000
209, 1.268725, 0.000000, 0.000000
210, 1.264471, 0.305980, 0.000000
211, 1.417036, 1.666282, 0.000000
212, 1.244228, 0.463444, 0.000000
213, 1.427056, 1.857294, 0.000000
214, 1.234777, 0.835586, 0.000000
215, 1.202281, 0.646075, 0.000000
216, 1.123014, 0.133967, 0.000000
217, 1.121434, 0.000000, 0.000000
218, 1.175523, 1.014019, 0.000000
219, 1.111057, 0.264424, 0.000000
220, 1.131105, 0.816136, 0.000000
221, 1.180136, 1.246738, 0.000000
222, 1.081815, 0.395229, 0.000000

- 156 -
Andrés Zarabozo Martínez Métodos numéricos

223, 1.194695, 1.469996, 0.000000


224, 1.215938, 1.677771, 0.000000
225, 1.069449, 0.718869, 0.000000
226, 1.228136, 1.877186, 0.000000
227, 1.072855, 0.892884, 0.000000
228, 1.032974, 0.522098, 0.000000
229, 1.000000, 0.000000, 0.000000
230, 0.993712, 0.111964, 0.000000
231, 0.974928, 0.222521, 0.000000
232, 0.985400, 0.800166, 0.000000
233, 0.993378, 0.940211, 0.000000
234, 0.943883, 0.330279, 0.000000
235, 0.956961, 0.619959, 0.000000
236, 0.984128, 1.042489, 0.000000
237, 0.900969, 0.433884, 0.000000
238, 0.908253, 0.880242, 0.000000
239, 0.881762, 0.709896, 0.000000
240, 0.968509, 1.486987, 0.000000
241, 1.000807, 1.700009, 0.000000
242, 0.918269, 1.240118, 0.000000
243, 0.846724, 0.532032, 0.000000
244, 1.025621, 1.897438, 0.000000
245, 0.843327, 0.974604, 0.000000
246, 0.802854, 0.795968, 0.000000
247, 0.781831, 0.623490, 0.000000
248, 0.751021, 1.088769, 0.000000
249, 0.723119, 0.883010, 0.000000
250, 0.707107, 0.707107, 0.000000
251, 0.791544, 1.730488, 0.000000
252, 0.755425, 1.532664, 0.000000
253, 0.820497, 1.917950, 0.000000
254, 0.700764, 1.331699, 0.000000
255, 0.623490, 0.781831, 0.000000
256, 0.628707, 0.961914, 0.000000
257, 0.608334, 1.168378, 0.000000
258, 0.532032, 0.846724, 0.000000
259, 0.513908, 1.024962, 0.000000
260, 0.592549, 1.751134, 0.000000
261, 0.556982, 1.567234, 0.000000
262, 0.615372, 1.938463, 0.000000
263, 0.516188, 1.380476, 0.000000
264, 0.433884, 0.900969, 0.000000
265, 0.460891, 1.216817, 0.000000
266, 0.395504, 1.069903, 0.000000
267, 0.330279, 0.943883, 0.000000
268, 0.369893, 1.582445, 0.000000
269, 0.340301, 1.404842, 0.000000
270, 0.392043, 1.770125, 0.000000
271, 0.304717, 1.245069, 0.000000
272, 0.410248, 1.958975, 0.000000
273, 0.264905, 1.100687, 0.000000
274, 0.222521, 0.974928, 0.000000
275, 0.152769, 1.257928, 0.000000
276, 0.132989, 1.115929, 0.000000
277, 0.168770, 1.423452, 0.000000
278, 0.111964, 0.993712, 0.000000
279, 0.182011, 1.598901, 0.000000
280, 0.195481, 1.787944, 0.000000
281, 0.205124, 1.979488, 0.000000
282, 0.000000, 1.000000, 0.000000
283, 0.000000, 1.118304, 0.000000
284, 0.000000, 1.261798, 0.000000
285, 0.000000, 1.432135, 0.000000
286, 0.000000, 1.621423, 0.000000
287, 0.000000, 1.810712, 0.000000
288, 0.000000, 2.000000, 0.000000
249 ! Number of elements
1,282, 278, 276, 283
2,230, 229, 217, 216
3,278, 274, 273, 276
4,231, 230, 216, 219
5,274, 267, 266, 273
6,234, 231, 219, 222
7,267, 264, 259, 266
8,237, 234, 222, 228
9,264, 258, 256, 259
10,243, 237, 228, 235

- 157 -
Andrés Zarabozo Martínez Métodos numéricos

11,258, 255, 249, 256


12,247, 243, 235, 239
13,255, 250, 246, 249
14,250, 247, 239, 246
15,284, 283, 276, 275
16,217, 209, 208, 216
17,285, 284, 275, 277
18,209, 199, 198, 208
19,176, 166, 167, 177
20,175, 179, 190, 186
21,167, 168, 178, 177
22,174, 175, 186, 185
23,168, 169, 180, 178
24,173, 174, 185, 184
25,169, 170, 181, 180
26,172, 173, 184, 183
27,170, 171, 182, 181
28,171, 172, 183, 182
29,187, 176, 177, 188
30,199, 187, 188, 198
31,288, 287, 280, 281
32,286, 285, 277, 279
33,287, 286, 279, 280
34,190, 201, 197, 186
35,201, 213, 211, 197
36,213, 226, 224, 211
37,226, 244, 241, 224
38,272, 281, 280, 270
39,244, 253, 251, 241
40,262, 272, 270, 260
41,253, 262, 260, 251
42,219, 216, 208, 210
43,222, 219, 210, 212
44,228, 222, 212, 215
45,275, 276, 273, 271
46,235, 228, 215, 225
47,239, 235, 225, 232
48,246, 239, 232, 238
49,249, 246, 238, 245
50,256, 249, 245, 248
51,259, 256, 248, 257
52,266, 259, 257, 265
53,273, 266, 265, 271
54,277, 275, 271, 269
55,186, 197, 196, 185
56,184, 185, 196, 195
57,183, 184, 195, 194
58,182, 183, 194, 193
59,181, 182, 193, 192
60,180, 181, 192, 191
61,177, 178, 189, 188
62,178, 180, 191, 189
63,208, 198, 200, 210
64,198, 188, 189, 200
65,279, 277, 269, 268
66,280, 279, 268, 270
67,260, 270, 268, 261
68,197, 211, 207, 196
69,251, 260, 261, 252
70,211, 224, 223, 207
71,241, 251, 252, 240
72,224, 241, 240, 223
73,212, 210, 200, 202
74,200, 189, 191, 202
75,191, 192, 203, 202
76,212, 202, 203, 215
77,271, 265, 263, 269
78,268, 269, 263, 261
79,265, 257, 254, 263
80,261, 263, 254, 252
81,196, 207, 206, 195
82,194, 195, 206, 205
83,193, 194, 205, 204
84,192, 193, 204, 203
85,207, 223, 221, 206
86,240, 252, 254, 242
87,223, 240, 242, 221

- 158 -
Andrés Zarabozo Martínez Métodos numéricos

88,254, 257, 248, 242


89,245, 238, 233, 236
90,238, 232, 227, 233
91,232, 225, 220, 227
92,220, 225, 215, 214
93,204, 214, 215, 203
94,248, 245, 236, 242
95,233, 227, 218, 236
96,227, 220, 214, 218
97,214, 204, 205, 218
98,205, 206, 221, 218
99,221, 242, 236, 218
100,2, 10, 9, 1
101,3, 12, 10, 2
102,4, 13, 12, 3
103,5, 15, 13, 4
104,6, 16, 15, 5
105,7, 18, 16, 6
106,8, 19, 18, 7
107,11, 20, 19, 8
108,14, 21, 20, 11
109,17, 22, 21, 14
110,10, 24, 23, 9
111,12, 25, 24, 10
112,13, 26, 25, 12
113,15, 27, 26, 13
114,16, 28, 27, 15
115,18, 29, 28, 16
116,19, 30, 29, 18
117,20, 31, 30, 19
118,21, 32, 31, 20
119,22, 33, 32, 21
120,24, 35, 34, 23
121,25, 36, 35, 24
122,26, 37, 36, 25
123,27, 38, 37, 26
124,28, 39, 38, 27
125,29, 40, 39, 28
126,30, 41, 40, 29
127,31, 42, 41, 30
128,32, 43, 42, 31
129,33, 44, 43, 32
130,35, 46, 45, 34
131,36, 47, 46, 35
132,37, 48, 47, 36
133,38, 49, 48, 37
134,39, 50, 49, 38
135,40, 51, 50, 39
136,41, 52, 51, 40
137,42, 53, 52, 41
138,43, 54, 53, 42
139,44, 55, 54, 43
140,46, 57, 56, 45
141,47, 58, 57, 46
142,48, 59, 58, 47
143,49, 60, 59, 48
144,50, 61, 60, 49
145,51, 62, 61, 50
146,52, 63, 62, 51
147,53, 64, 63, 52
148,54, 65, 64, 53
149,55, 66, 65, 54
150,57, 68, 67, 56
151,58, 69, 68, 57
152,59, 70, 69, 58
153,60, 71, 70, 59
154,61, 72, 71, 60
155,62, 73, 72, 61
156,63, 74, 73, 62
157,64, 75, 74, 63
158,65, 76, 75, 64
159,66, 77, 76, 65
160,68, 79, 78, 67
161,69, 80, 79, 68
162,70, 81, 80, 69
163,71, 82, 81, 70
164,72, 83, 82, 71

- 159 -
Andrés Zarabozo Martínez Métodos numéricos

165,73, 84, 83, 72


166,74, 85, 84, 73
167,75, 86, 85, 74
168,76, 87, 86, 75
169,77, 88, 87, 76
170,79, 90, 89, 78
171,80, 91, 90, 79
172,81, 92, 91, 80
173,82, 93, 92, 81
174,83, 94, 93, 82
175,84, 95, 94, 83
176,85, 96, 95, 84
177,86, 97, 96, 85
178,87, 98, 97, 86
179,88, 99, 98, 87
180,90, 101, 100, 89
181,91, 102, 101, 90
182,92, 103, 102, 91
183,93, 104, 103, 92
184,94, 105, 104, 93
185,95, 106, 105, 94
186,96, 107, 106, 95
187,97, 108, 107, 96
188,98, 109, 108, 97
189,99, 110, 109, 98
190,101, 112, 111, 100
191,102, 113, 112, 101
192,103, 114, 113, 102
193,104, 115, 114, 103
194,105, 116, 115, 104
195,106, 117, 116, 105
196,107, 118, 117, 106
197,108, 119, 118, 107
198,109, 120, 119, 108
199,110, 121, 120, 109
200,112, 123, 122, 111
201,113, 124, 123, 112
202,114, 125, 124, 113
203,115, 126, 125, 114
204,116, 127, 126, 115
205,117, 128, 127, 116
206,118, 129, 128, 117
207,119, 130, 129, 118
208,120, 131, 130, 119
209,121, 132, 131, 120
210,123, 134, 133, 122
211,124, 135, 134, 123
212,125, 136, 135, 124
213,126, 137, 136, 125
214,127, 138, 137, 126
215,128, 139, 138, 127
216,129, 140, 139, 128
217,130, 141, 140, 129
218,131, 142, 141, 130
219,132, 143, 142, 131
220,134, 145, 144, 133
221,135, 146, 145, 134
222,136, 147, 146, 135
223,137, 148, 147, 136
224,138, 149, 148, 137
225,139, 150, 149, 138
226,140, 151, 150, 139
227,141, 152, 151, 140
228,142, 153, 152, 141
229,143, 154, 153, 142
230,145, 156, 155, 144
231,146, 157, 156, 145
232,147, 158, 157, 146
233,148, 159, 158, 147
234,149, 160, 159, 148
235,150, 161, 160, 149
236,151, 162, 161, 150
237,152, 163, 162, 151
238,153, 164, 163, 152
239,154, 165, 164, 153
240,156, 167, 166, 155
241,157, 168, 167, 156

- 160 -
Andrés Zarabozo Martínez Métodos numéricos

242,158, 169, 168, 157


243,159, 170, 169, 158
244,160, 171, 170, 159
245,161, 172, 171, 160
246,162, 173, 172, 161
247,163, 174, 173, 162
248,164, 175, 174, 163
249,165, 179, 175, 164
34 ! Number of radiating faces
1, 179,190
2, 281,288
3, 190,201
4, 201,213
5, 213,226
6, 226,244
7, 272,281
8, 244,253
9, 262,272
10, 253,262
11, 1,2
12, 2,3
13, 3,4
14, 4,5
15, 5,6
16, 6,7
17, 7,8
18, 8,11
19, 11,14
20, 17,22
21, 22,33
22, 33,44
23, 44,55
24, 55,66
25, 66,77
26, 77,88
27, 88,99
28, 99,110
29, 110,121
30, 121,132
31, 132,143
32, 143,154
33, 154,165
34, 165,179
15 ! Number of fixed temperature nodes
1, 229
2, 230
3, 231
4, 234
5, 237
6, 243
7, 247
8, 250
9, 255
10, 258
11, 264
12, 267
13, 274
14, 278
15, 282

- 161 -

También podría gustarte