Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ingeniería Aeronáutica
ETSEIAT
2012
Andrés Zarabozo Martínez Métodos numéricos
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:
-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
-4-
Andrés Zarabozo Martínez Métodos numéricos
-5-
Andrés Zarabozo Martínez Métodos numéricos
-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
-7-
Andrés Zarabozo Martínez Métodos numéricos
x = 1. + 3. 25 * 5. / 3.
x = cos(1.25) + y**2.
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
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):
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
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.
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).
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.
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)).
- 10 -
Andrés Zarabozo Martínez Métodos numéricos
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:
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.
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
A = pi * r * r
end subroutine
real A1, r1
r1 = 3.
call areaCircle(A1, r1)
- 11 -
Andrés Zarabozo Martínez Métodos numéricos
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.
- 12 -
Andrés Zarabozo Martínez Métodos numéricos
1.7. Programas
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
- 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
(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)
(1.4)
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
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
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.
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.
𝑥𝑖− 𝑥𝑖 𝑥𝑖+
- 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)
−
(2.3)
𝐻
𝐻
𝐻
𝐻4
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
( ) ( ) ( ) 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)
4
| ( )| (2.6)
4 ( ) (2.7)
( )( ) ( ) ( ) (2.8)
(2.9)
(2.10)
Por lo tanto:
( ) (2.11)
( )( ) ( ) ( )
(2.12)
( ) ( ) ( )
- 19 -
Andrés Zarabozo Martínez Métodos numéricos
2.3. Programa
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)).
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.
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.
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.
- 21 -
Andrés Zarabozo Martínez Métodos numéricos
(2.13)
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.
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.
- 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:
∫ ( ) ∑( − ) ( ) [ − ] (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).
𝑓(𝑥)
𝑎 𝑏
𝑥 𝑥 𝑥 . 𝑥𝑛− 𝑥𝑛 𝑥
Si los intervalos son iguales éste se puede calcular fácilmente con la posición de los extremos.
(3.2)
- 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)
( ) (3.4)
{ (3.5)
( )( ) ( − )( + ) ( )
( ) (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.
∫ ( ) (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
𝑓(𝑥)
𝑔(𝜉)
𝑥 𝜉
𝑎 𝑏
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)
(3.15)
𝑔(𝜉)
𝑃(𝜉)
𝜉
- 25 -
Andrés Zarabozo Martínez Métodos numéricos
( ) ( )
( ) ( ) (3.16)
( ) ( ) ( ) ( ) ( − ) ( )
(3.17)
( ) ( ) ( ) ( )
(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.
( ∑ ( )) (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
𝑔(𝜉)
𝑃(𝜉)
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)
∫ ( ) ( ) ( ) (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.
𝑓(𝑥)
𝑎 𝑏
𝑥 𝑥 𝑥 . 𝑥𝑛− 𝑥𝑛 𝑥
- 27 -
Andrés Zarabozo Martínez Métodos numéricos
[ ( ) ( ) ( )] [ ( − ) ( − ) ( )] (3.25)
[ ( ) ( ) ( ) ( − ) ( − ) ( )]
( ) ( )
( ∑ ( ) ∑ ( )) (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.27)
( ) (3.28)
Donde son constantes desconocidas reales y son constantes conocidas tal que
.
( ) +
( ) (3.29)
+ (3.30)
( ) ( ) ( )
( ) +
( ) ( ) ( ) (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.
+ (3.33)
( ) ( ) ( )
+
( ) ( ) ( ) ( ) (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
∫ ( ) ∫ ( ) ( ) (3.37)
− −
∫ ( ) ( ) (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
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.
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
integer i
real z(n), x(n), dx, invPi, a, b
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
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
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.)
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
end program
- 32 -
Andrés Zarabozo Martínez Métodos numéricos
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.
( ) (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
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.
- 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)
∫ ( ( ) ) . (3.42)
!Results
print*, integ - (.2 * dsin(dble(5.)) + 1.)
end program
- 34 -
Andrés Zarabozo Martínez Métodos numéricos
( ) ( ) ( ) ( ) (3.43)
!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
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.
( ) [ ]
{ (4.1)
( ) [ ]
(4.2)
̃ (4.3)
|̃ + |
(4.4)
|̃ |
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.
- 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)
( ) ( ) ( ) (4.6)
( )
(4.7)
( )
𝑓(𝑥 )
𝑓(𝑥 )
𝑥 𝑥
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:
( ) ( )
( ) (4.8)
Y por lo tanto:
( ) (4.9)
( ) ( )
- 37 -
Andrés Zarabozo Martínez Métodos numéricos
𝑓(𝑥 )
𝑓(𝑥 )
𝑥
𝑥 𝑥 𝑥
𝑓(𝑥 )
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.
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
( ) ( )
(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.
𝑓(𝑥 )
𝑓(𝑥 )
𝑥 𝑥
𝑥 𝑥
𝑓(𝑥 )
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.
𝑓(𝑥 )
𝑓(𝑥 )
𝑥 𝑥 𝑥
- 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.
𝑥 𝑥 𝑥 𝑥
- 40 -
Andrés Zarabozo Martínez Métodos numéricos
4.6. Programas
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.
𝐴 𝐵
𝑇 𝑇
𝑃
(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)
(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
(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)
√ (4.19)
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.
do i = 1, itMax
if (x1.eq.x2) exit
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.
x1 = x2
x2 = x3
fx1 = fx2
end do
end program
- 43 -
Andrés Zarabozo Martínez Métodos numéricos
( ) (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)
x2 = x1 - fx1 / slope
x1 = x2
end do
end program
- 44 -
Andrés Zarabozo Martínez Métodos numéricos
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.
(5.1)
( ){ } { }
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.
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
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)
{ (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)
( ) (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 ( ).
( ) (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.
( ) (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)
( ) (5.14)
( ) ( ) (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
De forma general si se tiene la siguiente matriz modificada para ir obteniendo los valores de
y de (hasta el pívot ):
(5.20)
( )
∑ (5.21)
Los valores de (donde son los elementos de la fila por detrás de ) se obtienen de la
siguiente forma:
−
( ∑ ) (5.22)
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
{ } { } { } { } { } (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)
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.
( )
( ) (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.
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.
Una matriz definida positiva es una matriz tal que para cualquier vector de elementos no
nulos cumpla .
̃ (5.32)
- 51 -
Andrés Zarabozo Martínez Métodos numéricos
( ̃) ̃ ̃ ̃ (5.33)
( ̃) ( ) ̃ (5.34)
( ̃) ̃ ̃ ̃ (5.35)
( ̃ ̃ ) (5.36)
̃
Debido a que la matriz es simétrica los términos dentro de los paréntesis son iguales.
̃ (5.37)
̃
̃ (5.38)
( ) ( ) ( ) ( )
( ) ( ) (5.39)
⏟
⏟ ⏟
( − )
( )
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.
(5.40)
- 52 -
Andrés Zarabozo Martínez Métodos numéricos
(5.41)
+ (5.42)
+
(5.43)
+ + +
+ + (5.44)
+
( + )
[ ( )]
( ) ( )
(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.
𝑟𝑖𝑇 𝑟𝑖 𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑟𝑖
𝑥𝑖 𝑟𝑖 𝛼𝑖
𝑟𝑖𝑇 𝐴𝑟𝑖 𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖
- 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)
+ ( + )
( )
( ) (5.48)
(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).
( )
(5.52)
(5.53)
- 54 -
Andrés Zarabozo Martínez Métodos numéricos
(5.54)
( )
(5.55)
(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 .
𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑑𝑖
𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖
𝑟𝑖𝑇 𝑟𝑖 𝑟𝑖𝑇 𝑟𝑖
𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑇 𝑑𝑖 𝑟𝑖 𝛽𝑖 𝑑𝑖− 𝛼𝑖
𝑟𝑖− 𝑟𝑖− 𝑑𝑖𝑇 𝐴𝑑𝑖
𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑑𝑖
𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑑𝑖
- 55 -
Andrés Zarabozo Martínez Métodos numéricos
[ ]{ } { } (5.58)
{ } (5.59)
{ } [ ]{ } { } (5.60)
{ } (5.61)
{ }{ }
(5.62)
{ }[ ]{ }
{ } { } { } (5.63)
{ } [ ]{ } { } (5.64)
{ }{ }
(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
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.
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.
( − ) ( − )
( − )( − ) ( − )( − ) ( − ) − − (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)
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
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
!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
( ) { } (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)
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.
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)
!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
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)
( )
∑ (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
!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
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
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 .
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)
- 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.
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
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
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
!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
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)
( )
⃗( ) ⃗( ) ⃗( ) ( ) (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)
(6.6)
(6.7)
- 73 -
Andrés Zarabozo Martínez Métodos numéricos
Dependiendo del número de variables independientes respecto de las que se deriva, las
ecuaciones diferenciales pueden ser:
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.
Suponiendo que se quiere aproximar la solución del siguiente problema con un valor inicial:
( ) ( ( )) ( ) (7.1)
+ (7.2)
̃+ ( ̃) ( ) (7.3)
- 74 -
Andrés Zarabozo Martínez Métodos numéricos
(7.4)
( ) (7.5)
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)
(7.8)
{ 4
50
40
30
20
10
0
0 0.5 1 1.5 2 2.5 3 3.5 4
- 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.
̃+ ( + ̃+ ) ( ) (7.9)
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.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.11)
( ) ( ) ( ) ( )
( ) ( ) (7.12)
( ) ( )
( ) ( ) ( ( ) ) ( )
(7.13)
( ) ( )
( ) [( ) ( ) ] ( )
( ) ( )
( ) ( ) (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)
+ ( ) (7.17)
Donde
( ) ( ( )) (7.18)
( ) ( ) [ ̅ ̅ ] ( ) (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.
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.
−
−
- 78 -
Andrés Zarabozo Martínez Métodos numéricos
∑ (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.
( )
( )
(7.24)
( )
4 ( )
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
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.
−
−
−
+ ∑ (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:
⁄ ⁄
- 80 -
Andrés Zarabozo Martínez Métodos numéricos
( ) ( + )
+ (7.27)
+ [( ) ( ) ( + )] (7.28)
( ) (7.31)
(7.32)
( ) (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
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
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)
+ −
( ) (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)
+ + ( )
+ +
( ) (8.8)
− −
( ) (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.
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
𝑦
( 𝑚) ( 𝑚) (𝑛 𝑚)
( ) ( ) (𝑛 )
𝑦
( ) ( ) (𝑛 )
𝑥
𝑥
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)
- 84 -
Andrés Zarabozo Martínez Métodos numéricos
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.
̃( ̃ ) ( ̃) (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.
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)
(8.16)
( ) (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
(8.19)
[ ] ( ) [ ] (8.20)
Ecuación adimensional
̃ ̃ (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)
̃ ̃
[ ] ( ) ̃ (8.25)
̃ ̃
Discretización
̃ ̃+ ̃ ̃−
( ) (8.26)
̃
- 86 -
Andrés Zarabozo Martínez Métodos numéricos
̃ ̃+ ̃−
( ) (8.27)
̃
Introduciendo estas dos ecuaciones en la ecuación (8.25) se obtiene la ecuación del problema
discretizada.
̃+ ̃ ̃− ̃+ ̃−
[ ] ( ) ̃ (8.28)
(8.29)
̃+ ̃ ̃− ̃+ ̃−
( ) ̃ (8.30)
̃ ̃ (8.31)
̃
̃ ̃ ̃ ̃ ̃
( ) ̃
( ̃) ̃+ ̃ ̃− ̃+ ̃− (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
̃ ̃ ̃ ̃ ̃
( ) ̃
(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)
̃
̃( ̃ ) ̃ ̃ (8.37)
̃( ) (8.38)
̃
̃( ̃ ) (8.39)
̃
̃ ⁄ . (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)
̃
̃ ̃ ̃ ̃ ( ) (8.42)
̃
- 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
̃ ̃ ̃
̃ (8.43)
- 89 -
Andrés Zarabozo Martínez Métodos numéricos
8.4. Programas
Iniciar variables
Generar matrices:
𝐾y𝑅
Imprimir resultados
¿Nuevo tamaño
de malla?
Fin
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.
integer i
real*8 t, tn, kn
tn = 1020. / tref
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.
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
end subroutine
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
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
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.
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 .
!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
- 94 -
Andrés Zarabozo Martínez Métodos numéricos
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.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.
̅ (9.2)
̅ (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.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
∫ ( )( ̅) ∫ ( )( ⃗ ) (9.7)
̃
∫ ( ) ( ̅ ̃) ∫ ( )( ̅ ) ̃( ) ̅ (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.
̃ ∑ ( ) (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.
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
𝑀
𝑀 𝑀
𝑉 𝑉 𝑉
Δ𝑥
(9.10)
- 97 -
Andrés Zarabozo Martínez Métodos numéricos
Carga distribuida
𝑀
𝑀 𝑀
𝑉 𝑉 𝑉
Δ𝑥
( ) ( ) (9.11)
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)
( ) ⁄
(9.14)
( )
( ) (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)
( ) () ()
( ) ̅ ̅ ( ) ̅ ̅ (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)
( ) ( )
∫ ( ) [ ( )] ∫ ( ) (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)
( ) ( ) ( )
∫ ( ) [ ] ∫ (9.25)
- 99 -
Andrés Zarabozo Martínez Métodos numéricos
( ) ()
∫ ̅ () ̅ ∫ (9.26)
( )
( ) (9.27)
Además para que la integral de la izquierda se pueda integrar el desplazamiento virtual debe
tener segunda derivada.
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)
𝑁 𝑁
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.31)
−
En la siguiente tabla se pueden ver una lista de puntos de integración y de pesos para los tres
primeros valores de .
√ √
√ √
Como normalmente las funciones de formas son lineales, se suelen tener que integrar
polinomios, obteniendo resultados exactos con la cuadratura de Gauss.
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.
{ } [ ]{ } { } (9.32)
- 101 -
Andrés Zarabozo Martínez Métodos numéricos
𝜂 𝑥
(𝑏 𝑏 )
(𝑐 𝑐 )
(𝑎 𝑎 )
𝜉 𝑥
( )( ) ( )( ) (9.33)
( ) ( )
{ } [ ]{ } { } (9.34)
( ) ( )
(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)
( ) [( ) ( ) ( ) ] (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.
𝜂 𝑥
𝜉 𝑥
( )( ) (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
4 4
(9.55)
[ ] [ ]
(9.57)
Se pueden aumentar el orden de los elementos introduciendo más nodos por elemento.
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
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 ).
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
𝑅
𝑘
𝑅 𝑇𝑝 𝑅
𝜆𝑅 (𝜆 ≫ )
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
(9.63)
- 105 -
Andrés Zarabozo Martínez Métodos numéricos
(9.64)
̂ ̂
(9.66)
̂ ̂
̂ ̂
̂ ( ̂ 4) ⃗ (9.67)
̂ ̂
(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
̇
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
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:
( ) (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)
∫ ∫ ∫ ̂ (9.75)
∫ ( ̂) ∫ ⏟( ̂) ∫ (⏟) ̂ (9.76)
∫ ∫ ( ̂) (9.77)
( ) ( ) (9.78)
Discretización
( ) [ ( ) ( ) ( ) 4( )] ( ) (9.79)
[ 4]
- 107 -
Andrés Zarabozo Martínez Métodos numéricos
(9.80)
[ ] [ ] [ 4]
Se utilizan las mismas funciones de forma para interpolar la función de peso del elemento.
( ) ( ) ( ) ( ) (9.81)
∫ ∫ ( ̂) (9.82)
∫ ∫ ( ̂) (9.83)
(9.84)
Donde:
∫ (9.85)
∫ ( ̂) (9.86)
Ensamblaje
∑ ∑ (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
| ( ) (9.90)
(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)
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.).
∫ ∫ || ∑( | |) (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)
∫ ( ) ∫ ( ) (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
[ ] [ ]
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
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.
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
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
!Read Elements
read(5,*) nElem
allocate(elemNode(nElem,4))
do i = 1, nElem
read(5,*) aux, elemNode(i,:)
end do
- 112 -
Andrés Zarabozo Martínez Métodos numéricos
close(5)
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
!Initial temperature
if (alpha .ge. 1) then
T0 = 0.9
else
T0 = alpha
end if
do i = 1, 4
- 113 -
Andrés Zarabozo Martínez Métodos numéricos
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).
integer i
real J(nIP,2,2), invJ(nIP,2,2)
do i = 1, nIP
subroutine assembleK()
implicit none
- 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,:)
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
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)
- 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
!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
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
- 116 -
Andrés Zarabozo Martínez Métodos numéricos
integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult
!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.
- 117 -
Andrés Zarabozo Martínez Métodos numéricos
!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
end do
endIT = i
if (bool) endIT = i - 1
end subroutine
subroutine getW()
implicit none
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)
!Emitted power
localW = L * aux * (localT(1) + localT(2))
!Global power
W = W + localW
end do
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
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
do i = 1, n_el
write(6,*) i, conec(:, i)
end do ! i
!**************************************************************
subroutine writeTemperature()
implicit none
! 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
- 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)
Las primeras dos soluciones mostradas en las siguientes figuras corresponden para valores de
muy pequeño y muy grande.
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
. − . .
.
. − . .
.
. − . .
.
. . . .
. . . .
. . . .
. . . .
. . .
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
α
- 122 -
Andrés Zarabozo Martínez Métodos numéricos
10. Apéndice
10.1. Programación en Fortran
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
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
end program
- 124 -
Andrés Zarabozo Martínez Métodos numéricos
10.2. 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))
xInt = x(1)
step = (x(n) - x(1)) / real(nExit - 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
!***************************************************
end subroutine
- 126 -
Andrés Zarabozo Martínez Métodos numéricos
10.3. Integración
program program4
implicit none
integer, parameter :: n = 300
integer i
real, parameter :: pi = acos(-1.)
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
!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
end subroutine
!***************************************************
integer i
real z(n), x(n), dx, invPi, a, b
- 127 -
Andrés Zarabozo Martínez Métodos numéricos
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
end subroutine
- 128 -
Andrés Zarabozo Martínez Métodos numéricos
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.
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)
!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
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
do i = 1, itMax
if (x1.eq.x2) exit
x3 = x2 - fx2 / slope
x1 = x2
x2 = x3
fx1 = fx2
end do
end program
- 131 -
Andrés Zarabozo Martínez Métodos numéricos
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)
x2 = x1 - fx1 / slope
x1 = x2
end do
end program
- 132 -
Andrés Zarabozo Martínez Métodos numéricos
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
!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
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
!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)
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)
!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
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
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
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
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
end subroutine
- 141 -
Andrés Zarabozo Martínez Métodos numéricos
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
!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
end program
!******************************************************************
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
!******************************************************************
- 143 -
Andrés Zarabozo Martínez Métodos numéricos
integer i
real*8 t, tn, kn
tn = 1020. / tref
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
module subroutines
implicit none
contains
!**************************************************************
subroutine readMesh()
implicit none
integer i
real aux, aux2
!Read Elements
read(5,*) nElem
allocate(elemNode(nElem,4))
do i = 1, nElem
read(5,*) aux, elemNode(i,:)
end do
- 145 -
Andrés Zarabozo Martínez Métodos numéricos
close(5)
!**************************************************************
subroutine init()
implicit none
real aux
integer i
!Initial temperature
if (alpha .ge. 1) then
T0 = 0.9
else
T0 = alpha
end if
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))
- 146 -
Andrés Zarabozo Martínez Métodos numéricos
!**************************************************************
integer i
real J(nIP,2,2), invJ(nIP,2,2)
do i = 1, nIP
!**************************************************************
subroutine assembleK()
implicit none
do i = 1, nElem
!Saves, in eN(4), the number of the nodes in the element
eN = elemNode(i,:)
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
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)
!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
- 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
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
!**************************************************************
integer, intent(in) :: n
real, intent(inout) :: b (n), a(n,n)
integer :: row, pivot
real :: mult
- 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.
!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
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
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)
!Emitted power
localW = L * aux * (localT(1) + localT(2))
!Global power
W = W + localW
end do
!**************************************************************
!**************************************************************
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
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
do i = 1, n_el
write(6,*) i, conec(:, i)
end do ! i
!**************************************************************
subroutine writeTemperature()
implicit none
- 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
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)
!**************************************************************
! 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();
- 153 -
Andrés Zarabozo Martínez Métodos numéricos
- 154 -
Andrés Zarabozo Martínez Métodos numéricos
- 155 -
Andrés Zarabozo Martínez Métodos numéricos
- 156 -
Andrés Zarabozo Martínez Métodos numéricos
- 157 -
Andrés Zarabozo Martínez Métodos numéricos
- 158 -
Andrés Zarabozo Martínez Métodos numéricos
- 159 -
Andrés Zarabozo Martínez Métodos numéricos
- 160 -
Andrés Zarabozo Martínez Métodos numéricos
- 161 -