Está en la página 1de 7

Test de convergencia para el desarrollo en serie de un potencial electrostático

Enrico Bandiello
(Dated: 03/04/2010)
En este ejercicio vamos a ver cómo se comporta, en relación a la convergencia, el desarrollo en
serie de un potencial electrostático bidimensional (es decir, que sólo depende de dos coordenadas).
Para el estudio de dicho potencial se usará un programa en C++ escrito a propósito. El potencial
se evaluará en un grid de 100 × 100 puntos. En primer lugar se averiguarán los lı́mites de cálculo
debidos a los errores de overflow, luego se estudiará la convergencia puntual de la serie que define
el potencial y, en fin, se dibujará el potencial, utilizando los datos de las análisis anteriores.

Desde ahora en adelante se indicarà con Φn (x, y) el


término n−esimo de la suma en (1), es decir:

4 V (−1)n
Φn (x, y) := cos(kxn x) sinh(kxn y) (2)
akxn sinh(kxn b/2)

II. LÍMITES DE CÁLCULO

Para calcular el potencial se ha escrito un programa en


lenguaje C++ en el que se calcula el potencial definido
Figura 1. El sistema bajo examen
por (1) en puntos varios puntos del dominio D. En parti-
cular, se ha genderado un en un grid de 100×100 puntos,
I. EL PROBLEMA
para poder obtener una buena resolución. El uso del len-
guaje C++ se debe al hecho que proporciona una enorme
velocidad de cálculo, que es importante cuando se deben
Estudiamos un potencial electrostático Φ(x, y) en una elaborar datos mediante procedimentos iterativos.
cavidad de sección rectangular que es infinita en una di- El problema principal en este tipo de elaboraciones es
rección (que se considerará como eje z en un oportuno que el C++ limitadas para tratar con números demasia-
sistema de referencia). do pequeños (errores de redondeo) o demasiado grandes
Sean a = 1 m y b = 0.5 m las dimensiones transversales (errores de overflow ). En nuestro caso el problema era
de la cavidad; ponemos un sistema de refencia que tenga exactamente de overflow, ya que los términos Φn (x, y)
los ejes x e y paralelos a las paredes y con origen en contienen funciones seno hiperbólico, cuyo crecimiento es
el centro geométrico de la sección transversal, como la exponencial para valores grande del argumento; es decir
Figura (1). que al crecer el valor del n se llega a un punto en el que
Las paredes en x = ±a/2 están a potencial V = 0 V las funciones sinh() alcanzan valores tan grandes que no
mientras que las paredes en y = ±b/2 están a poten- pueden ser contenidos en las variables que se utilizan.2
cial V = ±10 V. El potencial electrostático en la zona En estos casos el compilador asigna a las variables el valor
que estamos considerando obviamente non depende de la NaN, es decir “Not A Number ”).
coordenada z, sino sólo de las coordenadas x e y y su Para poder superar en parte este problema se ha hecho
forma analı́tica es: lo siguiente: por cada punto (x, y) del grid se han calcu-
lado los Φn (x, y) partiendo de n = 0 hasta un nmax (x, y),
∞ diferente por cada pareja (x, y), que representa el núme-
X 4 V (−1)n
Φ(x, y) := cos(kxn x) sinh(kxn y) ro más elevado de iteraciones que está permitido sin que
n=0
akxn sinh(kxn b/2) Φn (x, y) se vuelva NaN. Luego se ha representado la fun-
(1) ción nmax (x, y) (Figura 2). Se ve que en algunos puntos el
con overflow se alcanza de forma más rápida, mientras que en
π
kxn = (2n + 1)
2
La función Φ(x, y) queda definida en un dominio D con por construcción, Φ(x, y) deberı́a tener dos valores diferentes.
forma de un rectángulo de lados a y b pero sin vértices.1 Estamos evidentemente considerando un caso ideal, en el que
Φ(x, y) no es continua. En los cálculos se han evitado por lo
tanto los puntos (±0.50, ±0.25).
2 De hecho, el valor más grande que se puede almacenar en una
variable de tipo double es ≈ 1.8 · 10+308 , para el compilador
1 El dominio D no incluye los vértices del rectángulo en los que, utilizado, GNU g++ versión 4.4.
2

