Andrés Zarabozo Métodos Numéricos. Apuntes Ingeniería Aeronáutica ETSEIAT 2012 Andrés Zarabozo Martínez Métodos numéricos Acerca de estos apuntes Estos apuntes se han realizado para cubrir el temario de la asignatura “métodos numéricos”, que se imparte en el quinto curso de Ingeniería Aeronáutica en la Escola Tècnica Superior d’Enginyeries Industrial i Aeronàutica de Terrassa, de la Universitat Politècnica de Catalunya (ETSEIAT – UPC). Licencia Esta obra está bajo una licencia Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) de Creative Commons. Para ver una copia de esta licencia, visite: http://creativecommons.org/licenses/by-sa/3.0/deed.es_ES En líneas generales: Es libre de: Compartir – Copiar, distribuir y comunicar públicamente la obra. Transformar la obra y crear obras derivadas. Hacer un uso comercial de esta obra. Bajo las condiciones siguientes: Reconocimiento — Debe reconocer al autor de la obra original (pero no de una manera que sugiera que tiene su apoyo o apoya el uso que hace de su obra). Compartir bajo la Misma Licencia — Si altera o transforma esta obra, o genera una obra derivada, sólo puede distribuir la obra generada bajo una licencia idéntica a ésta. -2- Andrés Zarabozo Martínez Métodos numéricos Índice 1. Programación en Fortran 1.1. Tipos de variables .......................................................................................................... 7 1.2. Expresiones aritméticas ................................................................................................ 7 1.3. Bucles y condiciones ..................................................................................................... 8 1.4. Vectores y matrices ....................................................................................................... 9 1.5. Subrutinas ................................................................................................................... 11 1.6. Lectura y escritura de datos ........................................................................................ 12 1.7. Programas ................................................................................................................... 13 Programa 1. Mínimo error de un tipo de variable .............................................................. 13 Programa 2. Cálculo del número π...................................................................................... 15 2. Interpolación 2.1. SPLINE.......................................................................................................................... 17 2.2. Interpolación cúbica en un solo intervalo ................................................................... 18 2.3. Programa ..................................................................................................................... 20 Programa 3. Entrada de datos e interpolación ................................................................... 20 3. Integración 3.1. Fórmula de Newton-Cotes .......................................................................................... 23 3.2. Regla del punto medio ................................................................................................ 25 3.3. Regla del trapecio ........................................................................................................ 25 3.4. Regla de Simpson ........................................................................................................ 27 3.5. Extrapolación de Richardson ....................................................................................... 28 3.6. Programas ................................................................................................................... 30 Programa 4. Obtención de la serie de Fourier .................................................................... 30 Programa 5. Iteraciones y extrapolación ............................................................................ 33 4. Resolución numérica de ecuaciones no lineales 4.1. Método de la bisección ............................................................................................... 36 4.2. Método de Newton - Raphson .................................................................................... 36 4.3. Método de la secante.................................................................................................. 37 4.4. Método de regula falsi ................................................................................................ 38 4.5. Teorema del punto fijo................................................................................................ 39 4.6. Programas ................................................................................................................... 41 -3- Andrés Zarabozo Martínez Métodos numéricos Programa 6. Deflexión de un cable ..................................................................................... 41 Programa 7. Resolución mediante Newton-Raphson ......................................................... 44 5. Resolución numérica de sistemas lineales 5.1. Método de eliminación de Gauss................................................................................ 45 5.2. Matrices mal condicionadas........................................................................................ 46 5.3. Descomposición LU ..................................................................................................... 47 5.4. Doolittle ....................................................................................................................... 47 5.5. Crout ............................................................................................................................ 48 5.6. Matrices dispersas....................................................................................................... 49 5.7. Método del gradiente conjugado................................................................................ 51 5.8. Ejemplo de aplicación del método del gradiente conjugado ...................................... 56 5.9. Programas ................................................................................................................... 58 Programa 1. Resolución de un sistema mediante Gauss .................................................... 58 Programa 2. Sistema con matriz mal condicionada ............................................................ 61 Programa 3. Doolitle ........................................................................................................... 64 Programa 4. Crout ............................................................................................................... 66 Programa 5. Matriz banda................................................................................................... 69 6. Resolución numérica de sistemas no lineales 6.1. 7. Método de Newton para sistemas no lineales............................................................ 72 Ecuaciones diferenciales, problemas de valor inicial 7.1. Tipos de ecuaciones diferenciales ............................................................................... 74 7.2. Método de Euler.......................................................................................................... 74 7.3. Ejemplo de resolución mediante el método de Euler. ................................................ 75 7.4. Método implícito de Euler........................................................................................... 75 7.5. Método de Heun ......................................................................................................... 76 7.6. Método de Runge-Kutta de segundo orden ............................................................... 77 7.7. Método de Runge-Kutta de órdenes superiores......................................................... 78 7.8. Método adaptativo de Runge-Kutta ........................................................................... 80 7.9. Esquema de Crank-Nicolson........................................................................................ 81 7.10. Método de Runge-Kutta para EDOs de grados superiores ......................................... 81 8. Método de diferencias finitas 8.1. Diferencias finitas en una dimensión. ......................................................................... 82 8.2. Diferencias finitas en dos dimensiones ....................................................................... 83 -4- Andrés Zarabozo Martínez Métodos numéricos 8.3. Ejemplo de problema mecánico.................................................................................. 84 8.4. Programas ................................................................................................................... 90 Programa 6. Ejemplo de problema mecánico ..................................................................... 90 9. Método de elementos finitos 9.1. Forma fuerte del problema ......................................................................................... 96 9.2. Método de Rayleigh-Ritz y método de Galerkin ......................................................... 96 9.3. Ejemplo de formulación fuerte para problema estructural ........................................ 97 9.4. Funciones de forma ................................................................................................... 100 9.5. Cuadratura de Gauss ................................................................................................. 101 9.6. Tipos de elementos en 2D ......................................................................................... 101 9.7. Ejemplo de problema térmico................................................................................... 105 9.8. Programa ................................................................................................................... 111 Programa 7. Radiador espacial .......................................................................................... 111 10. Apéndice 10.1. Programación en Fortran .......................................................................................... 123 Programa 1. Mínimo error de un tipo de variable ............................................................ 123 Programa 2. Cálculo del número π.................................................................................... 124 10.2. Interpolación ............................................................................................................. 125 Programa 3. Entrada de datos e interpolación ................................................................. 125 10.3. Integración ................................................................................................................ 127 Programa 4. Obtención de la serie de Fourier .................................................................. 127 Programa 5. Iteraciones y extrapolación .......................................................................... 129 10.4. Resolución numérica de ecuaciones no lineales ....................................................... 131 Programa 6. Deflexión de un cable ................................................................................... 131 Programa 7. Resolución mediante Newton-Raphson ....................................................... 132 10.5. Resolución numérica de ecuaciones lineales ............................................................ 133 Programa 8. Resolución de un sistema mediante Gauss .................................................. 133 Programa 9. Sistema con matriz mal condicionada .......................................................... 134 Programa 10. Doolittle ...................................................................................................... 136 Programa 11. Crout ........................................................................................................... 138 Programa 12. Matriz Banda .............................................................................................. 140 10.6. Método de diferencias finitas ................................................................................... 142 Programa 13. Ejemplo de problema mecánico ................................................................. 142 -5- Andrés Zarabozo Martínez Métodos numéricos 10.7. Método de elementos finitos.................................................................................... 145 Programa 15. Radiador especial........................................................................................ 145 10.8. Datos de entrada del Programa 13, radiador espacial .............................................. 154 -6- Andrés Zarabozo Martínez Métodos numéricos 1. Programación en Fortran 1.1. Tipos de variables En Fortran se suelen usar cinco tipos básicos de variables: Boolean: Es una variable de un solo bit y por lo tanto solo puede tener dos posibles valores (.true. o .false.). Integer: Solo permite tener un valor enteros, en general ocupa bits. El primer bit contiene el signo y por lo tanto el módulo del número ocupa los restantes bits. El valor máximo es igual a . Real: Es similar al Double usado en otros lenguajes de programación como C. Permite números en decimales y en general ocupa bits. De forma similar al Integer el primer bit contiene el signo del número. Complex: Son números complejos compuestos de dos números Real separados por una coma y entre paréntesis. El primer número representa el valor real y el segundo el valor complejo. Character: Se utiliza para escribir letras. Se suele generar un vector donde cada posición es un caracter. Para definir una variable se debe declarar primero el tipo y luego el nombre de la variable. Las variables tienen que tener un nombre entre y letras o números siendo la primera siempre una letra. En Fortran no hay diferencia entre mayúsculas y minúsculas. real x integer i También se puede definir el tamaño en memoria de las distintas variables como por ejemplo: real*8 x integer*8 i 1.2. Expresiones aritméticas Las cinco operaciones aritméticas básicas son: la suma (+), la resta (-), la multiplicación (*), la división (/) y el exponente (**). Fortran también reconoce otro tipo de funciones como por ejemplo funciones trigonométricas, logaritmos… Las operaciones aritméticas devuelven un resultado (que puede ser un Real o Integer) y debe ser almacenado en una variable. -7- Andrés Zarabozo Martínez Métodos numéricos x = 1. + 3. 25 * 5. / 3. x = cos(1.25) + y**2. El orden de las operaciones es: Primero: Todas las operaciones exponenciales y se desarrollan de derecha a izquierda. Segundo: Todas las multiplicaciones y divisiones, el orden es de izquierda a derecha. Tercero: Todas las operaciones de suma y resta, el orden es de izquierda a derecha. En este libro se va a centrar el estudio del uso de Fortran para aplicación en métodos numéricos. Los programas se deben escribir de forma óptima para el cálculo. La latencia es el tiempo que se consume en una operación. Las operaciones básicas (menos los exponentes) tienen latencias muy bajas, en especial la suma, la resta y la multiplicación. La división tiene una latencia un poco más alta aunque en los nuevos procesadores como por ejemplo los Intel i7 la diferencia en latencia es despreciable, en ordenadores antiguos la latencia puede ser hasta cinco veces más lenta. Las operaciones exponenciales, trigonométricas, logarítmicas… son demasiado lentas y deben ser evitadas en la medida de lo posible. Por ejemplo si se quiere calcular la siguiente ecuación: ( ) ∑ (1.1) Se debería evitar hacer la operación exponente y se podría escribir de la siguiente forma (la terminología de los bucles en Fortran se explica más adelante). p = a(n) do i .eq. n, 1, -1 p = p * x + a (n - 1) end do 1.3. Bucles y condiciones El bucle estándar en Fortran es do. Se le da un valor inicial a una variable Integer y se le define el valor final. El código que se ejecuta en el bucle se debe finalizar con end do. do i .eq. 1, 10, 2 x=x+i end do -8- Andrés Zarabozo Martínez Métodos numéricos Por defecto cada vez que se ejecuta el bucle se le suma uno a la variable (en el ejemplo i) pero se puede cambiar el valor que se añade poniendo después del valor final una coma y el sumando. La función if ejecuta solo el código si se cumple la condición impuesta. Para poner condiciones en Fortran se utiliza la siguiente sintaxis (abreviaciones del inglés): - Mayor que: .gt. Menor que: .lt. Mayor o igual a: .ge. Menor o igual a: .le. Igual a: .eq. Diferente de: .ne. Se puede complementar la función if utilizando las funciones else (si la condición del if no se cumple se ejecuta el código que sigue al else) o elseif (parecido al else pero se le añade una condición más para que se ejecute el código). Se pueden poner tantos elseif como se quieran en un mismo conjunto de if. Se debe finalizar el código de esta función con endif. if (a .gt. 2) then b=1 else b=0 end if La función do while ejecuta repite el código hasta que la condición deje de cumplirse. El código dentro del do while se ejecuta hasta que se finaliza (con end do) y vuelve a la línea del principio para comprobar si se cumple aún la condición. Si se desea salir del bucle en algún punto intermedio se puede utilizar la función exit. do while (a .lt. 5) a=a+1 end do 1.4. Vectores y matrices Se usan los vectores y matrices para utilizar un solo nombre que refiera a un conjunto de direcciones de memoria. Todos los datos almacenados en un vector o una matriz deben ser del mismo tipo. Para usar un vector o matriz (a partir de ahora solo se referirán a matrices ya que el funcionamiento es casi el mismo) se debe primero decláralo. Se puede declarar de forma estática o de forma dinámica. Si se declara de forma dinámica no se define la dimensión de la matriz, mientras que si se define de forma estática si que se define la dimensión. -9- Andrés Zarabozo Martínez Métodos numéricos Para declarar una matriz de forma estática se pone el tipo de las variables que almacena seguido del nombre de la matriz y en paréntesis sus dimensiones, se utiliza una coma para definir las distintas columnas de la matriz (el valor de la dimensión de cada columna debe ser un integro). real a(4,9) integer b(2,n) Para declarar una matriz de forma dinámica se debe utilizar el parámetro allocatable y utilizar dos puntos para las columnas que no se quiere definir la dimensión. Una vez se decide dar un valor a la dimensión se utiliza la función allocate. real, allocatable : : a(4, :) integer n print*,"Dimensions of the matrix?" read(*,*) n allocate(a(:,n)) Una matriz creada de forma dinámica puede ser eliminada (para liberar espacio en la memoria) con la función dellocate. Para saber si una matriz dinámica está creada o no en un momento dado se puede usar la función intrínseca allocatable (la función devuelve un valor booleano). Las tablas se puede utilizar globalmente, referenciando un conjunto de elementos seguidos o de forma individual. Si solo se indica el nombre de la matriz se referencia todos los elementos. Para referenciar un valor específico se debe introducir la posición del valor de la matriz. Si se quiere referenciar un rango se utiliza el doble punto para delimitar el rango. real M(2,4), V(3) V(2) = 1. M(2,2:4) = V(2) En el ejemplo anterior se introduce el valor de V(2) (es decir ) en los tres valores de la matriz M (M(2,2), M(2,3), M(2,4)). Las operaciones que se pueden hacer con matrices son: x * M: Multiplicación de cada elemento de una matriz M y un escalar x. x + M: Suma de cada elemento de una matriz M y un escalar x. M * M: Multiplicación de cada elemento por su homologo elemento entre dos matrices de misma dimensión. - 10 - Andrés Zarabozo Martínez Métodos numéricos traspose(M): Transpuesta de una matriz. matmul(M,M): Multiplicación matricial entre dos matrices. dot_product(V,V): Producto escalar entre dos vectores. Las matrices se almacenan en direcciones consecutivas de memoria. En el caso de un vector los valores se almacena secuencialmente, empezando por el primero del vector V(1) hasta el último valor V(n). V(1) V(2) V(3) … V(n-1) V(n) Figura 1.1. Orden de los valores de un vector en la memoria. En el caso de matrices, los valores se almacenan por columnas. Por ejemplo si se tiene una matriz M(2,2,2) el orden en la memoria es: M(1,1,1) M(2,1,1) M(1,2,1) M(2,2,1) M(1,1,2) M(2,1,2) M(1,2,2) M(2,2,2) Figura 1.2. Orden de los valores de una matriz en la memoria. 1.5. Subrutinas Las subrutinas o subroutine son como funciones en otros lenguajes de programación. Se crea una subrutina de la misma forma que el programa principal, con la única diferencia que se deben poner las variables de referencia que se le quieren pasar a la subrutina. Es recomendable definir al principio de la rutina si la variable es de entrada o de salida. De esta forma el compilador puede informar de errores en el programa, si por ejemplo se le intenta dar un valor a una variable de entrada. En las subrutinas las variables se envían como referencia, es decir, se envía la dirección de memoria de la variable. Si la variable es una matriz se envía la dirección del primer valor de la matriz. subroutine areaCircle(A, r) implicit none real, intent (in) :: r real, intent (out) :: A real, parameter :: pi = acos(-1) A = pi * r * r end subroutine La subrutina de ejemplo calcula el área de un círculo. El valor de entrada es el radio y devuelve el área. Para llamar a la subrutina se utiliza la función call. real A1, r1 r1 = 3. call areaCircle(A1, r1) - 11 - Andrés Zarabozo Martínez 1.6. Métodos numéricos Lectura y escritura de datos Cuando se quiere trabajar con un archivo para leer o escribir datos se debe usar la función open. Se le asigna un número de unidad al archivo abierto que es el identificador. Dentro de la función se debe definir el archivo y el acceso. El acceso se puede definir por ejemplo como secuencial, es decir, que cada vez que se escriba o se lea pasa a la siguiente línea. Para el archivo se debe introducir la ruta completa o bien si el archivo está en la misma carpeta se puede simplemente poner el nombre. Para leer un archivo se debe utilizar la función read, seguido de una variable o matriz en donde se quiera almacenar los datos de lectura. Para escribir se usa write seguido de las variables o los datos que se quieren introducir. Una vez se termina de usar el archivo es conveniente cerrarlo usando close. open(unit = 1, file='fileData', access='SEQUENTIAL') read(1,*) n write(1,*) 2 * n close(1) - 12 - Andrés Zarabozo Martínez 1.7. Métodos numéricos Programas Programa 1. Mínimo error de un tipo de variable El primer programa sirve de ejemplo para poder ver un poco como funcionan los programas escritos en Fortran. El objetivo es calcular el mínimo valor para un tipo de variable. Se utilizan variables real ya que no tiene sentido hacerlo con integer (el error sería ). Se busca el menor número tal que . En Fortran existe una función intrínseca que calcula lo mismo y que se llama epsilon(). Como todo programa se debe empezar declarando el programa y las variables que se van a utilizar. Se necesita al menos una variable donde se pueda almacenar el resultado deseado (dándole un valor inicial) y también se necesita una variable para el bucle que se va a realizar. program program1 implicit none integer i Small = 1. end program El bucle que se quiere realizar consiste en ir dividiendo por dos el valor de la variable small e ir comprobando que se cumpla la ecuación . Se elige en este ejemplo un bucle tipo do pese a que sería más lógico utilizar un bucle while, de esta forma se puede ver como funciona también la condición if. Dentro de cada iteración se debe comprobar que se cumpla la ecuación descrita, y si se cumple se debe dividir el valor del resultado por dos. En caso de que no se cumpla la condición hay que salir de bucle utilizando exit. do i = 1, 1000 if (1. + small .gt. 1.) then small = 0.5 * small else exit end if end do El resultado aún no es exactamente el valor almacenado en small, el valor bueno es el resultado multiplicado por dos. Para poder ver el valor en pantalla se usa la función print*,. Se puede también utilizar la función epsilon(small) para poder comparar el resultado. - 13 - Andrés Zarabozo Martínez Métodos numéricos small = 2 * small print*, small print*, epsilon(small) Se puede cambiar el tipo de variable cuando se define esa, pudiendo probar con variables con más precisión. real*8 small8 real*16 small16 - 14 - Andrés Zarabozo Martínez Métodos numéricos Programa 2. Cálculo del número π Utilizando solo una cuerda de y un cuadrado de se puede calcular el número . Se dibuja un cuarto de círculo de radio un metro dentro del cuadrado y se van lanzando bolas sobre el cuadrado. Estadísticamente el número de bolas dentro de cada zona es proporcional al área. El área de un cuarto de círculo es: (1.2) Siendo el número de bolas totales lanzadas y círculo, la relación entre y es: el número de bolas que caen en el cuarto de ⁄ Por lo tanto el número (1.3) es igual a: (1.4) Para obtener un número aleatorio se utiliza la función random_number(). De esta forma se simboliza que se lanza una bola y aleatoriamente cae en una posición concreta del cuadrado. Como en todos los programas lo primero que se hace es declarar el programa y las variables. Para obtener mayor precisión se utilizan variables con double precision. Se necesitan cuatro variables. Dos variables e para definir la posición donde cae la bola, se podría también utilizar un vector. Y luego dos variables que definan el número de bolas totales y las que han caído dentro de cuarto de círculo. program program2 implicit none real*8 x, y integer*8 total, inside total = 0 inside = 0 Se debe empezar el proceso iterativo mediante un bucle. Se muestra a continuación otra forma de hacer bucles. Se utiliza la función continue y la función go to. La segunda debe tener un número integro para que el compilador sepa a donde tiene que ir. El primer paso del bucle es generar la posición aleatoria y sumarle un valor al número total de bolas lanzadas. Una vez se lanza la bola se debe comprobar si cae dentro del cuarto de círculo. Como el centro del eje de coordenadas se define en el centro del circulo se debe cumplir que . - 15 - Andrés Zarabozo Martínez Métodos numéricos Lo siguiente ya es calcular el valor de . Como las iteraciones se hacen muy rápido se puede marcar que muestre el valor de cada cierto número de iteraciones. La función mod(x,y) devuelve el resto de la división de íntegros. Hay que acordarse de que siempre que se hace un cálculo con variables de diferentes tipos se deben convertir al tipo de la variable que se está calculando. Esto puede evitar errores de cálculos que no son detectados por el compilador. En este problema, como se han calculado las variables con double precision se deben convertir con la función dble(). 10 continue !Ball thrown call random_number(x) call random_number(y) total = total + 1 !Looks where the ball fell if(x*x + y*y .lt. 1.) inside = inside + 1 !Shows the result every 1000 iterations if (mod(total, 1000) .eq. 0) then print*, total, 4. * dble(inside) / dble(total) end if go to 10 end program Este programa tiene un bucle que nunca finaliza, hay que tener cuidado con este tipo de bucles ya que, pese a que en este programa esto no afecta al resultado, en otro programa más complicado puede meterse en un bucle infinito y no calcular nada. Con este tipo de bucles se puede salir utilizando la función exit normalmente dentro de un if. - 16 - Andrés Zarabozo Martínez Métodos numéricos 2. Interpolación 2.1. SPLINE En análisis numérico, un spline es una curva diferenciable definida en porciones mediante polinomios. Esto es útil para poder generar curvas en funciones donde se tienen una serie de puntos definidos o también para simplificar la función mediante tramos definidos como polinomios. El caso más sencillo de spline es el polinomio de primer orden, es decir, rectas que unan los puntos. Éste genera curvas con puntas donde la pendiente no está definida en los puntos. Cuanto mayor es el orden del polinomio de la aproximación, aparecen más oscilaciones, generando curvas de peor calidad. Figura 2.1. Aproximación de primer orden (recta) y aproximación de un orden muy superior. Se suelen usar polinomios de ordenes bajos, normalmente suelen ser de segundo o tercer orden. En general se busca una curva que pase por los puntos definidos y que lo haga con la misma pendiente que la función en los puntos. Esto se consigue con polinomios de tercer orden. Si lo único que se tiene es la distribución de puntos de la función se debe hacer una estimación de la pendiente utilizando puntos de alrededor. Si la separación entre los puntos es uniforme la pendiente de un punto se puede igualar a la pendiente de la recta entre los dos puntos adyacentes. 𝑥𝑖− 𝑥𝑖 𝑥𝑖+ Figura 2.2. Aproximación de la pendiente mediante dos puntos adyacentes. - 17 - Andrés Zarabozo Martínez Métodos numéricos Siendo la pendiente: | Donde el error es ( los puntos. + − + − ( ) (2.1) ) y decrece de forma cuadrática con la disminución del intervalo entre En el caso de estar en los puntos extremos, al faltar uno de los puntos, se aproxima la pendiente con el propio punto. Por ejemplo si se está en el último punto no se tendría un punto a la derecha y por lo tanto la pendiente sería: − | − ( ) (2.2) Se puede ver que el error ( ) ha aumentado considerablemente con esta aproximación. 2.2. Interpolación cúbica en un solo intervalo Para encontrar la función interpolada de tercer orden en un intervalo, se hace primero un [ ] se transforma a una variable definida en cambio de variable. Teniendo una variable [ ]. El cambio de variable es simplemente: un intervalo unitario (2.3) Se usan polinomios de Hermite para encontrar la función interpolada. Se tienen cuatro funciones básicas de Hermite, siendo la función interpolada una combinación lineal de estas cuatro funciones. Las funciones solo pueden empezar en solo pueden ser o . o y deben acabar en o . Las en y 𝐻 𝐻 𝐻 𝐻4 𝜉 Figura 2.3. Las cuatro funciones básicas de Hermite. Se busca un polinomio que pase por dos puntos conocidos ( también coincida ( y ). - 18 - y ) y que además la pendiente Andrés Zarabozo Martínez Métodos numéricos El polinomio es por lo tanto: ( ) ( ) ( ) 4( ) (2.4) El valor de las funciones básicas de Hermite se pueden calcular fácilmente ya que son polinomios de tercer orden. Se calcula como ejemplo la cuarta función 4 . Esta función tiene doble raíz en (ya que la pendiente en ese punto es ) y la tercera raíz en . A parte se sabe que la pendiente en es . Por lo tanto la función tiene la siguiente forma, donde es una constante que se debe calcular. ( 4 Como la pendiente en ) (2.5) es , se puede obtener el valor de la constante. 4 ( | )| (2.6) Por lo tanto el cuarto polinomio es: ( 4 ) (2.7) Las demás funciones se obtienen de forma similar y son: ( )( ) ( ) ( ) (2.8) Para el valor de la pendiente también se tiene que hacer el cambio de variable. (2.9) Sabiendo del cambio de variable que: (2.10) Por lo tanto: ( ) (2.11) Finalmente la función interpolada es: ( )( ) ( ( ) ) - 19 - ( ( ) ) ( ) (2.12) Andrés Zarabozo Martínez 2.3. Métodos numéricos Programa Programa 3. Entrada de datos e interpolación En este programa se ve un ejemplo de programa que puede leer y escribir en un archivo. Además se utiliza en el programa una subrutina para hacer la interpolación. El programa debe de ser capaz de leer un archivo con una serie de puntos de una función. Pregunta cuantos puntos se quieren tener de salida y genera unos puntos utilizando la interpolación cúbica. Los nuevos puntos calculados se escriben en un fichero de salida para poder comparar la función de entrada y la de salida. Se empieza escribiendo la subrutina. Se debe empezar definiendo las variables que se van a usar. Esta subrutina calcula un valor de ( ) (yx) para una posición de (x). Para calcular la función interpolada se necesitan los valores de la función en los extremos del tramo ( y ) y las pendientes en esos puntos ( y ), se utiliza un vector de cuatro posiciones para guardar estos valores (v1(4)). Además se necesita saber el valor del tramo y , se guardan también en un vector (v2(2)). subroutine hermite (v1, v2, x, yx) implicit none real, intent(in) :: v1(4), v2(2), x real, intent(out) :: yx Se tiene que hacer el cambio de variable de a definido por la ecuación (2.3). real :: chi, span span =v2(2) - v2(1) chi = (x - v2(1)) / span Se calcula ahora el valor ( ) con la formula de la interpolación descrita en la ecuación (2.12). Se puede utilizar el carácter & al final de una línea para indicar que el código sigue como si no hubiese un salto de línea, esto facilita la lectura del código y no afecta al programa. yx = v1(1) * (1. + 2. * chi) * (1. - chi) * (1. - chi) + & v1(2) * span * chi * (1. - chi) * (1. - chi) + & v1(3) * chi * chi * (3. - 2. * chi) + & v1(4) * span * chi * chi * (chi - 1.) end subroutine Se debe hacer ahora el programa principal que es el que lea los datos de entrada calcule los nuevos valores y los escriba en un fichero. - 20 - Andrés Zarabozo Martínez Métodos numéricos Lo primero que se debe hacer es definir las variables. Se usan vectores y matrices para guardar los datos de entrada. Se define una matriz para guardar el valor de la función y el valor de su derivada, y un vector para almacenar la posición en el eje . Como el programa no sabe aún cuantos valores de la función se tienen (los debe leer del archivo) se deben definir estas matrices como allocatable. Como variables adicionales se definen el número de valores de entrada (n) y el número de valores de salida (nExit). Además de estas variables se definen otras que ayudarán a la hora de programar. program program3 implicit none real, allocatable :: ydy(:,:), x(:) real xInt, yInt, step integer n, i, nExit, last Se debe leer el archive con los datos para saber la dimensión de las matrices. Se pone como primer dato el número de valores de la función, y luego, en cada línea los valores de la función. Se utiliza la función allocate para dar las dimensiones a las matrices. open(unit = 1, file='initialData', access='SEQUENTIAL') read(1,*) n allocate(ydy(2,n), x(n)) do i = 1, n read(1,*) x(i), ydy(1,i) end do close(1) Como solo se tiene la información de los puntos y de la función en los puntos se debe aproximar la derivada. Se utiliza la ecuación (2.2) para los puntos externos y la ecuación (3.1) para el resto. Una vez calculadas las derivadas se pide el número de puntos de salida. ydy(2,1) = (ydy(1,2) - ydy(1,1)) / (x(2) - x(1)) do i = 2, n - 1 ydy(2,i) = (ydy(1, i+1) - ydy (1, i-1)) / (x(i+1) - x(i-1)) end do ydy(2,n) = (ydy(1,n) - ydy(1,n-1)) / (x(n) - x(n-1)) print *, 'Introduce number of points:' read(*,*) nExit - 21 - Andrés Zarabozo Martínez Métodos numéricos Se iguala la variable xInt a x(1). La variable xInt es la posición Calcula también el paso entre los puntos interpolados. de la función interpolada. Se (2.13) Como se va a empezar a escribir resultados se abre el archivo de resultados. El parámetro que se le ha puesto en status genera un nuevo documento cada vez que se ejecuta el programa. En caso de que el documento ya exista, borra el anterior y crea uno nuevo. xInt = x(1) step = (x(n) - x(1)) / real(nExit - 1) open(unit=2, file='dataExit', access='SEQUENTIAL', status='REPLACE') Se empieza ahora el bucle de cálculo. Cada vez que se hace una iteración se calcular los puntos que forman el intervalo en el que xInt está. last = 1 do i = 1, nExit !Find interval do while (xInt .gt. x(last+1)) last = last + 1 end do Se llama a la subrutina para obtener el valor de yInt para el punto xInt. Una vez se obtiene el valor, se escribe el resultado en el archivo. Finalmente antes de terminar el bucle se toma un nuevo valor de xInt y se asegura que todos los valores iniciales de se han tomado. call hermite(ydy(:,last:last+1), x(last:last+1), xInt, yInt) write(2,*) xInt, yInt xInt = xInt + step xInt = min(xInt, x(n)) end do close(2) end program Debido a que Fortran únicamente envía del vector la dirección de memoria del primer valor asignado, se puede escribir la llamada de la subrutina de la siguiente manera. call hermite(ydy(1,last), x(last), xInt, yInt) - 22 - Andrés Zarabozo Martínez Métodos numéricos 3. Integración 3.1. Fórmula de Newton-Cotes Si se tiene una función ( ) con [ ], la integral se define según: Sean los elementos de área por debajo de la función donde Si es suficientemente grande tal que | y la partición de los elementos es | regular, la integral entre y de ( ) es igual a un sumatorio de los elementos. ∫ ( ) ∑( − [ ) ( ) Si la función está definida en un rango de valores de los valores de ( ). − ] (3.1) , podría haber problemas para obtener Una primera forma de calcular la integral es a través de la formula de Newton Cotes. Se puede muestrear la función en una serie de puntos y extrapolar los puntos a funciones que se puedan integrar como polinomios. Finalmente se hace la integral de los polinomios. Como convenio, cuando se escogen los puntos de los intervalos para integrar, se escogen los dos extremos y el resto se suelen coger de forma que el intervalo entre puntos es regular (siendo muy cómodo que el intervalo sea igual). Se considera una función como la que se ve en la Figura 3.1. 𝑦 𝑓(𝑥) 𝑎 𝑥 𝑏 𝑥 𝑥 . 𝑥𝑛− Figura 3.1. Función aleatoria dividida en 𝑥𝑛 𝑥 intervalos. Si los intervalos son iguales éste se puede calcular fácilmente con la posición de los extremos. (3.2) Teniendo el valor de ( ) para todos los puntos ( ) se calculan las funciones ( ) polinómicas que aproximan a para cada intervalo. Esta aproximación polinómica puede - 23 - Andrés Zarabozo Martínez Métodos numéricos ser del orden que se desee, pudiendo aproximar con rectas, parábola u otros.La integral es entonces la integral de los polinomios (el conjunto se define como ). ∫ ( ) ( ) ∫ (3.3) El polinomio se calcula mediante la interpolación polinómica de Lagrange. Para un intervalo que empieza en , el polinomio interpolado en la forma de Lagrange es la siguiente combinación lineal. ( ) Donde (3.4) es la delta de Kronecker. { (3.5) Por lo tanto el polinomio interpolado queda: ( ) ( )( )( ( ) ( ) ( − − )( )( + + ) ( ) ( ) ) (3.6) Si es muy grande, el polinomio tiene muchas oscilaciones y puede variar mucho respecto a la función inicial. Los valores típicos de son y . Al tener un pequeño, el polinomio de Lagrange queda muy simplificado. El error es la diferencia entre la integral que se quiere obtener y el valor obtenido. ( ) ∫ (3.7) En general el error al interpolar una función en un polinomio de orden Por lo tanto el error al integral es del orden de: + ∫ + + 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. + ∑∫ ∑ Como además se sabe que ( ( ) (3.9) +( − ) + + (3.10) )⁄ , el error compuesto es por lo tanto del orden de: ( ) - 24 - + (3.11) Andrés Zarabozo Martínez 3.2. Métodos numéricos Regla del punto medio La regla del punto medio establece que la función en los intervalos es constante, tomando solo un punto del intervalo. Los intervalos se normalizan para que quede una función comprendida entre y . 𝑓(𝑥) 𝑥 𝑏 𝑎 𝑔(𝜉) 𝜉 Figura 3.2. Normalización de la función. Siendo: ( ) ∫ ∫ ( ) (3.12) − Se aproxima ( ) a una recta cuyo valor es ( ). La integral de esta función es por lo tanto: ∫ ( ) ∫ − ( ) ( ) (3.13) − Pese a que este caso sería el caso en que el error simple no es . Según el teorema de Taylor, una función se puede aproximar como un polinomio de la siguiente forma: ( ) ( ) ( ) ( ) (3.14) ( )). Pero el segundo La aproximación que se usa en este caso es de orden ( ( ) término (que en teoría tendría que definir el error) es cero al integrarse, ya que es una función antisimétrica entre y . Por lo tanto el error viene definido por el tercer término y es: (3.15) 3.3. Regla del trapecio Se aumenta el orden y ahora se toman dos puntos del intervalo en vez de uno. El polinomio que aproxima el intervalo es por lo tanto una recta que pasa por los dos límites del intervalo. Se vuelve a normalizar la función para que esté contenida entre y . 𝑔(𝜉) 𝑃(𝜉) 𝜉 Figura 3.3. Polinomio normalizado produciendo un trapecio en el intervalo. - 25 - Andrés Zarabozo Martínez Métodos numéricos La integral del polinomio es igual al área del trapecio. ( ) ( ) ( ) ( ) (3.16) La integral completa es la suma de las integrales de los distintos intervalos. ( ) ( ) ( ) ( ) ( − ) ( ) (3.17) Agrupando términos iguales se puede simplificar la expresión. ( ) ( − ) ∑ ( ) (3.18) Se define el primer término de la ecuación anterior como . ( ) ( ) ( ) ( ) (3.19) Al estar aproximando de forma lineal el error simple es un término de segundo orden que al integrar se convierte en tercer orden. El error compuesto es de segundo orden. Los errores son del mismo orden de magnitud que los de la regla del punto medio, pero no son iguales. (3.20) En general no basta con calcular una vez la integral para obtener un resultado válido. Se deben probar distintos valores de intervalos para comprobar si el resultado converge. Para no tener que calcular desde el principio cada vez. Es recomendable aprovechar los resultados obtenidos en las anteriores integraciones y una forma de hacerlo es dividir por dos el valor del intervalo , es decir poner un punto más en el centro de cada intervalo. De esta forma solo se tienen que calcular la mitad de puntos. Si se hace con este método se empezaría calculando la integral con un intervalo resultado saldría de hacer el siguiente cálculo: . El − ( ∑ ( )) (3.21) Nunca se debe dar por válido el resultado de la primera integración y por lo tanto hay que ⁄ y por lo tanto hacer una segunda. Se tiene , 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 3.4. Métodos numéricos Regla de Simpson En la regla de Simpson se extrapolan los intervalos en parábolas. Se toman tres puntos de cada intervalo ( ), los puntos son los extremos y el punto central del intervalo. De forma similar ]. se centra a los estudios anteriores, se centra el intervalo en [ 𝑔(𝜉) 𝑃(𝜉) 𝜉 Figura 3.4. Extrapolación parabólica utilizando tres puntos. Para obtener el valor de la integral por del intervalo se puede usar el polinomio interpolante de la ecuación (3.6), como se ha dicho antes el orden es . ( ) ( ) ( )( )( ( ) ( ) ) ( ) Se integra el polinomio entre ( ( )( )( ) ) ( ) ( ( ( ) )( )( ) ) (3.23) y . ( ∫ ) ( ) ( ) (3.24) − Para calcular la integral completa se deben sumar las integrales de todos los intervalos. En este caso se toman grupos de tres puntos, y por el número de puntos (Figura 3.5) debe ser un número par. 𝑦 𝑓(𝑥) 𝑏 𝑎 𝑥 𝑥 𝑥 . 𝑥𝑛− 𝑥𝑛 𝑥 Figura 3.5. Límites de los intervalos de integración. - 27 - Andrés Zarabozo Martínez Métodos numéricos La integral completa es por lo tanto (siendo como antes [ ( ) ( ) ( )] ( [ − ( )⁄ ): ) ( − ) ( )] (3.25) Si se agrupan los términos similares se obtiene: [ ( ( ) ( ) ( ) ( ) ( ) ( ∑ ( ) − ( ∑ ( ) − ) ( )) )] (3.26) El cálculo del error es similar al de la regla del punto medio. Como es una regla cuadrática se 4 podría pensar que el error seria que viene de integrar . Pero es una función antisimétrica y al integrarla entre y el error compuesto es 3.5. da cero. El error simple es por lo tanto 4 y . Extrapolación de Richardson Se puede acelerar el cálculo numérico (aumentando por lo tanto el orden de convergencia) con métodos como la extrapolación de Richardson. Permite a partir de un orden de convergencia , tener una aproximación . Es preferible que sea . Supongase que ( ) es una estimación de orden para: ( ) (3.27) Al no poder hacer el límite infinito, se hace una aproximación de utilizando ( ). ( ) Donde (3.28) son constantes desconocidas reales y . son constantes conocidas tal que Si solo se toma el primer término, la aproximación queda: ( ) + ( ) (3.29) como función de ⁄ . Dividiendo el paso por dos se escribe ( ) ( ) + ( (3.30) ) Utilizando las ecuaciones (3.29) y (3.30) se elimina la constante desconocida ( ( ) ) ( ) ( ) ( ) - 28 - + ( ( + ) ) . (3.31) (3.32) Andrés Zarabozo Martínez Métodos numéricos Con este proceso, se obtiene una mejor aproximación de eliminando el mayor término de error que es ( ). Este proceso se puede repetir para eliminar términos de error para obtener una mejor aproximación. El problema es que no se suele saber el valor de . Se suele usar igual al orden de cuadratura del método usado o hacer una aproximación del valor haciendo algunas iteraciones. Se calcula la aproximación de para el intervalo ⁄ . ( ) Se elimina la constante desconocida ( ( ) ( + (3.33) ) utilizando la ecuación (3.30). ) ( ) ( ) ( + ) (3.34) Si está a punto de converger se podría decir que el hecho de dividir el intervalo por la mitad no afecta al resultado. ( ) ( ) ( ) ( ) (3.35) Pudiendo aislar : ( ( ) ( )) ( ( ) ( ) - 29 - ( ) ( ) ( ) ) ( ) (3.36) Andrés Zarabozo Martínez 3.6. Métodos numéricos Programas Programa 4. Obtención de la serie de Fourier En este programa se quiere calcular los coeficientes de una serie de Fourier. Los coeficientes de la serie de cosenos se obtienen utilizando la fórmula integral. ∫ ( ) ∫ − ( ) ( ) (3.37) − De forma similar se pueden obtener los coeficientes de la serie de senos. ∫ ( ) ( ) (3.38) − Una vez se tienen los coeficientes de la serie de cosenos y los coeficientes de la serie de senos se pueden calcular la amplitud y el desfase. √ ( ) (3.39) Las integrales se hacen utilizando el método del trapecio. Se crea una subrutina que calcule la integral de una función. A esta subrutina se le debe dar un vector y(n) donde se almacenen los valores de la función. subroutine trapice(y, b, z, n) implicit none integer, intent (in) :: n real, intent (in) :: y(n), b real, intent (out) :: z z = 0.5 * (y(1) + y(n))+ sum(y(2:n-1)) z = z * b / (real(n) - 1.) end subroutine La subrutina fourier debe calcular las fases y las amplitudes. Debe ir llamando a la subrutina trapice para calcular los coeficientes de la serie de cosenos y senos. Los valores de las amplitudes y de las fases se almacenan en una matriz llamada modes(2,0:m). Se le asigna un rango definido a la matriz (0:m) para mantener el convenio de subíndices. La variable n es el número de puntos seleccionados de la función para hacer las integrales. La variable m es el número de términos de la serie de Fourier que se quieren calcular. Se añaden además una serie de parámetros como pi o su inversa invPi. Como se sabe que se va a dividir por bastantes veces es recomendable tener una variable que guarde su inversa y así solo tener que hacer multiplicaciones. - 30 - Andrés Zarabozo Martínez Métodos numéricos subroutine fourier (y, modes, n, m) implicit none integer, intent (in) :: n, m real, intent (in) :: y(n) real, intent (out) :: modes(2, 0:m) integer i real z(n), x(n), dx, invPi, a, b real, parameter :: pi = acos(-1.) invPi = 1. / pi Se inicializa el vector de los puntos . dx = 2. * pi / (real(n) - 1.) x(1) = -pi do i = 2, n x(i) = x(i-1) + dx end do Se calculan ahora los coeficientes de las series y luego finalmente las amplitudes y fases. El primer coeficiente se calcula fuera del bucle, este valor es ya la amplitud y no hay fase porque no multiplica una función trigonométrica. !First coeficient call trapice(y, 2.*pi, a, n) modes(1,0) = a * 0.5 * invPi do i = 1, m !Cos coeficients z = y * cos(real(i) * x) call trapice(z, 2.*pi, a, n) a = a * invPi !Sin coeficients z = y * sin(real(i) * x) call trapice(z, 2.*pi, b, n) b = b * invPi !Amplitudes and phases modes(1,i) = sqrt(a*a + b*b) modes(2,i) = -atan(b / a) end do end subroutine - 31 - Andrés Zarabozo Martínez Métodos numéricos Finalmente se escribe la funcion principal del programa. Se utiliza una función de ejemplo que ya está escrita con sus amplitudes y fases para poder comprobar si el programa funciona bien. La función escogida es: . ( . ) ( . ) (3.40) El programa debe primero seleccionar una serie de puntos y calcular el valor de la función almacenándolos en el vector y(n). El programa llama a la subrutina fourier que es la que se encarga de devolver las amplitudes y fases. program program4 implicit none integer, parameter :: n = 300 integer i real, parameter :: pi = acos(-1.) real y(n), step, x, modes(2, 0:8) x = -pi step = 2. * pi / (real(n) - 1.) !Discretization do i = 1,n y(i) = 0.5 + 3. * cos(2. * x + 0.75) + 1. * cos(6. * x + 0.25) x = x + step end do !Amplitudes and phases call fourier (y, modes, n, 8) !Print results do i = 0, 8 print* , modes(1,i), modes(2,i) end do end program - 32 - Andrés Zarabozo Martínez Métodos numéricos Programa 5. Iteraciones y extrapolación En este programa se calcula la integral de una función mediante el método del trapecio pero disminuyendo en cada iteración el tamaño del intervalo entre dos puntos. Como ya se ha explicado en el tema 3.3, si se divide el intervalo en dos, en los puntos donde ya se ha evaluado la función no hace falta volver a calcularlos y por lo tanto solo hay que hacer la mitad de cálculos para cada iteración. Para este programa se utilizan variables con double precision. Para ello las funciones trigonométricas que se deben usar son dsin y dcos. En ambas se debe introducir una variable de double precision. Para transformar el tipo de variable se usa la función dble. Se crea una subrutina que calcula la función. La función de ejemplo es: ( ) (3.41) subroutine evaluateFunction(x, y) implicit none real* 8, intent(in) :: x real* 8, intent(out) :: y y = dcos(5. * x) + 3. * x * x end subroutine El programa principal se encarga de ir evaluando la función y sumando esos valores a la variable suma. Con ésta se puede calcular la integral en función del valor del intervalo de la iteración. Se inicializan los valores de las distintas variables y se evalúa la suma de los puntos extremos, que si además se divide por dos se obtiene el coeficiente de la ecuación (3.19). El número de intervalos viene definido por la variable n. program program5 implicit none integer :: i, j, n real*8, parameter :: a = 0., b = 1. real*8 suma, prevInteg, integ, h, sumEnds, aux, x n = 10 h = (b - a) / dble(n) suma = 0. !Sum of limits divided by two call evaluateFunction(a, aux) sumEnds = aux call evaluateFunction(b, aux) sumEnds = (sumEnds + aux) * 0.5 - 33 - Andrés Zarabozo Martínez Métodos numéricos Lo siguiente es hacer el bucle iterativo. En cada iteración simplemente hay que sumar los valores de la función a la variable suma. Se debe diferenciar la primera iteración de las demás ya que en la primera hay que evaluar la función en todos los puntos y en las demás simplemente hay que evaluarla cuando j (subíndice del punto ) sea impar. do i = 1, 10 !Sum of the values of the function if(i .eq. 1) then x=a+h do j = 1, (n - 1) call evaluateFunction (x, aux) suma = suma + aux x=x+h end do else x=a+h do j = 1, (n - 1), 2 call evaluateFunction (x, aux) suma = suma + aux x=x+2*h end do end if La integral se obtiene multiplicando la suma de todos los puntos (dividiendo por dos los límites) y multiplicándolo por el intervalo, ecuación (3.18). Una vez obtenido el valor de la integral se calcula el tamaño del intervalo y el número de intervalos para la próxima iteración. !Integral integ = h * (sumEnds + suma) !Number of intervals and size of interval n=2*n h = 0.5 * h Se sabe que el resultado analítico de la integral es: ∫ ( ( ) ) . (3.42) El resultado que se imprime es la comparación del resultado calculado y el resultado analítico. !Results print*, integ - (.2 * dsin(dble(5.)) + 1.) end program - 34 - Andrés Zarabozo Martínez Métodos numéricos El programa ya está acabado. Si se ejecuta se puede ver como el error va disminuyendo a medida que se van haciendo iteraciones. Si se aumenta el número de iteraciones (en este programa se tiene que cambiar el último valor del bucle do) se puede ver que llega un punto en el que el error vuelve a aumentar. Esto es debido a los errores de redondeo. En este programa se necesita aumentar mucho el número de iteraciones porque se han utilizado variables de mucha precisión justamente para evitar este problema. Se puede extrapolar el resultado de la integral utilizando el método e extrapolación de Richardson. El valor de la integral extrapolada se calcula utilizando la ecuación (3.32). Como se usa el método del trapecio, el orden de convergencia es . ( ) ( ) ( ) ( ) (3.43) El resultado de cada iteración se puede mostrar junto al resultado utilizando la extrapolación de Richardson. !Richardson extrapolation if(i .eq. 1) then print*,"No extrapolation", " With extrapolation" analitical = .2 * dsin(dble(5.)) - 1. else aux = (4. * integ - prevInteg) / 3. print*, integ - analitical, aux - analitical end if prevInteg = integ end do end program - 35 - Andrés Zarabozo Martínez Métodos numéricos 4. Resolución numérica de ecuaciones no lineales 4.1. Método de la bisección Los métodos de resolución numérica de ecuaciones no lineales permiten la obtención de resultados de para una función tal que ( ) . A la solución se le llama raíz o cero de la función. El primer método se basa en el teorema de Bolzano. Sea una función real continua en un ] con ( ) y ( ) de signos contrarios. Entonces existe al menos un intervalo cerrado [ ), con ( ) punto del intervalo abierto ( . El teorema como tal no especifica el número de puntos, pero afirma que al menos existe uno. ] tal ( )⁄ ) de un intervalo [ El método consiste en ir tomando el punto medio ( que ( ) y ( ) de signos contrarios. Se forman dos tramos y se escoge el tramo tal que la función en los límites sea de signo contrario. Si por ejemplo ( ) y ( ) se tienen dos opciones: ( ) [ ] ( ) [ ] { (4.1) El proceso se repite en cada iteración. La solución es: (4.2) Si no hubiese errores de redondeo al hacer infinitas iteraciones se obtendría el resultado. ̃ (4.3) La velocidad con la cual la sucesión de iteraciones converge se llama orden de convergencia. Si se tiene una secuencia ̃ que converge a un valor , se dice que la sucesión converge con orden a . |̃ |̃ | + | El número es llamado orden de convergencia, y en el caso del método de Bolzano por lo tanto un método muy lento. (4.4) . Es En general no se puede calcular el orden de convergencia exacto, pero utilizando unas cuantas iteraciones se puede estimar, aunque siempre considerando que a función converge. 4.2. Método de Newton - Raphson El método de Newton - Raphson es un método con un orden de convergencia mucho mayor, en general su orden de convergencia es . - 36 - Andrés Zarabozo Martínez Métodos numéricos Para éste método se debe escoger un punto que se aproxime a la solución. La cercanía del punto a la solución es importante para que el resultado converja. Se puede aproximar la función en una recta en ese punto utilizando la serie de Taylor. ( ) Se busca el punto ( ) ( ) ( en el cual ( ) ) ( ) (4.5) . ( ) ( ) ( ) ( ) ( ) (4.6) (4.7) 𝑓(𝑥 ) 𝑓(𝑥 ) 𝑥 𝑥 Figura 4.1. Primera iteración del método de Newton-Raphson. Se obtiene una regla de recurrencia y por lo tanto se pueden ir haciendo iteraciones hasta obtener el resultado deseado. Además es una regla cuadrática ( ). Pero tiene algunos problemas: 4.3. Contiene la derivada de la función, y en ocasiones no es posible obtenerla si por ejemplo no se tiene una expresión analítica de la función. Es un método abierto, la convergencia no está garantizada por un teorema de convergencia global. El resultado depende del primer valor que se estima. Se pueden por ejemplo tener problemas con máximos y mínimos. Método de la secante Con este método se evita el primer problema que tiene el método de Newton-Raphson. Se aproxima la tangente mediante la secante que pasa por dos puntos. En este método se necesitan dos puntos iniciales. La aproximación de la derivada es: ( ) ( ) ( ) (4.8) Y por lo tanto: ( ) - 37 - ( ) ( ) (4.9) Andrés Zarabozo Martínez Métodos numéricos 𝑓(𝑥 ) 𝑓(𝑥 ) 𝑥 𝑥 𝑥 𝑥 𝑓(𝑥 ) Figura 4.2. Dos primeras iteraciones del método de la secante. En este caso se gana en simplicidad y flexibilidad de ejecución pero se pierde en orden de convergencia. Este método no es cuadrático pero su orden de convergencia suele ser entre . y . , y por lo tanto no es tan rápido como el método de Newton-Raphson. Este método tiene el mismo problema que el método de Newton-Raphson por lo que no se puede asegurar la convergencia y ésta depende de los valores iniciales. 4.4. Método de regula falsi El método de regula falsi o falsa posición es una combinación del método de la secante y el método de la bisección. El orden de convergencia ronda la unidad (convergiendo más lentamente que el método de la secante) pero éste método asegura la convergencia a diferencia de por ejemplo el método de la secante. Se debe empezar con dos valores iniciales tal que los signos de la función es esos puntos son opuestos, garantizando que hay al menos una raíz en el interior del intervalo (teorema de Bolzano). Se traza una recta entre los dos puntos y se calcula el cero de esta recta. 𝑓(𝑥 ) 𝑓(𝑥 ) 𝑥 𝑥 𝑥 𝑥 𝑓(𝑥 ) Figura 4.3. Dos primeras iteraciones del método regula falsi. - 38 - Andrés Zarabozo Martínez Se calcula el punto Métodos numéricos a partir de los puntos y . ( ) ( ) ( ) ( ) (4.10) Una vez se obtiene el nuevo punto se calcula ( ) y se elige un nuevo intervalo que cumpla que la raíz esté dentro de él. En el caso del ejemplo de la Figura 4.3 se toman los números y , ya que ( ) ( ) . Se repite el proceso de forma iterativa. Éste método puede resultar lento si por ejemplo se tiene una función como el de la Figura 4.4 y además no se puede asegurar que el resultado haya convergido correctamente (no se puede asegurar que el error sea mayor de lo estimado). Esto es debido a que en esta función las iteraciones avanzan solo en una dirección. 𝑓(𝑥 ) 𝑓(𝑥 ) 𝑥 𝑥 𝑥 𝑥 𝑓(𝑥 ) Figura 4.4. Dos primeras iteraciones. 4.5. Teorema del punto fijo El último método de estudio consiste en obtener una ecuación del tipo ( ). de forma iterativa utilizando un valor inicial + ( ). Se resuelve Gráficamente este método consiste en encontrar el punto donde se cruza una función ( ). Para ello se empieza con un valor , se calcula el valor de ( ) y se y otra función busca del valor de que sea igual. 𝑓(𝑥 ) 𝑓(𝑥 ) 𝑥 𝑥 𝑥 Figura 4.5. Dos primeras iteraciones, convergiendo. - 39 - Andrés Zarabozo Martínez Métodos numéricos Este método puede no converger. Para que converja se debe cumplir que en la solución | ( )| . Si no se cumple la condición, la solución diverge alejándose en cada iteración de la solución, como se puede ver en la Figura 4.6. 𝑥 𝑥 𝑥 𝑥 Figura 4.6. Tres primeras iteraciones, divergiendo. - 40 - Andrés Zarabozo Martínez 4.6. Métodos numéricos Programas Programa 6. Deflexión de un cable En muchas películas de superagentes como por ejemplo James Bond se suelen ver como atraviesan una calle entre edificios solamente con un cable. Considerando que realmente pueden clavar el cable en el edificio de en frente y que se mantiene sujeto, se quiere estudiar si realmente el cable se mantiene rígido como muestran normalmente. Se tiene una cable sujeto en los extremos entre dos paredes y aguantando un peso en el centro, como muestra la Figura 4.7. El cable está caracterizado por sus propiedades y . En general las cuerdas que se usan para estos casos se llaman cuerdas de piano y son bastante rígidas. Está claro que en ningún caso estas cuerdas se pueden enrollar en un reloj o en el cinturón. 𝑙 𝐴 𝐵 𝑇 𝑇 𝑃 Figura 4.7. Diagrama del cable con un peso en el medio. La tensión se relaciona con el peso del superagente utilizando el equilibrio de fuerzas verticales, siendo el ángulo que forma el cable deflectado con la horizontal. (4.11) Suponiendo que la deformación es lineal la tensión del cable deformación . genera una pequeña (4.12) La longitud del cable estirado se puede relacionar con la longitud inicial del cable . (4.13) Por lo tanto la deformación es: (4.14) Se juntan las ecuaciones (4.11), (4.12) y (4.14) se obtiene una relación entre el peso del superagente y el ángulo . ( ) - 41 - (4.15) Andrés Zarabozo Martínez Métodos numéricos Simplificando la ecuación un poco se obtiene la ecuación que se quiere resolver numéricamente. En muchos problemas de física es bueno adimensionalizar las ecuaciones ya que estas muestran en un parámetro la relación entre propiedades importantes del problema. En este caso se relaciona el peso del superagente con la rigidez del cable. (4.16) Se debe hacer una aproximación del resultado para tener un valor inicial. Se puede considerar que el ángulo es pequeño | | . Esto no implica que y ya que la ⁄ ecuación no tiene sentido. El problema está en el coseno de la ecuación (4.15). Se aproxima con un orden superior: (4.17) Además se puede incluso hacer otra aproximación para facilitar la resolución de la ecuación. (4.18) Por lo tanto la solución aproximada es: √ (4.19) Se utiliza el método de la secante para resolver la ecuación. Se puede aproximar el resultado utilizando un número cercano de la aproximación obtenida, por ejemplo . . Se toman los siguientes valores de las propiedades del cable y del superagente: − (4.20) Lo primero que hay que hacer en este programa es calcular los valores iniciales. Además se − ⁄ crea una variable . . program Program6 implicit none integer i, j, n integer, parameter :: itMax = 7 real, parameter :: k = 0.25E-3 real x1, x2, x3, fx1, fx2, slope x1 = (2. * k)**(1./3.) x2 = 1.1 * x1 Se empieza ahora el bucle iterativo. En este se debe evaluar la función en el último valor calculado de (para el código es x2). Como el primer valor (el primer x1) solo se tiene que calcular una vez éste se calcula justo antes de iniciar el bucle. - 42 - Andrés Zarabozo Martínez Métodos numéricos Como protección se pone una salida del bucle en caso de que x1 sea igual a x2. Este caso significaría que ya se tiene la solución y se evita además hacer cálculos con divisiones por cero. fx1 = k + sin(x1) - tan(x1) print*, 'x= ', x1, 'f(x) = ', fx1 do i = 1, itMax if (x1.eq.x2) exit fx2 = k + sin(x2) - tan (x2) print*, 'x = ', x2, 'f(x) = ',fx2 Para hacer la nueva iteración se calcula la pendiente utilizando los dos resultados anteriores y se usa la ecuación (4.9) para calcular el nuevo valor x3. Una vez calculado se vuelven a establecer las variables x1 y x2. slope = (fx2 - fx1) / (x2 - x1) x3 = x2 - fx2 / slope x1 = x2 x2 = x3 fx1 = fx2 end do end program - 43 - Andrés Zarabozo Martínez Métodos numéricos Programa 7. Resolución mediante Newton-Raphson Se resuelve la misma ecuación mediante el método de Newton-Raphson. En este caso no se necesitan tener dos valores iniciales pero sí que se necesita la derivada de la función. ( ) (4.21) Como se utilizan varias veces las funciones trigonométricas se puede optimizar el programa creando dos variables cosx y sinx que calculen solo una vez por iteración la función trigonométrica. program Program7 implicit none integer i, j, n integer, parameter :: itMax = 7 real, parameter :: k = 0.25E-3 real x1, x2, fx1, slope, cosx, sinx x1 = (2. * k)**(1./3.) do i = 1, itMax cosx = cos(x1) sinx = sin(x1) fx1 = k + sinx - sinx / cosx slope = cosx - 1. / (cosx * cosx) print*, 'x = ', x1, 'f(x) = ', fx1 if (fx1 .eq. 0) exit x2 = x1 - fx1 / slope x1 = x2 end do end program - 44 - Andrés Zarabozo Martínez Métodos numéricos 5. Resolución numérica de sistemas lineales 5.1. Método de eliminación de Gauss El método de eliminación de Gauss es un algoritmo de álgebra lineal para determinar soluciones de un sistema de ecuaciones lineales. Se obtienen las soluciones del sistema lineal mediante la reducción del sistema dado a otro equivalente en el que cada ecuación tiene una incógnita menos que la anterior. Se transforma la matriz del sistema de ecuaciones en una matriz triangular superior. Obteniendo la solución de la última incógnita y pudiendo ir hacia atrás resolviendo las demás incógnitas del sistema. (5.1) ( ){ } { } A un sistema de ecuaciones lineal se le pueden hacer una serie de operaciones llamadas elementales. a. Multiplicar una ecuación por un escalar no nulo. b. Intercambiar de posición dos ecuaciones. c. Sumar a una ecuación un múltiplo de otra. En el caso del sistema matricial, estás se traducen en: a. Multiplicar una fila de la matriz y la fila del vector solución ( ) por un escalar. b. Intercambiar dos columnas de la matriz y dos filas del vector incógnitas. c. Sumar los términos de una fila a otra de la matriz y del vector solución. Para poder obtener la matriz triangular se debe, para cada fila: Se debe ir a la columna que empiece a partir de la diagonal . Si éste valor es nulo se debe cambiar la columna por otra que esté a la derecha y que tenga un valor no nulo. Si coincide que se está en la última fila con todos los valores nulos, el sistema es indeterminado. Se deben obtener ceros por debajo de sumando múltiplos adecuados de la fila superior a las filas de debajo. Una vez obtenida la matriz triangular se pueden ir obteniendo los calores de las resultados partiendo del último. El buen resultado de este método depende de la calidad de la matriz, que está relacionado con el radio espectral de la matriz, definido por el supremo de entre los valores absolutos de los elementos de su espectro. - 45 - Andrés Zarabozo Martínez 5.2. Métodos numéricos Matrices mal condicionadas Existen varias formas de definir una matriz mal condicionada. Una matriz de un sistema de ecuaciones lineales ( ) está mal condicionada si, por ejemplo, pequeños errores o variaciones en los elementos de o tienen un gran efecto en la solución exacta de . Otra forma de definirlo de forma sencilla es que una matriz está mal condiciona si el determinante es anormalmente pequeño. Se puede comparar con la norma de la matriz ‖ ‖, estando mal condicionada si | | ‖ ‖. La norma de la matriz (RMS) se puede calcular como: ‖ ‖ √∑ ∑ (5.2) Como ejemplo se define el siguiente sistema de ecuaciones siguiente, donde : { (5.3) ( ) No se puede despreciar ya que si se hiciese el sistema no tendría solución (el determinante es nulo). Se utiliza el método de eliminación de Gauss. { (5.4) La solución del sistema es por lo tanto: ( ) (5.5) Se puede ver que tanto la solución de como la de depende mucho del valor de . Un problema de redondeo del programa podría arruinar el resultado. Se puede comprobar que el determinante es mucho más pequeño que la norma. | | ‖ ‖ √ ( ) √ (5.6) Cuando se tiene una matriz mal condicionada se debe evitar que los valores problemáticos (números muy pequeños) estén en la diagonal. Se debe por lo tanto reordenar la matriz en caso de tener ese problema. Si se quiere ser riguroso en la reordenación de la matriz se debe conseguir una matriz lo más parecido a una matriz diagonal dominante. Se debe calcular un parámetro de calidad en todas las filas (desde la fila del pívot hasta la fila n). Éste es el cociente entre el valor de la columna y los elementos de la fila. | (| Donde viene dado por el elemento de la columna ( [ ]. y viene dado por - 46 - | |) (5.7) [ ] donde es la posición del pívot) Andrés Zarabozo Martínez Métodos numéricos Para garantizar que la matriz esté bien condicionada se cambia la fila del pívot por aquella fila que tenga mayor. Otro método menos riguroso consiste en buscar el máximo valor de los elementos de la columna por debajo del pívot y cambiar la fila por la del pívot. Aunque de esta forma no se garantiza que no haya números muy grandes en el resto de la fila. 5.3. Descomposición LU La descomposición LU (donde LU viene de las siglas inglesas Lower-Upper) es una forma de factorización de una matriz como el producto de una matriz triangular inferior y una superior. Esto puede ser útil cuando se debe resolver varios sistemas de ecuaciones donde la matriz no varía y lo que varía es el vector . Un ejemplo sería tener una estructura y se deben calcular varios estados de carga distintos. (5.8) ) ( ( ) En este libro se estudian dos métodos de descomposición LU. Ambos dependen de qué matriz ( o ) tenga unos en su diagonal. El método Doolittle introduce unos en la matriz ( ) y el método Crout tiene los unos en la matriz ( ). Una vez se tienen las matrices y se resuelve el sistema y luego . Como son diagonales, no hace falta hacer el método de Gauss para obtener la solución. ( 5.4. ) y (5.9) 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 4 (5.10) 4 ( 4 4 ) ( 4 44 ) 4 4 4 ( 4 4 4 En los elementos de la matriz eliminación de Gauss. 4 4 4 4 4 4 4 (5.11) 4 4 4 4 4 44 ) aparecen las operaciones que se hacen al utilizar el método de - 47 - Andrés Zarabozo Martínez Métodos numéricos Para obtener las matrices con el método Doolittle se hacen las operaciones similares a la triangulación de Gauss. Se triangula la matriz dejando en los ceros el multiplicador. Como ejemplo se parte de la siguiente matriz : ( ) (5.12) Se empieza con el pívot de la primera columna. En los elementos multiplicador (valores encuadrados). y se deja el valor del ( ) (5.13) ( ) (5.14) Se hace lo mismo para el siguiente pívot. Por lo tanto las matrices y son: ( 5.5. ) ( ) (5.15) Crout De forma similar al método Doolittle se multiplican dos matrices forma de la matriz . y genéricas para ver la 4 ( 4) ) ( 4 4 4 (5.16) 4 44 4 4 4 4 ( 4 4 4 4 4 4 4 4 4 (5.17) 4 4 4 4 4 44 ) 4 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 4 4 4 4 - 48 - 4 4 4 4 4 ) (5.18) 4 4 4 44 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 4 4 4 4 4 4 4 4 4 4 ) (5.19) 44 Se pueden resolver y 4 y luego 4 . Este proceso se va repitiendo con cada submatriz utilizando la primera columna para obtener las variables y la primera fila para obtener las variables . De forma general si se tiene la siguiente matriz y de (hasta el pívot ): modificada para ir obteniendo los valores de (5.20) ( ) Los valores (donde son los elementos de la columna a partir de siguiente forma: ) se obtienen de la − ∑ Los valores de siguiente forma: (5.21) (donde son los elementos de la fila por detrás de ) se obtienen de la − ( 5.6. ∑ ) (5.22) Matrices dispersas Una matriz dispersa es una matriz donde la mayor parte de los elementos son ceros. Existen métodos para agilizar la resolución de sistemas de ecuaciones disminuyendo la carga computacional y el tamaño consumido en memoria para almacenar todos los valores. Almacenamiento Skyline Se generan vectores en cada fila de la matriz dispersa tomando desde el primero hasta el último elemento no nulo de cada fila. Es posible que hayan ceros entre los elementos seleccionados. Por ejemplo, se quiere almacenar la siguiente matriz: (5.23) ( ) - 49 - Andrés Zarabozo Martínez Métodos numéricos Los cuatro vectores que se forman son: { } { } { } { } { } (5.24) Se escriben todos estos valores en un vector contiguo. De esta forma se almacenan solo elementos de los que tiene la matriz. Para saber como están ordenados los valores del vector se necesitan dos vectores punteros. El vector indica la posición del primer valor no nulo de la fila y el vector indica la cantidad de valores que hay en esa fila. (5.25) { } { } Alternativamente en vez del vector se puede utilizar otro vector que posición del vector empieza la siguiente fila. donde se define a partir de (5.26) { } Si por ejemplo que se quiere recuperar la tercera fila se va al vector o . Estos vectores indican que se tienen tres elementos y que empiezan a partir de la quinta posición del vector de valores. Además gracias al vector se sabe que los valores empiezan a partir de la tercera columna. Por lo tanto: ( ) (5.27) Compress Space Row En este método solo se almacenan los elementos no nulos. En el caso de tener algún cero en la diagonal también se tendría que almacenar. De forma similar al método anterior se utilizan tres vectores donde el primero es para almacenar los valores de las matrices. Además se utiliza un vector que indica la posición de la columna del elemento y un vector que indica en que posición del vector de valores se encuentra el salto de línea. Utilizando la matriz de ejemplo de la ecuación (5.23) se definen los tres vectores: ( ) ( ) ( (5.28) ) En el vector puntero se puede introducir un valor adicional que define la posición de la fila siguiente del valor que ya no existiría en . No es necesario pero se hace por comodidad. - 50 - Andrés Zarabozo Martínez Métodos numéricos Si por ejemplo se quiere recuperar la tercera fila de se iría primero al vector puntero que indica que en la tercera fila aparecen los valores y del vector ( y ). Utilizando el vector se sabe que estos valores están en las columnas y respectivamente. Por lo tanto: ( ) (5.29) Matriz banda Una matriz banda es una matriz donde los valores no nulos son confinados en un entorno de la diagonal principal. Se forma una banda de valores no nulos que completan la diagonal principal y algunas diagonales en cada uno de sus costados. El ancho de banda de la matriz es el número de columnas de elementos no nulos en las filas centrales. Por ejemplo una matriz con un ancho de banda de sería: 4 4 44 (5.30) 4 4 ( ) No es necesario almacenar todos los ceros de la matriz, se pueden guardar, por ejemplo, los datos de la matriz anterior en una matriz reducida . (5.31) 4 ( ) El ancho de la matriz reducida es igual al ancho de banda y la columna central contiene los elementos de la diagonal principal. 5.7. Método del gradiente conjugado El método del gradiente conjugado es un algoritmo para resolver numéricamente sistemas de ecuaciones lineales cuyas matrices son simétricas y definidas positivas. Una matriz definida positiva es una matriz tal que para cualquier vector nulos cumpla . de elementos no Se utiliza ̃ para definir la aproximación de la solución real . Si se cumplen las condiciones de la ecuación (5.32) entonces también se cumple la ecuación (5.33). ̃ (5.32) - 51 - Andrés Zarabozo Martínez Métodos numéricos ( ̃) ̃ ̃ ̃ (5.33) Por lo tanto ( ) es el mínimo de esa función, es decir: ( ̃) ( ) ̃ (5.34) Utilizando notación indicial se puede demostrar la afirmación anterior. ( ̃) ̃ ̃ ̃ (5.35) ) (5.36) Derivando la expresión respecto a ̃ . ( ̃ Debido a que la matriz ̃ ̃ es simétrica los términos dentro de los paréntesis son iguales. ̃ ̃ (5.37) El extremo coincide con la solución del sistema . La aproximación ̃ es igual a la solución del sistema más un error: ̃ ( Por lo tanto y recordando que ( ) ( ) ( (5.38) ) : ) ( ) ( ) ⏟ ⏟ ( ) ( ) (5.39) ⏟ ( − ) Se llega a la conclusión que siempre que se introduzca la solución aproximada el valor de mayor, por lo que la solución real coincide con el mínimo. es Por lo tanto encontrando el mínimo se obtiene la solución real. El método del descenso máximo elige la dirección más rápida de descenso para aproximarse a la solución. Si se hace eso en cada iteración al final se llega al mínimo. Se llama al error de la iteración . También se define el residuo . El objetivo es que tanto como sean cero. Según la ecuación (5.37) se puede ver que el gradiente de la función es el residuo. (5.40) - 52 - Andrés Zarabozo Martínez Métodos numéricos Se puede también relacionar el residuo con el error. (5.41) La matriz representa la matriz de transformación lineal entre el error y el residuo Empezando con una aproximación lineal la siguiente aproximación moviéndose en dirección del gradiente y en sentido opuesto. + . se obtiende (5.42) + Se debe obtener el mínimo siguiendo la dirección del movimiento. + (5.43) Utilizando la regla de la cadena queda: + + + + + (5.44) + Se busca que el residuo de la siguiente iteración sea cero, por lo tanto: ( + [ ) ( ( )] ) ( ) (5.45) Para reducir el número de operaciones se deben evitar los productos de matriz por vector. A partir de la ecuación (5.42) se tiene: ( + ) + (5.46) + El nuevo residuo se puede obtener a partir del anterior y la operación no se tiene que repetir. El proceso iterativo básico se puede ver esquematizado en la Figura 5.1. 𝑥𝑖 𝑟𝑖 𝛼𝑖 𝑟𝑖𝑇 𝑟𝑖 𝑟𝑖𝑇 𝐴𝑟𝑖 𝑥𝑖+ 𝑟𝑖+ 𝑥𝑖 𝑟𝑖 Figura 5.1. Esquema iterativo básico del método. - 53 - 𝛼𝑖 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖 Andrés Zarabozo Martínez Métodos numéricos Este esquema permite obtener una solución rápida si las curvas de nivel son más o menos circulares. Si tienen forma de elipses alargadas, el esquema puede tardar mucho en obtener la solución del sistema. Para aproximarse mejor a la solución se debe buscar una dirección ortogonal a todas las direcciones anteriores, asegurándose así que solo se pasa una vez por la misma dirección. Estando por ejemplo en la primera iteración, la nueva aproximación es: (5.47) El error en la dirección de ortogonalidad es nulo ( iteraciones: ( + ). Si esto se cumple en todas las ) + ( ) ( Pudiendo obtener la constante ) (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). Se puede obtener la constante para la primera iteración de la siguiente forma: ( ) (5.52) Siendo la nueva aproximación . ̅ ) no se calcula desde el principio si no que se van La secuencia de los vectores ( ̅ ̅ calculando a medida que se hacen las iteración. En el caso de la primera iteración este vector es simplemente: (5.53) - 54 - Andrés Zarabozo Martínez Métodos numéricos Para la siguiente iteración se debe conseguir que componente en la dirección para asegurarlo. sea ortogonal a . Se elimina la (5.54) Donde es una constante y se obtiene utilizando la condición de ortogonalidad. ( ) (5.55) Por lo tanto es: (5.56) Para las siguientes direcciones se debe asegurar que son ortogonales a las anteriores es decir: − (5.57) − Pero mediante una demostración que no se va a realizar en este libro se puede llegar a la conclusión que todos las constantes son cero para . Pudiendo utilizar la ecuación (5.56) para obtener el valor de . El esquema iterativo se presenta en la Figura 5.2. 𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑟𝑖𝑇 𝐴𝑑𝑖− 𝑇 𝑑𝑖− 𝐴𝑑𝑖− 𝑑𝑖 𝑟𝑖 𝛽𝑖 𝑑𝑖− 𝑥𝑖+ 𝑥𝑖 𝛼𝑖 𝑑𝑖 𝑟𝑖+ 𝑟𝑖 𝛼𝑖 𝐴𝑟𝑖 𝛼𝑖 𝑑𝑖𝑇 𝑟𝑖 𝑑𝑖𝑇 𝐴𝑑𝑖 Figura 5.2. Esquema iterativo del método. Aprovechando la ortogonalidad de las derivadas de búsqueda se puede reescribir el esquema anterior de forma que solo sea necesario un producto de matriz por vector. El siguiente esquema es el más utilizado ya que se reducen el número de productos de matriz necesarios. 𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑟𝑖𝑇 𝑟𝑖 𝑇 𝑟𝑖− 𝑟𝑖− 𝑑𝑖 𝑥𝑖+ 𝑟𝑖+ 𝑟𝑖 𝑥𝑖 𝑟𝑖 𝛽𝑖 𝑑𝑖− 𝛼𝑖 𝑑𝑖 𝛼𝑖 𝐴𝑑𝑖 Figura 5.3. Esquema iterativo más utilizado del método. - 55 - 𝛼𝑖 𝑟𝑖𝑇 𝑟𝑖 𝑑𝑖𝑇 𝐴𝑑𝑖 Andrés Zarabozo Martínez 5.8. Métodos numéricos Ejemplo de aplicación del método del gradiente conjugado Como ejemplo se considera el siguiente sistema: [ ]{ } { } (5.58) Se toma como aproximación inicial: { } (5.59) Lo primero que se tiene que calcular es el residuo inicial. { } Al ser los valores iniciales el residuo es igual a [ ]{ } { } (5.60) . { } (5.61) Lo siguiente que se calcula es la dirección de la primera iteración { }{ . } (5.62) { }[ ]{ } Por lo tanto la solución al hacer una iteración es: { } { } [ } { } (5.63) Y se calcula el nuevo residuo. { Al hacer la nueva iteración se calcula la constante ]{ Se calcula y { } (5.64) . { − } }{ } (5.65) − { }{ } { } . { } - 56 - { } (5.66) 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). { } - 57 - { } { } (5.68) Andrés Zarabozo Martínez 5.9. Métodos numéricos Programas Programa 1. Resolución de un sistema mediante Gauss El programa debe resolver un sistema lineal, considerando que la matriz está bien condicionada. Se crea una subrutina que resuelve el sistema. Se deben crear dos variables integer para los bucles do. Como convenio el elemento de la diagonal a la que se le quiere hacer ceros por debajo se llama pívot. Se crea otra variable mult donde se almacena el multiplicador de cada fila. subroutine solver(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot real :: mult Se debe crear ahora la matriz diagonal. El primer bucle se encarga de ir cambiando la posición del pívot y va desde la primera posición hasta la penúltima. El segundo bucle se encarga de ir cambiando los valores de las filas de por debajo del pívot en ceros, por lo tanto éste bucle empieza en la siguiente fila del pívot y acaba en la última fila. !Triangulate the matrix do pivot = 1, n-1 do row = pivot+1, n Una vez dentro del segundo bucle se deben ir convirtiendo los elementos de la columna en ceros. Primero se calcula el multiplicador que es igual al elemento de la fila dividido por elemento de la diagonal. Para utilizar el convenio de numeración que sigue Fortran se utiliza al nombrar elementos de la matriz se utiliza el primer valor para la columna y el segundo para la fila, siendo el contrario de lo que se suele usar, por lo que se deberá enviar a la subrutina la función transpuesta. Seguido, a la fila dada se le resta la fila del pívot multiplicada por el multiplicador. Esto solo se hace para los elementos que estén una columna por detrás de la del pívot, no es necesario modificar los elementos por debajo del pívot ya que se sabe que esa operación da cero (y no es necesario poner esos ceros). Se hace la misma operación para el vector . do row = pivot+1, n mult = a(pivot, row) / a(pivot,pivot) a(pivot+1:n,row) = a(pivot+1:n,row) - mult * a(pivot+1:n,pivot) b(row) = b(row) - mult * b(pivot) end do - 58 - Andrés Zarabozo Martínez Métodos numéricos Una vez se tiene la matriz triangular se pueden obtener las soluciones. La primera solución es trivial de obtener. En este programa el propio vector se va modificando para ir introduciendo las soluciones. !Obtain solutions b(n) = b(n) / a(n,n) Se debe hacer un bucle para obtener las demás soluciones. Se parte de la penúltima fila y se llega hasta la primera (restando uno al valor de la fila en cada iteración). En cada iteración del bucle se obtiene un nuevo resultado. Una vez triangulada la matriz, el sistema queda de la siguiente forma: ( − ) ( − ) ( − )( − ) ( − )( − ) ( − ) ( − )( − ) ( − ) ( − − ){ (5.69) − − } { } Si por ejemplo se quiere obtener la antepenúltima solución lo primero que se hace es aislar la variable que se quiere encontrar ( ( − )( − ) − ). Para ello se pasa del otro lado los términos de la matriz multiplicando a las soluciones ya conocidas (en este caso − y ). Por lo tanto la ecuación queda: ( − )( − ) − − ( − )( − ) − ( − ) (5.70) La operación ( − )( − ) equivale a hacer el producto escalar de los ( − ) − elementos de la fila que estén por detrás del pívot y de los elementos del vector solución por debajo de la fila del pívot. Una vez se obtiene el resultado de la parte de la derecha de la ecuación (5.70) simplemente se divide por ( − )( − ) para obtener la solución. do row=n-1,1,-1 b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine El programa principal debe inicializar la matriz funciona correctamente. y el vector y comprobar que la subrutina La subrutina solo funciona correctamente si la matriz está bien condicionada. Tanto la matriz como el vector se generan con números aleatorios. Los valores que no estén en la diagonal que se generen estarán comprendidos entre . y . y los elementos de la diagonal siempre - 59 - Andrés Zarabozo Martínez Métodos numéricos serán como mínimo igual al número de filas de la matriz por lo que la suma de los elementos fuera de la diagonal siempre serán menor que los de la diagonal (en cada fila). program program8 implicit none integer, parameter :: n = 20 integer i, j real :: a(n,n), aTrans(n,n), b(n), x(n), rand !Initialize matrix and vector do i = 1, n do j = 1, n call random_number(rand) a(i,j) = 0.5 - rand end do a(i,i) = (1. + rand) * real(n) call random_number(rand) b(i) = rand end do Se resuelve ahora el sistema. Como ya se dijo antes, en la subrutina se utiliza el convenio de estructura del fortran por lo que se debe hacer la transpuesta de la matriz para que coincida que el primer índice de la matriz sea la columna. Como la solución del sistema en la subrutina se escribe directamente en vector pero con los valores del vector b. se debe enviar el !Solve system aTrans = transpose(a) x=b call solver(aTrans, x, n) Para comprobar que el programa funciona bien se calcula . Esto en teoría tiene que dar un vector nulo. Se imprime el máximo valor absoluto de ese vector (dando el error más grande) y se comprueba que el valor sea prácticamente cero. La función Matmul multiplica las matrices según el convenio matemático, primer índice filas y segundo índice columnas. !Errors x = matmul(a, x) - b print *, 'If the code is correct this is a small number: ', maxval(abs(x)) end program Nota, la subrutina modifica tanto la matriz como el vector que se envía. El vector es ya la solución (que se ha almacenado en ) pero la matriz queda triangulada. Por suerte en vez de enviar la matriz se ha enviado la matriz aTrans. - 60 - Andrés Zarabozo Martínez Métodos numéricos Programa 2. Sistema con matriz mal condicionada En este programa se trabaja con una matriz mal condicionada. Se debe por lo tanto reorganizar los elementos de la matriz para obtener un buen resultado. En modificar las filas de la matriz y del vector se utiliza un vector llamado puntero donde se almacena la posición de las filas. Por ejemplo, se tiene una matriz y un vector de puntero que inicialmente son: ( ) { } (5.71) Si se quiere cambiar la primera fila por la tercera simplemente hay que cambiar el valor del vector puntero, dejando la matriz y el vector de la siguiente forma: ( ) Así se sabe que en la primera fila de la matriz de la matriz , aunque la matriz no exista. { } (5.72) están situados los elementos de la tercera fila De forma similar al programa anterior se crea una subrutina que resuelve el sistema. En este caso se crea además un vector puntero (point) y lo primero es inicializar los valores. subroutine solveMatrix(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot, point(n), i, pos_row, posPiv real :: mult, x(n) !Initialize point vector do row=1,n point(row)=row end do Para reorganizar la matriz se utiliza un método menos riguroso que consiste en poner el número más grande que haya por debajo del pívot. Esto no garantiza que la matriz esté perfectamente condicionada pero es más rápido. do pivot = 1, n-1 !Organize matrix mult = 0. do row = pivot, if (abs(a(pivot,point(row))) .GT. mult) then i = row mult = abs(a(pivot,point(row))) end if end do - 61 - Andrés Zarabozo Martínez Métodos numéricos Se tiene ahora la posición de la fila que se quiere cambiar por la del pívot. Se debe por lo tanto intercambiar en el puntero el valor de estas dos filas. row = point(pivot) point(pivot) = point(i) point(i) = row Se utiliza la variable posPiv sirve para guardar la posición del pívot y no tener que utilizar todo el rato point(pivot). posPiv = point(pivot) La parte del código que triangula la matriz es similar a la del programa anterior. Hay que tener cuidado en seleccionar bien la fila ya que ésta puede haber sido cambiada por otra. !Make zeros under Pivot do row = pivot+1, n posRow = point(row) mult = a(pivot, posRow) / a(pivot,posPiv) a(pivot+1:n,posRow) = a(pivot+1:n,posRow) - mult * a(pivot+1:n,posPiv) b(posRow) = b(posRow) - mult * b(posPiv) end do end do De forma similar, el código que obtiene los resultados se tiene que modificar para que seleccione bien las filas que se deben usar. !Obtain Results x(n) = b(point(n)) / a(n,point(n)) do row = n-1,1,-1 posRow = point(row) x(row) = b(posRow) - dot_product(a(row+1:n,posRow), x(row+1:n)) x(row) = x(row) / a(row,posRow) end do b=x end subroutine Se crea ahora el codigo del programa principal. El codigo es similar al del programa anterior. Se tiene un generador de matrices que genera una matriz mal condicionada. Los valores de la matriz fuera de la diagonal principal varían entre -0.5 y 0.5 y los de la diagonal son del orden − de . - 62 - Andrés Zarabozo Martínez Métodos numéricos program program9 implicit none integer, parameter :: size = 20 integer i, j real :: a(size,size), aTrans(size,size), b(size), x(size), rand !Generate matrix do i = 1, size do j = 1, size call random_number(rand) a(i,j) = 0.5 - rand !Number between -0.5 and 0.5 end do a(i,i) = rand * 1.E-5 !Very small number for the diagonal call random_number(rand) b(i) = rand !Number between 0. and 1. end do El sistema resuelve las matrices con el convenio de numeración de matrices de Fortran (como en el programa anterior). Se debe por lo tanto enviar la transpuesta de la matriz a la subrutina. !Solve system aTrans = transpose(a) x=b call solveMatrix(aTrans, x, size) Se comprueba el resultado haciendo la operación absoluto, que indica el mayor error. y buscando el máximo valor !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 en la matriz ). Se resuelve primer seguido de y (almacenadas subroutine luSustitution(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n) real, intent(in) :: a(n,n) integer :: row, i !Ly = b do row = 1, n b(row) = b(row) & - dot_product(a(1:row-1,row),b(1:row-1)) end do !Ux = y do row = n, 1, -1 b(row) = b(row) & - dot_product(a(row+1:n,row),b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine - 64 - Andrés Zarabozo Martínez Métodos numéricos El programa principal es parecido a los anteriores programas que resuelven sistemas de ecuaciones lineales. La matriz que se genera está bien condicionada. En este programa se debe llamar primero a la subrutina que se encarga de generar las matrices y y luego se obtiene el resultado del sistema. program program10 implicit none integer, parameter :: n = 50 integer i, j real :: a(n,n), aTrans(n,n), b(n), x(n), rand !Generate matrix do i = 1, n do j = 1, n call random_number(rand) a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5 end do a(i,i) = 0.1 * (1. + rand) * real(n) ! Good matrix call random_number(rand) b(i) = rand ! A number between 0. and 1. end do !Solve system aTrans = transpose(a) x=b call luDecomposition(aTrans, n) call luSustitution(aTrans, x, n) !Check results x = matmul(a, x) - b print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program - 65 - Andrés Zarabozo Martínez Métodos numéricos Programa 4. Crout En este programa se resuelve un sistema de ecuaciones lineales utilizando el método de descomposición de Crout. De forma similar al programa anterior, primero se descompone la matriz del sistema y luego se usa esa matriz para resolver el sistema. La primera subrutina descompone la matriz. Se considera que la matriz está bien condicionada. Se usa un bucle para ir moviendo el pivot e ir obteniendo los valores de las matrices y . subroutine croutDescomp(a, n) implicit none integer, intent(in) :: n real, intent(inout) :: a(n,n) integer :: row, column, i do i = 1, n De forma general si se tiene la siguiente matriz y de (hasta el pívot ): modificada para ir obteniendo los valores de (5.73) ( ) Los valores (donde son los elementos de la columna a partir de siguiente forma: ) se obtienen de la − ∑ (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 siguiente forma: (donde son los elementos de la fila por detrás de ) se obtienen de la − ( ∑ - 66 - ) (5.75) Andrés Zarabozo Martínez Métodos numéricos De forma similar, el sumatorio se traduce en el código en un producto escalar entre los elementos a la izquierda del pívot y los elementos por encima del elemento en . !Obtain U do column = i + 1, n a(i, column) = a(i, column) – dot_product(a(i,1:i-1),a(1:i-1,column)) a(i, column) = a(i, column) / a(i,i) end do end do end subroutine La segunda subrutina calcula la solución del sistema utilizando la matriz descompuesta de Crout. Esta subrutina es muy parecida a la utilizada en el programa anterior. La diferencia con Doolitle es que la matriz ya no tiene unos en la diagonal por lo que la división por los elementos de la diagonal se hace en el primer sistema y en cambio la matriz sí que tiene unos en la diagonal. subroutine croutSust(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n) real, intent(in) :: a(n,n) integer :: row, i !Ly = b do row = 1, n b(row) = b(row) - dot_product(a(row,1:row-1), b(1:row-1)) b(row) = b(row) / a(row,row) end do !Ux = y do row = n, 1, -1 b(row) = b(row) - dot_product(a(row,row+1:n),b(row+1:n)) end do end subroutine El programa principal es parecido a los programas anteriores. Primero genera una matriz bien condicionada, luego llama a las subrutinas que resuelven el sistema y finalmente calcula el error. La diferencia entre éste programa y los demás es que en éste no se hace la transpuesta de la matriz. Se hace una copia de la matriz para poder luego calcular el error. program program11 implicit none integer, parameter :: size = 50 integer i, j real :: a(size,size), aCopy(size,size), b(size), x(size), rand - 67 - Andrés Zarabozo Martínez Métodos numéricos do i = 1, size do j = 1, size call random_number(rand) a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5 end do a(i,i) = 0.1 * (1. + rand) * real(size) ! Good matrix call random_number(rand) b(i) = rand ! A number between 0. and 1. end do aCopy = a x=b call croutDescomp(aCopy,size) call croutSust(aCopy, x, size) x = matmul(a, x) - b print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program - 68 - Andrés Zarabozo Martínez Métodos numéricos Programa 5. Matriz banda El objetivo del programa es implementar el método de eliminación de Gauss a una matriz Banda, reduciendo el número de operaciones en los elementos que se saben que son nulos. Se define la matriz del sistema como una matriz reducida a(-d:d,size). Siguiendo el convenio de Fortran el primer índice indica las columnas y el segundo las filas. Los elementos de la diagonal están situados en la columna y el ancho de banda de la matriz es . La subrutina que resuelve el sistema es parecida a la del Programa 1, primero se triangula la matriz del sistema y luego se obtienen los resultados. Se tiene que tener mucho cuidado con las primeras y últimas filas, ya que éstas no tienen tantos valores como el ancho de banda. Cada vez que se escribe un bucle o se define un vector de fila se tiene que utilizar la función min() para que devuelva como mucho el número de elementos del ancho de banda o si hay menos, el número de elementos disponibles. Se toma por ejemplo una matriz con un ancho de banda de e un punto intermedio. El subíndice indica la columna y el superíndice indica la fila, en el ejemplo se mira la matriz a partir de la fila . Los elementos de la diagonal principal tienen como subíndice . 𝑑 ⬚ 𝐴 𝐴7− 𝐴8− 𝑑 𝐴 𝐴 (5.76) 7 𝐴 𝐴7 𝐴7 𝐴8− 𝐴8 𝐴8 𝐴8 𝐴− 𝐴− 𝐴 𝐴 (⬚ 𝐴 ) Se puede ver que solo se necesitan modificar las filas que hay por debajo del pívot. Además solo se pueden restar elementos de la fila del pívot a las demás filas. subroutine gaussBand(a, b, d, n) implicit none integer, intent(in) :: d, n real, intent(inout) :: a(-d:d,n), b(n) integer pivot, row, disp real mult !Triangulate matrix do pivot = 1, n - 1 do row = pivot + 1, min(pivot + d, n) Como ya se ha dicho antes la función min(pivot + d, n) se utiliza para asegurarse de que el programa no busca valores que están fuera de la matriz. - 69 - Andrés Zarabozo Martínez Métodos numéricos Para triangular la matriz se tiene que tener cuidado en definir bien los rangos de los vectores. La matriz reducida no está escrita en el programa como la matriz de la ecuación (5.76). Está escrita de la siguiente forma: 8 − 7 − 8 − 7 7 7 8 8 8 ( (5.77) ) A diferencia del Programa 1 los elementos que se eliminan no están debajo del pívot. En el caso del ejemplo se deben eliminar los elementos 7− y 8− . Para ello se define la variable disp que indica el número de filas que hay entre la fila y el pívot. Éste valor no puede superar por lo que también es útil para poder definir rangos de columnas. disp = row - pivot mult = a(-disp,row) / a(0, pivot) a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - & mult * a(1:d,pivot) b(row) = b(row) - mult * b(pivot) end do end do De forma similar, para resolver las variables, se tiene que tener cuidado de no salirse de los rangos de la matriz (utilizando disp = min(d, n - row)) y de definir bien los rangos de los vectores. Una vez triangulada la matriz, se obtiene una matriz reducida donde se tienen ceros a la izquierda de la columna central (que contiene los elementos de la diagonal principal). 7 7 7 8 8 8 (5.78) − − − − ( − ) Por lo tanto el producto escalar como mucho se hace utilizando un vector de dimensión que siempre empieza a partir de la columna . En el caso de las últimas filas se debe tener cuidado de no utilizar elementos que no existen. Se utiliza la variable disp para obtener el número máximo de columnas que se tienen a la derecha del pívot. - 70 - Andrés Zarabozo Martínez Métodos numéricos !Solve x do row = n, 1, -1 disp = min(d, n - row) b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp)) b(row) = b(row) / a(0,row) end do end subroutine El programa principal es parecido a los otros programas. Se define la matriz de forma distinta ya que ésta no es una matriz cuadrada. Se genera la matriz de forma que esté bien condicionada. Program program12 implicit none integer, parameter :: size = 50, d = 5 integer i, j, left, right real :: a(-d:d,size), aCopy(-d:d,size), b(size), bCopy(size), x(size), rand do i = 1, size do j = -d, d call random_number(rand) a(j,i) = 0.5 - rand ! A number between -0.5 and 0.5 end do a(0,i) = (1. + rand) * real(size) !Good matrix call random_number(rand) b(i) = rand !A number between 0. and 1. end do aCopy = a x=b !Solve call gaussBand(aCopy, b, d, size) bCopy = b Como la matriz operación que se ha generado es la matriz reducida no se puede hacer directamente la . Se debe hacer la operación para cada fila de la matriz . !Check results bCopy = b do i = 1, size left = min(d, i - 1) right = min(d, size - i) x(i) = dot_product(a(-left:right, i),bCopy(i-left:i+right)) - x(i) end do print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program - 71 - Andrés Zarabozo Martínez Métodos numéricos 6. Resolución numérica de sistemas no lineales 6.1. Método de Newton para sistemas no lineales Utilizando sistemas de elementos finitos se obtiene un sistema de ecuaciones que no tienen por qué ser lineales. Se puede extender el método de Newton para resolver sistemas multivariables. Para que se pueda resolver el problema se necesitan tantas ecuaciones como incógnitas, que cumplan que ⃗ ( ) donde ⃗ , y además unos valores iniciales . ( ) ( ) ( ) ( ) El residuo es el valor que se obtiene al poner las soluciones la solución del sistema entonces es nulo. (6.1) en las funciones ⃗ ( ). Si es De forma similar al método de Newton-Raphson, se utiliza una aproximación mediante series de Taylor para aproximar linealmente ⃗ a . ⃗( ) ⃗( ) ⃗( ) ( ) (6.2) La matriz de derivadas ⃗ ( ) se suele escribir como matriz . Por ejemplo en los problemas de elementos finitos estructurales esta matriz es la matriz de rigidez. Los elementos de la matriz son: ( ) ( ) ( ) ( ) ( ) ( ) ( ) | (6.3) ̅ ( ( ) ( ) ( ) ) Para calcularla se necesitan hacer muchas derivadas parciales y este es un proceso caro por lo que existen métodos que buscan reducir al máximo el cálculo de esa matriz, por ejemplo, el método de cuasi Newton. El objetivo del método es encontrar la solución a la ecuación (6.2), se elige tal que: tal que ⃗ ( ) sea cero. Por lo tanto, volviendo ( ) ( - 72 - ) (6.4) Andrés Zarabozo Martínez Como la matriz inversa. Métodos numéricos es cuadrada se puede resolver el sistema, siempre que la matriz − ⃗ tenga (6.5) En la práctica no se debe usar la inversa de la matriz ya que el cálculo es extremadamente costoso. Se puede resolver la ecuación resolviendo primero un sistema de ecuaciones lineales. Se define como . El sistema lineal que se resuelve es el siguiente: (6.6) Al obtener se puede resolver fácilmente la nueva iteración. (6.7) - 73 - Andrés Zarabozo Martínez Métodos numéricos 7. Ecuaciones diferenciales, problemas de valor inicial 7.1. Tipos de ecuaciones diferenciales Una ecuación diferencial es una ecuación en la que intervienen derivadas de una o más funciones desconocidas. Resolviendo la ecuación diferencial se obtiene la función desconocida. Dependiendo del número de variables independientes respecto de las que se deriva, las ecuaciones diferenciales pueden ser: Ordinarias: aquellas que contienen derivadas respecto a una sola variable independiente. Parciales: aquellas que contienen derivadas respecto a dos o más variables. El orden de la derivada más alta en una ecuación diferencial se denomina orden de la ecuación. En cambio el grado de la ecuación es la potencia de la derivada de mayor orden que aparece en la ecuación, siempre y cuando la ecuación esté en forma polinómica, de no ser así se considera que no tiene grado. Las ecuaciones diferenciales que se estudian en este tema son problemas de valor inicial. Se busca la solución numérica de una ecuación diferencial ordinaria de primer orden de la forma ( ) con una condición inicial ( ). Ecuaciones de órdenes superiores se pueden transformar en sistemas de ecuaciones diferenciales de primer orden. ( ), siendo una ecuación Un ejemplo típico de mecánica es la ecuación diferencial ̈ diferencial ordinaria de segundo orden. Se busca la solución ( ), es decir, utilizando la expresión de las fuerzas sobre una masa se busca la posición que va teniendo a lo largo del tiempo. 7.2. Método de Euler El método de Euler es un método para resolver ecuaciones diferenciales ordinarias a partir de un valor inicial. Es el método más básico y explicito para resolver problemas de valor inicial. Suponiendo que se quiere aproximar la solución del siguiente problema con un valor inicial: ( ) ( )) ( ( ) (7.1) Se puede tomar un valor constante de cada intervalo . (7.2) + Utilizando la aproximación de primer orden de la serie de Taylor, se puede obtener la aproximación de un punto separado por . ̃+ ( ̃) ( ) (7.3) Los valores ̃ son aproximaciones de la función en los puntos . El método de Euler es un método explícito, es decir, la solución ̃ + es una función explícita de para . - 74 - Andrés Zarabozo Martínez Métodos numéricos El error se propaga con cada intervalo y el error acumulado es del orden . (7.4) El error es por lo tanto de primer orden por lo que el método no es recomendable. 7.3. Ejemplo de resolución mediante el método de Euler. Como ejemplo de resolución con este método se toman los siguientes valores: ( ) (7.5) Se busca la aproximación utilizando el método de Euler para obtener ( ). Para empezar se utiliza un intervalo igual uno. El método se resuelve utilizando la ecuación (7.3). Por lo tanto para el tramo de inicio se debe ), en este caso ( ) calcular ( . ( ) ( ) (7.6) Con este paso se ha calculado la pendiente de la recta que pasa por el punto inicial y va hasta el primer punto. El primer punto es por lo tanto: ( ) (7.7) Se hace lo mismo para los siguientes tres puntos (7.8) { 4 La solución exacta de esta EDO es (gris) con la aproximada (negro). . En la siguiente figura se comparan la solución real 50 40 30 20 10 0 0 0.5 1 1.5 2 2.5 3 3.5 4 Figura 7.1. Solución real (gris) y solución aproximada (negro). 7.4. Método implícito de Euler El método implícito de Euler o método hacia atrás de Euler es muy parecido al método de Euler (que también se le llama método hacia adelante) pero difiere en que es un método - 75 - Andrés Zarabozo Martínez Métodos numéricos implícito. Éste método es más estable que el anterior y permite utilizar intervalos mayores, aunque como siempre, hay que tener cuidado con que no afecte a la calidad de la solución. La diferencia ente los dos métodos es en aproximación de la pendiente ( ( ( ̃+ + ̃+ ) ( ). ) (7.9) La nueva aproximación de ̃ + aparece en ambos lados de la ecuación y por lo tanto se tiene que resolver una ecuación algebraica. Se puede por ejemplo el teorema del punto fijo para resolverlo. Se puede desarrollar la función costosos. en serie de Taylor pero hacer derivadas de la función es muy Este método también es de orden uno y el error es similar al del método de Euler. 7.5. Método de Heun El método de Heun también es conocido como el método modificado de Euler. También es similar al método de Runge-Kutta de dos pasos. Se calcula primero el valor intermedio de ̃ + y luego el valor aproximado + en el siguiente punto de integración. En este método se cambia la terminología ya que ̃ deja de ser el resultado y pasa a ser una primera aproximación para luego calcular el resultado ( ̃+ ) ( ( + ) ( + ̃ + )) (7.10) Este método utiliza el método de Euler para calcular una estimación de las coordenadas del siguiente punto y, con este dato, se corrige la estimación original. Considerando que el valor ), de ( ̃) en la parte derecha de la ecuación es la pendiente de la solución en el punto ( esto se puede combinar con la estimación de Euler en el siguiente punto para dar la pendiente ( ̃)). La solución es el punto intermedio de la línea tangente en el punto de la derecha ( entre las dos soluciones. 𝑦 𝑦̃𝑖+ 𝑓(𝑥 𝑦𝑖 ) 𝑓(𝑥𝑖+ 𝑦̃𝑖+ ) 𝑥𝑖 𝑥𝑖 𝑥 Figura 7.2. Método de Heun de forma gráfica. - 76 - Andrés Zarabozo Martínez 7.6. Métodos numéricos Método de Runge-Kutta de segundo orden El método de Runge-Kutta de segundo orden se basa en la aproximación de la serie de Taylor de segundo orden. ( ) ( ) ( ) ( ) ( ) (7.11) La primera derivada se sustituye por la ecuación diferencial ( ) derivada se obtiene haciendo la derivada de la ecuación diferencial. ( ( ) ) ( ) ( ) ( ( ). La segunda ( ) ) (7.12) La expansión de Taylor se convierte en: ( ) ( ) ( ( ( ) ) ( ( ) [( ( ) ) ) ( ) ( ( ) ) (7.13) ) ] ( ) La expansión de Taylor para dos variables es: ( ) ( ( ) ) ( ) (7.14) Se puede ver que la expresión entre corchetes de la ecuación (7.12) se puede interpretar como: ( ( )) ( ) ( ) ( ) ( ( ) ) ( ) (7.15) Obteniendo: ( ) ( ) ( ( )) ( ) (7.16) Se puede escribir con la connotación numérica. ( + ) (7.17) Donde ( ) ( ( Se puede ver que para el caso del método de Euler se tiene )) y (7.18) . La forma explícita general del método de segundo orden de Runge-Kutta asumiendo: ( Donde ̅ ( )y ̅ ) ( ( ) [ ̅ ( - 77 - ̅ ] )). ( ) (7.19) 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 ⁄ y coeficientes cumplen la ecuación (7.17). Estos coeficientes se suelen ordenar en una tabla conocida como Butcher tableau, donde se ponen los vectores y y la matriz de la siguiente forma. Figura 7.3. Butcher tableau. Para el método de Runge-Kutta de segundo orden la tabla queda de la siguiente forma. Figura 7.4. Runge-Kutta de segundo orden. 7.7. Método de Runge-Kutta de órdenes superiores Se puede aumentar el orden del método de Runge-Kutta aumentando los pasos que se hacen. De forma similar a la ecuación (7.17) la solución general para orden viene dada por: + ∑ ( ) (7.20) ) (7.21) Donde ( ( ) ) ( ( − − Para cada método particular, se debe proveer con el íntegro (número de pasos) y los coeficientes (para ), b (para ) y (para ). La matriz se llama la matriz de Runge-Kutta, mientras que los vectores y son los pesos y los nodos. Los valores se suelen escribir en el Butcher tableau. − − Figura 7.5. Butcher tableau. - 78 - Andrés Zarabozo Martínez Métodos numéricos Para que el método de Runge-Kutta sea consistente se debe cumplir que: − ∑ (7.22) El siguiente valor ( + ) se determina con el valor actual ( ) más la media ponderada de los incrementos, donde cada incremento es el producto del tamaño del intervalo ( ) y una pendiente estimada por la función en la parte derecha de la ecuación diferencial. Pese que aumentar el orden del método de Runge-Kutta aumenta la precisión del resultado, estimar la función suele ser muy caro, y un problema con un orden debe evaluar veces la función. En general se suelen utilizar órdenes cercanos a o como compromiso entre precisión y carga computacional. Como ejemplo el problema de Runge-Kutta de orden viene dado por la siguiente ecuación: + ( 4) + (7.23) Para que se cumpla que sea un valor promedio de la derivada se debe cumplir que la suma de los valores que multiplican a los coeficientes sea igual a , en este caso se cumple. Los coeficientes son: ( ) ( ) ( ) (7.24) 4 ( ) En este caso se tiene que: es el incremento basado en la pendiente al principio del intervalo, usando (método de Euler). es el incremento basado en la pendiente en el punto medio del intervalo, usando . . es también el incremento basado en la pendiente en el punto medio del intervalo, usando . . . 4 es el incremento basado en la pendiente al final del intervalo usando Haciendo la media ponderada de estos cuatro incrementos se le da más importancia a los incrementos en el punto medio del intervalo. Los pesos se escogen de manera que si es independiente de , por lo que la ecuación diferencial es equivalente a una simple integral, el método de cuarto orden es similar a la regla de Simpson. Como su nombre lo indica este método es de cuarto orden por lo que el error entre intervalos es del orden de y el error acumulado es del orden de 4 . - 79 - Andrés Zarabozo Martínez 7.8. Métodos numéricos Método adaptativo de Runge-Kutta Este método es capaz de ir ajustando el intervalo . Zonas de la solución que tienen una forma suave (la pendiente no cambia mucho) no requieren intervalos pequeños mientras que zonas donde la pendiente cambia rápidamente sí que requieren intervalos pequeños ya que si no la solución no sería buena. Implementando este método en un programa se puede automatizar el proceso de selección del intervalo y así agilizar el programa si necesidad de estropear la solución. Siempre se debe mantener el error local dentro de unos márgenes. Para avaluar el cambio de intervalo se calcula una estimación del error de truncamiento local del método de Runge-Kutta de dos órdenes distintos. Se pueden introducir los dos métodos en el Butcher tableau, uno de orden . La tabla se representa de la siguiente manera. y otro de orden − − − Figura 7.6. Butcher tableau para el método adaptativo. El paso de menor orden viene dado por: ∑ + (7.25) Donde son los mismos que para el paso de mayor orden. Se comparan las soluciones dadas por los dos pasos para calcular el error. + + + ∑( ) (7.26) Este error es del orden ( ). Si el error está dentro de unos márgenes de precisión significa que la solución del orden inferior es suficientemente buena (comparada con la de orden superior) por lo que la curva es suave en ese punto, pudiendo incrementar el intervalo. Como ejemplo, el método de Runge-Kutta adaptativo más simple es el que combina el método de Heun (segundo orden) con el método de Euler (primer orden). La tabla extendida queda: ⁄ ⁄ Figura 7.7. Runge-Kutta adaptativo de menor orden. - 80 - Andrés Zarabozo Martínez 7.9. Métodos numéricos Esquema de Crank-Nicolson El esquema de Crank-Nicolson es un método implícito. Viene dado por la siguiente ecuación: ( ) ( + + ) (7.27) Es un método muy estable pero también es muy sensible a perturbaciones El esquema de Crank-Nicolson es un caso particular de la familia de esquemas que se obtienen [ ] el peso dado a ( ) frente al dado a ponderando mediante un parámetro ( + + ) en la fórmula de integración numérica. [( + ) ( ) ( + )] (7.28) En el caso del esquema de Crank-Nicolson dado por la ecuación (7.27) . . . Si se le da más peso al segundo término se parece más el método de Euler hacia atrás y se vuelve más [ . ]. estable. Por lo general estos métodos suelen tener 7.10. Método de Runge-Kutta para EDOs de grados superiores Cuando el orden de la ecuación diferencial es mayor que uno, se debe convertir la ecuación diferencial en un sistema de ecuaciones diferenciales de primer orden. Si se tiene una ecuación diferencial de la forma: − ( ) (7.29) Se debe escribir un sistema de ecuaciones diferenciales de la forma: − − (7.30) Por ejemplo, si se quiere resolver un sistema de segundo orden de la forma: ( ) (7.31) Se debe convertir la ecuación en un sistema de dos ecuaciones tal que: (7.32) El sistema de ecuaciones diferenciales queda: ( ) (7.33) Para cada intervalo se calculan de forma separada el siguiente valor de la solución ( y ). Para cada EDO se obtienen sus respectivos coeficientes . Al ser una ecuación diferencial de segundo orden se deben tener dos condiciones iniciales: ( ) ( ) ( ) - 81 - ( ) (7.34) Andrés Zarabozo Martínez Métodos numéricos 8. Método de diferencias finitas 8.1. Diferencias finitas en una dimensión. Una diferencia finita es una expresión matemática de la forma ( divide la diferencia finita por se obtiene el cociente diferencial. ) ( ). Si se Se puede discretizar un dominio en diferencias finitas, buscando en esos puntos las soluciones aproximadas ( ) de un sistema de ecuaciones diferenciales. Se define una malla de una dimensión como la de la Figura 8.1 𝜙𝑖− 𝜙𝑖− 𝜙𝑖 𝜙𝑖+ 𝜙𝑖+ Ω Figura 8.1. Discretización del dominio en una dimensión. La solución ( ) debe cumplir ( ) para . Aunque la malla no sea uniforme normalmente se pueden hacer transformaciones. En el caso de tener un dominio sin un orden definido y al que no se le puede aplicar una transformación, las diferencias finitas no tienen sentido. Se busca cambiar las ecuaciones diferenciales por un sistema de ecuaciones lineales donde solo aparecen las soluciones aproximadas en los nodos. Para ello se deben obtener aproximaciones de las derivadas en los nodos. Se utiliza la serie de Taylor para aproximar la función en una zona dividida por diferencias finitas. Se aproximan primero el punto y el punto . + ( 4) (8.1) − ( 4) (8.2) Se resta la ecuación (8.2) a la ecuación (3.1) pero aproximadas hasta el segundo orden. + ( − ) (8.3) Pudiendo obtener la aproximación de segundo orden de la derivada primera. + − ( ) (8.4) Se puede obtener la segunda derivada de la función sumando las ecuaciones (3.1) y (8.2). + − + − - 82 - ( 4) ( ) (8.5) Andrés Zarabozo Martínez Métodos numéricos En el caso de estar situados en los nodos extremos no se pueden aplicar estas ecuaciones. Se podría utilizar la aproximación de primer orden de la primera derivada: + ( ) (8.6) Pero ésta no es una buena solución. La aproximación de un orden superior requiere tomar el siguiente nodo. Utilizar el nodo puede provocar la necesidad de aumentar el ancho de banda del sistema aumentando el número de operaciones. La aproximación de un punto más a la derecha es: ( + ) (8.7) Se utiliza multiplica la ecuación (3.1) por cuatro y se le resta la ecuación (8.7). + ( + + + ) ( ) (8.8) Para el caso de la derivada por la izquierda la metodología es la misma. − − ( ) (8.9) En general los valores de las derivadas por la izquierda son los mismos que los de la derecha pero si la derivada es impar se deben cambiar los signos (como en el caso de la primera derivada en las ecuaciones (8.8) y (8.9)). Se puede aumentar el orden de aproximación Taylor para obtener expresiones para derivadas de mayor orden. El problema de aumentar el orden de aproximación de Taylor es que se necesitan funciones muy suaves. Si por ejemplo se resuelven las ecuaciones de Euler, que admiten discontinuidades (ondas de choque), y se utiliza un esquema de alto orden, la solución muestra unas oscilaciones en la presión y densidad que no reflejan la realidad. Para problemas térmicos donde las funciones suelen ser suaves se puede usar un orden alto. Existen métodos llamados espectrales que cada nodo toma información de todo el dominio. Pero si la geometría es complicada tampoco se pueden usar órdenes altos. 8.2. Diferencias finitas en dos dimensiones El caso bidimensional es parecido al anterior pero esta vez el mallado se hace en dos direcciones. En general se suele definir un mallado uniforme, con forma rectangular, como el de la Figura 8.2. El intervalo en las dos direcciones puede ser diferente. Aunque la geometría del problema no sea rectangular se pueden hacer transformaciones del mallado. Para geometrías complejas se utilizan volúmenes estructurados para dividir el dominio en distintos bloques donde aplicar diferencias finitas. El código escrito por Onera para problemas aerodinámicos (ELSA) utiliza volúmenes finitos estructurados. - 83 - Andrés Zarabozo Martínez Métodos numéricos 𝑦 ( 𝑚) ( 𝑦 ( ) ( 𝑚) (𝑛 𝑚) ( ) (𝑛 ) ( ) (𝑛 ) ) 𝑥 𝑥 Figura 8.2. Discretización en dos dimensiones. Las derivadas parciales que solo sean en una dirección son las obtenidas para el caso unidimensional. Por ejemplo la derivada primera en la dirección es: + − ( ) (8.10) La derivada cruzada de segundo orden se obtiene utilizando las series de Taylor. Se hace la derivada en dos pasos: ( | ( ) ) ( + ) − (8.11) [ ] Se hace ahora la derivada en la dirección . | [ + + + − − + − − ] ( ) (8.12) En general se suelen guardar todos los nodos en un solo vector en vez de una matriz ya que se necesita resolver un sistema de ecuaciones del tipo . El valor de la posición en el vector es: ( 8.3. ) (8.13) Ejemplo de problema mecánico En una película llamada “Total Recall” se muestra un innovativo método de transporte para ir desde Inglaterra hasta Australia. El método consiste en hacer caer un ascensor por un túnel a través del centro de la tierra aprovechándose únicamente de la gravedad. Empezando sin ningún tipo de velocidad ni de empuje adicional más que la gravedad, el viaje dura 17 minutos. Para comprobar si lo que se muestra la película es correcto se hacen las siguientes suposiciones: - La masa de la tierra se distribuye de forma uniforme dentro de una esfera de ⁄ . . El parámetro gravitacional de la tierra es El túnel es una línea recta que pasa por el centro de la tierra. - 84 - Andrés Zarabozo Martínez - - Métodos numéricos La única fuerza externa actuando en el cuerpo a parte de la gravedad es la fricción aerodinámica. Se puede computar como . . Se podría incluso asumir que la densidad del aire en el túnel se mantiene constante e igual a la densidad del aire a nivel del mar. Se ignoran las fuerzas centrífugas debidas a la rotación de la tierra y la aceleración de Coriolis. Visto que por lógica la única forma que el ascensor llegue al otro lado en el caso de haber fricción aerodinámica se debe tener una velocidad inicial nula. Este problema se puede resolver analíticamente si se considera que no hay fuerzas externas aparte de la gravedad, pudiendo llegar de un lado al otro de la tierra empezando con velocidad nula. Utilizando la formulación adimensional explicada más adelante se puede obtener la solución analítica para el caso de empezar con velocidad nula y sin fricción: ̃( ̃ ) ( ̃) (8.14) Siendo esta solución el caso más favorable, el tiempo que tardaría en recorrer toda la tierra sería de unos minutos. Se empieza a ver que los guionistas no se han molestado por investigar un poco de física antes de inventar sus mundos de ficción. Debido a que los minutos de caída libre no pueden conseguirse empezando sin velocidad inicial, el objetivo del problema es calcular la velocidad inicial que se necesitaría para poder llegar en 17 minutos al otro lado de la tierra. Ecuación del movimiento Lo primero que se debe hacer es obtener la ecuación que gobierna el problema. La ecuación del movimiento se basa en la segunda ley de Newton. ∑ (8.15) Hay dos fuerzas presentes en el ascensor: la gravedad y la fricción aerodinámica. (8.16) La fricción se puede simplificar utilizando la siguiente expresión: ( ) (8.17) Considerando la densidad de la tierra constante en todo el túnel. La masa que ejerce una fuerza sobre el ascensor, en una posición desde el centro de la tierra es: (8.18) - 85 - Andrés Zarabozo Martínez Métodos numéricos La fuerza de gravedad en esa posición es: (8.19) El origen se ha puesto en el centro de la tierra y el inicio del movimiento en ecuación diferencial que gobierna el movimiento es finalmente: ] ( [ ) [ ] . La (8.20) Ecuación adimensional En general es recomendable adimensionar las ecuaciones antes de resolverlas. En la ecuación anterior hay dos parámetros que se deben adimensionalizar: la posición y el tiempo . La posición se adimensionaliza con el radio de la tierra y para el tiempo se define un tiempo de referencia el cual se le puede dar un valor más tarde. ̃ ̃ (̃ (̃ ) ] [ [ ) La ecuación anterior se divide por (̃ (̃ (8.21) ) ] ) ⁄ ] (̃ [ ) (8.22) para que todos los sumandos sean adimensionales. ̃ ̃ ̃ ) ̃ ] ( [ [ ] ̃ Para simplifica la ecuación anterior se puede elegir un valor de multiplicado por ningún coeficiente. (8.23) de forma que ̃ no esté (8.24) La ecuación adimensionalizada queda: ̃ ] ( [ ̃ ̃ ) ̃ (8.25) ̃ Discretización La ecuación diferencial se discretiza utilizando diferencias finitas. Para el caso de la derivada segunda, ésta se discretiza para los nodos desde hasta de la siguiente forma: ̃ ̃+ ̃ ̃ - 86 - ̃− ( ) (8.26) Andrés Zarabozo Martínez Métodos numéricos Para el caso de la primera derivada, la discretización queda: ̃ ̃+ ̃− ( ̃ ) (8.27) Introduciendo estas dos ecuaciones en la ecuación (8.25) se obtiene la ecuación del problema discretizada. ̃+ ̃ ̃− ] ( [ ̃+ ̃− ) (8.28) ̃ Para simplificar la ecuación anterior se nombra el término constante de la fricción como un coeficiente . (8.29) ̃+ ̃ ̃− ( ̃+ ̃− ) (8.30) ̃ Las condiciones de contorno son la posición conocida en los extremos. ̃ ̃ (8.31) El sistema de ecuaciones se puede expresar mediante un vector de ecuaciones. ̃ ̃ ( ̃) ̃+ ̃ ̃ ̃ ( ̃− ( ̃ ̃ ̃+ ) ̃− ̃ (8.32) ) ̃ ̃ [ ] El sistema de ecuaciones anterior no es lineal por lo se debe utilizar el método de Newton para sistemas no lineales para resolverlo. La matriz de derivadas para este sistema es: (̃ ̃ ) (̃ (̃ + ̃ ) ̃− ) (̃ + [ (8.33) ̃− ) ] Para obtener el resultado de cada iteración se debe resolver un sistema lineal y una suma vectorial. ̃ - 87 - + ̃ (8.34) Andrés Zarabozo Martínez Métodos numéricos El residuo inicial se obtiene introduciendo los valores iniciales en el sistema de ecuaciones. Para el primer y último nodo el residuo es cero puesto que la solución es conocida. ̃ ̃+ ̃ ̃ ̃ ( ̃− ( ̃ ̃ ̃ ̃+ ) ̃− (8.35) ) ̃ [ ] Los valores iniciales se pueden calcular obteniendo la solución analítica en el caso que no haya fricción aerodinámica. La ecuación diferencial es una simple de segundo grado. ̃ ̃ ̃ La solución es de la siguiente forma, siendo y ̃( ̃ ) (8.36) constantes. ̃ ̃ (8.37) Como condiciones iniciales se puede utilizar la posición inicial y la posición final. ̃( ) (8.38) ̃ ̃( ̃ ) (8.39) ̃ Siendo el tiempo final: ̃ ⁄ . (8.40) El tiempo transcurrido entre cada nodo se define utilizando el tiempo total ( número de nodos utilizados para la simulación ⁄ . minutos) y el (8.41) Por lo tanto los valores iniciales se estiman como: ̃ ̃ ̃ ̃ ̃ ̃ ( ) (8.42) Estimación del coeficiente de fricción La contribución de la fricción aerodinámica viene dada por un coeficiente (definido en la ecuación (8.29)) multiplicado por la velocidad al cuadrado. El parámetro se puede dividir el coeficiente de fricción del aire (que se puede considerar del orden de magnitud 1) y el ratio ⁄ . Si el aire es “respirable” entre la masa de aire dentro del túnel y la masa del ascensor este número no puede ser pequeño conociendo el tamaño del túnel. En la película el ascensor - 88 - Andrés Zarabozo Martínez Métodos numéricos parecía muy grande y para dar un poco de credibilidad a la película se podría considerar que ese ratio es de orden de magnitud 1. Por lo tanto se define . . Velocidad inicial La velocidad inicial se puede calcular utilizando la aproximación de segundo orden por la derecha. ̃ ̃ ̃ ̃ El programa escrito para resolver este problema se detalla en el siguiente apartado. - 89 - (8.43) Andrés Zarabozo Martínez 8.4. Métodos numéricos Programas Programa 6. Ejemplo de problema mecánico El programa debe resolver un problema de diferencias finitas con un sistema no lineal. Al ser un sistema no lineal se debe tener un bucle iterativo para ese sistema. Se puede también poner un bucle mayor para hacer un estudio de convergencia de malla, cambiando el tamaño de malla cada vez que obtenga una solución. La estructura del programa es la siguiente: Iniciar variables Generar matrices: 𝐾y𝑅 Resolver sistema lineal 𝐾 𝛿𝑥 𝑅 Obtener nueva solución 𝑥 𝑖+ 𝑥 𝑖 𝛿𝑥 Calcular velocidad inicial ¿Nueva iteración del sistema no lineal? Imprimir resultados ¿Nuevo tamaño de malla? Fin Figura 8.3. Estructura del programa. Para este programa se crean tres subrutinas: una para iniciar variables, otra para generar las matrices y y la tercera para resolver el sistema lineal. Se describen primero las subrutinas. - 90 - Andrés Zarabozo Martínez Métodos numéricos La primera subrutina genera el vector ̃ . Debido a que esta variable depende del tamaño de la malla se tiene que hacer cada vez que se cambie el tamaño de ésta. Se utiliza la ecuación (8.42) para obtener estos valores. subroutine initialValues(x0, n, tref, h) implicit none integer, intent (in) :: n real*8, intent(in) :: tref, h real*8, intent (out) :: x0(n) integer i real*8 t, tn, kn tn = 1020. / tref kn = (1. + dcos(tn)) / dsin(tn) x0(1) = -1. do i = 2, n - 1 t = dble(i - 1) * h x0(i) = - dcos(t) + kn * dsin(t) end do x0(n) = 1. end subroutine La segunda subrutina genera las matrices calcular las matrices. y . Se utilizan las ecuaciones (8.33) y (8.35) para subroutine writeSystem(K, R, x, n, tref, h, ka) implicit none integer, intent (in) :: n real*8, intent (in) :: x(n), tref, h, ka real*8, intent (out) :: K(3,n), R(n) integer i real*8 h2 h2 = 1. / (h * h) !Write matrix K K(2,1) = 1. K(3,1) = 0. do i = 2, n - 1 K(1,i) = h2 - ka * 2. * (x(i+1) - x(i-1)) * h2 K(2,i) = 1. - 2. * h2 K(3,i) = h2 + ka * 2. * (x(i+1) - x(i-1)) * h2 end do K(1,n) = 0. K(2,n) = 1. - 91 - Andrés Zarabozo Martínez Métodos numéricos !Write vector R R(1) = 0. do i = 2, n - 1 R(i) = x(i) + (x(i+1) - 2. * x(i) + x(i-1)) * h2 + & ka * (x(i+1) - x(i-1)) * (x(i+1) - x(i1)) * h2 end do R(n) = 0. end subroutine La tercera subrutina es la que resuelve el sistema lineal. El sistema está compuesta por una matriz banda de solo tres columnas por lo que es recomendable utilizar un solver que se aproveche de esta condición. subroutine gaussBand(a, b, d, n) implicit none integer, intent(in) :: d, n real*8, intent(inout) :: a(-d:d,n), b(n) integer pivot, row, disp real*8 mult !Triangulate matrix do pivot = 1, n - 1 do row = pivot + 1, min(pivot + d, n) disp = row - pivot !Gauss mult = a(-disp,row) / a(0, pivot) a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - & mult * a(1:d,pivot) b(row) = b(row) - mult * b(pivot) end do end do !Solve x do row = n, 1, -1 disp = min(d, n - row) b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp)) b(row) = b(row) / a(0,row) end do end subroutine La rutina principal se encarga de seguir el esquema de la Figura 8.3, llamando a las 3 subrutinas descritas. Lo primero que debe hacer es definir las variables que se utilizaran. Se crean una serie de variables de configuración del programa. - 92 - Andrés Zarabozo Martínez - Métodos numéricos es la constante del termino de fricción, equivale a la k es el número de nodos de la primera malla es el número de veces que se cambia la malla es el número máximo de iteraciones para resolver cada malla es el valor máximo aceptable en el vector R program finiteDifferences implicit none integer n, i, j, maxIt, maxLoop, kas real*8, allocatable :: K(:,:), R(:), x(:) real*8 v, v1, h, tref, ka, error !Program configuration ka = 0.5 !Constant in drag n = 1000 !Initial number of nodes maxLoop = 10 !Maximum number of times the program is runned maxIt = 100 !Maximum iteration in Newton's method error = 0.00001 !Maximum Error tref = 6.371E6 * 6.371E6 * 6.371E6 / 3.986E14 tref = tref ** 0.5 El primer bucle es el que se encara de regenerar las mallas. Debe primero crear las matrices K, R y x. Una vez ha generado esas matrices en memoria se llama a la subrutina que se encarga de asignar los valores iniciales. !Loop for number of nodes do j = 1, maxLoop allocate (K(3,n), R(n), x(n)) !Initial values for x h = (1020. / tref) / dble(n - 1) call initialValues(x, n, tref, h) v = 0. Seguidamente, se empiezan las iteraciones que resuelven el problema para la malla dada. El bucle se termina o bien cuando llega al máximo de iteraciones o cuando el error menor que el marcado en la variable . !Loop for number of iterations do i = 1, maxIt !Generate matrix K and vector R call writeSystem (K, R, x, n, tref, h, ka) !Solve K·dx = -R R=-R call gaussBand(K, R, 1, n) - 93 - Andrés Zarabozo Martínez Métodos numéricos !Solve x1 = x0 + dx x=x+R !Initial velocity v1 = v v = (4. * x(2) - 3. * x(1) - x(3)) / (2. * h) !Print results if(maxval(abs(R)) .lt. error) then print*, "Number of nodes: ", n print*, "Error in R: ", maxval(abs(R)) print*, "Iterations needed: ", i print*, "Initial velocity: ", " ", v print*, " " exit elseif (i .eq. maxIt) then print*, "Number of nodes: ", n print*, "No solution found. " print*, " " end if end do Una vez se acaba el cálculo se le da un nuevo valor a la malla si es necesario borrando antes las matrices K, R y x. !Renew discretization deallocate(K, R, x) n = 1000 + n end do end program Los resultados generados por el programa anterior son los siguientes: Number of nodes: Error in R: Iterations needed: Initial velocity: 1000 4.05833953591406877E-010 6 33.901530208195759 Number of nodes: Error in R: Iterations needed: Initial velocity: 2000 3.99446362148938426E-010 6 33.988404464699350 Number of nodes: Error in R: Iterations needed: Initial velocity: 3000 3.98089342760615747E-010 6 34.006278684062110 Number of nodes: Error in R: Iterations needed: Initial velocity: 4000 3.97452197374683662E-010 6 34.012788837112836 - 94 - Andrés Zarabozo Martínez Métodos numéricos Number of nodes: Error in R: Iterations needed: Initial velocity: 5000 3.97345468277236172E-010 6 34.015867125092669 Number of nodes: Error in R: Iterations needed: Initial velocity: 6000 3.97189273253109707E-010 6 34.017561828242137 Number of nodes: Error in R: Iterations needed: Initial velocity: 7000 3.97116818907919676E-010 6 34.018593137328239 Number of nodes: Error in R: Iterations needed: Initial velocity: 8000 3.97085218660822430E-010 6 34.019267018567149 Number of nodes: Error in R: Iterations needed: Initial velocity: 9000 3.97022337062319620E-010 6 34.019731410085285 Number of nodes: Error in R: Iterations needed: Initial velocity: 10000 3.97022961043059028E-010 6 34.020064936000409 Se puede ver que la velocidad inicial converge hacia unos 34.02. Hay que recordar que el error es el valor absoluto máximo de la matriz R pero para el cálculo de la velocidad inicial se debe hacer una operación matemática que incluye la longitud de malla por lo que el error de la velocidad es distinto. La velocidad dada está en unidades adimensionales por lo que para pasarla a unidades internacionales se debe multiplicar por la longitud de referencia dividida por el tiempo de referencia. ⁄ ̃ Se puede ver que la velocidad inicial para que se cumplan los - 95 - (8.44) minutos es desorbitada. Andrés Zarabozo Martínez Métodos numéricos 9. Método de elementos finitos 9.1. Forma fuerte del problema El método de elementos finitos (MEF) es un método numérico general para la aproximación de soluciones de ecuaciones diferenciales parciales, como por ejemplo la ecuación de Laplace. ( ̅ ) (9.1) El MEF permite obtener una solución numérica aproximada sobre un dominio (medio continuo) dividido en un número elevado de subdominios no intersectantes entre sí denominados elementos finitos. Dentro de cada elemento se distinguen una serie de puntos representativos llamados nodos. Dos nodos son adyacentes si pertenecen al mismo elemento. ( ) . Además de la ecuación diferencial se . Estas condiciones pueden ser: La solución obtenida para el sistema es deben tener condiciones de contorno Condición de contorno de Dirichlet, especifica el valor de la solución en los puntos del contorno del dominio. ̅ (9.2) Condición de contorno de Neumann, especifica el valor de la derivada de la solución en el contorno del dominio. ̅ (9.3) Las condiciones de contorno del problema completo son una combinación de los dos tipos anteriores. (9.4) La definición del problema es lo que se llama la forma fuerte del problema, esto incluye la ecuación diferencial y las condiciones de contorno. Hasta este punto no se ha hecho ninguna discretización ni ninguna aproximación. 9.2. Método de Rayleigh-Ritz y método de Galerkin El objetivo del método es resolver la ecuación diferencial definida en la ecuación (3.1). Una forma de resolver la ecuación bajando un orden a la ecuación diferencial es integrando la función en todo el dominio. Si la función es cero en todo el dominio entonces la integral debe ser cero. ∫ Pero esto no asegura que (9.5) , para ello se introduce una función de peso ( ). ∫ ( ) ( ̅ ) - 96 - ( ) (9.6) Andrés Zarabozo Martínez Métodos numéricos A parte de transformar la ecuación diferencial se deben también transformar las condiciones de contorno. ∫ ̅) ( )( ⃗ ) ( )( ∫ (9.7) El método integral consiste en introducir una aproximación de ̃ en cada nodo. ∫ ( ) ( ̅ ̃) ̃ ( )( ∫ ̅ ) ̃( ) ̅ (9.8) Con esta ecuación se obtiene la solución del método de Rayleigh-Ritz. En general este método no se usa mucho. El método de Galerkin utiliza la siguiente aproximación para la función. ̃ Siendo una combinación lineal de es un sistema de ecuaciones lineales. ( ) ∑ (9.9) . Si además la ecuación integral es lineal, lo que queda El problema con este método es que en general estas funciones están definidas en todo el dominio y es muy complicado concentrar la combinación de que cumplan todas las condiciones de contorno. 9.3. Ejemplo de formulación fuerte para problema estructural Un ejemplo clásico de aplicación del método de elementos finitos es en problemas estructurales. Se desarrolla a modo de ejemplo en este apartado la formulación débil de un problema estructural de vigas. En una viga se pueden tener tres tipos de cargas: cargas concentradas, cargas distribuidas y momentos. Aislando una porción de la viga se obtienen las ecuaciones diferenciales para los distintos esfuerzos. Se denomina al esfuerzo cortante vertical y al momento flector. Carga concentrada 𝑃 𝑀 𝑀 𝑉 𝑉 𝑀 𝑉 Δ𝑥 Figura 9.1. Carga concentrada. (9.10) - 97 - Andrés Zarabozo Martínez Métodos numéricos Carga distribuida 𝑞 𝑀 𝑀 𝑉 𝑉 𝑀 𝑉 Δ𝑥 Figura 9.2. Carga concentrada. ( ) ( ) (9.11) Carga concentrada 𝑀 𝑀 𝑀 𝑉 𝑉 𝑀 𝑉 Δ𝑥 Figura 9.3. Carga concentrada. (9.12) Se estudia el problema de flexión en la viga. Siendo elemento de la viga se tiene: la inversa del radio de curvatura ( ) ( ) del (9.13) Siendo la dirección de la fibra neutra el ángulo de curvatura. La derivada del ángulo se puede aproximar y dejarlo en función del desplazamiento vertical . ( ) ( ) (9.14) ⁄ También se puede relacionar el momento flector con el desplazamiento vertical: ( ) (9.15) Se reescribe la ecuación anterior utilizando las ecuaciones diferenciales obtenidas para el caso de carga distribuida (ecuación (9.11)). ( ) - 98 - ( ) (9.16) 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 ( ) ̅ Rotación ( ) ̅ (9.18) Cortante ( ) ) ( (9.17) ̅ (9.19) Momento ( ) ̅ (9.20) Para este ejemplo se consideran las siguientes condiciones de frontera: ( ) ( ) ̅ ̅ () ) ( () ̅ ̅ (9.21) Se empieza ahora definiendo la forma débil del problema. Se utiliza la ecuación integral definida en la ecuación (9.6). En este problema se podría considerar que la función es el desplazamiento virtual. ∫ ( ∫ ) (9.22) Se integra la parte de la izquierda por partes. ∫ ( [ ) ( ) )] ( ∫ ( ( ) ) (9.23) La parte de la izquierda está definido para los dos extremos de la barra introduciendo ahí las condiciones de contorno, en este caso es el cortante. ∫ ( ( ) ) () ̅ ∫ (9.24) Se vuelve a integrar por partes. ∫ ( ( ) ) ( ) ] [ - 99 - ∫ ( ) (9.25) Andrés Zarabozo Martínez Métodos numéricos En este caso la condición de contorno que se aplica es el momento. ( ) ∫ () ̅ () ̅ ∫ (9.26) Para que se cumpla la ecuación anterior se ha impuesto que: ( ) ( ) (9.27) Además para que la integral de la izquierda se pueda integrar el desplazamiento virtual debe tener segunda derivada. 9.4. Funciones de forma Para resolver la ecuación diferencial utilizando MEF se debe crear un dominio de elementos finitos. Éste se compone de elementos y nodos. Los elementos pueden tener múltiples formas, aunque se suelen emplear elementos triangulares o cuadriláteros (en el caso 2D). También se necesita una forma de caracterizar las propiedades físicas de los elementos. Los vínculos entre los nodos de un elemento se caracterizan por las funciones de forma. La función de forma asociada al nodo y el elemento debe satisfacer que sea la unidad en el nodo y cero en los demás. (9.28) Por ejemplo, considerando una viga, la distribución de los desplazamientos a lo largo del elemento (con un nodo en cada extremo) sería: { }{ } (9.29) Siendo y los desplazamientos en los nodos. Las funciones de forma en este caso serían rectas que deben satisfacer la ecuación (9.28). (9.30) 𝑁 𝑁 𝜉 Figura 9.4. Funciones de forma para un elemento de una dimensión. Una vez obtenida la distribución de las funciones ya se puede integrar. Introduciendo las funciones de forma que suelen ser lineales se pueden integrar fácilmente las expresiones obtenidas en la forma débil. - 100 - Andrés Zarabozo Martínez 9.5. Métodos numéricos Cuadratura de Gauss En general no es necesario integrar analíticamente todas las expresiones de la forma débil una vez introducidas las funciones de forma. Se puede, por ejemplo, utilizar la cuadratura de gauss para obtener el resultado numérico de la integral. A diferencia de otros métodos de integración numérica, los puntos de evaluación de la función están definidos. El resultado obtenido en la cuadratura de Gauss de puntos es el de integrar ]. un polinomio de orden o menos. El dominio de la cuadratura por regla es de [ ∫ ( ) ( ) ∑ (9.31) − Donde es el peso para el punto de integración . En la siguiente tabla se pueden ver una lista de puntos de integración y de pesos para los tres primeros valores de . Núm. de puntos Puntos de integración √ Pesos √ √ √ Tabla 9.1. Puntos de integración y pesos. Como normalmente las funciones de formas son lineales, se suelen tener que integrar polinomios, obteniendo resultados exactos con la cuadratura de Gauss. 9.6. Tipos de elementos en 2D En el apartado 9.5 se puede ver un elemento para el caso unidimensional con dos nodos y sus funciones de forma. Los siguientes elementos son los que más se utilizan en el caso bidimensional. Las funciones de forma se definen en coordenadas locales y . Elementos triangulares Los elementos triangulares más básicos se componen de tres nodos en los vértices del elemento. Se utilizan coordenadas locales para para obtener las funciones de forma. Para pasar de unas coordenadas a otras se utiliza el siguiente cambio: { } [ ]{ } - 101 - { } (9.32) Andrés Zarabozo Martínez Métodos numéricos 𝜂 𝑥 (𝑏 𝑏 ) (𝑐 𝑐 ) (𝑎 𝑎 ) 𝜉 𝑥 Figura 9.5. Transformación entre coordenadas locales y coordenadas globales. El área del elemento es: ( )( ) ( )( ) (9.33) La función inversa es: [ { } ]{ } { ( ) ( ( ) ( ) } ) (9.34) Las funciones de forma en coordenadas locales son: (9.35) (9.36) (9.37) Las tres funciones de forma suman la unidad. Las derivadas de las funciones de forma respecto a las dos variables son: (9.38) (9.39) (9.40) Utilizando la transformación las funciones de forma en las coordenadas globales queda: ( ) [( ) ( ) ( ) ] (9.41) ( ) [( ) ( ) ( ) ] (9.42) ( ) [( ) ( ) ( ) ] (9.43) - 102 - Andrés Zarabozo Martínez Métodos numéricos ( ) ( ) (9.44) ( ) ( ) (9.45) ( ) ( ) (9.46) Elementos cuadriláteros Los elementos cuadriláteros más básicos se componen de cuatro nodos en los vértices del elemento. 𝑥 𝜂 𝜉 𝑥 Figura 9.6. Transformación de coordenadas de un elemento rectangular. Las funciones de formas para este elemento genérico son: 4 ( )( ) (9.47) ( )( ) (9.48) ( )( ) (9.49) ( )( ) (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: 4 ( ) ( ) (9.51) ( ) ( ) (9.52) ( ) ( ) 4 - 103 - ( ) (9.53) ( ) (9.54) Andrés Zarabozo Martínez Métodos numéricos La matriz de derivadas de las funciones de forma es 4 4 (9.55) [ ] [ ] Para pasar de las coordenadas locales a las globales se utiliza el Jacobino. − (9.56) Donde éste se calcula como: (9.57) Donde es la posición en donde se quiere evaluar el Jacobino. También existen otros tipos de elementos cuadriláteros utilizando más nodos. El procedimiento de obtención de las funciones de forma y sus derivadas es igual que en el caso de tener solo cuatro nodos. Elemento cuadrilátero de elementos Se pueden aumentar el orden de los elementos introduciendo más nodos por elemento. 𝜂 𝜉 Figura 9.7. Elemento rectangular con nodos. Se han introducido nueve nodos en el nodo. Las funciones de forma son por lo tanto más complicadas. La función de forma del nodo debe anularse en los nuevos puntos, por ejemplo ). en el punto ( ( ) ( ) (9.58) Se tienen tres tipos diferentes de nodos en este elemento, se tienen: nodos de las esquinas que tienen funciones de forma similares a la mostrada para , nodos laterales y el nodo central. ( )( ( ) )( - 104 - ( ) ) (9.59) (9.60) Andrés Zarabozo Martínez Métodos numéricos Elemento cuadrilátero de nodos Serendipity Eliminando el nodo central se obtiene un elemento de nodos que tiene las ventajas de reducir el orden de las funciones de forma. En este caso se tienen dos tipos de nodos: los de las esquinas y los de los laterales. ( )( )( ( ) )( (9.61) ) (9.62) A parte de eliminar un grado de la ecuación (eliminando el nodo central) los elementos del lateral son más simples (pierden los términos de orden ). 9.7. Ejemplo de problema térmico El ejemplo que se desarrolla aquí es un problema térmico con radiación. En este apartado se desarrolla el ejemplo y el programa descrito en este tema es el que resuelve este ejemplo. La siguiente figura muestra la sección de un radiador para uso en el espacio profundo. Debido a su doble simetría solo se muestra una cuarta parte de la sección. 𝑇 𝑞𝑟 𝜎𝑇 4 𝑅 𝑅 𝑘 𝑇𝑝 𝑅 𝜆𝑅 (𝜆 ≫ ) Figura 9.8. Sección del radiador espacial. La carga de pago del radiador situada en la zona central debe mantenerse a conocida. El radiador actúa como un cuerpo negro según la ley de Stefan-Boltzmann. La temperatura ambiente equivalente es tan baja que se puede despreciar. Para este ejemplo se utilizará como connotación de matrices las letras sin cursiva y en negrita. Forma débil La ecuación que gobierna la distribución de temperaturas es la ley de Fourier. (9.63) Donde es el flujo de calor por unidad de longitud, gradiente local de temperaturas. - 105 - es la conductividad térmica y es el Andrés Zarabozo Martínez Métodos numéricos Debido a la falta de fuentes de calor y que el problema es estacionario, la ley de Fourier se simplifica a la ecuación de Laplace. (9.64) Se tienen dos tipos de condiciones de contorno. La condición de contorno de Dirichlet está presente en el centro donde la temperatura es conocida. La condición de contorno de Neumann está en la pared exterior del radiador, siendo el flujo de calor de radiación. 4 ⃗ (9.65) Es recomendable adimensionar el problema para simplificar el problema y reducir las dependencias. Se define la temperatura de referencia como la temperatura de la carga de pago y la longitud de referencia como . La ecuación de Laplace adimensionalizada queda: ̂ ̂ ̂ (9.66) ̂ Las condiciones de contorno quedan: ̂ ̂ ̂ ̂ ̂ ̂ 4) ⃗ ( (9.67) El término constante en la condición de contorno de Neumann puede expresarse como un coeficiente . (9.68) Este parámetro es una relación entre el flujo de calor a través del radiador y el calor de radiación que se puede emitir, siempre que la diferencia de temperaturas entre el interior y la superficie como la temperatura superficial son del mismo orden. (9.69) 4 La potencial adimensional del radiador se puede definir como: ̇ (9.70) 4 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 - 106 - ( ) (9.71) Andrés Zarabozo Martínez Métodos numéricos Por lo tanto el orden de magnitud de la potencia adimensional es ( ) para ≫ . A partir de este momento todas las variables que se utilicen son adimensionales por lo que la notación con acento circunflejo ya no se utiliza. Se tienen que tener en cuenta las siguientes expresiones: - - Regla de la derivada de un producto ( ) ∫ ( ) (9.72) Teorema de la divergencia ̂ ∫ (9.73) La forma débil se obtiene integrando la ecuación de Laplace multiplicada por una función arbitraria . ∫ (9.74) Se integra esta expresión por partes: ∫ ∫ ̂ ∫ (9.75) La integral de línea se hace donde se tienen condiciones de contorno ( una función tal que en la condición de contorno de Dirichlet sea cero. ∫ ( ̂) ∫ ⏟( ̂) ). Se elige (⏟) ̂ ∫ (9.76) Siendo la forma débil del problema: ∫ ∫ ( ) ( ̂) (9.77) ( ) (9.78) Discretización La temperatura ( ) se interpola a partir de las temperaturas funciones de forma ( ) para cada nodo contenido en el elemento. Se utilizan elementos cuadriláteros. La temperatura puede escribirse como: ( ) [ ( ) ( ) ( ) ( ) de un punto dentro de un elemento 4( )] ( ) [ 4] - 107 - las correspondientes (9.79) Andrés Zarabozo Martínez Métodos numéricos El gradiente de temperatura es: 4 (9.80) [ ] [ 4] [ ] Se utilizan las mismas funciones de forma para interpolar la función de peso ( ) ( ) ( ) ( ) del elemento. (9.81) Aplicando la ecuación (9.77) a cada elemento se obtiene: ∫ ( ∫ ̂) (9.82) Se introducen las expresiones que contienen las funciones de forma. ∫ ( ∫ ̂) (9.83) Y ésta se puede reescribir como: (9.84) Donde: ∫ ( ∫ (9.85) ̂) (9.86) Ensamblaje El sistema global se obtiene añadiendo la contribución de cada elemento. ∑ ∑ (9.87) Esto se debe hacer usando la numeración global de nodos y elementos. La ecuación queda: (9.88) Esta ecuación debe cumplirse para cualquier cualquier . que es lo mismo que decir que se cumple para (9.89) Debido a la no linealidad del problema (causada por el flujo de radiación) el sistema se tiene que resolver de forma iterativa. - 108 - Andrés Zarabozo Martínez Métodos numéricos El calor de radiación se linealiza de la siguiente forma: | ( El vector ) (9.90) puede reescribirse como: (9.91) El subíndice indica que está evaluado con las temperaturas de la iteración anterior. La ecuación (9.89) se escribe finalmente como un sistema lineal. ( Donde y ) (9.92) deben ser evaluadas para cada iteración. Integración Los elementos que se usan son cuadriláteros de cuatro nodos. Las integrales de volumen son del orden (de segundo orden) y de área ( dimensiones) por lo que se necesitan cuatro puntos de integración para la cuadratura de Gauss, dos en cada dimensión. 𝜂 𝑥 : I 𝜉 𝑥 Figura 9.9. Elemento cuadrilátero de nodos en coordenadas locales (izq.) y globales (der.). La integral de la ecuación (9.85) se calcula de la siguiente forma: 4 ∫ || ∫ ∑( | Donde es el peso (siendo igual a en todos los casos). El Jacobino forma derivadas en un cierto punto se obtiene como: |) (9.93) y las funciones de − (9.94) El flujo de calor se considera lineal en el elemento y puede integrarse fácilmente (analíticamente) en el contorno de Neumann. La integral en un lado del elemento (de longitud ) es: ∫ ( ) ∫ ( ) (9.95) − [ - 109 - ] Andrés Zarabozo Martínez Métodos numéricos Utilizando las funciones de forma en una dimensión de la ecuación (9.30). Se linealiza ahora esta ecuación. | ( ) | ( ) | ( ) | ( ) [ ] 4 4 ( 4 4 ( [ ( ) ) ( ) ] 4 4 [ ] 4 4 [ ) ] [ (9.96) ] Potencia del radiada Una vez calculada la distribución de temperaturas en todo el dominio se puede calcular la potencia del radiador. Se calcula como la integral de todo el flujo de calor en el contorno de Neumann. Para un elemento la potencia adimensional se calcula utilizando un único punto de integración de Gauss ya que es del orden de . ∫ 4 ∫ ( 4 4) Para obtener la potencia total se suman las contribuciones de todos los elementos. - 110 - (9.97) Andrés Zarabozo Martínez 9.8. Métodos numéricos Programa Programa 7. Radiador espacial Se presenta ahora el código que resuelve el ejemplo descrito en la sección 9.7. Para poder visualizar la solución, el siguiente código está adaptado para que la distribución de temperaturas la lea un programa llamado GID de la empresa CIMNE La versión gratuita del programa se puede descargar desde la página de la empresa. Tiene limitados el número de nodos que se pueden utilizar pero para este ejemplo es suficiente. Al programa se le debe introducir la malla (con los elementos y los nodos) y los contornos con condiciones de contorno, incluida en el apéndice de este libro, sección 10.8. El programa se estructura mediante un módulo que incluye todas las variables y subrutinas. El programa principal solo tiene las variables que se pueden configurar y se dedica a ir llamando a las distintas subrutinas para que vayan haciendo el cálculo. El error es la diferencia máxima entre temperaturas de iteraciones consecutivas. La secuencia del programa es: - Cargar la malla del archivo “imput_mesh.txt” Inicializar las variables, crear las coordenadas locales de los elementos cuadriláteros y las matrices de las funciones de forma y de sus derivadas Se ensambla la matriz , ésta es la que no cambia entre iteraciones El solver es la subrutina que tiene el bucle iterativo que va calculando las nuevas temperaturas y con esas las matrices y y resuelve el sistema lineal. Una vez se tiene la distribución de temperaturas se calcula la potencia radiada Las dos últimas dos subrutinas sirven para escribir los archivos necesarios para que los pueda leer el programa GID. program spaceRadiator use subroutines implicit none integer i !Program configurator alpha = 100. maxIterations = 30 error = 0.0001 !Program sequence call readMesh(); print*, "Read Mesh Done!" call init(); print*, "Init Done!" call assembleK(); print*, "Assemble K Done!"; print*," " call solver(); print*, "Solver Done!" call getW(); Print*, "Get W Done!" call writeGidMesh(); call writeTemperature(); end program spaceRadiator - 111 - Andrés Zarabozo Martínez Métodos numéricos El módulo subroutines incluye todas las variables y subrutinas. Las variables se utilizan de forma global, es decir que cada subrutina puede cambiar sus valores. module subroutines implicit none !Variables: Local means element coordinates. X: coordinates of node; !N: shape function; DN: deriv.N; IP: Integ. points real, save :: localX(4,2), localN(4,4), localDN(4,2,4), localIP(4,2), alpha real, allocatable, save :: node(:,:), K(:,:), T(:), q0(:), T0(:), Kr(:,:), Ktot(:,:), Tit(:,:) integer, allocatable, save :: elemNode(:,:), boundIn(:), boundExt(:,:) integer, save :: nNode, nElem, nIn, nExt, nIP, nX integer, save :: maxIterations, endIT real, save :: error contains La primera subrutina Se encarga de abrir el archivo “imput_mesh.txt” y obtener los datos del mallado. subroutine readMesh() implicit none integer i real aux, aux2 open(UNIT = 5, FILE = 'input_mesh.txt', ACCESS = 'SEQUENTIAL') !Read nodal coordinates read(5,*) nNode allocate (node(nNode,2)) do i = 1, nNode read(5,*) aux, node(i,:), aux2 !First and last numbers not needed end do !Read Elements read(5,*) nElem allocate(elemNode(nElem,4)) do i = 1, nElem read(5,*) aux, elemNode(i,:) end do !Read Boundary nodes that Radiate read(5,*) nExt allocate(boundExt(nExt,2)) do i = 1, nExt read(5,*) aux, boundExt(i,:) end do - 112 - Andrés Zarabozo Martínez Métodos numéricos !Read Boundary nodes with constant Temperature read(5,*) nIn allocate(boundIn(nIn)) do i = 1, nIn read(5,*) aux, boundIn(i) end do close(5) end subroutine readMesh La subrutina init() se encarga de inicializar variables y de crear las coordenadas locales de los elementos y de los puntos de integración y las matrices de funciones de formas y de sus derivadas. subroutine init() implicit none real aux integer i allocate(K(nNode, nNode), Kr(nNode, nNode), KTot(nNode,nNode), & T(nNode), T0(nNode), q0(nNode)) allocate(Tit(nNode,maxIterations)) K = 0.; Kr = 0.; KTot = 0.; T = 0.; T0 = 0.; q0 = 0.; nIP = 4; nX = 4; Tit = 0. !Initial temperature if (alpha .ge. 1) then T0 = 0.9 else T0 = alpha end if !Node positions localX(1,1) = -1.; localX(2,1) = 1.; localX(3,1) = 1.; localX(4,1) = -1.; localX(node, xi-eta) localX(1,2) = -1. localX(2,2) = -1. localX(3,2) = 1. localX(4,2) = 1. !Integration points position localIP(IP, xi-eta) aux = 1. / sqrt(3.) localIP = localX * aux do i = 1, 4 !Shape functions localN(IP, shape function) localN(i,1) = (1. - localIP(i,1)) * (1. - localIP(i,2)) localN(i,2) = (1. + localIP(i,1)) * (1. - localIP(i,2)) localN(i,3) = (1. + localIP(i,1)) * (1. + localIP(i,2)) localN(i,4) = (1. - localIP(i,1)) * (1. + localIP(i,2)) - 113 - Andrés Zarabozo Martínez Métodos numéricos !Derivative localDN(IP, dxi - deta, shape function) localDN(i,1,1) = - 1. + localIP(i,2); localDN(i,2,1) = - 1. + localIP(i,1) localDN(i,1,2) = 1. - localIP(i,2); localDN(i,2,2) = - 1. - localIP(i,1) localDN(i,1,3) = 1. + localIP(i,2); localDN(i,2,3) = 1. + localIP(i,1) localDN(i,1,4) = - 1. - localIP(i,2); localDN(i,2,4) = 1. - localIP(i,1) end do localDN = 0.25 * localDN; localN = 0.25 * localN end subroutine init La subrutina assembleK se encarga de calcular y ensamblar . Ésta es la matriz de rigidez que no cambia entre iteraciones. La subrutina calcula las matrices (ecuación (9.93)) y luego las ensambla (en la matriz global) para cada elemento. Para poder calcular se debe llamar a la subrutina isoTransform que devuelve la matriz de derivadas de las funciones de forma y el Jacobiano para cada punto de integración, utilizando la ecuación (9.94). subroutine isoTransform (x, dN, detJ) !Returns dN and detJ implicit none real, intent(in) :: x(nX,2) real, intent(out) :: dN(nIP,2,nX), detJ(nIP) integer i real J(nIP,2,2), invJ(nIP,2,2) do i = 1, nIP !Obtain Jacobian and determinant. J = D x J(i,:,:) = matmul(localDN(i,:,:),x) detJ(i) = abs(J(i,1,1) * J(i,2,2) - J(i,2,1) * J(i,1,2)) !Obtain the inverse of a 2x2 matrix invJ(i,1,1) = J(i,2,2); invJ(i,1,2) = -J(i,1,2) invJ(i,2,1) = -J(i,2,1); invJ(i,2,2) = J(i,1,1) invJ(i,:,:) = (1. / detJ(i)) * invJ(i,:,:) !Obtain dN = invJ * localDN dN(i,:,:) = matmul(invJ(i,:,:), localDN(i,:,:)) end do end subroutine isoTransform subroutine assembleK() implicit none integer i, j, l, eN(nX) !Remember nX is number of nodes per element real x(nX,2), dN(nIP,2,nX), detJ(nIP) real localK(nX,nX) - 114 - Andrés Zarabozo Martínez Métodos numéricos do i = 1, nElem !Saves, in eN(4), the number of the nodes in the element eN = elemNode(i,:) !Saves, in x(4,2), the positions of the nodes !in global coordinates of the element do j = 1, nX x(j,:) = node(eN(j),:) end do localK = 0. call isoTransform(x, dN, detJ) !K = sum(|J| Dt D) do j = 1, nIP localK = localK + detJ(j) * matmul(transpose(dN(j,:,:)),dN(j,:,:)) end do !Introduces the values in the global matrix K do j = 1, nX do l = 1, nX K(eN(j), eN(l)) = K(eN(j), eN(l)) + localK(j,l) end do end do end do end subroutine assembleK La siguiente subrutina es muy parecida a la subrutina assembleK pero ésta se encarga de ensamblar las matrices y . Éstas matrices se deben calcular en cada iteración. subroutine assembleQ() implicit none integer i, j, k, x(2) real localQ(2), localT(2), localKr(2,2), L real aux !Restarts q0 and Kr q0 = 0.; Kr = 0. do i = 1, nExt !Pointer to node number x = boundExt(i,:) !Length L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1)) L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2)) L = sqrt(L) !Temperatures at the nodes localT(1) = T0(x(1)); localT(2) = T0(x(2)) - 115 - Andrés Zarabozo Martínez Métodos numéricos !Matrix q0 !Heat on the nodes localQ(1) = localT(1)*localT(1)*localT(1)*localT(1) + 0.5 * & localT(2)*localT(2)*localT(2)*localT(2) localQ(2) = localT(2)*localT(2)*localT(2)*localT(2) + 0.5 * & localT(1)*localT(1)*localT(1)*localT(1) aux = L / alpha localQ = localQ * aux !Introduce values in global q q0(x(1)) = q0(x(1)) + localQ(1) q0(x(2)) = q0(x(2)) + localQ(2) !Matrix Kr !Local Kr aux = 4./6. localKr(1,1) = 2. * aux * localT(1)*localT(1)*localT(1) localKr(2,1) = aux * localT(1)*localT(1)*localT(1) localKr(1,2) = aux * localT(2)*localT(2)*localT(2) localKr(2,2) = 2. * aux * localT(2)*localT(2)*localT(2) aux = - L / alpha localKr = localKr * aux !Introduce values in global Kr do j = 1, 2 do k = 1, 2 Kr(x(j),x(k)) = Kr(x(j),x(k)) + localKr(j,k) end do end do end do endsubroutine assembleQ La subrutina innerBoundary introduce las condiciones de contorno de Dirichlet. Simplemente, para todos los nodos donde la ecuación es conocida, borra la ecuación e introduce una nueva ecuación . subroutine innerBoundary() implicit none integer i, n do i = 1, nIn n = boundIn(i) KTot(n,:) = 0.; KTot(n,n) = 1. T(n) = 1. !Boundary temperature is 1 end do end subroutine innerBoundary - 116 - Andrés Zarabozo Martínez Métodos numéricos La subrutina solveSystem es un simple código de resolución de sistemas lineales mediante el método de Gauss. De forma similar a los programas escritos en el tema de resolución de sistemas lineales, la matriz de entrada debe estar transpuesta para gestionar de forma más eficiente la memoria. subroutine solveSystem(a, b, n) !Matrix needs to be transposed implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot real :: mult !Triangulate the matrix do pivot = 1, n-1 do row = pivot+1, n mult = a(pivot, row) / a(pivot,pivot) a(pivot+1:n,row) = a(pivot+1:n,row) - mult * & a(pivot+1:n,pivot) b(row) = b(row) - mult * b(pivot) end do end do !Obtain solutions b(n) = b(n) / a(n,n) do row=n-1,1,-1 b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine Finalmente la subrutina solver es la que se encarda del bucle iterativo y calcula la distribución de las temperaturas en los nodos. Para cada iteración calcula los vectores y llamando a la subrutina assembleQ. Luego construye un sistema lineal (ecuación (9.92)) y le introduce las condiciones de contorno llamando a la subrutina innerBoundary. Finalmente resuelve el sistema, escribe los resultados y los verifica para saber si el bucle debe finalizarse. subroutine solver() implicit none integer i, j real a(nNode, nNode) logical bool bool = .true. do i = 1, maxIterations !bucle iterativo !Obteins matrix Kr and vector q0 call assembleQ(); - 117 - Andrés Zarabozo Martínez Métodos numéricos !Builds linear system Ax=b Where A=KTot and b=T KTot = K - Kr T = q0 !Introduces Dirichlett boundary conditions call innerBoundary() !Solves system a = transpose(KTot) call solveSystem(a, T, nNode) !Writtes result Tit(:,i) = T !End loop if(maxval(abs(T - T0)).lt. error) then print*, " " print*, "Final iteration: ", i print*, " " bool = .false. exit end if !New iteration T0 = T print*, "Iteration ", i,"Done!" end do endIT = i if (bool) endIT = i - 1 end subroutine Una vez ya se tiene la distribución de temperaturas, se puede calcular la potencia adimensional. Se calcula la potencia radiada en cada elemento (ecuación (9.97)) y ésta se va sumando a la global. subroutine getW() implicit none real L, W, localW, aux, localT(2) integer i, x(2) aux = 0.5 W = 0. do i = 1, nExt !Pointer to node number x = boundExt(i,:) - 118 - Andrés Zarabozo Martínez Métodos numéricos !Length L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1)) L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2)) L = sqrt(L) !Temperatures at the nodes localT(1) = T0(x(1))*T0(x(1))*T0(x(1))*T0(x(1)) localT(2) = T0(x(2))*T0(x(2))*T0(x(2))*T0(x(2)) !Emitted power localW = L * aux * (localT(1) + localT(2)) !Global power W = W + localW end do print*, " " print*, "Alpha:", alpha print*, "Non-dim. power:", W print*, " " end subroutine getW Las siguientes dos subrutinas son una adaptación de un código para que el GiD pueda leer el resultado de la distribución de nodos, elementos y temperaturas. subroutine writeGidMesh() implicit none ! x : Nodal Coordinates ! conec : Conectivity (Nodes of elements) ! n_nod : Number of Nodes ! n_el : Number of Elements integer n_nod, n_el, conec(4,nElem), i real x(2,nNode) !Convert the variables to R.F. variables n_nod = nNode; n_el = nElem x(1,:) = node(:,1); x(2,:) = node(:,2) conec = transpose(elemNode) open(UNIT=6,FILE='radiation_analysis.post.msh',ACCESS='SEQUENTIAL',& STATUS='REPLACE') ! Create File write(6,*) '# postprocess mesh for GiD' ! File Header write(6,*) 'MESH "RADIATION_FEA" dimension 2 ElemType Quadrilateral Nnode 4' ! Write Nodal Coordinates write(6,*) 'Coordinates' write(6,*) '# node number coordinate_x coordinate_y' - 119 - Andrés Zarabozo Martínez Métodos numéricos do i = 1, n_nod write(6,*) i, x(:, i) end do ! i write(6,*) 'end coordinates' ! Write Surface Elements write(6,*) 'Elements' write(6,*) '# element node_1 node_2 node_3 node_4' do i = 1, n_el write(6,*) i, conec(:, i) end do ! i write(6,*) 'end elements' close(6) ! Close File end subroutine writeGidMesh !************************************************************** subroutine writeTemperature() implicit none integer n_nod, n_ite real temperature(nNode, endIT) integer nodeF, iter character*(*) temp_h, scalar, endvalues, values character*(*) header, filename parameter (temp_h = 'Result "TEMPERATURE" "ITERATION=" ') parameter (scalar = ' Scalar OnNodes') parameter (endvalues = 'End Values', values = 'Values') parameter (header = 'GiD Post Results File 1.0') parameter (filename = 'radiation_analysis.post.res') !Convert the variables to R.F. variables n_nod = nNode; n_ite = endIT; temperature(:,:) = Tit(:,1:endIT) 10 20 ! Format specs format (A) ! Single character field format (A, I0, A) ! Use to write iteration number ! Open Output File & Overwrite open(UNIT=6, FILE=filename, ACCESS='SEQUENTIAL', & STATUS='REPLACE') ! Write Header write(6,10) header ! Write Temperature Distribution for Each Iteration do iter = 1, n_ite write(6,20) temp_h, iter, scalar write(6,10) values - 120 - Andrés Zarabozo Martínez Métodos numéricos do nodeF = 1, n_nod write(6,*) nodeF, temperature(nodeF, iter) end do ! nodeF write(6,10) endvalues end do ! iter ! Close file close(6) end subroutine writeTemperature end module subroutines Los siguientes resultados corresponden a las temperaturas adimensionales en un cuarto de radiador con . El radiador se ha mallado con 288 nodos. El programa finaliza cuando el error es menor que . . Las primeras dos soluciones mostradas en las siguientes figuras corresponden para valores de muy pequeño y muy grande. Figura 9.10. Temperaturas adimensionales para Figura 9.11.Temperaturas adimensionales para . . . La Figura 9.10 muestra el resultado cuando la conductividad es muy baja. Como ya se suponía, la temperatura en el interior es alta mientras que en el exterior la temperatura es muy baja. Como caso opuesto, la Figura 9.11 muestra el resultado cuando la conductividad es muy alta. La temperatura en todo el dominio es muy alta. Los valores de la potencia adimensional ver en la Tabla 9.2 y en la Figura 9.12. para distintos valores del parámetro - 121 - se pueden Andrés Zarabozo Martínez . . . Métodos numéricos . − . . . − . . . − . . . . . . . . . . . . . . . . . . . . . Tabla 9.2. Potencia adimensional para distintos valores de . 12 10 8 θ 6 4 2 0 1.E-03 1.E-02 1.E-01 1.E+00 1.E+01 1.E+02 1.E+03 1.E+04 1.E+05 α Figura 9.12. Potencia adimensional para distintos valores de . Como se había predicho en el tema 9.7, cuando la conductividad es muy baja ( ) la potencia adimensional tiende a ser muy baja también (del orden de magnitud de ). Mientras ) que si la conductividad es alta ( ≫ ) la solución converge hacia ( . - 122 - Andrés Zarabozo Martínez Métodos numéricos 10. Apéndice 10.1. Programación en Fortran Programa 1. Mínimo error de un tipo de variable program program1 implicit none real small = 1. integer i do i = 1, 1000 if (1. + small .gt. 1.) then small = 0.5 * small else exit end if end do small = 2. * small print*, small print*, epsilon(small) end program - 123 - Andrés Zarabozo Martínez Métodos numéricos Programa 2. Cálculo del número π program program2 implicit none real*8 x, y integer*8 total, inside total = 0 inside = 0 10 continue !Ball thrown call random_number(x) call random_number(y) total = total + 1 !Looks where the ball fell if(x*x + y*y .lt. 1.) inside = inside + 1 !Shows the result every 1000 iterations if (mod(total, 1000) .eq. 0) then print*, total, 4. * dble(inside) / dble(total) end if go to 10 end program - 124 - Andrés Zarabozo Martínez Métodos numéricos 10.2. Interpolación Programa 3. Entrada de datos e interpolación program program3 implicit none real, allocatable :: ydy(:,:), x(:) real xInt, yInt, step integer n, i, nExit, last !Reading Data open(unit = 1, file='initialData', access='SEQUENTIAL') read(1,*) n allocate(ydy(2,n), x(n)) do i = 1, n read(1,*) x(i), ydy(1,i) end do close(1) !Obtaining Slopes ydy(2,1) = (ydy(1,2) - ydy(1,1)) / (x(2) - x(1)) do i = 2, n - 1 ydy(2,i) = (ydy(1, i+1) - ydy (1, i-1)) / (x(i+1) - x(i-1)) end do ydy(2,n) = (ydy(1,n) - ydy(1,n-1)) / (x(n) - x(n-1)) print *, 'Introduce number of points:' read(*,*) nExit xInt = x(1) step = (x(n) - x(1)) / real(nExit - 1) open(unit=2, file='dataExit', access='SEQUENTIAL', status='REPLACE') last = 1 do i = 1, nExit !Find interval do while (xInt .gt. x(last+1)) last = last + 1 end do !Obtain results call hermite(ydy(:,last:last+1), x(last:last+1), xInt, yInt) write(2,*) xInt, yInt !New step xInt = xInt + step xInt = min(xInt, x(n)) end do close(2) end program - 125 - Andrés Zarabozo Martínez Métodos numéricos !*************************************************** subroutine hermite (v1, v2, x, yx) implicit none real, intent(in) :: v1(4), v2(2), x real, intent(out) :: yx real :: chi, span span =v2(2) - v2(1) chi = (x - v2(1)) / span yx = v1(1) * (1. + 2. * chi) * (1. - chi) * (1. - chi) + & v1(2) * span * chi * (1. - chi) * (1. - chi) + & v1(3) * chi * chi * (3. - 2. * chi) + & v1(4) * span * chi * chi * (chi - 1.) end subroutine - 126 - Andrés Zarabozo Martínez Métodos numéricos 10.3. Integración Programa 4. Obtención de la serie de Fourier program program4 implicit none integer, parameter :: n = 300 integer i real, parameter :: pi = acos(-1.) real y(n), step, x, modes(2, 0:8) x = -pi step = 2. * pi / (real(n) - 1.) !Discretization do i = 1,n y(i) = 0.5 + 3. * cos(2. * x + 0.75) + 1. * cos(6. * x + 0.25) x = x + step end do !Amplitudes and phases call fourier (y, modes, n, 8) !Print results do i = 0, 8 print* , modes(1,i), modes(2,i) end do end program !*************************************************** subroutine trapice(y, b, z, n) implicit none integer, intent (in) :: n real, intent (in) :: y(n), b real, intent (out) :: z z = 0.5 * (y(1) + y(n))+ sum(y(2:n-1)) z = z * b / (real(n) - 1.) end subroutine !*************************************************** subroutine fourier (y, modes, n, m) implicit none integer, intent (in) :: n, m real, intent (in) :: y(n) real, intent (out) :: modes(2, 0:m) integer i real z(n), x(n), dx, invPi, a, b - 127 - Andrés Zarabozo Martínez Métodos numéricos real, parameter :: pi = acos(-1.) invPi = 1. / pi dx = 2. * pi / (real(n) - 1.) x(1) = -pi do i = 2, n x(i) = x(i-1) + dx end do !First coeficient call trapice(y, 2.*pi, a, n) modes(1,0) = a * 0.5 * invPi do i = 1, m !Cos coeficients z = y * cos(real(i) * x) call trapice(z, 2.*pi, a, n) a = a * invPi !Sin coeficients z = y * sin(real(i) * x) call trapice(z, 2.*pi, b, n) b = b * invPi !Amplitudes and phases modes(2,i) = -atan(b / a) modes(1,i) = sqrt(a*a + b*b) end do end subroutine - 128 - Andrés Zarabozo Martínez Métodos numéricos Programa 5. Iteraciones y extrapolación program program5 implicit none integer :: i, j, n real*8, parameter :: a = 0., b = 1. real*8 suma, prevInteg, integ, h, sumEnds, aux, x, analitical n = 10 h = (b - a) / dble(n) suma = 0. !Sum of limits divided by two call evaluateFunction(a, aux) sumEnds = aux call evaluateFunction(b, aux) sumEnds = (sumEnds + aux) * 0.5 do i = 1, 10 !Sum of the values of the function if(i .eq. 1) then x=a+h do j = 1, (n - 1) call evaluateFunction (x, aux) suma = suma + aux x=x+h end do else x=a+h do j = 1, (n - 1), 2 call evaluateFunction (x, aux) suma = suma + aux x=x+2*h end do end if !Integral integ = h * (sumEnds + suma) !Number of intervals and size of interval n=2*n h = h * 0.5 !Richardson extrapolation if(i .eq. 1) then print*,"No extrapolation", " With extrapolation" analitical = .2 * dsin(dble(5.)) - 1. else aux = (4. * integ - prevInteg) / 3. print*, integ - analitical, aux - analitical end if prevInteg = integ end do end program - 129 - Andrés Zarabozo Martínez Métodos numéricos !*************************************************** subroutine evaluateFunction(x, y) implicit none real* 8, intent(in) :: x real* 8, intent(out) :: y y = dcos(5. * x) + 3. * x * x end subroutine - 130 - Andrés Zarabozo Martínez Métodos numéricos 10.4. Resolución numérica de ecuaciones no lineales Programa 6. Deflexión de un cable program Program6 implicit none integer i, j, n integer, parameter :: itMax = 7 real, parameter :: k = 0.25E-3 real x1, x2, x3, fx1, fx2, slope x1 = (2. * k)**(1./3.) x2 = 1.1 * x1 fx1 = k + sin(x1) - tan(x1) print*, 'x= ', x1, 'f(x) = ', fx1 do i = 1, itMax if (x1.eq.x2) exit fx2 = k + sin(x2) - tan (x2) print*, 'x = ', x2, 'f(x) = ',fx2 slope = (fx2 - fx1) / (x2 - x1) x3 = x2 - fx2 / slope x1 = x2 x2 = x3 fx1 = fx2 end do end program - 131 - Andrés Zarabozo Martínez Métodos numéricos Programa 7. Resolución mediante Newton-Raphson program Program7 implicit none integer i, j, n integer, parameter :: itMax = 7 real, parameter :: k = 0.25E-3 real x1, x2, fx1, slope, cosx, sinx x1 = (2. * k)**(1./3.) do i = 1, itMax cosx = cos(x1) sinx = sin(x1) fx1 = k + sinx - sinx / cosx slope = cosx - 1. / (cosx * cosx) print*, 'x = ', x1, 'f(x) = ', fx1 if (fx1 .eq. 0) exit x2 = x1 - fx1 / slope x1 = x2 end do end program - 132 - Andrés Zarabozo Martínez Métodos numéricos 10.5. Resolución numérica de ecuaciones lineales Programa 8. Resolución de un sistema mediante Gauss program program8 implicit none integer, parameter :: n = 20 integer i, j real :: a(n,n), aTrans(n,n), b(n), x(n), rand !Initialize matrix and vector do i = 1, n do j = 1, n call random_number(rand) a(i,j) = 0.5 - rand end do a(i,i) = (1. + rand) * real(n) call random_number(rand) b(i) = rand end do !Solve system aTrans = transpose(a) x=b call solver(aTrans, x, n) !Errors x = matmul(a, x) - b print *, 'If the code is correct this is a small number: ', maxval(abs(x)) end program !**************************************************************************** subroutine solver(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot real :: mult !Triangulate the matrix do pivot = 1, n-1 do row = pivot+1, n mult = a(pivot, row) / a(pivot,pivot) a(pivot+1:n,row) = a(pivot+1:n,row) - mult & * a(pivot+1:n,pivot) b(row) = b(row) - mult * b(pivot) end do end do !Obtain solutions b(n) = b(n) / a(n,n) do row=n-1,1,-1 b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine - 133 - Andrés Zarabozo Martínez Métodos numéricos Programa 9. Sistema con matriz mal condicionada program program9 implicit none integer, parameter :: size = 20 integer i, j real :: a(size,size), aTrans(size,size), b(size), x(size), rand !Generate matrix do i = 1, size do j = 1, size call random_number(rand) a(i,j) = 0.5 - rand !Number between -0.5 and 0.5 end do a(i,i) = rand * 1.E-5 !Very small number for the diagonal call random_number(rand) b(i) = rand !Number between 0. and 1. end do !Solve system aTrans = transpose(a) x=b call solveMatrix(aTrans, x, size) !Check results x = matmul(a, x) - b print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program !**************************************************************************** subroutine solveMatrix(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot, point(n), i, posRow, posPiv real :: mult, x(n) !Initialize pointer vector do row = 1,n point(row) = row end do do pivot = 1, n-1 !Organize matrix mult = 0. do row = pivot, n !Searches biggest number under Pivot if (abs(a(pivot,point(row))) .GT. mult) then i = row mult = abs(a(pivot,point(row))) end if end do - 134 - Andrés Zarabozo Martínez Métodos numéricos row = point(pivot) point(pivot) = point(i) point(i) = row posPiv = point(pivot) !Make zeros under Pivot do row = pivot+1, n posRow = point(row) mult = a(pivot, posRow) / a(pivot,posPiv) a(pivot+1:n,posRow) = a(pivot+1:n,posRow) - mult & * a(pivot+1:n,posPiv) b(posRow) = b(posRow) - mult * b(posPiv) end do end do !Obtain Results x(n) = b(point(n)) / a(n,point(n)) do row = n-1,1,-1 posRow = point(row) x(row) = b(posRow) - & dot_product(a(row+1:n,posRow), x(row+1:n)) x(row) = x(row) / a(row,posRow) end do b=x end subroutine - 135 - Andrés Zarabozo Martínez Métodos numéricos Programa 10. Doolittle program program10 implicit none integer, parameter :: n = 50 integer i, j real :: a(n,n), aTrans(n,n), b(n), x(n), rand !Generate matrix do i = 1, n do j = 1, n call random_number(rand) a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5 end do a(i,i) = 0.1 * (1. + rand) * real(n) ! Good matrix call random_number(rand) b(i) = rand ! A number between 0. and 1. end do !Solve system aTrans = transpose(a) x=b call luDecomposition(aTrans, n) call luSustitution(aTrans, x, n) !Check results x = matmul(a, x) - b print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program !**************************************************************************** subroutine luDecomposition(a, n) implicit none integer, intent(in) :: n real, intent(inout) :: a(n,n) integer :: row, pivot real :: mult do pivot = 1, n-1 do row = pivot+1, n mult = a(pivot, row) / a(pivot,pivot) a(pivot+1:n,row) = a(pivot+1:n,row) & - mult * a(pivot+1:n,pivot) a(pivot,row) = mult end do end do end subroutine !**************************************************************************** - 136 - Andrés Zarabozo Martínez Métodos numéricos subroutine luSustitution(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n) real, intent(in) :: a(n,n) integer :: row, i !Ly = b do row = 1, n b(row) = b(row) - dot_product(a(1:row-1,row),b(1:row-1)) end do !Ux = y do row = n, 1, -1 b(row) = b(row) - dot_product(a(row+1:n,row),b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine - 137 - Andrés Zarabozo Martínez Métodos numéricos Programa 11. Crout program program11 implicit none integer, parameter :: size = 50 integer i, j real :: a(size,size), aCopy(size,size), b(size), x(size), rand do i = 1, size do j = 1, size call random_number(rand) a(i,j) = 0.5 - rand ! A number between -0.5 and 0.5 end do a(i,i) = 0.1 * (1. + rand) * real(size) ! Good matrix call random_number(rand) b(i) = rand ! A number between 0. and 1. end do aCopy = a x=b call croutDescomp(aCopy,size) call croutSust(aCopy, x, size) x = matmul(a, x) - b print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program !**************************************************************************** subroutine croutDescomp(a, n) implicit none integer, intent(in) :: n real, intent(inout) :: a(n,n) integer :: row, column, i do i = 1, n !Obtain L do row = i, n a(row,i) = a(row,i) - dot_product(a(row,1:i-1),a(1:i-1,i)) end do !Obtain U do column = i + 1, n a(i, column) = a(i, column) - & dot_product(a(i,1:i-1),a(1:i-1,column)) a(i, column) = a(i, column) / a(i,i) end do end do end subroutine !**************************************************************************** - 138 - Andrés Zarabozo Martínez Métodos numéricos subroutine croutSust(a, b, n) implicit none integer, intent(in) :: n real, intent(inout) :: b (n) real, intent(in) :: a(n,n) integer :: row, i !Ly = b do row = 1, n b(row) = b(row) - dot_product(a(row,1:row-1), b(1:row-1)) b(row) = b(row) / a(row,row) end do !Ux = y do row = n, 1, -1 b(row) = b(row) - dot_product(a(row,row+1:n),b(row+1:n)) end do end subroutine - 139 - Andrés Zarabozo Martínez Métodos numéricos Programa 12. Matriz Banda Program program12 implicit none integer, parameter :: size = 50, d = 5 integer i, j, left, right real :: a(-d:d,size), aCopy(-d:d,size), b(size), bCopy(size), x(size), rand do i = 1, size do j = -d, d call random_number(rand) a(j,i) = 0.5 - rand !A number between -0.5 and 0.5 end do a(0,i) = (1. + rand) * real(size) !Good matrix call random_number(rand) b(i) = rand !A number between 0. and 1. end do aCopy = a x=b !Solve call gaussBand(aCopy, b, d, size) !Check results bCopy = b do i = 1, size left = min(d, i - 1) right = min(d, size - i) x(i) = dot_product(a(-left:right, i),bCopy(i-left:i+right)) - x(i) end do print *, 'If the code is correct this is a small number:', maxval(abs(x)) end program !**************************************************************************** subroutine gaussBand(a, b, d, n) implicit none integer, intent(in) :: d, n real, intent(inout) :: a(-d:d,n), b(n) integer pivot, row, disp real mult !Triangulate matrix do pivot = 1, n - 1 do row = pivot + 1, min(pivot + d, n) disp = row - pivot !Gauss mult = a(-disp,row) / a(0, pivot) a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - & mult * a(1:d,pivot) b(row) = b(row) - mult * b(pivot) end do end do - 140 - Andrés Zarabozo Martínez Métodos numéricos !Solve x do row = n, 1, -1 disp = min(d, n - row) b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp)) b(row) = b(row) / a(0,row) end do end subroutine - 141 - Andrés Zarabozo Martínez Métodos numéricos 10.6. Método de diferencias finitas Programa 13. Ejemplo de problema mecánico program finiteDifferences implicit none integer n, i, j, maxIt, maxLoop, kas real*8, allocatable :: K(:,:), R(:), x(:) real*8 v, v1, h, tref, ka, error !Program configuration ka = 0.5 !Constant in drag n = 1000 !Initial number of nodes maxLoop = 10 !Maximum number of times the program is runned maxIt = 100 !Maximum iteration in Newton's method error = 0.00001 !Maximum Error tref = 6.371E6 * 6.371E6 * 6.371E6 / 3.986E14 tref = tref ** 0.5 !Loop for number of nodes do j = 1, maxLoop allocate (K(3,n), R(n), x(n)) !Initial values for x h = (1020. / tref) / dble(n - 1) call initialValues(x, n, tref, h) v = 0. !Loop for number of iterations do i = 1, maxIt !Generate matrix K and vector R call writeSystem (K, R, x, n, tref, h, ka) !Solve K·dx = -R R=-R call gaussBand(K, R, 1, n) !Solve x1 = x0 + dx x=x+R !Initial velocity v1 = v v = (4. * x(2) - 3. * x(1) - x(3)) / (2. * h) !Print results if(maxval(abs(R)) .lt. error) then print*, "Number of nodes: ", n print*, "Error in R: ", maxval(abs(R)) print*, "Iterations needed: ", i print*, "Initial velocity: ", " ", v print*, " " exit - 142 - Andrés Zarabozo Martínez Métodos numéricos elseif (i .eq. maxIt) then print*, "Number of nodes: ", n print*, "No solution found. " print*, " " end if end do !Renew discretization deallocate(K, R, x) n = 1000 + n end do end program !****************************************************************** subroutine writeSystem(K, R, x, n, tref, h, ka) implicit none integer, intent (in) :: n real*8, intent (in) :: x(n), tref, h, ka real*8, intent (out) :: K(3,n), R(n) integer i real*8 h2 h2 = 1. / (h * h) !Write matrix K K(2,1) = 1. K(3,1) = 0. do i = 2, n - 1 K(1,i) = h2 - ka * 2. * (x(i+1) - x(i-1)) * h2 K(2,i) = 1. - 2. * h2 K(3,i) = h2 + ka * 2. * (x(i+1) - x(i-1)) * h2 end do K(1,n) = 0. K(2,n) = 1. !Write vector R R(1) = 0. do i = 2, n - 1 R(i) = x(i) + (x(i+1) - 2. * x(i) + x(i-1)) * h2 + & ka * (x(i+1) - x(i-1)) * (x(i+1) - x(i-1)) * h2 end do R(n) = 0. end subroutine !****************************************************************** subroutine initialValues(x0, n, tref, h) implicit none integer, intent (in) :: n real*8, intent(in) :: tref, h real*8, intent (out) :: x0(n) - 143 - Andrés Zarabozo Martínez Métodos numéricos integer i real*8 t, tn, kn tn = 1020. / tref kn = (1. + dcos(tn)) / dsin(tn) x0(1) = -1. do i = 2, n - 1 t = dble(i - 1) * h x0(i) = - dcos(t) + kn * dsin(t) end do x0(n) = 1. end subroutine !****************************************************************** subroutine gaussBand(a, b, d, n) implicit none integer, intent(in) :: d, n real*8, intent(inout) :: a(-d:d,n), b(n) integer pivot, row, disp real*8 mult !Triangulate matrix do pivot = 1, n - 1 do row = pivot + 1, min(pivot + d, n) disp = row - pivot !Gauss mult = a(-disp,row) / a(0, pivot) a(1-disp:d-disp,row) = a(1-disp:d-disp,row) - & mult * a(1:d,pivot) b(row) = b(row) - mult * b(pivot) end do end do !Solve x do row = n, 1, -1 disp = min(d, n - row) b(row) = b(row) - dot_product(a(1:disp,row),b(row+1:row+disp)) b(row) = b(row) / a(0,row) end do end subroutine - 144 - Andrés Zarabozo Martínez Métodos numéricos 10.7. Método de elementos finitos Programa 15. Radiador especial module subroutines implicit none !Variables: Local means element coordinates. X: coordinates of node; !N: shape function; DN: deriv.N; IP: Integ. points real, save :: localX(4,2), localN(4,4), localDN(4,2,4), localIP(4,2), alpha real, allocatable, save :: node(:,:), K(:,:), T(:), q0(:), T0(:), Kr(:,:), Ktot(:,:), Tit(:,:) integer, allocatable, save :: elemNode(:,:), boundIn(:), boundExt(:,:) integer, save :: nNode, nElem, nIn, nExt, nIP, nX integer, save :: maxIterations, endIT real, save :: error contains !************************************************************** subroutine readMesh() implicit none integer i real aux, aux2 open(UNIT = 5, FILE = 'input_mesh.txt', ACCESS = 'SEQUENTIAL') !Read nodal coordinates read(5,*) nNode allocate (node(nNode,2)) do i = 1, nNode read(5,*) aux, node(i,:), aux2 !First and last numbers not needed end do !Read Elements read(5,*) nElem allocate(elemNode(nElem,4)) do i = 1, nElem read(5,*) aux, elemNode(i,:) end do !Read Boundary nodes that Radiate read(5,*) nExt allocate(boundExt(nExt,2)) do i = 1, nExt read(5,*) aux, boundExt(i,:) end do - 145 - Andrés Zarabozo Martínez Métodos numéricos !Read Boundary nodes with constant Temperature read(5,*) nIn allocate(boundIn(nIn)) do i = 1, nIn read(5,*) aux, boundIn(i) end do close(5) end subroutine readMesh !************************************************************** subroutine init() implicit none real aux integer i allocate(K(nNode, nNode), Kr(nNode, nNode), KTot(nNode,nNode), & T(nNode), T0(nNode), q0(nNode)) allocate(Tit(nNode,maxIterations)) K = 0.; Kr = 0.; KTot = 0.; T = 0.; T0 = 0.; q0 = 0.; nIP = 4; nX = 4; Tit = 0. !Initial temperature if (alpha .ge. 1) then T0 = 0.9 else T0 = alpha end if !Node positions localX(1,1) = -1.; localX(2,1) = 1.; localX(3,1) = 1.; localX(4,1) = -1.; localX(node, xi-eta) localX(1,2) = -1. localX(2,2) = -1. localX(3,2) = 1. localX(4,2) = 1. !Integration points position localIP(IP, xi-eta) aux = 1. / sqrt(3.) localIP = localX * aux do i = 1, 4 !Shape functions localN(IP, shape function) localN(i,1) = (1. - localIP(i,1)) * (1. - localIP(i,2)) localN(i,2) = (1. + localIP(i,1)) * (1. - localIP(i,2)) localN(i,3) = (1. + localIP(i,1)) * (1. + localIP(i,2)) localN(i,4) = (1. - localIP(i,1)) * (1. + localIP(i,2)) !Derivative localDN(IP, dxi - deta, shape function) localDN(i,1,1) = - 1. + localIP(i,2); localDN(i,2,1) = - 1. + localIP(i,1) localDN(i,1,2) = 1. - localIP(i,2); localDN(i,2,2) = - 1. - localIP(i,1) localDN(i,1,3) = 1. + localIP(i,2); localDN(i,2,3) = 1. + localIP(i,1) localDN(i,1,4) = - 1. - localIP(i,2); localDN(i,2,4) = 1. - localIP(i,1) end do - 146 - Andrés Zarabozo Martínez Métodos numéricos localDN = 0.25 * localDN; localN = 0.25 * localN end subroutine init !************************************************************** subroutine isoTransform (x, dN, detJ) !Returns dN and detJ implicit none real, intent(in) :: x(nX,2) real, intent(out) :: dN(nIP,2,nX), detJ(nIP) integer i real J(nIP,2,2), invJ(nIP,2,2) do i = 1, nIP !Obtain Jacobian and determinant. J = D x J(i,:,:) = matmul(localDN(i,:,:),x) detJ(i) = abs(J(i,1,1) * J(i,2,2) - J(i,2,1) * J(i,1,2)) !Obtain the inverse of a 2x2 matrix invJ(i,1,1) = J(i,2,2); invJ(i,1,2) = -J(i,1,2) invJ(i,2,1) = -J(i,2,1); invJ(i,2,2) = J(i,1,1) invJ(i,:,:) = (1. / detJ(i)) * invJ(i,:,:) !Obtain dN = invJ * localDN dN(i,:,:) = matmul(invJ(i,:,:), localDN(i,:,:)) end do end subroutine isoTransform !************************************************************** subroutine assembleK() implicit none integer i, j, l, eN(nX) !Remember nX is number of nodes per element real x(nX,2), dN(nIP,2,nX), detJ(nIP) real localK(nX,nX) do i = 1, nElem !Saves, in eN(4), the number of the nodes in the element eN = elemNode(i,:) !Saves, in x(4,2), the positions of the nodes !in global coordinates of the element do j = 1, nX x(j,:) = node(eN(j),:) end do localK = 0. call isoTransform(x, dN, detJ) - 147 - Andrés Zarabozo Martínez Métodos numéricos !K = sum(|J| Dt D) do j = 1, nIP localK = localK + detJ(j) * matmul(transpose(dN(j,:,:)),dN(j,:,:)) end do !Introduces the values in the global matrix K do j = 1, nX do l = 1, nX K(eN(j), eN(l)) = K(eN(j), eN(l)) + localK(j,l) end do end do end do end subroutine assembleK !************************************************************** subroutine assembleQ() implicit none integer i, j, k, x(2) real localQ(2), localT(2), localKr(2,2), L real aux !Restarts q0 and Kr q0 = 0.; Kr = 0. do i = 1, nExt !Pointer to node number x = boundExt(i,:) !Length L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1)) L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2)) L = sqrt(L) !Temperatures at the nodes localT(1) = T0(x(1)); localT(2) = T0(x(2)) !Matrix q0 !Heat on the nodes localQ(1) = localT(1)*localT(1)*localT(1)*localT(1) + 0.5 * & localT(2)*localT(2)*localT(2)*localT(2) localQ(2) = localT(2)*localT(2)*localT(2)*localT(2) + 0.5 * & localT(1)*localT(1)*localT(1)*localT(1) aux = L / alpha localQ = localQ * aux !Introduce values in global q q0(x(1)) = q0(x(1)) + localQ(1) q0(x(2)) = q0(x(2)) + localQ(2) - 148 - Andrés Zarabozo Martínez Métodos numéricos !Matrix Kr !Local Kr aux = 4./6. localKr(1,1) = 2. * aux * localT(1)*localT(1)*localT(1) localKr(2,1) = aux * localT(1)*localT(1)*localT(1) localKr(1,2) = aux * localT(2)*localT(2)*localT(2) localKr(2,2) = 2. * aux * localT(2)*localT(2)*localT(2) aux = - L / alpha localKr = localKr * aux !Introduce values in global Kr do j = 1, 2 do k = 1, 2 Kr(x(j),x(k)) = Kr(x(j),x(k)) + localKr(j,k) end do end do end do endsubroutine assembleQ !************************************************************** subroutine innerBoundary() implicit none integer i, n do i = 1, nIn n = boundIn(i) KTot(n,:) = 0.; KTot(n,n) = 1. T(n) = 1. !Boundary temperature is 1 end do end subroutine innerBoundary !************************************************************** subroutine solveSystem(a, b, n) !Matrix needs to be transposed implicit none integer, intent(in) :: n real, intent(inout) :: b (n), a(n,n) integer :: row, pivot real :: mult !Triangulate the matrix do pivot = 1, n-1 do row = pivot+1, n mult = a(pivot, row) / a(pivot,pivot) a(pivot+1:n,row) = a(pivot+1:n,row) - mult * & a(pivot+1:n,pivot) b(row) = b(row) - mult * b(pivot) end do end do - 149 - Andrés Zarabozo Martínez Métodos numéricos !Obtain solutions b(n) = b(n) / a(n,n) do row=n-1,1,-1 b(row) = b(row) - dot_product(a(row+1:n,row), b(row+1:n)) b(row) = b(row) / a(row,row) end do end subroutine !************************************************************** subroutine solver() implicit none integer i, j real a(nNode, nNode) logical bool bool = .true. do i = 1, maxIterations !bucle iterativo !Obteins matrix Kr and vector q0 call assembleQ(); !Builds linear system Ax=b Where A=KTot and b=T KTot = K - Kr T = q0 !Introduces Dirichlett boundary conditions call innerBoundary() !Solves system a = transpose(KTot) call solveSystem(a, T, nNode) !Writtes result Tit(:,i) = T !End loop if(maxval(abs(T - T0)).lt. error) then print*, " " print*, "Final iteration: ", i print*, " " bool = .false. exit end if !New iteration T0 = T print*, "Iteration ", i,"Done!" end do - 150 - Andrés Zarabozo Martínez Métodos numéricos endIT = i if (bool) endIT = i - 1 end subroutine !************************************************************** subroutine getW() implicit none real L, W, localW, aux, localT(2) integer i, x(2) aux = 0.5 W = 0. do i = 1, nExt !Pointer to node number x = boundExt(i,:) !Length L = (node(x(1),1) - node(x(2),1)) * (node(x(1),1) - node(x(2),1)) L = L + (node(x(1),2) - node(x(2),2)) * (node(x(1),2) - node(x(2),2)) L = sqrt(L) !Temperatures at the nodes localT(1) = T0(x(1))*T0(x(1))*T0(x(1))*T0(x(1)) localT(2) = T0(x(2))*T0(x(2))*T0(x(2))*T0(x(2)) !Emitted power localW = L * aux * (localT(1) + localT(2)) !Global power W = W + localW end do print*, " " print*, "Alpha:", alpha print*, "Non-dim. power:", W print*, " " end subroutine getW !************************************************************** !************************************************************** subroutine writeGidMesh() implicit none ! x : Nodal Coordinates ! conec : Conectivity (Nodes of elements) ! n_nod : Number of Nodes ! n_el : Number of Elements - 151 - Andrés Zarabozo Martínez Métodos numéricos integer n_nod, n_el, conec(4,nElem), i real x(2,nNode) !Convert the variables to R.F. variables n_nod = nNode; n_el = nElem x(1,:) = node(:,1); x(2,:) = node(:,2) conec = transpose(elemNode) open(UNIT=6,FILE='radiation_analysis.post.msh',ACCESS='SEQUENTIAL',& STATUS='REPLACE') ! Create File write(6,*) '# postprocess mesh for GiD' ! File Header write(6,*) 'MESH "RADIATION_FEA" dimension 2 ElemType Quadrilateral Nnode 4' ! Write Nodal Coordinates write(6,*) 'Coordinates' write(6,*) '# node number coordinate_x coordinate_y' do i = 1, n_nod write(6,*) i, x(:, i) end do ! i write(6,*) 'end coordinates' ! Write Surface Elements write(6,*) 'Elements' write(6,*) '# element node_1 node_2 node_3 node_4' do i = 1, n_el write(6,*) i, conec(:, i) end do ! i write(6,*) 'end elements' close(6) ! Close File end subroutine writeGidMesh !************************************************************** subroutine writeTemperature() implicit none integer n_nod, n_ite real temperature(nNode, endIT) integer nodeF, iter character*(*) temp_h, scalar, endvalues, values character*(*) header, filename parameter (temp_h = 'Result "TEMPERATURE" "ITERATION=" ') parameter (scalar = ' Scalar OnNodes') parameter (endvalues = 'End Values', values = 'Values') parameter (header = 'GiD Post Results File 1.0') parameter (filename = 'radiation_analysis.post.res') !Convert the variables to R.F. variables n_nod = nNode; n_ite = endIT; temperature(:,:) = Tit(:,1:endIT) - 152 - Andrés Zarabozo Martínez 10 20 Métodos numéricos ! Format specs format (A) ! Single character field format (A, I0, A) ! Use to write iteration number ! Open Output File & Overwrite open(UNIT=6, FILE=filename, ACCESS='SEQUENTIAL', & STATUS='REPLACE') ! Write Header write(6,10) header ! Write Temperature Distribution for Each Iteration do iter = 1, n_ite write(6,20) temp_h, iter, scalar write(6,10) values do nodeF = 1, n_nod write(6,*) nodeF, temperature(nodeF, iter) end do ! nodeF write(6,10) endvalues end do ! iter ! Close file close(6) end subroutine writeTemperature end module subroutines !************************************************************** ! Main Program !************************************************************** program spaceRadiator use subroutines implicit none integer i !Program configurator alpha = 100. maxIterations = 30 error = 0.0001 !Program sequence call readMesh(); print*, "Read Mesh Done!" call init(); print*, "Init Done!" call assembleK(); print*, "Assemble K Done!"; print*," " call solver(); print*, "Solver Done!" call getW(); Print*, "Get W Done!" call writeGidMesh(); call writeTemperature(); end program spaceRadiator - 153 - Andrés Zarabozo Martínez Métodos numéricos 10.8. Datos de entrada del Programa 15, radiador espacial Los siguientes datos se utilizan como datos de entrada para el programa del radiador espacial. Debe ser nombrado “imput_mesh.txt”. Consiste en una malla con nodos para . 288 ! Number of nodes 1, 10.000000, 0.000000, 0.000000 2, 10.000000, 0.100000, 0.000000 3, 10.000000, 0.200000, 0.000000 4, 10.000000, 0.300000, 0.000000 5, 10.000000, 0.400000, 0.000000 6, 10.000000, 0.500000, 0.000000 7, 10.000000, 0.600000, 0.000000 8, 10.000000, 0.700000, 0.000000 9, 9.208628, 0.000000, 0.000000 10, 9.208628, 0.103795, 0.000000 11, 10.000000, 0.800000, 0.000000 12, 9.208628, 0.210336, 0.000000 13, 9.208628, 0.318936, 0.000000 14, 10.000000, 0.900000, 0.000000 15, 9.208628, 0.428909, 0.000000 16, 9.208628, 0.539569, 0.000000 17, 10.000000, 1.000000, 0.000000 18, 9.208628, 0.650228, 0.000000 19, 9.208628, 0.760201, 0.000000 20, 9.208628, 0.868801, 0.000000 21, 9.208628, 0.975342, 0.000000 22, 9.208628, 1.079137, 0.000000 23, 8.427669, 0.000000, 0.000000 24, 8.427669, 0.110203, 0.000000 25, 8.427669, 0.224086, 0.000000 26, 8.427669, 0.340729, 0.000000 27, 8.427669, 0.459213, 0.000000 28, 8.427669, 0.578617, 0.000000 29, 8.427669, 0.698020, 0.000000 30, 8.427669, 0.816504, 0.000000 31, 8.427669, 0.933147, 0.000000 32, 8.427669, 1.047030, 0.000000 33, 8.427669, 1.157233, 0.000000 34, 7.666995, 0.000000, 0.000000 35, 7.666995, 0.118371, 0.000000 36, 7.666995, 0.240048, 0.000000 37, 7.666995, 0.364205, 0.000000 38, 7.666995, 0.490014, 0.000000 39, 7.666995, 0.616650, 0.000000 40, 7.666995, 0.743286, 0.000000 41, 7.666995, 0.869096, 0.000000 42, 7.666995, 0.993252, 0.000000 43, 7.666995, 1.114929, 0.000000 44, 7.666995, 1.233300, 0.000000 45, 6.935578, 0.000000, 0.000000 46, 6.935578, 0.127460, 0.000000 47, 6.935578, 0.257043, 0.000000 48, 6.935578, 0.388218, 0.000000 49, 6.935578, 0.520454, 0.000000 50, 6.935578, 0.653221, 0.000000 51, 6.935578, 0.785988, 0.000000 52, 6.935578, 0.918224, 0.000000 53, 6.935578, 1.049399, 0.000000 54, 6.935578, 1.178982, 0.000000 55, 6.935578, 1.306442, 0.000000 56, 6.241194, 0.000000, 0.000000 57, 6.241194, 0.136723, 0.000000 58, 6.241194, 0.274023, 0.000000 59, 6.241194, 0.411755, 0.000000 60, 6.241194, 0.549775, 0.000000 61, 6.241194, 0.687940, 0.000000 62, 6.241194, 0.826105, 0.000000 63, 6.241194, 0.964126, 0.000000 64, 6.241194, 1.101858, 0.000000 65, 6.241194, 1.239158, 0.000000 66, 6.241194, 1.375881, 0.000000 67, 5.590209, 0.000000, 0.000000 68, 5.590209, 0.145558, 0.000000 - 154 - Andrés Zarabozo Martínez Métodos numéricos 69, 5.590209, 0.290142, 0.000000 70, 5.590209, 0.433997, 0.000000 71, 5.590209, 0.577365, 0.000000 72, 5.590209, 0.720490, 0.000000 73, 5.590209, 0.863614, 0.000000 74, 5.590209, 1.006982, 0.000000 75, 5.590209, 1.150837, 0.000000 76, 5.590209, 1.295421, 0.000000 77, 5.590209, 1.440979, 0.000000 78, 4.987445, 0.000000, 0.000000 79, 4.987445, 0.153537, 0.000000 80, 4.987445, 0.304800, 0.000000 81, 4.987445, 0.454357, 0.000000 82, 4.987445, 0.602777, 0.000000 83, 4.987445, 0.750628, 0.000000 84, 4.987445, 0.898479, 0.000000 85, 4.987445, 1.046899, 0.000000 86, 4.987445, 1.196456, 0.000000 87, 4.987445, 1.347718, 0.000000 88, 4.987445, 1.501255, 0.000000 89, 4.436137, 0.000000, 0.000000 90, 4.436137, 0.160408, 0.000000 91, 4.436137, 0.317636, 0.000000 92, 4.436137, 0.472480, 0.000000 93, 4.436137, 0.625734, 0.000000 94, 4.436137, 0.778193, 0.000000 95, 4.436137, 0.930652, 0.000000 96, 4.436137, 1.083906, 0.000000 97, 4.436137, 1.238750, 0.000000 98, 4.436137, 1.395978, 0.000000 99, 4.436137, 1.556386, 0.000000 100, 3.937967, 0.000000, 0.000000 101, 3.937967, 0.166071, 0.000000 102, 3.937967, 0.328508, 0.000000 103, 3.937967, 0.488220, 0.000000 104, 3.937967, 0.646115, 0.000000 105, 3.937967, 0.803102, 0.000000 106, 3.937967, 0.960088, 0.000000 107, 3.937967, 1.117983, 0.000000 108, 3.937967, 1.277695, 0.000000 109, 3.937967, 1.440132, 0.000000 110, 3.937967, 1.606203, 0.000000 111, 3.493172, 0.000000, 0.000000 112, 3.493172, 0.170548, 0.000000 113, 3.493172, 0.337443, 0.000000 114, 3.493172, 0.501598, 0.000000 115, 3.493172, 0.663926, 0.000000 116, 3.493172, 0.825341, 0.000000 117, 3.493172, 0.986756, 0.000000 118, 3.493172, 1.149085, 0.000000 119, 3.493172, 1.313239, 0.000000 120, 3.493172, 1.480134, 0.000000 121, 3.493172, 1.650683, 0.000000 122, 3.100706, 0.000000, 0.000000 123, 3.100706, 0.173947, 0.000000 124, 3.100706, 0.344591, 0.000000 125, 3.100706, 0.512758, 0.000000 126, 3.100706, 0.679274, 0.000000 127, 3.100706, 0.844965, 0.000000 128, 3.100706, 1.010655, 0.000000 129, 3.100706, 1.177171, 0.000000 130, 3.100706, 1.345338, 0.000000 131, 3.100706, 1.515982, 0.000000 132, 3.100706, 1.689929, 0.000000 133, 2.758440, 0.000000, 0.000000 134, 2.758440, 0.176421, 0.000000 135, 2.758440, 0.350172, 0.000000 136, 2.758440, 0.521920, 0.000000 137, 2.758440, 0.692333, 0.000000 138, 2.758440, 0.862078, 0.000000 139, 2.758440, 1.031823, 0.000000 140, 2.758440, 1.202236, 0.000000 141, 2.758440, 1.373984, 0.000000 142, 2.758440, 1.547735, 0.000000 143, 2.758440, 1.724156, 0.000000 144, 2.463382, 0.000000, 0.000000 145, 2.463382, 0.178145, 0.000000 - 155 - Andrés Zarabozo Martínez 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, Métodos numéricos 2.463382, 2.463382, 2.463382, 2.463382, 2.463382, 2.463382, 2.463382, 2.463382, 2.463382, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.211913, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 2.000000, 1.821629, 1.815673, 1.815169, 2.000000, 1.815784, 1.812997, 1.811110, 1.808492, 1.806234, 1.804310, 1.808224, 1.636086, 1.630681, 1.630370, 1.813192, 1.625911, 1.619998, 1.619546, 1.616625, 1.608731, 1.606702, 1.615396, 1.446553, 1.443569, 1.441455, 1.622146, 1.432886, 1.421536, 1.424186, 1.405719, 1.400527, 1.400477, 1.275691, 1.268725, 1.264471, 1.417036, 1.244228, 1.427056, 1.234777, 1.202281, 1.123014, 1.121434, 1.175523, 1.111057, 1.131105, 1.180136, 1.081815, 0.354438, 0.529341, 0.703317, 0.876831, 1.050344, 1.224321, 1.399224, 1.575517, 1.753662, 0.000000, 0.179288, 0.357637, 0.535284, 0.712461, 0.889404, 1.066347, 1.243525, 1.421171, 1.599521, 1.778809, 0.000000, 0.180000, 0.360000, 0.540000, 0.720000, 0.900000, 1.080000, 1.260000, 1.440000, 1.620000, 0.000000, 0.180872, 0.361012, 1.800000, 0.541894, 0.719583, 0.898145, 1.079273, 1.266466, 1.455508, 1.637391, 0.000000, 0.176823, 0.353756, 1.818681, 0.528767, 0.705203, 0.888848, 1.072482, 1.266208, 1.463877, 1.655375, 0.167221, 0.000000, 0.338019, 1.837785, 0.508613, 0.683612, 0.865111, 1.052398, 1.256977, 1.462519, 0.151792, 0.000000, 0.305980, 1.666282, 0.463444, 1.857294, 0.835586, 0.646075, 0.133967, 0.000000, 1.014019, 0.264424, 0.816136, 1.246738, 0.395229, - 156 - 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 Andrés Zarabozo Martínez Métodos numéricos 223, 1.194695, 1.469996, 224, 1.215938, 1.677771, 225, 1.069449, 0.718869, 226, 1.228136, 1.877186, 227, 1.072855, 0.892884, 228, 1.032974, 0.522098, 229, 1.000000, 0.000000, 230, 0.993712, 0.111964, 231, 0.974928, 0.222521, 232, 0.985400, 0.800166, 233, 0.993378, 0.940211, 234, 0.943883, 0.330279, 235, 0.956961, 0.619959, 236, 0.984128, 1.042489, 237, 0.900969, 0.433884, 238, 0.908253, 0.880242, 239, 0.881762, 0.709896, 240, 0.968509, 1.486987, 241, 1.000807, 1.700009, 242, 0.918269, 1.240118, 243, 0.846724, 0.532032, 244, 1.025621, 1.897438, 245, 0.843327, 0.974604, 246, 0.802854, 0.795968, 247, 0.781831, 0.623490, 248, 0.751021, 1.088769, 249, 0.723119, 0.883010, 250, 0.707107, 0.707107, 251, 0.791544, 1.730488, 252, 0.755425, 1.532664, 253, 0.820497, 1.917950, 254, 0.700764, 1.331699, 255, 0.623490, 0.781831, 256, 0.628707, 0.961914, 257, 0.608334, 1.168378, 258, 0.532032, 0.846724, 259, 0.513908, 1.024962, 260, 0.592549, 1.751134, 261, 0.556982, 1.567234, 262, 0.615372, 1.938463, 263, 0.516188, 1.380476, 264, 0.433884, 0.900969, 265, 0.460891, 1.216817, 266, 0.395504, 1.069903, 267, 0.330279, 0.943883, 268, 0.369893, 1.582445, 269, 0.340301, 1.404842, 270, 0.392043, 1.770125, 271, 0.304717, 1.245069, 272, 0.410248, 1.958975, 273, 0.264905, 1.100687, 274, 0.222521, 0.974928, 275, 0.152769, 1.257928, 276, 0.132989, 1.115929, 277, 0.168770, 1.423452, 278, 0.111964, 0.993712, 279, 0.182011, 1.598901, 280, 0.195481, 1.787944, 281, 0.205124, 1.979488, 282, 0.000000, 1.000000, 283, 0.000000, 1.118304, 284, 0.000000, 1.261798, 285, 0.000000, 1.432135, 286, 0.000000, 1.621423, 287, 0.000000, 1.810712, 288, 0.000000, 2.000000, 249 ! Number of elements 1,282, 278, 276, 283 2,230, 229, 217, 216 3,278, 274, 273, 276 4,231, 230, 216, 219 5,274, 267, 266, 273 6,234, 231, 219, 222 7,267, 264, 259, 266 8,237, 234, 222, 228 9,264, 258, 256, 259 10,243, 237, 228, 235 - 157 - 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 Andrés Zarabozo Martínez 11,258, 12,247, 13,255, 14,250, 15,284, 16,217, 17,285, 18,209, 19,176, 20,175, 21,167, 22,174, 23,168, 24,173, 25,169, 26,172, 27,170, 28,171, 29,187, 30,199, 31,288, 32,286, 33,287, 34,190, 35,201, 36,213, 37,226, 38,272, 39,244, 40,262, 41,253, 42,219, 43,222, 44,228, 45,275, 46,235, 47,239, 48,246, 49,249, 50,256, 51,259, 52,266, 53,273, 54,277, 55,186, 56,184, 57,183, 58,182, 59,181, 60,180, 61,177, 62,178, 63,208, 64,198, 65,279, 66,280, 67,260, 68,197, 69,251, 70,211, 71,241, 72,224, 73,212, 74,200, 75,191, 76,212, 77,271, 78,268, 79,265, 80,261, 81,196, 82,194, 83,193, 84,192, 85,207, 86,240, 87,223, Métodos numéricos 255, 243, 250, 247, 283, 209, 284, 199, 166, 179, 168, 175, 169, 174, 170, 173, 171, 172, 176, 187, 287, 285, 286, 201, 213, 226, 244, 281, 253, 272, 262, 216, 219, 222, 276, 228, 235, 239, 246, 249, 256, 259, 266, 275, 197, 185, 184, 183, 182, 181, 178, 180, 198, 188, 277, 279, 270, 211, 260, 224, 251, 241, 210, 189, 192, 202, 265, 269, 257, 263, 207, 195, 194, 193, 223, 252, 240, 249, 235, 246, 239, 276, 208, 275, 198, 167, 190, 178, 186, 180, 185, 181, 184, 182, 183, 177, 188, 280, 277, 279, 197, 211, 224, 241, 280, 251, 270, 260, 208, 210, 212, 273, 215, 225, 232, 238, 245, 248, 257, 265, 271, 196, 196, 195, 194, 193, 192, 189, 191, 200, 189, 269, 268, 268, 207, 261, 223, 252, 240, 200, 191, 203, 203, 263, 263, 254, 254, 206, 206, 205, 204, 221, 254, 242, 256 239 249 246 275 216 277 208 177 186 177 185 178 184 180 183 181 182 188 198 281 279 280 186 197 211 224 270 241 260 251 210 212 215 271 225 232 238 245 248 257 265 271 269 185 195 194 193 192 191 188 189 210 200 268 270 261 196 252 207 240 223 202 202 202 215 269 261 263 252 195 205 204 203 206 242 221 - 158 - Andrés Zarabozo Martínez Métodos numéricos 88,254, 257, 248, 242 89,245, 238, 233, 236 90,238, 232, 227, 233 91,232, 225, 220, 227 92,220, 225, 215, 214 93,204, 214, 215, 203 94,248, 245, 236, 242 95,233, 227, 218, 236 96,227, 220, 214, 218 97,214, 204, 205, 218 98,205, 206, 221, 218 99,221, 242, 236, 218 100,2, 10, 9, 1 101,3, 12, 10, 2 102,4, 13, 12, 3 103,5, 15, 13, 4 104,6, 16, 15, 5 105,7, 18, 16, 6 106,8, 19, 18, 7 107,11, 20, 19, 8 108,14, 21, 20, 11 109,17, 22, 21, 14 110,10, 24, 23, 9 111,12, 25, 24, 10 112,13, 26, 25, 12 113,15, 27, 26, 13 114,16, 28, 27, 15 115,18, 29, 28, 16 116,19, 30, 29, 18 117,20, 31, 30, 19 118,21, 32, 31, 20 119,22, 33, 32, 21 120,24, 35, 34, 23 121,25, 36, 35, 24 122,26, 37, 36, 25 123,27, 38, 37, 26 124,28, 39, 38, 27 125,29, 40, 39, 28 126,30, 41, 40, 29 127,31, 42, 41, 30 128,32, 43, 42, 31 129,33, 44, 43, 32 130,35, 46, 45, 34 131,36, 47, 46, 35 132,37, 48, 47, 36 133,38, 49, 48, 37 134,39, 50, 49, 38 135,40, 51, 50, 39 136,41, 52, 51, 40 137,42, 53, 52, 41 138,43, 54, 53, 42 139,44, 55, 54, 43 140,46, 57, 56, 45 141,47, 58, 57, 46 142,48, 59, 58, 47 143,49, 60, 59, 48 144,50, 61, 60, 49 145,51, 62, 61, 50 146,52, 63, 62, 51 147,53, 64, 63, 52 148,54, 65, 64, 53 149,55, 66, 65, 54 150,57, 68, 67, 56 151,58, 69, 68, 57 152,59, 70, 69, 58 153,60, 71, 70, 59 154,61, 72, 71, 60 155,62, 73, 72, 61 156,63, 74, 73, 62 157,64, 75, 74, 63 158,65, 76, 75, 64 159,66, 77, 76, 65 160,68, 79, 78, 67 161,69, 80, 79, 68 162,70, 81, 80, 69 163,71, 82, 81, 70 164,72, 83, 82, 71 - 159 - Andrés Zarabozo Martínez Métodos numéricos 165,73, 84, 83, 72 166,74, 85, 84, 73 167,75, 86, 85, 74 168,76, 87, 86, 75 169,77, 88, 87, 76 170,79, 90, 89, 78 171,80, 91, 90, 79 172,81, 92, 91, 80 173,82, 93, 92, 81 174,83, 94, 93, 82 175,84, 95, 94, 83 176,85, 96, 95, 84 177,86, 97, 96, 85 178,87, 98, 97, 86 179,88, 99, 98, 87 180,90, 101, 100, 89 181,91, 102, 101, 90 182,92, 103, 102, 91 183,93, 104, 103, 92 184,94, 105, 104, 93 185,95, 106, 105, 94 186,96, 107, 106, 95 187,97, 108, 107, 96 188,98, 109, 108, 97 189,99, 110, 109, 98 190,101, 112, 111, 100 191,102, 113, 112, 101 192,103, 114, 113, 102 193,104, 115, 114, 103 194,105, 116, 115, 104 195,106, 117, 116, 105 196,107, 118, 117, 106 197,108, 119, 118, 107 198,109, 120, 119, 108 199,110, 121, 120, 109 200,112, 123, 122, 111 201,113, 124, 123, 112 202,114, 125, 124, 113 203,115, 126, 125, 114 204,116, 127, 126, 115 205,117, 128, 127, 116 206,118, 129, 128, 117 207,119, 130, 129, 118 208,120, 131, 130, 119 209,121, 132, 131, 120 210,123, 134, 133, 122 211,124, 135, 134, 123 212,125, 136, 135, 124 213,126, 137, 136, 125 214,127, 138, 137, 126 215,128, 139, 138, 127 216,129, 140, 139, 128 217,130, 141, 140, 129 218,131, 142, 141, 130 219,132, 143, 142, 131 220,134, 145, 144, 133 221,135, 146, 145, 134 222,136, 147, 146, 135 223,137, 148, 147, 136 224,138, 149, 148, 137 225,139, 150, 149, 138 226,140, 151, 150, 139 227,141, 152, 151, 140 228,142, 153, 152, 141 229,143, 154, 153, 142 230,145, 156, 155, 144 231,146, 157, 156, 145 232,147, 158, 157, 146 233,148, 159, 158, 147 234,149, 160, 159, 148 235,150, 161, 160, 149 236,151, 162, 161, 150 237,152, 163, 162, 151 238,153, 164, 163, 152 239,154, 165, 164, 153 240,156, 167, 166, 155 241,157, 168, 167, 156 - 160 - Andrés Zarabozo Martínez Métodos numéricos 242,158, 169, 168, 157 243,159, 170, 169, 158 244,160, 171, 170, 159 245,161, 172, 171, 160 246,162, 173, 172, 161 247,163, 174, 173, 162 248,164, 175, 174, 163 249,165, 179, 175, 164 34 ! Number of radiating faces 1, 179,190 2, 281,288 3, 190,201 4, 201,213 5, 213,226 6, 226,244 7, 272,281 8, 244,253 9, 262,272 10, 253,262 11, 1,2 12, 2,3 13, 3,4 14, 4,5 15, 5,6 16, 6,7 17, 7,8 18, 8,11 19, 11,14 20, 17,22 21, 22,33 22, 33,44 23, 44,55 24, 55,66 25, 66,77 26, 77,88 27, 88,99 28, 99,110 29, 110,121 30, 121,132 31, 132,143 32, 143,154 33, 154,165 34, 165,179 15 ! Number of fixed temperature nodes 1, 229 2, 230 3, 231 4, 234 5, 237 6, 243 7, 247 8, 250 9, 255 10, 258 11, 264 12, 267 13, 274 14, 278 15, 282 - 161 -