LORENE
poisson_ylm.C
1 /*
2  * Method of Non_class_members for solving Poisson equations
3  * with a multipole falloff condition at the outer boundary
4  *
5  */
6 
7 /*
8  * Copyright (c) 2004 Joshua A. Faber
9  *
10  * This file is part of LORENE.
11  *
12  * LORENE is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2
14  * as published by the Free Software Foundation.
15  *
16  * LORENE is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with LORENE; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  */
26 
27 
28 
29 /*
30  * $Id: poisson_ylm.C,v 1.4 2016/12/05 16:18:10 j_novak Exp $
31  * $Log: poisson_ylm.C,v $
32  * Revision 1.4 2016/12/05 16:18:10 j_novak
33  * Suppression of some global variables (file names, loch, ...) to prevent redefinitions
34  *
35  * Revision 1.3 2014/10/13 08:53:30 j_novak
36  * Lorene classes and functions now belong to the namespace Lorene.
37  *
38  * Revision 1.2 2014/10/06 15:16:09 j_novak
39  * Modified #include directives to use c++ syntax.
40  *
41  * Revision 1.1 2004/12/29 16:32:02 k_taniguchi
42  * *** empty log message ***
43  *
44  *
45  * $Header: /cvsroot/Lorene/C++/Source/Non_class_members/PDE/poisson_ylm.C,v 1.4 2016/12/05 16:18:10 j_novak Exp $
46  *
47  */
48 
49 // C headers
50 #include <cstdlib>
51 #include <cmath>
52 
53 // Lorene headers
54 #include "matrice.h"
55 #include "tbl.h"
56 #include "mtbl_cf.h"
57 #include "map.h"
58 #include "base_val.h"
59 #include "proto.h"
60 #include "type_parite.h"
61 
62 
63 
64  //----------------------------------------------
65  // Version Mtbl_cf
66  //----------------------------------------------
67 
68 /*
69  *
70  * Solution de l'equation de poisson
71  *
72  * Entree : mapping : le mapping affine
73  * source : les coefficients de la source qui a ete multipliee par
74  * r^4 ou r^2 dans la ZEC.
75  * La base de decomposition doit etre Ylm
76  * k_ylm: exponent in radial dependence of field: phi \propto r^{-k}
77  * Sortie : renvoie les coefficients de la solution dans la meme base de
78  * decomposition (a savoir Ylm)
79  *
80  */
81 
82 
83 
84 namespace Lorene {
85 Mtbl_cf sol_poisson_ylm(const Map_af& mapping, const Mtbl_cf& source, const int nylm, const double* intvec)
86 {
87 
88  // Verifications d'usage sur les zones
89  int nz = source.get_mg()->get_nzone() ;
90  assert (nz>1) ;
91  assert (source.get_mg()->get_type_r(0) == RARE) ;
92  // assert (source.get_mg()->get_type_r(nz-1) == UNSURR) ;
93  for (int l=1 ; l<nz ; l++)
94  assert(source.get_mg()->get_type_r(l) == FIN) ;
95 
96  // assert ((dzpuis==4) || (dzpuis==2) || (dzpuis==3)) ;
97 
98 
99  // Bases spectrales
100  const Base_val& base = source.base ;
101 
102  // donnees sur la zone
103  int nr, nt, np ;
104  int base_r ;
105  double alpha, beta, echelle ;
106  int l_quant, m_quant;
107 
108  //Rangement des valeurs intermediaires
109  Tbl *so ;
110  Tbl *sol_hom ;
111  Tbl *sol_part ;
112  Matrice *operateur ;
113  Matrice *nondege ;
114 
115 
116  // Rangement des solutions, avant raccordement
117  Mtbl_cf solution_part(source.get_mg(), base) ;
118  Mtbl_cf solution_hom_un(source.get_mg(), base) ;
119  Mtbl_cf solution_hom_deux(source.get_mg(), base) ;
120  Mtbl_cf resultat(source.get_mg(), base) ;
121 
122  solution_part.set_etat_qcq() ;
123  solution_hom_un.set_etat_qcq() ;
124  solution_hom_deux.set_etat_qcq() ;
125  resultat.set_etat_qcq() ;
126 
127  for (int l=0 ; l<nz ; l++) {
128  solution_part.t[l]->set_etat_qcq() ;
129  solution_hom_un.t[l]->set_etat_qcq() ;
130  solution_hom_deux.t[l]->set_etat_qcq() ;
131  resultat.t[l]->set_etat_qcq() ;
132  for (int k=0 ; k<source.get_mg()->get_np(l)+2 ; k++)
133  for (int j=0 ; j<source.get_mg()->get_nt(l) ; j++)
134  for (int i=0 ; i<source.get_mg()->get_nr(l) ; i++)
135  resultat.set(l, k, j, i) = 0 ;
136  }
137 
138  // nbre maximum de point en theta et en phi :
139  int np_max, nt_max ;
140 
141  //---------------
142  //-- NOYAU -----
143  //---------------
144 
145  nr = source.get_mg()->get_nr(0) ;
146  nt = source.get_mg()->get_nt(0) ;
147  np = source.get_mg()->get_np(0) ;
148 
149  nt_max = nt ;
150  np_max = np ;
151 
152  alpha = mapping.get_alpha()[0] ;
153  beta = mapping.get_beta()[0] ;
154 
155  for (int k=0 ; k<np+1 ; k++)
156  for (int j=0 ; j<nt ; j++)
157  if (nullite_plm(j, nt, k, np, base) == 1)
158  {
159  // calcul des nombres quantiques :
160  donne_lm(nz, 0, j, k, base, m_quant, l_quant, base_r) ;
161 
162  // Construction operateur
163  operateur = new Matrice(laplacien_mat(nr, l_quant, 0., 0, base_r)) ;
164  (*operateur) = combinaison(*operateur, l_quant, 0., 0, base_r) ;
165 
166  //Operateur inversible
167  nondege = new Matrice(prepa_nondege(*operateur, l_quant, 0., 0, base_r)) ;
168 
169  // Calcul de la SH
170  sol_hom = new Tbl(solh(nr, l_quant, 0., base_r)) ;
171 
172  //Calcul de la SP
173  so = new Tbl(nr) ;
174  so->set_etat_qcq() ;
175  for (int i=0 ; i<nr ; i++)
176  so->set(i) = source(0, k, j, i) ;
177 
178  sol_part = new Tbl(solp(*operateur, *nondege, alpha, beta,
179  *so, 0, base_r)) ;
180 
181  // Rangement dans les tableaux globaux ;
182 
183  for (int i=0 ; i<nr ; i++) {
184  solution_part.set(0, k, j, i) = (*sol_part)(i) ;
185  solution_hom_un.set(0, k, j, i) = (*sol_hom)(i) ;
186  solution_hom_deux.set(0, k, j, i) = 0. ;
187  }
188 
189 
190 
191  delete operateur ;
192  delete nondege ;
193  delete so ;
194  delete sol_hom ;
195  delete sol_part ;
196  }
197 
198 
199 
200  //---------------
201  //- COQUILLES ---
202  //---------------
203 
204  for (int zone=1 ; zone<nz ; zone++) {
205  nr = source.get_mg()->get_nr(zone) ;
206  nt = source.get_mg()->get_nt(zone) ;
207  np = source.get_mg()->get_np(zone) ;
208 
209  if (np > np_max) np_max = np ;
210  if (nt > nt_max) nt_max = nt ;
211 
212  alpha = mapping.get_alpha()[zone] ;
213  beta = mapping.get_beta()[zone] ;
214 
215  for (int k=0 ; k<np+1 ; k++)
216  for (int j=0 ; j<nt ; j++)
217  if (nullite_plm(j, nt, k, np, base) == 1)
218  {
219  // calcul des nombres quantiques :
220  donne_lm(nz, zone, j, k, base, m_quant, l_quant, base_r) ;
221 
222  // Construction de l'operateur
223  operateur = new Matrice(laplacien_mat
224  (nr, l_quant, beta/alpha, 0, base_r)) ;
225 
226  (*operateur) = combinaison(*operateur, l_quant, beta/alpha, 0,
227  base_r) ;
228 
229  // Operateur inversible
230  nondege = new Matrice(prepa_nondege(*operateur, l_quant,
231  beta/alpha, 0, base_r)) ;
232 
233  // Calcul DES DEUX SH
234  sol_hom = new Tbl(solh(nr, l_quant, beta/alpha, base_r)) ;
235 
236  // Calcul de la SP
237  so = new Tbl(nr) ;
238  so->set_etat_qcq() ;
239  for (int i=0 ; i<nr ; i++)
240  so->set(i) = source(zone, k, j, i) ;
241 
242  sol_part = new Tbl (solp(*operateur, *nondege, alpha,
243  beta, *so, 0, base_r)) ;
244 
245 
246  // Rangement
247  for (int i=0 ; i<nr ; i++) {
248  solution_part.set(zone, k, j, i) = (*sol_part)(i) ;
249  solution_hom_un.set(zone, k, j, i) = (*sol_hom)(0, i) ;
250  solution_hom_deux.set(zone, k, j, i) = (*sol_hom)(1, i) ;
251  }
252 
253 
254  delete operateur ;
255  delete nondege ;
256  delete so ;
257  delete sol_hom ;
258  delete sol_part ;
259  }
260  }
261 
262  //-------------------------------------------
263  // On est parti pour le raccord des solutions
264  //-------------------------------------------
265  // Tableau de 0 et 1 sur les zones, indiquant si le Plm considere
266  // intervient dans le developpement de cette zone.
267  int * indic = new int [nz] ;
268  int taille ;
269  Tbl *sec_membre ; // termes constants du systeme
270  Matrice *systeme ; //le systeme a resoudre
271 
272  // des compteurs pour le remplissage du systeme
273  int ligne ;
274  int colonne ;
275 
276  // compteurs pour les diagonales du systeme :
277  int sup ;
278  int inf ;
279  int sup_new, inf_new ;
280 
281  // on boucle sur le plus grand nombre possible de Plm intervenant...
282  for (int k=0 ; k<np_max+1 ; k++)
283  for (int j=0 ; j<nt_max ; j++)
284  if (nullite_plm(j, nt_max, k, np_max, base) == 1) {
285 
286  ligne = 0 ;
287  colonne = 0 ;
288  sup = 0 ;
289  inf = 0 ;
290 
291  for (int zone=0 ; zone<nz ; zone++)
292  indic[zone] = nullite_plm(j, source.get_mg()->get_nt(zone),
293  k, source.get_mg()->get_np(zone), base);
294 
295  // taille du systeme a resoudre pour ce Plm
296  taille = indic[0] ;
297  for (int zone=1 ; zone<nz ; zone++)
298  taille+=2*indic[zone] ;
299 
300  // on verifie que la taille est non-nulle.
301  // cas pouvant a priori se produire...
302 
303  if (taille != 0) {
304 
305  sec_membre = new Tbl(taille) ;
306  sec_membre->set_etat_qcq() ;
307  for (int l=0 ; l<taille ; l++)
308  sec_membre->set(l) = 0 ;
309 
310  systeme = new Matrice(taille, taille) ;
311  systeme->set_etat_qcq() ;
312  for (int l=0 ; l<taille ; l++)
313  for (int c=0 ; c<taille ; c++)
314  systeme->set(l, c) = 0 ;
315 
316  //Calcul des nombres quantiques
317  //base_r est donne dans le noyau, sa valeur dans les autres
318  //zones etant inutile.
319 
320  donne_lm (nz, 0, j, k, base, m_quant, l_quant, base_r) ;
321 
322 
323  //--------------------------
324  // NOYAU
325  //---------------------------
326 
327  if (indic[0] == 1) {
328  nr = source.get_mg()->get_nr(0) ;
329 
330  alpha = mapping.get_alpha()[0] ;
331  // valeur de x^l en 1 :
332  systeme->set(ligne, colonne) = 1. ; /* ligne=0, colonne=0 */
333  // coefficient du Plm dans la solp
334  for (int i=0 ; i<nr ; i++)
335  sec_membre->set(ligne) -= solution_part(0, k, j, i) ; /* ligne=0 */
336 
337  ligne++ ; /* ligne=1, colonne=0 */
338  // on prend les derivees que si Plm existe
339  //dans la zone suivante
340 
341  if (indic[1] == 1) {
342  // derivee de x^l en 1 :
343  systeme->set(ligne, colonne) = 1./alpha*l_quant ; /* ligne=1, colonne=0 */
344 
345  // coefficient de la derivee du Plm dans la solp
346  if (base_r == R_CHEBP)
347  // cas en R_CHEBP
348  for (int i=0 ; i<nr ; i++)
349  sec_membre->set(ligne) -=
350  4*i*i/alpha
351  *solution_part(0, k, j, i) ; /* ligne=1 */
352  else
353  // cas en R_CHEBI
354  for (int i=0 ; i<nr ; i++)
355  sec_membre->set(ligne) -=
356  (2*i+1)*(2*i+1)/alpha
357  *solution_part(0, k, j, i) ; /* ligne=1 */
358 
359  // on a au moins un diag inferieure dans ce cas ...
360  inf = 1 ;
361  }
362  colonne++ ; /* ligne=1, colonne=1 */
363  }
364 
365  //-----------------------------
366  // COQUILLES
367  //------------------------------
368 
369  for (int zone=1 ; zone<nz ; zone++)
370  if (indic[zone] == 1) {
371 
372  nr = source.get_mg()->get_nr(zone) ;
373  alpha = mapping.get_alpha()[zone] ;
374  echelle = mapping.get_beta()[zone]/alpha ;
375 
376  //Frontiere avec la zone precedente :
377  if (indic[zone-1] == 1) ligne -- ; /* ligne=0, colonne=1 */
378 
379  //valeur de (x+echelle)^l en -1 :
380  systeme->set(ligne, colonne) =
381  -pow(echelle-1, double(l_quant)) ; /* ligne=0, colonne=1 */
382 
383  // valeur de 1/(x+echelle) ^(l+1) en -1 :
384  systeme->set(ligne, colonne+1) =
385  -1/pow(echelle-1, double(l_quant+1)) ; /* ligne=0, colonne=1, colonne+1=2 */
386 
387  // la solution particuliere :
388  for (int i=0 ; i<nr ; i++)
389  if (i%2 == 0)
390  sec_membre->set(ligne) += solution_part(zone, k, j, i) ;
391  else sec_membre->set(ligne) -= solution_part(zone, k, j, i) ; /* ligne=0 */
392 
393  // les diagonales :
394  sup_new = colonne+1-ligne ; /* ligne=0, colonne=1, colonne+1-ligne=2 */
395  if (sup_new > sup) sup = sup_new ;
396 
397  ligne++ ; /* ligne=1 */
398 
399  // on prend les derivees si Plm existe dans la zone
400  // precedente :
401 
402  if (indic[zone-1] == 1) {
403  // derivee de (x+echelle)^l en -1 :
404  systeme->set(ligne, colonne) =
405  -l_quant*pow(echelle-1, double(l_quant-1))/alpha ; /* ligne=1, colonne=1 */
406  // derivee de 1/(x+echelle)^(l+1) en -1 :
407  systeme->set(ligne, colonne+1) =
408  (l_quant+1)/pow(echelle-1, double(l_quant+2))/alpha ; /* ligne=1, colonne=1, colonne+1=2 */
409 
410 
411 
412  // la solution particuliere :
413  for (int i=0 ; i<nr ; i++)
414  if (i%2 == 0)
415  sec_membre->set(ligne) -=
416  i*i/alpha*solution_part(zone, k, j, i) ; /* ligne=1 */
417  else
418  sec_membre->set(ligne) +=
419  i*i/alpha*solution_part(zone, k, j, i) ; /* ligne=1 */
420 
421  // les diagonales :
422  sup_new = colonne+1-ligne ; /* ligne=1, colonne=1, colonne+1-ligne=1 */
423  if (sup_new > sup) sup = sup_new ;
424 
425  ligne++ ; /* ligne=2 */
426  }
427 
428 
429  if(zone < nz-1) {
430 
431  // Frontiere avec la zone suivante :
432  //valeur de (x+echelle)^l en 1 :
433  systeme->set(ligne, colonne) =
434  pow(echelle+1, double(l_quant)) ; /* ligne=2, colonne=1 */
435 
436  // valeur de 1/(x+echelle)^(l+1) en 1 :
437  systeme->set(ligne, colonne+1) =
438  1/pow(echelle+1, double(l_quant+1)) ; /* ligne=2, colonne=1, colonne+1=2 */
439 
440  // la solution particuliere :
441  for (int i=0 ; i<nr ; i++)
442  sec_membre->set(ligne) -= solution_part(zone, k, j, i) ; /* ligne=2 */
443 
444  // les diagonales inf :
445  inf_new = ligne-colonne ; /* ligne=2, colonne=1, ligne-colonne=1 */
446  if (inf_new > inf) inf = inf_new ;
447 
448  ligne ++ ; /* ligne=3 */
449 
450  // Utilisation des derivees ssi Plm existe dans la
451  //zone suivante :
452  if (indic[zone+1] == 1) {
453 
454  //derivee de (x+echelle)^l en 1 :
455  systeme->set(ligne, colonne) =
456  l_quant*pow(echelle+1, double(l_quant-1))/alpha ; /* ligne=3, colonne=1 */
457 
458  //derivee de 1/(echelle+x)^(l+1) en 1 :
459  systeme->set(ligne, colonne+1) =
460  -(l_quant+1)/pow(echelle+1, double(l_quant+2))/alpha ; /* ligne=3, colonne=1, colonne+1=2 */
461 
462  // La solution particuliere :
463  for (int i=0 ; i<nr ; i++)
464  sec_membre->set(ligne) -=
465  i*i/alpha*solution_part(zone, k, j, i) ; /* ligne=3 */
466 
467  // les diagonales inf :
468  inf_new = ligne-colonne ; /* ligne=3, colonne=1, ligne-colonne=2 */
469  if (inf_new > inf) inf = inf_new ;
470 
471  }
472  colonne += 2 ; /* ligne=colonne=3 -> ligne=colonne=1 next block of two */
473  } else {
474 
475 
476 
477  //-------------------------
478  // Ylm outer boundary
479  //---------------------------
480 
481  /* ligne=2, colonne=1 */
482 
483  // The coefficient for A_n is (k+l)(echelle+1)^l
484  systeme->set(ligne, colonne) =
485  pow(echelle+1, double(l_quant)) ; /* ligne=2, colonne=1 */
486 
487  // The coefficient for B_n is (k-(l+1))(echelle+1)^{-(l+1)}
488  systeme->set(ligne, colonne+1) =
489  pow(echelle+1, double(-1-l_quant)) ; /* ligne=2, colonne=1, colonne+1=2 */
490 
491  // Here we have -f - multipole integral
492  //(pos source->neg field!!)
493 
494  int indylm;
495  double intterm=0.;
496  if(l_quant*l_quant < nylm && m_quant<=l_quant) {
497  indylm=l_quant*l_quant+2*m_quant;
498  if(k%2==0 && k>=2)indylm-=1;
499  intterm=intvec[indylm];
500  cout <<"l,m:"<<l_quant<<" "<<m_quant<<" "<<j<<" "<<k<<" "<<indylm<<" "<<intterm<<endl;
501  }
502  // This is just for testing!!!
503  //if(l_quant==1 && m_quant==1&& k%2==0) {
504  // intterm=1.0 ;
505  //} else {
506  // intterm=0.;
507  //}
508 
509  sec_membre->set(ligne) -= intterm;
510 
511  // La solution particuliere :
512  for (int i=0 ; i<nr ; i++)
513  sec_membre->set(ligne) -=
514  solution_part(zone, k, j, i) ; /* ligne=2 */
515 
516  // les diagonales inf :
517  inf_new = ligne-colonne ; /* ligne=2, colonne=1, ligne-colonne=1 */
518  if (inf_new > inf) inf = inf_new ;
519 
520  }
521  }
522 
523 
524  //-------------------------
525  // resolution du systeme
526  //--------------------------
527 
528  systeme->set_band(sup, inf) ;
529  systeme->set_lu() ;
530 
531  Tbl facteurs(systeme->inverse(*sec_membre)) ;
532  int conte = 0 ;
533 
534 
535  // rangement dans le noyau :
536 
537  if (indic[0] == 1) {
538  nr = source.get_mg()->get_nr(0) ;
539  for (int i=0 ; i<nr ; i++)
540  resultat.set(0, k, j, i) = solution_part(0, k, j, i)
541  +facteurs(conte)*solution_hom_un(0, k, j, i) ;
542  conte++ ;
543  }
544 
545  // rangement dans les coquilles :
546  for (int zone=1 ; zone<nz ; zone++)
547  if (indic[zone] == 1) {
548  nr = source.get_mg()->get_nr(zone) ;
549  for (int i=0 ; i<nr ; i++)
550  resultat.set(zone, k, j, i) =
551  solution_part(zone, k, j, i)
552  +facteurs(conte)*solution_hom_un(zone, k, j, i)
553  +facteurs(conte+1)*solution_hom_deux(zone, k, j, i) ;
554  conte+=2 ;
555  }
556 
557  delete sec_membre ;
558  delete systeme ;
559  }
560 
561  }
562 
563  delete [] indic ;
564 
565  return resultat;
566 }
567 }
Lorene prototypes.
Definition: app_hor.h:67
const Mg3d * get_mg() const
Returns the Mg3d on which the Mtbl_cf is defined.
Definition: mtbl_cf.h:463
#define R_CHEBP
base de Cheb. paire (rare) seulement
Definition: type_parite.h:168
int get_nzone() const
Returns the number of domains.
Definition: grilles.h:465
Cmp pow(const Cmp &, int)
Power .
Definition: cmp_math.C:351
Tbl & set(int l)
Read/write of the value in a given domain.
Definition: cmp.h:724