Figura 2. Número máximo de iteraciones por cada punto Figura 3. Número de iteraciones necesarios para alcanzar, en
(x,y). cada punto (x, y), una precisión de 0.001 V.

otros se puede seguir sumando prácticamente ad libitum,


como los del segmento y = 0 en los que todos los términos
de la suma son obviamente nulos; por esta razón se ha
puesto de toda forma un lı́mite máximo a las iteraciones,
que en el caso de la Figura 2 es de 104 .
Ahora, nos interesa es buscar el máximo número de ite-
raciones que consigan darnos un resultado útil en todo el
dominio de la función Φ(x, y); este número es obviamente
el mı́nimo de los valores de nmax (x, y) en la gráfica de Fi-
gura 2, que numericamente ha resultado ser nmax = 449;
dicho en otras palabras, cualquiera sea el punto (x, y)
podemos sumar hasta 449 términos en la función (1) sin
Figura 4. Gráfico de la función ∆ (x, y).
tener un overflow.
Se puede notar en este caso la simetrı́a del problema: el
número máximo de iteraciones sólo depende de la coor-
Una cosa que se ha notado ha sido que la convergencia
denada y y no de la x, como se podı́a esperar.
de la serie (1) es puntual pero no es uniforme, es decir
que, fijado un  > 0 no existe un n? tal que
III. ESTUDIO DE LA CONVERGENCIA n
X


Φj − |Φ| <  ∀n > n? (4)


La segunda operación que se ha efectuado ha sido un
j=0


estudio de la convergencia: se ha fijado una precisión ar-
bitraria  = 0.001V y, por cada punto del grid, se ha en la que k · k∞ es la norma uniforme. La (4) indica
calculado cuántas iteraciones n (x, y) hacı́an falta para que la convergencia depende del punto (x, y) en el que se
que calcula la serie. Como consecuencia, dado que podemos
sumar sólo hasta un número de términos nmax en (2), es
|Φn +1 (x, y)| − |Φn (x, y)| <  (3) que en algunos puntos (x, y) sı́ será satisfecha la (3), pero
también será
Donde los módulos se usan porque la serie es de signo
alternado. n

Los resultados se presentan en la Figura (3), en el que X
∆ (x, y) = Φn (x, y) − |Φ(x, y)| >  (5)

se representa la función n (x, y).
Un procedimiento alternativo hubiera sido fijar uno n=0

(o más) puntos y determinar cómo variaba el potencial


en función del número de términos que ı́bamos suman- Ésto pasa sobre todo cerca de los vértices que hemos
do, pero eso sólo hubiera proporcionado una información quitado del dominio, como se ve en la Figura 3, en la que
parcial, mientras que con el procedimiento que hemos se ha representado la función ∆ (x, y). Por lo tanto, no
adoptado se ve enseguida cómo se comporta el potencial se podrá representar uniformemente el potencial con una
Φ(x, y) en todo el dominio. precisión prefijada, sino sólo hasta una número prefijado
Numéricamente, se ve que el número de iteraciones ne- de términos en (2), por lo menos con el procedimiento
cesarias varı́a desde 0 (para los puntos del tipo (x, 0)) has- sencillo que hemos adoptado.
ta 99 para algunos puntos del tipo (x, ±0.25). Otra vez
se puede notar la simetrı́a de la situación, exactamente
como en el párrafo anterior.
3

1. El número de términos necesarios para alcanzar la


