1 // vim: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab:
3 // Trabajo Práctico II de Análisis Numérico I
4 // Este programa resuelve un sistema de ecuaciones diferenciales
5 // resultante de un problema físico de oscilación de líquidos.
6 // Copyright (C) 2002 Leandro Lucarella <leandro@lucarella.com.ar>
8 // Este programa es Software Libre; usted puede redistribuirlo
9 // y/o modificarlo bajo los términos de la "GNU General Public
10 // License" como lo publica la "FSF Free Software Foundation",
11 // o (a su elección) de cualquier versión posterior.
13 // Este programa es distribuido con la esperanza de que le será
14 // útil, pero SIN NINGUNA GARANTIA; incluso sin la garantía
15 // implícita por el MERCADEO o EJERCICIO DE ALGUN PROPOSITO en
16 // particular. Vea la "GNU General Public License" para más
19 // Usted debe haber recibido una copia de la "GNU General Public
20 // License" junto con este programa, si no, escriba a la "FSF
21 // Free Software Foundation, Inc.", 59 Temple Place - Suite 330,
22 // Boston, MA 02111-1307, USA.
24 // $URL: http://www.llucax.hn.org:81/svn/facultad/75.12/tp2/77891.cpp $
25 // $Date: 2002-11-24 02:48:38 -0300 (dom, 24 nov 2002) $
35 typedef unsigned int Indice;
38 typedef Numero (*Friccion)( Datos&, Numero, Numero );
39 typedef Numero (*Funcion)( Datos&, Numero, Numero, Numero );
40 typedef void (*Metodo)( Datos& );
42 Numero to; // Tiempo inicial
43 Numero tf; // Tiempo final
45 Numero xo; // X inicial = X(to) = Z(to)
46 Numero yo; // Y inicial = Y(to) = X'(to) = Z'(to)
47 Numero D; // Diametro del tubo
48 Numero n; // Viscosidad cinemática del líquido
49 Numero g; // Aceleración de la gravedad
50 Numero f; // Factor de fricción
51 Numero L; // Longitud del tubo
52 Numero Le; // Factor de pérdida de carga
53 Numero G; // Factor geométrico
54 Funcion fx; // Función asociada a la derivada de x
55 Funcion fy; // Función asociada a la derivada de y
56 Friccion fi; // Factor asociado a pérdidas por fricción
59 // Factor de fricción nulo.
60 Numero friccionNula( Datos&, Numero, Numero );
62 // Factor de fricción laminar.
63 Numero friccionLaminar( Datos&, Numero, Numero );
65 // Factor de fricción turbulenta.
66 Numero friccionTurbulenta( Datos&, Numero, Numero );
68 // Factor de fricción turbulenta (con depósitos).
69 Numero friccionTurbulentaConDepositos( Datos&, Numero, Numero );
71 // Función asociada a la primera derivada (x'=z').
72 Numero funcionX( Datos&, Numero, Numero, Numero );
74 // Función asociada a la segunda derivada (y'=x''=z'').
75 Numero funcionY( Datos&, Numero, Numero, Numero );
77 // Calcula la ecuación diferencial por el método de Euler.
80 // Calcula la ecuación diferencial por el método de Runge-Kutta de órden 4.
83 // Calcula la ecuación diferencial por el método de Nystrom.
84 void nystrom( Datos& );
87 const Numero DEFAULT_N = 1000, // Cantidad de pasos por defecto
90 DEFAULT_xo = 2.9866369,
99 const Funcion DEFAULT_fx = &funcionX,
100 DEFAULT_fy = &funcionY;
101 const Friccion DEFAULT_fi = &friccionNula;
103 int main( int argc, char* argv[] ) {
105 // Se fija que tenga los argumentos necesarios para correr.
107 cerr << "Faltan argumentos. Modo de uso:" << endl;
108 cerr << "\t" << argv[0] << " método fi G tf N to xo yo D n g f L Le" << endl;
109 cerr << "Desde fi en adelante son opcionales. Los valores por defecto son:" << endl;
110 cerr << "\tfi = n" << endl;
111 cerr << "\tG = " << DEFAULT_G << endl;
112 cerr << "\ttf = " << DEFAULT_tf << endl;
113 cerr << "\tN = " << DEFAULT_N << endl;
114 cerr << "\tto = " << DEFAULT_to << endl;
115 cerr << "\txo = " << DEFAULT_xo << endl;
116 cerr << "\tyo = " << DEFAULT_yo << endl;
117 cerr << "\tD = " << DEFAULT_D << endl;
118 cerr << "\tn = " << DEFAULT_n << endl;
119 cerr << "\tg = " << DEFAULT_g << endl;
120 cerr << "\tf = " << DEFAULT_f << endl;
121 cerr << "\tL = " << DEFAULT_L << endl;
122 cerr << "\tLe = " << DEFAULT_Le << endl;
126 // Selecciona el método deseado.
127 Metodo metodo = NULL;
128 switch ( char( argv[1][0] ) ) {
139 cerr << "Debe especificar un método válido:" << endl;
140 cerr << "\te: Euler" << endl;
141 cerr << "\tr: Runge-Kutta 4" << endl;
142 cerr << "\tn: Nystrom" << endl;
146 // Se inicializan los datos.
147 Numero N = DEFAULT_N;
151 D.k = ( D.tf - D.to ) / N;
165 // Si se pasaron datos como argumento, se los va agregando.
167 case 15: D.Le = Numero( atof( argv[14] ) );
168 case 14: D.L = Numero( atof( argv[13] ) );
169 case 13: D.f = Numero( atof( argv[12] ) );
170 case 12: D.g = Numero( atof( argv[11] ) );
171 case 11: D.n = Numero( atof( argv[10] ) );
172 case 10: D.D = Numero( atof( argv[9] ) );
173 case 9: D.yo = Numero( atof( argv[8] ) );
174 case 8: D.xo = Numero( atof( argv[7] ) );
175 case 7: D.to = Numero( atof( argv[6] ) );
176 case 6: N = Numero( atof( argv[5] ) );
177 case 5: D.tf = Numero( atof( argv[4] ) );
178 // Se recalcula el paso (k) si se cambio to, N o tf.
179 D.k = ( D.tf - D.to ) / N;
180 case 4: D.G = Numero( atof( argv[3] ) );
181 case 3: switch ( char( argv[2][0] ) ) { // Tipo de fricción
183 D.fi = &friccionNula;
186 D.fi = &friccionLaminar;
189 D.fi = &friccionTurbulenta;
192 D.fi = &friccionTurbulentaConDepositos;
195 cerr << "Debe especificar un tipo de fricción válido:" << endl;
196 cerr << "\tn: Nula" << endl;
197 cerr << "\tl: Laminar" << endl;
198 cerr << "\tt: Turbulenta" << endl;
199 cerr << "\td: Turbulenta (con depósitos)" << endl;
204 // Imprime el paso utilizado.
205 cerr << "Paso k = " << D.k << endl;
207 // Ejecuta el método correspondiente con los datos correspondientes.
214 Numero friccionNula( Datos& D, Numero x, Numero y ) {
220 Numero friccionLaminar( Datos& D, Numero x, Numero y ) {
222 return 32 * D.n / ( D.D * D.D );
226 Numero friccionTurbulenta( Datos& D, Numero x, Numero y ) {
228 return D.f * fabs( y ) / ( 2 * D.D );
232 Numero friccionTurbulentaConDepositos( Datos& D, Numero x, Numero y ) {
234 return D.f * fabs( y ) * D.Le / ( 2 * D.D * D.L);
238 Numero funcionX( Datos& D, Numero t, Numero x, Numero y ) {
244 Numero funcionY( Datos& D, Numero t, Numero x, Numero y ) {
246 return - D.fi( D, x, y ) * y - D.g * D.G * x / D.L;
250 void euler( Datos& D ) {
260 // Calculo los datos para este punto.
261 x = xo + D.k * D.fx( D, t, xo, yo );
262 y = yo + D.k * D.fy( D, t, xo, yo );
264 // Imprimo resultados.
265 cout << t << " " << x << " " << y << endl;
267 // Reemplazo valores iniciales.
276 void rk4( Datos& D ) {
291 // Imprimo datos iniciales.
292 cout << t << " " << x << " " << y << endl;
296 // Calculo los datos para este punto.
297 qx1 = D.k * D.fx( D, t, x, y );
298 qy1 = D.k * D.fy( D, t, x, y );
300 qx2 = D.k * D.fx( D, t + D.k / 2.0, x + qx1 / 2.0, y + qy1 / 2.0 );
301 qy2 = D.k * D.fy( D, t + D.k / 2.0, x + qx1 / 2.0, y + qy1 / 2.0 );
303 qx3 = D.k * D.fx( D, t + D.k / 2.0, x + qx2 / 2.0, y + qy2 / 2.0 );
304 qy3 = D.k * D.fy( D, t + D.k / 2.0, x + qx2 / 2.0, y + qy2 / 2.0 );
306 qx4 = D.k * D.fx( D, t + D.k, x + qx3, y + qy3 );
307 qy4 = D.k * D.fy( D, t + D.k, x + qx3, y + qy3 );
309 x += unSexto * ( qx1 + 2 * qx2 + 2 * qx3 + qx4 );
310 y += unSexto * ( qy1 + 2 * qy2 + 2 * qy3 + qy4 );
313 // Imprimo resultados.
314 cout << t << " " << x << " " << y << endl;
320 void nystrom( Datos& D ) {
322 Numero gGk2_L = D.g * D.G * D.k * D.k / D.L,
324 x1 = ( 1 - gGk2_L * 0.5 ) * D.xo,
330 // Imprimo valores iniciales.
331 cout << t << " " << xo << " " << y << endl;
332 y = ( x1 - xo ) / D.k;
333 cout << t << " " << x1 << " " << y << endl;
337 // Calculo los datos para este punto.
338 fi = D.fi( D, x1, y );
339 x2 = ( ( fi - 1 ) * xo + ( 2 - gGk2_L ) * x1 ) / ( fi + 1 );
341 // Prepara para próxima iteración
345 y = ( x1 - xo ) / D.k;
347 // Imprimo resultados.
348 cout << t << " " << x2 << " " << y << endl;