LORENE
poisson_compact.C
1 /*
2  * Copyright (c) 2000-2006 Philippe Grandclement
3  * Copyright (c) 2007 Michal Bejger
4  * Copyright (c) 2007 Eric Gourgoulhon
5  *
6  * This file is part of LORENE.
7  *
8  * LORENE is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * LORENE is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with LORENE; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23 
24 
25 
26 
27 /*
28  * $Id: poisson_compact.C,v 1.8 2018/11/16 14:34:36 j_novak Exp $
29  * $Log: poisson_compact.C,v $
30  * Revision 1.8 2018/11/16 14:34:36 j_novak
31  * Changed minor points to avoid some compilation warnings.
32  *
33  * Revision 1.7 2016/12/05 16:18:09 j_novak
34  * Suppression of some global variables (file names, loch, ...) to prevent redefinitions
35  *
36  * Revision 1.6 2014/10/13 08:53:29 j_novak
37  * Lorene classes and functions now belong to the namespace Lorene.
38  *
39  * Revision 1.5 2014/10/06 15:16:09 j_novak
40  * Modified #include directives to use c++ syntax.
41  *
42  * Revision 1.4 2007/10/16 21:54:23 e_gourgoulhon
43  * Added new function sol_poisson_compact (multi-domain version).
44  *
45  * Revision 1.3 2006/09/05 13:39:46 p_grandclement
46  * update of the bin_ns_bh project
47  *
48  * Revision 1.2 2002/10/16 14:37:12 j_novak
49  * Reorganization of #include instructions of standard C++, in order to
50  * use experimental version 3 of gcc.
51  *
52  * Revision 1.1.1.1 2001/11/20 15:19:28 e_gourgoulhon
53  * LORENE
54  *
55  * Revision 2.2 2000/03/16 16:28:06 phil
56  * Version entirement revue et corrigee
57  *
58  * Revision 2.1 2000/03/09 13:51:55 phil
59  * *** empty log message ***
60  *
61  * Revision 2.0 2000/03/09 13:44:56 phil
62  * *** empty log message ***
63  *
64  *
65  * $Header: /cvsroot/Lorene/C++/Source/Non_class_members/PDE/poisson_compact.C,v 1.8 2018/11/16 14:34:36 j_novak Exp $
66  *
67  */
68 
69 // Headers C
70 #include <cstdlib>
71 #include <cmath>
72 #include <cassert>
73 
74 // Headers Lorene
75 #include "map.h"
76 #include "diff.h"
77 #include "matrice.h"
78 #include "type_parite.h"
79 #include "proto.h"
80 #include "base_val.h"
81 #include "utilitaires.h"
82 
84  // Single domain version //
86 
87 /*
88  * Cette fonction resout, dans le noyau :
89  * a*(1-xi^2)*lap(uu)+b*xi*duu/dxi = source
90  * avec a>0 et b<0 ;
91  * Pour le stokage des operateurs, il faut faire reamorce = true au
92  * debut d'un nouveau calcul.
93  */
94 
95 namespace Lorene {
96 Mtbl_cf sol_poisson_compact(const Mtbl_cf& source, double a, double b,
97  bool reamorce) {
98 
99  // Verifications :
100  assert (source.get_etat() != ETATNONDEF) ;
101 
102  assert (a>0) ;
103  assert (b<0) ;
104 
105  // Les tableaux de stockage :
106  const int nmax = 200 ;
107  static Matrice* tab_op[nmax] ;
108  static int nb_deja_fait = 0 ;
109  static int l_deja_fait[nmax] ;
110  static int n_deja_fait[nmax] ;
111 
112  if (reamorce) {
113  for (int i=0 ; i<nb_deja_fait ; i++)
114  delete tab_op[i] ;
115  nb_deja_fait = 0 ;
116  }
117 
118  int nz = source.get_mg()->get_nzone() ;
119 
120  // Pour le confort (on ne travaille que dans le noyau) :
121  int nr = source.get_mg()->get_nr(0) ;
122  int nt = source.get_mg()->get_nt(0) ;
123  int np = source.get_mg()->get_np(0) ;
124 
125  int l_quant ;
126  int m_quant ;
127  int base_r ;
128 
129  // La solution ...
130  Mtbl_cf solution(source.get_mg(), source.base) ;
131  solution.set_etat_qcq() ;
132  solution.t[0]->set_etat_qcq() ;
133 
134  for (int k=0 ; k<np+1 ; k++)
135  for (int j=0 ; j<nt ; j++)
136  if (nullite_plm(j, nt, k, np, source.base) == 1)
137  {
138  // calcul des nombres quantiques :
139  donne_lm(nz, 0, j, k, source.base, m_quant, l_quant, base_r) ;
140 
141 
142  //On gere le cas l_quant == 0 (c'est bien simple y'en a pas !)
143  if (l_quant == 0) {
144  for (int i=0 ; i<nr ; i++)
145  solution.set(0, k, j, i) = 0 ;
146  }
147 
148  // cas l_quant != 0
149  else {
150  // On determine si la matrice a deja ete calculee :
151  int indice = -1 ;
152 
153  // Le cas l==1 est non singulier : pas de base de Gelerkin
154  int taille = (l_quant == 1) ? nr : nr-1 ;
155 
156  Matrice operateur (taille, taille) ;
157  for (int conte=0 ; conte<nb_deja_fait ; conte++)
158  if ((l_deja_fait[conte]== l_quant) && (n_deja_fait[conte] == nr))
159  indice = conte ;
160 
161  if (indice == -1) {
162  if (nb_deja_fait >= nmax) {
163  cout << "sol_poisson_compact : trop de matrices ..." << endl;
164  abort() ;
165  }
166  // Calcul a faire :
167  operateur = a*lap_cpt_mat (nr, l_quant, base_r)
168  + b*xdsdx_mat(nr, l_quant, base_r) ;
169  operateur = combinaison_cpt (operateur, l_quant, base_r) ;
170 
171  l_deja_fait[nb_deja_fait] = l_quant ;
172  n_deja_fait[nb_deja_fait] = nr ;
173  tab_op[nb_deja_fait] = new Matrice(operateur) ;
174 
175  nb_deja_fait++ ;
176  }
177  else {
178  // rien a faire :
179  operateur = *tab_op[indice] ;
180  }
181 
182  // La source :
183  Tbl so(taille) ;
184  so.set_etat_qcq() ;
185  for (int i=0 ; i<taille ; i++)
186  so.set(i) = source(0, k, j, i) ;
187  so = combinaison_cpt (so, base_r) ;
188 
189  Tbl part (operateur.inverse(so)) ;
190 
191  if (taille == nr)
192  for (int i=0 ; i<nr ; i++)
193  solution.set(0, k, j, i) = part(i) ; // cas l==1
194  else {
195  solution.set(0, k, j, nr-1) = 0 ;
196  for (int i=nr-2 ; i>=0 ; i--)
197  if (base_r == R_CHEBP) { //Gelerkin pair
198  solution.set(0, k, j, i) = part(i) ;
199  solution.set(0, k, j, i+1) += part(i) ;
200  }
201  else { //Gelerkin impaire
202  solution.set(0, k, j, i) = part(i)*(2*i+3) ;
203  solution.set(0, k, j, i+1) += part(i)*(2*i+1) ;
204  }
205  }
206  }
207  }
208  else // cas ou nullite_plm = 0 :
209  for (int i=0 ; i<nr ; i++)
210  solution.set(0, k, j, i) = 0 ;
211 
212  // Mise a zero du coefficient (inusite) k=np+1
213  for (int j=0; j<nt; j++)
214  for(int i=0 ; i<nr ; i++)
215  solution.set(0, np+1, j, i) = 0 ;
216 
217  for (int zone=1 ; zone<nz ; zone++)
218  solution.t[zone]->set_etat_zero() ;
219 
220  return solution ;
221 }
222 
223 
224 
226  // Multi domain version //
228 
229 
230 Mtbl_cf sol_poisson_compact(const Map_af& mapping, const Mtbl_cf& source,
231  const Tbl& ac, const Tbl& bc, bool ) {
232 
233  // Number of domains inside the star :
234  int nzet = ac.get_dim(1) ;
235  assert(nzet<=source.get_mg()->get_nzone()) ;
236 
237  // Some checks
238  assert (source.get_mg()->get_type_r(0) == RARE) ;
239  for (int l=1 ; l<nzet ; l++)
240  assert(source.get_mg()->get_type_r(l) == FIN) ;
241 
242  // Spectral bases
243  const Base_val& base = source.base ;
244 
245  // Result
246  Mtbl_cf resultat(source.get_mg(), base) ;
247  resultat.annule_hard() ;
248 
249  // donnees sur la zone
250  int nr, nt, np ;
251  int base_r ;
252  double alpha, beta, echelle ;
253  int l_quant, m_quant;
254 
255  // Determination of the size of the systeme :
256  int size = 0 ;
257  int max_nr = 0 ;
258  for (int l=0 ; l<nzet ; l++) {
259  nr = mapping.get_mg()->get_nr(l) ;
260  size += nr ;
261  if (nr > max_nr) max_nr = nr ;
262  }
263 
264  Matrice systeme (size, size) ;
265  systeme.set_etat_qcq() ;
266  Tbl sec_membre (size) ;
267  Tbl soluce (size) ;
268  soluce.set_etat_qcq() ;
269 
270  np = mapping.get_mg()->get_np(0) ;
271  nt = mapping.get_mg()->get_nt(0) ;
272  Matrice* work ;
273 
274  // On bosse pour chaque l, m :
275  for (int k=0 ; k<np+1 ; k++)
276  for (int j=0 ; j<nt ; j++)
277  if (nullite_plm(j, nt, k, np, base) == 1) {
278 
279  systeme.annule_hard() ;
280  sec_membre.annule_hard() ;
281 
282  int column_courant = 0 ;
283  int ligne_courant = 0 ;
284 
285  //--------------------------
286  // NUCLEUS
287  //--------------------------
288 
289  nr = mapping.get_mg()->get_nr(0) ;
290  alpha = mapping.get_alpha()[0] ;
291  base.give_quant_numbers (0, k, j, m_quant, l_quant, base_r) ;
292 
293  if (l_quant == 0) {
294  for (int i=0 ; i<size ; i++)
295  soluce.set(i) = 0 ;
296  }
297  else {
298 
299  Diff_dsdx2 d2_n(base_r, nr) ; // suffix _n stands for "nucleus"
300  Diff_sxdsdx sxd_n(base_r, nr) ;
301  Diff_sx2 sx2_n(base_r, nr) ;
302  Diff_x2dsdx2 x2d2_n(base_r,nr) ;
303  Diff_xdsdx xd_n(base_r,nr) ;
304  Diff_id id_n(base_r,nr) ;
305 
306  work = new Matrice( ac(0,0) * ( d2_n + 2.*sxd_n -l_quant*(l_quant+1)*sx2_n )
307  + ac(0,2) * ( x2d2_n + 2.*xd_n -l_quant*(l_quant+1)*id_n )
308  + alpha * bc(0,1) * xd_n ) ;
309 
310  // cout << *work << endl ;
311  // arrete() ;
312 
313  // regularity conditions :
314  int nbr_cl = 0 ;
315  if (l_quant > 1) {
316  nbr_cl = 1 ;
317  if (l_quant%2==0) {
318  //Even case
319  for (int col=0 ; col<nr ; col++)
320  if (col%2==0)
321  systeme.set(ligne_courant, col+column_courant) = 1 ;
322  else
323  systeme.set(ligne_courant, col+column_courant) = -1 ;
324  }
325  else {
326  //Odd case
327  for (int col=0 ; col<nr ; col++)
328  if (col%2==0)
329  systeme.set(ligne_courant, col+column_courant) = 2*col+1 ;
330  else
331  systeme.set(ligne_courant, col+column_courant) = -(2*col+1) ;
332  }
333  ligne_courant ++ ;
334  }
335 
336  // L'operateur :
337  for (int lig=0 ; lig<nr-1-nbr_cl ; lig++) {
338  for (int col=0 ; col<nr ; col++)
339  systeme.set(lig+ligne_courant,col+column_courant) = (*work)(lig,col) ;
340  sec_membre.set(lig+ligne_courant) = alpha*alpha*source(0, k, j, lig) ;
341  }
342 
343  delete work ;
344  ligne_courant += nr-1-nbr_cl ;
345 
346  // Le raccord :
347  for (int col=0 ; col<nr ; col++) {
348  // La fonction
349  systeme.set(ligne_courant, col+column_courant) = 1 ;
350  // Sa dérivée :
351  if (l_quant%2==0)
352  systeme.set(ligne_courant+1, col+column_courant) = 4*col*col/alpha ;
353  else
354  systeme.set(ligne_courant+1, col+column_courant) = (2*col+1)*(2*col+1)/alpha ;
355  }
356  column_courant += nr ;
357 
358  //--------------------------
359  // SHELLS
360  //--------------------------
361 
362  for (int l=1 ; l<nzet ; l++) {
363 
364  nr = mapping.get_mg()->get_nr(l) ;
365  alpha = mapping.get_alpha()[l] ;
366  beta = mapping.get_beta()[l] ;
367  echelle = beta/alpha ;
368  double bsa = echelle ;
369  double bsa2 = bsa*bsa ;
370 
371  base.give_quant_numbers (l, k, j, m_quant, l_quant, base_r) ;
372 
373  Diff_dsdx dx(base_r, nr) ;
374  Diff_xdsdx xdx(base_r, nr) ;
375  Diff_x2dsdx x2dx(base_r, nr) ;
376  Diff_x3dsdx x3dx(base_r, nr) ;
377  Diff_dsdx2 dx2(base_r, nr) ;
378  Diff_xdsdx2 xdx2(base_r, nr) ;
379  Diff_x2dsdx2 x2dx2(base_r, nr) ;
380  Diff_x3dsdx2 x3dx2(base_r, nr) ;
381  Diff_id id(base_r,nr) ;
382  Diff_mx mx(base_r,nr) ;
383 
384  work = new Matrice ( ac(l,0) * ( x2dx2 + 2.*bsa*xdx2 + bsa2*dx2 + 2.*xdx
385  + 2.*bsa*dx - l_quant*(l_quant+1)*id )
386  + ac(l,1) * ( x3dx2 + 2.*bsa*x2dx2 + bsa2*xdx2 + 2.*x2dx
387  + 2.*bsa*xdx - l_quant*(l_quant+1) *mx )
388  + alpha * ( bc(l,0) * ( x2dx + 2.*bsa*xdx + bsa2*dx )
389  + bc(l,1) * ( x3dx + 2.*bsa*x2dx + bsa2*xdx ) ) ) ;
390 
391  // matching with previous domain :
392  for (int col=0 ; col<nr ; col++) {
393  // La fonction
394  if (col%2==0)
395  systeme.set(ligne_courant, col+column_courant) = -1 ;
396  else
397  systeme.set(ligne_courant, col+column_courant) = 1 ;
398  // Sa dérivée :
399  if (col%2==0)
400  systeme.set(ligne_courant+1, col+column_courant) = col*col/alpha ;
401  else
402  systeme.set(ligne_courant+1, col+column_courant) = -col*col/alpha ;
403  }
404  ligne_courant += 2 ;
405 
406  // source must be multiplied by (x+echelle)^2
407  Tbl source_aux(nr) ;
408  source_aux.set_etat_qcq() ;
409  for (int i=0 ; i<nr ; i++)
410  source_aux.set(i) = source(l,k,j,i)*alpha*alpha ;
411  Tbl xso(source_aux) ;
412  Tbl xxso(source_aux) ;
413  multx_1d(nr, &xso.t, R_CHEB) ;
414  multx_1d(nr, &xxso.t, R_CHEB) ;
415  multx_1d(nr, &xxso.t, R_CHEB) ;
416  source_aux = beta*beta/alpha/alpha*source_aux+2*beta/alpha*xso+xxso ;
417 
418  // L'operateur :
419 
420  for (int lig=0 ; lig<nr-1 ; lig++) {
421  for (int col=0 ; col<nr ; col++)
422  systeme.set(lig+ligne_courant,col+column_courant) = (*work)(lig,col) ;
423  sec_membre.set(lig+ligne_courant) = source_aux(lig) ;
424  }
425 
426  // cout << *work << endl ;
427  // arrete() ;
428 
429  delete work ;
430  ligne_courant += nr-2 ;
431 
432  if (l<nzet-1) { // if this not the last shell
433  // matching with the next domain
434  for (int col=0 ; col<nr ; col++) {
435  // La fonction
436  systeme.set(ligne_courant, col+column_courant) = 1 ;
437  // Sa dérivée :
438  systeme.set(ligne_courant+1, col+column_courant) = col*col/alpha ;
439  }
440  }
441 
442  column_courant += nr ;
443 
444  } // end loop on the shells (index l)
445 
446  // cout << "systeme : " << systeme << endl ;
447  // arrete() ;
448 
449  // Solving the system:
450 
451  systeme.set_band (size, size) ;
452  systeme.set_lu() ;
453 
454  // cout << "Determinant: " << systeme.determinant() << endl ;
455  // cout << "Eigenvalues: " << systeme.val_propre() << endl ;
456 
457  soluce = systeme.inverse(sec_membre) ;
458 
459  } // end case l_quant != 0
460 
461  // cout << "soluce: " << soluce << endl ;
462  // arrete() ;
463 
464  // On range :
465  int conte = 0 ;
466  for (int l=0 ; l<nzet ; l++) {
467  nr = mapping.get_mg()->get_nr(l) ;
468  for (int i=0 ; i<nr ; i++) {
469  resultat.set(l,k,j,i) = soluce(conte) ;
470  conte++ ;
471  }
472  }
473 
474  } // end case nullite_plm == 1
475 
476  return resultat ;
477 
478 }
479 
480 
481 
482 
483 
484 
485 
486 
487 
488 
489 
490 
491 
492 
493 
494 }
Lorene prototypes.
Definition: app_hor.h:67
#define R_CHEBP
base de Cheb. paire (rare) seulement
Definition: type_parite.h:168
Base_val base
Bases of the spectral expansions.
Definition: mtbl_cf.h:210
#define R_CHEB
base de Chebychev ordinaire (fin)
Definition: type_parite.h:166