precisión  requerida, según la ecuación (3); se gene-
ra el fichero convergence.dat usado para dibujar
el gráfico en Figura (3).
2. El valor de Φ(x, n) hasta el órden más alto per-
mitido (nmax ), según la expresión (2); se genera el
fichero graph.dat usado para dibujar el gráfico en
Figura (5).
3. El valor de ∆ (x, y), según la expresión (5); se ge-
Figura 5. Aspecto final del potencial. nera el fichero graphcon.dat usado para dibujar el
gráfico de Figura 4.
En la última parte de la memoria se include el códi-
IV. CÁLCULO DE LA FORMA DEL
go fuente. El programa se puede fácilmente adaptar para
POTENCIAL
calcular diferentes potenciales bidimensionale expresados
como suma de una serie, haciendo los cambios oportunos
Como última tarea, se ha dibujado el potencial uti- en la función term() y eventualmente en el número máxi-
lizando el número máximo de iteraciones permitidos mo de iteraciones.
nmax = 449 y el resultado se puede ver en la Figura 5.
Obviamente el resultado es par en x e impar en y como
se esperaba y (a parte las aproximaciones numéricas) se
ve que las condiciones de contorno estás satisfechas:

Φ(±a/2, y) = 0 V
Φ(x, ±b/2) = ±10 V

por cada (x, y) ∈ D, por lo que se puede concluir que


el procedimiento adoptado es sostancialmente correcto,
aunque resultados numéricamente mejores se pueden ob-
tener utilizando librerı́as especializadas de funciones que
permitan trabajar con números de precisión arbitraria.

V. EL PROGRAMA

El programa en C++ que se ha escrito está constituido,


basicamente, por tres partes diferentes, cada una con su
función especı́fica
En la primera parte se definen las funciones que se han
utilizado; la primera de ellas, term(), calcula el término
general de orden i de la serie (2) por un punto (x, y),
la segunda función, overflow(), dado un punto (x, y),
restituie el máximo orden al que se puede llegar en cal-
cular los términos Φn (x, y) antes de que se vuelvan NaN
y la tercera función, sumpart() calcula la suma parcial
para la expresión hasta el orden n para un punto (x, y),
utlizando a su vez la función term().
En la segunda parte del programa se hace un barrido
del dominio D (evitando los vértices, como se ha dicho),
para calcular el número máximo de iteraciones permiti-
das en cada punto (x, y). Los resultados se escriben en un
fichero con nombre maxiter.dat y se usan para dibujar
el gráfico en la Figura 2.
En la tercera y última parte del programa se calcula
por cada punto (x, y):
4

VI. CÓDIGO FUENTE DEL PROGRAMA

// This program is free software: you can redistribute it and/or modify


// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright 2010 Enrico Bandiello

#include<cmath>
#include<iostream>
#include<fstream>
#include<iomanip>
#define PI 3.141592653589793
#define V 10.0
#define A 1.0
#define B 0.5
using namespace std;

/* This function calculates the i-th therm of the partial sum


* for the (x,y) point.
*/

inline double term(double x, double y, unsigned int i)


{

double k=0.0;

k=(PI/A)*(2*i+1);
return (cos(k*x)*sinh(k*y)*4.0*V*pow(-1.0,i))/(A*k*sinh(k*(B/2)));
}

/*
* This function is used to check the maximum number of iterations
* allowed before the sum goes overflow
*/

inline unsigned int overflow(double x, double y, unsigned int maxiter)


{

unsigned int i=0;

while(!isnan(term(x,y,i)) && i<maxiter+1)


{
i+=1;
}

return i-1;
}
5

/*
* The following function calculates partial sums up for phi
* to up "n" terms in the (x,y) point.
*/

inline double sumpart(double x, double y, unsigned int n)


{

double phi=0.0;
unsigned int i=0;

while(i<n+1)
{

phi+=term(x,y,i);
i+=1;

}
return phi;
}

int main()
{
// This file contains graph data
ofstream graph("graph.dat");

// This file contains data on convergence


ofstream convergence("convergence.dat");

// This file contains data on max number of iterations


ofstream maxiter("maxiter.dat");

// This file contains data on delta


ofstream graphcon("graphcon.dat");

graph.precision(6);
convergence.precision(6);

cout<<"\n*** Step 1: Checking the maximum number of iterations ***\n";


cout<<"\n\nHere we check, for heach point, the maximum number of"<<
"iterations that";
cout<<"\nis allowed before the value goes NaN (overflow)";

int n;

do
{
cout<<"\n\nPlease, input the highest number of iterations that"
<<"will be used in calulation (0<n<10001): ";
cin>>n;
} while(n<1 || n>10000);

/*
* Here we have to check that we’re not calculating th ES
* potential in the vertices of the rectangle, because there it’s
* undefined. So we have to put some constraints. Due to the
* unreliability of abs(), or fabs() functions when used to *compare*
* types other than integers; so, instead of simply comparing
6

* coordinates, we compare two integers (namely, ix & iy) that we


* subsequently use to compute the needed coordinates. This way, it
* works pretty well and with no unnecessary if...then checks, that
* surely will slow down the while() cycle.
*/

// Drawing the graph. We use a 100x100 grid in the XY plane


const double pasox=1.0/100;
const double pasoy=0.5/100;

double x=0;
double y=0;

unsigned int maxallowed=n;


double of;

// Skipping first point (-0.50,-025


int ix=-50,iy=-49;)

while(ix<51)
{

/*
* iy goes up to 50 *only if* fabs(ix)< 50;
* if fabs(ix)=50 then iy stops at -49;
*/

while(iy<50+(fabs(ix)!=50))
{

x=ix*pasox;
y=iy*pasoy;

of=overflow(x,y,n);

maxallowed<of?:maxallowed=of;

maxiter<<x<<"\t"<<y<<"\t"<<of<<"\n";

iy+=1;
}

ix+=1;

iy=-50+(fabs(ix)==50);

/*
* Back to the lowest value compatible with ix.
* iy goes down to 50 *only if* fabs(ix)<50;
* if fabs(ix)=50 then iy stops at -49
*/

maxiter.close();
cout<<"\nMax allowed iterations: "<<maxallowed;
cout<<"\nData for each point is in the file \"maxiter.dat\".";
cout<<"\n\n*** Step 2: Generating graphs ***\n";
7

cout<<"1. \"maxiter.dat\": maximum number of allowed iterations for"


<<"each point.";
cout<<"\n2. \"convergence.dat\": number of iterations for each point"
<<"to reach 0.001 V precision.";
cout<<"\n3. \"graphcon.dat\": diference between expected Phi(x,y) "
<<"and sum(Phi_n (x,y)).";
cout<<"\n4. \"graph.dat\": data to draw the potential (up to "
<<maxallowed<<" iterations for each point...)\n\n";

unsigned int numiter=0;

x=0;
y=0;
ix=-50;
iy=-49;

// epsilon = precision
double epsilon=0.001;
double deltav=0;

while(ix<51)
{

while(iy<50+(fabs(ix)!=50))
{

x=ix*pasox;
y=iy*pasoy;

numiter=0;

// check if deltav < epsilon

while((deltav=fabs(fabs(term(x,y,numiter+1))-fabs(term(x,y,numiter))))>epsilon)
{
numiter=numiter+1;
}

convergence<<x<<"\t"<<y<<"\t"<<numiter<<"\t"<<"\n";
graph<<x<<"\t"<<y<<"\t"<<sumpart(x,y,maxallowed)<<"\n";
graphcon<<x
<<"\t"
<<y<<"\t"
<<fabs(fabs(sumpart(x,y,maxallowed))-fabs(sumpart(x,y,numiter)))<<"\n";

iy+=1;

}
ix+=1;
iy=-50+(fabs(ix)==50);

}
convergence.close();
graph.close();
graphcon.close();

return 0;
}

También podría gustarte