map_af_dalembert.C

00001 /*
00002  *   Copyright (c) 2000-2004 Jerome Novak
00003  *
00004  *   This file is part of LORENE.
00005  *
00006  *   LORENE is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU General Public License as published by
00008  *   the Free Software Foundation; either version 2 of the License, or
00009  *   (at your option) any later version.
00010  *
00011  *   LORENE is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details.
00015  *
00016  *   You should have received a copy of the GNU General Public License
00017  *   along with LORENE; if not, write to the Free Software
00018  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 
00023 char map_af_dalembert_C[] = "$Header: /cvsroot/Lorene/C++/Source/Map/map_af_dalembert.C,v 1.16 2008/08/27 08:55:31 jl_cornou Exp $" ;
00024 
00025 /*
00026  * $Id: map_af_dalembert.C,v 1.16 2008/08/27 08:55:31 jl_cornou Exp $
00027  * $Log: map_af_dalembert.C,v $
00028  * Revision 1.16  2008/08/27 08:55:31  jl_cornou
00029  * Added R_JACO02 case
00030  *
00031  * Revision 1.15  2007/11/06 14:42:20  j_novak
00032  * Copy of field at previous time-steps to local variables to deal with the
00033  * dzpuis.
00034  *
00035  * Revision 1.14  2006/08/31 08:56:37  j_novak
00036  * Added the possibility to have a shift in the quantum number l in the operator.
00037  *
00038  * Revision 1.13  2004/06/08 14:01:27  j_novak
00039  * *** empty log message ***
00040  *
00041  * Revision 1.11  2004/03/04 15:15:48  e_gourgoulhon
00042  * Treatment of case fj in state ETATZERO at the end.
00043  *
00044  * Revision 1.10  2004/03/01 13:30:28  j_novak
00045  * Corrected some errors
00046  *
00047  * Revision 1.9  2004/03/01 09:57:03  j_novak
00048  * the wave equation is solved with Scalars. It now accepts a grid with a
00049  * compactified external domain, which the solver ignores and where it copies
00050  * the values of the field from one time-step to the next.
00051  *
00052  * Revision 1.8  2003/07/22 13:24:48  j_novak
00053  * *** empty log message ***
00054  *
00055  * Revision 1.7  2003/06/20 10:08:12  j_novak
00056  * *** empty log message ***
00057  *
00058  * Revision 1.6  2003/06/20 09:27:10  j_novak
00059  * Modif commentaires.
00060  *
00061  * Revision 1.5  2003/06/19 16:16:38  j_novak
00062  * Parabolic approximation for a non flat dalembert operator
00063  *
00064  * Revision 1.4  2003/06/18 08:45:27  j_novak
00065  * In class Mg3d: added the member get_radial, returning only a radial grid
00066  * For dAlembert solver: the way the coefficients of the operator are defined has been changed.
00067  *
00068  * Revision 1.3  2002/01/03 15:30:28  j_novak
00069  * Some comments modified.
00070  *
00071  * Revision 1.2  2002/01/02 14:07:57  j_novak
00072  * Dalembert equation is now solved in the shells. However, the number of
00073  * points in theta and phi must be the same in each domain. The solver is not
00074  * completely tested (beta version!).
00075  *
00076  * Revision 1.1.1.1  2001/11/20 15:19:27  e_gourgoulhon
00077  * LORENE
00078  *
00079  * Revision 1.7  2001/10/16  10:04:22  novak
00080  * cleaning (no more source terms for enhanced BC)
00081  *
00082  * Revision 1.6  2001/07/19 14:07:15  novak
00083  * tentative for new outgoing boundary condition
00084  *
00085  * Revision 1.5  2000/12/04 15:01:34  novak
00086  * *** empty log message ***
00087  *
00088  * Revision 1.4  2000/12/04 14:20:36  novak
00089  * odd case enabled
00090  *
00091  * Revision 1.3  2000/11/27 14:54:51  novak
00092  * 3D boundary conditions operational
00093  *
00094  * Revision 1.2  2000/10/24 16:18:34  novak
00095  * Outgoing wave boundary conditions and addition of the Tbl coeff
00096  *
00097  * Revision 1.1  2000/10/19 14:17:39  novak
00098  * Initial revision
00099  *
00100  *
00101  * $Header: /cvsroot/Lorene/C++/Source/Map/map_af_dalembert.C,v 1.16 2008/08/27 08:55:31 jl_cornou Exp $
00102  *
00103  */
00104 //Header C++
00105 #include <math.h>
00106 
00107 // Header Lorene:
00108 #include "tensor.h"
00109 #include "param.h"
00110 #include "proto.h"
00111 
00112 //**************************************************************************
00113 
00114 void Map_af::dalembert(Param& par, Scalar& fjp1, const Scalar& fj, const Scalar& fjm1,
00115                const Scalar& source) const {
00116 
00117 
00118     assert(source.get_etat() != ETATNONDEF) ; 
00119     assert(source.get_mp().get_mg() == mg) ; 
00120     assert(fj.get_etat() != ETATNONDEF) ; 
00121     assert(fj.get_mp().get_mg() == mg) ; 
00122     assert(fjm1.get_etat() != ETATNONDEF) ; 
00123     assert(fjm1.get_mp().get_mg() == mg) ; 
00124     assert(fjp1.get_mp().get_mg() == mg) ;
00125 
00126     assert(par.get_n_double() == 1) ;
00127     assert(par.get_n_int() >= 1) ;
00128     assert(par.get_n_int_mod() == 1) ;
00129     int& nap = par.get_int_mod() ;
00130     assert ((nap == 0) || (par.get_n_tbl_mod() > 1)) ;
00131 
00132     int nz = mg->get_nzone() ;
00133     bool ced = (mg->get_type_r(nz-1) == UNSURR) ;
00134     int nz0 = (ced ? nz - 1 : nz) ;
00135     double dt = par.get_double() ;
00136 
00137     Scalar fj_local = fj ;
00138     Scalar fjm1_local = fjm1 ;
00139     if (ced) {
00140     fj_local.annule_domain(nz-1) ;
00141     fjm1_local.annule_domain(nz-1) ;
00142     }
00143     Scalar sigma = 2*fj_local - fjm1_local ; // The source (first part)     
00144 
00145     // Coefficients
00146     //-------------
00147     
00148     Tbl* coeff ;
00149     if (nap == 0) {
00150       coeff = new Tbl(12,nz);
00151       coeff->set_etat_qcq() ;
00152       par.add_tbl_mod(*coeff) ;
00153     }
00154     else 
00155       coeff= &par.get_tbl_mod() ;
00156     Tbl a1(nz) ; a1 = 1 ; //Flat dalembertian
00157     Tbl a2(nz) ; a2 = 0 ;
00158     Tbl a3(nz) ; a3 = 0 ;
00159 
00160     if (par.get_n_tensor_mod() > 0) { // Metric in front of the dalembertian
00161       assert(par.get_n_tensor_mod() == 1) ;
00162       Scalar* metri = dynamic_cast<Scalar*>(&par.get_tensor_mod()) ;
00163       assert(metri != 0x0) ;
00164       assert (metri->get_etat() == ETATQCQ) ;
00165 
00166       const Map_af* tmap ; //Spherically symmetric grid and mapping
00167       if (nap == 0) {
00168     double* bornes = new double[nz+1] ;
00169     bornes[0] = beta[0] ;
00170     for (int i=0; i<nz; i++) bornes[i+1] = alpha[i] + beta[i] ;
00171     tmap = new Map_af(*mg->get_radial() , bornes) ;
00172     par.add_map(*tmap) ;
00173     delete [] bornes ;
00174       }
00175       else {
00176     tmap = dynamic_cast<const Map_af*>(&par.get_map()) ;
00177     assert (tmap != 0x0) ;
00178       }
00179       metri->set_spectral_va().ylm() ;
00180 
00181       Scalar xmetr(*tmap) ; // l=0 part of the potential in front of the Laplacian
00182       xmetr.set_etat_qcq() ;
00183       xmetr.std_spectral_base() ;
00184       xmetr.set_spectral_va().set_base_t(T_LEG_PP) ; // Only l=0 matters in any case...
00185       xmetr.set_spectral_va().set_etat_cf_qcq() ;
00186       Mtbl_cf* mt = xmetr.set_spectral_va().c_cf ; 
00187       mt->annule_hard() ;
00188       for (int lz=0; lz<nz0; lz++) 
00189     for (int ir=0; ir<mg->get_nr(lz); ir++) 
00190       mt->set(lz,0,0,ir) = (*metri->get_spectral_va().c_cf)(lz, 0, 0, ir) ; //only l=0
00191     
00192       if (mg->get_nt(0) != 1) xmetr = xmetr / sqrt(double(2)) ; 
00193       xmetr.set_spectral_va().ylm_i() ;
00194       xmetr.set_spectral_va().coef_i() ;
00195       const Mtbl& erre = this->r ;
00196 
00197       a1.set_etat_qcq() ;
00198       a2.set_etat_qcq() ;
00199       a3.set_etat_qcq() ;
00200       Scalar mime(*this) ;
00201       mime.annule_hard() ;
00202       for (int lz=0; lz<nz0; lz++) {
00203     int nr = mg->get_nr(lz);
00204     double r1 = erre(lz, 0, 0, nr-1) ;
00205     double rm1 = erre(lz, 0, 0, 0) ;
00206     double x1 = xmetr.val_grid_point(lz, 0, 0, nr-1) ;
00207     double xm1 = xmetr.val_grid_point(lz, 0, 0, 0) ;
00208     
00209     if (mg->get_type_r(lz) == RARE) { //In the nucleus, no a2*r
00210           a1.set(lz) = xm1 ;
00211           a2.set(lz) = 0 ;
00212           a3.set(lz) = (x1 - a1(lz)) / (r1 * r1);
00213     }
00214     else { // In the shells, general case
00215       int i0 = (nr-1)/2 ;
00216       double r0 = erre(lz, 0, 0, i0) ;
00217       double x0 = xmetr.val_grid_point(lz, 0, 0, i0) ;
00218       double p1 = (r1 - rm1)*(r1 - r0) ;
00219       double pm1 = (r0 - rm1)*(r1 - rm1) ;
00220       double p0 = (r0 - rm1)*(r1 - r0) ;
00221       a1.set(lz) = xm1*r1*r0/pm1 + x1*rm1*r0/p1 - x0*rm1*r1/p0 ;
00222       a2.set(lz) = x0*(rm1 + r1)/p0 - xm1*(r1 + r0)/pm1 
00223         - x1*(rm1 + r0)/p1 ;
00224       a3.set(lz) = xm1/pm1+x1/p1-x0/p0 ;
00225     }
00226 
00227     for (int k=0; k<mg->get_np(lz)+2; k++) 
00228       for (int j=0; j<mg->get_nt(lz); j++) 
00229         for (int i=0; i<nr; i++)
00230           mime.set_grid_point(lz, k, j, i) = a1(lz) + erre(lz, 0, 0, i)*
00231         (a2(lz) + erre(lz, 0, 0, i)*a3(lz)) ;
00232 
00233     Tbl diff = metri->domain(lz) - mime.domain(lz) ;
00234     double offset = max(diff) ; // Not sure that this is really 
00235     a1.set(lz) += offset ;  // necessary (supposed to ensure stability).
00236     mime.set_domain(lz) += offset ;
00237       }
00238 
00239       Scalar reste = (*metri - mime)*fj_local.laplacian() ;
00240       if (ced) reste.annule_domain(nz-1) ;
00241       sigma += (dt*dt)*(source + reste) ;
00242       if (ced) sigma.annule_domain(nz-1) ;
00243       sigma +=  (0.5*dt*dt)*mime*fjm1_local.laplacian() ; //Source (2nd part)
00244     }
00245     else {
00246       sigma += (dt*dt) * source ;
00247       if (ced) sigma.annule_domain(nz-1) ;
00248       sigma += (0.5*dt*dt)*fjm1_local.laplacian() ;
00249       if (par.get_n_int() > 1) { //there is a shift in the quantum number l
00250       int dl = -1 ;
00251       int l_min = par.get_int(1) ;
00252       sigma.set_spectral_va().ylm() ;      
00253       Scalar tmp = fjm1_local ;
00254       tmp.div_r() ; tmp.div_r() ; // f^(J-1) / r^2
00255       tmp.set_spectral_va().ylm() ;
00256       const Base_val& base = tmp.get_spectral_base() ;
00257       int l_q, m_q, baser ;
00258     
00259       for (int lz=0; lz<nz-1; lz++) {
00260           int nt = mg->get_nt(lz) ;
00261           int np = mg->get_np(lz) ;
00262           for (int k=0; k<np+2; k++) 
00263           for (int j=0; j<nt; j++) {
00264               base.give_quant_numbers(lz, k, j, m_q, l_q, baser) ;
00265               if ((nullite_plm(j, nt, k, np, base) == 1) && (l_q+dl >= l_min) ) {
00266               for (int i=0; i<mg->get_nr(lz); i++) {
00267                   sigma.set_spectral_va().c_cf->set(lz, k, j, i) -=
00268                   0.5*dt*dt*dl*(2*l_q + dl +1)
00269                   *(*tmp.get_spectral_va().c_cf)(lz, k, j, i) ;
00270               }
00271               }
00272           }
00273       }
00274       if (sigma.get_spectral_va().c != 0x0) {
00275           delete sigma.set_spectral_va().c ;
00276           sigma.set_spectral_va().c = 0x0 ;
00277       }
00278       }
00279     }
00280     if (ced) sigma.annule_domain(nz-1) ;
00281 
00282     //--------------------------------------------
00283     // The operator reads
00284     // Id - 0.5dt^2*(a1 + a2 r + a3 r^2)Laplacian
00285     //--------------------------------------------
00286     for (int i=0; i<nz; i++) {
00287     coeff->set(1,i) = a1(i) ; 
00288     coeff->set(2,i) = a2(i) ;
00289     coeff->set(3,i) = a3(i) ;
00290     coeff->set(4,i) = 0. ;
00291     coeff->set(5,i) = 0. ;
00292     coeff->set(6,i) = 0. ;
00293     coeff->set(7,i) = 0. ;
00294     coeff->set(8,i) = 0. ;
00295     coeff->set(9,i) = 0. ; 
00296     coeff->set(10,i) = beta[i] ;
00297     coeff->set(11,i) = alpha[i] ;
00298     }
00299 
00300     // Defining the boundary conditions
00301     // --------------------------------
00302     double R = this->val_r(nz0-1, 1., 0., 0.) ;
00303     int nr = mg->get_nr(nz0-1) ;
00304     int nt = mg->get_nt(nz0-1) ;
00305     int np2 = mg->get_np(nz0-1) + 2;
00306 
00307     // For each pair of quantic numbers l, m one the result must satisfy
00308     // bc1 * f_{l,m} (R) + bc2 * f_{l,m}'(R) = tbc3_{l,m}
00309     // Memory is allocated for the parameter (par) at first call
00310     double* bc1 ;
00311     double* bc2 ;
00312     Tbl* tbc3 ;
00313     Tbl* phijm1 = 0x0 ;
00314     Tbl* phij = 0x0 ;
00315     if (nap == 0) { 
00316       bc1 = new double ;
00317       bc2 = new double ;
00318       tbc3 = new Tbl(np2,nt) ;
00319       par.add_double_mod(*bc1,1) ;
00320       par.add_double_mod(*bc2,2) ;
00321       par.add_tbl_mod(*tbc3,1) ;
00322       // Hereafter the enhanced outgoing-wave condition needs 2 auxiliary
00323       // functions phij and phijm1 to define the evolution on the boundary
00324       // surface (outer sphere).
00325       if (par.get_int(0) == 2) {
00326     phijm1 = new Tbl(np2,nt) ;
00327     phij = new Tbl(np2,nt) ;
00328     par.add_tbl_mod(*phijm1,2) ;
00329     par.add_tbl_mod(*phij,3) ;
00330     phij->annule_hard() ;
00331     phijm1->annule_hard() ;
00332       }
00333       nap = 1 ;
00334     }
00335     else {
00336       bc1 = &par.get_double_mod(1) ;
00337       bc2 = &par.get_double_mod(2) ;
00338       tbc3 = &par.get_tbl_mod(1) ;
00339       if (par.get_int(0) == 2) {
00340     phijm1 = &par.get_tbl_mod(2) ;
00341     phij = &par.get_tbl_mod(3) ;
00342       }
00343     }
00344     switch (par.get_int(0)) {
00345     case 0:   // Homogeneous boundary conditions (f(t,r=R) =0)
00346       *bc1 = 1 ;
00347       *bc2 = 0 ;
00348       
00349       *tbc3 = 0 ;
00350       
00351       break ;
00352     case 1:  { // Outgoing wave condition (f(t,r) = 1/r S(t-r/c))
00353       Valeur bound3(mg) ;
00354       bound3 = R*(4*fj_local.get_spectral_va() - fjm1_local.get_spectral_va()) ;
00355       if (bound3.get_etat() == ETATZERO) {
00356     *bc1 = 3*R + 2*dt ;
00357     *bc2 = 2*R*dt ;
00358     *tbc3 = 0 ;
00359       }
00360       else {
00361     if (nz0>1) bound3.annule(0,nz0-2) ;
00362 
00363     bound3.coef() ;
00364     bound3.ylm() ;
00365     
00366     *bc1 = 3*R + 2*dt ;
00367     *bc2 = 2*R*dt ;
00368     
00369     tbc3->set_etat_qcq() ;
00370     double val ;
00371     for (int k=0; k<np2; k++)
00372       for (int j=0; j<nt; j++) {
00373         val = 0. ;
00374         for (int i=0; i<nr; i++) 
00375           val += (*bound3.c_cf)(nz0-1,k,j,i) ;
00376         tbc3->set(k,j) = val ;
00377       }
00378       }
00379       break ;
00380     }
00381     /******************************************************************
00382      * Enhanced outgoing wave condition. 
00383      * Time integration of the wave equation on the sphere for the 
00384      * auxiliary function phij.
00385      *****************************************************************/
00386      case 2: { 
00387       Valeur souphi(mg) ;
00388       souphi = fj_local.get_spectral_va()/R - fj_local.dsdr().get_spectral_va() ;
00389       if (nz0>1) souphi.annule(0,nz0-2) ;
00390       souphi.coef() ;
00391       souphi.ylm() ;
00392 
00393       bool zero = (souphi.get_etat() == ETATZERO) ;
00394       if (zero) {
00395     Base_val base_ref(mg->std_base_scal()) ; //## Maybe not good...
00396     base_ref.dsdx() ;
00397     base_ref.ylm() ;
00398     souphi.set_base(base_ref) ;
00399       }
00400 
00401       int l_s, m_s, base_r ;
00402       double val ;
00403       int dl = (par.get_n_int() > 1) ? -1 : 0 ;
00404       for (int k=0; k<np2; k++) {
00405     for (int j=0; j<nt; j++) {
00406       donne_lm(nz, nz0-1, j, k, souphi.base, m_s, l_s, base_r) ;
00407       l_s += dl ;
00408       val = 0. ;
00409       if (!zero)
00410           val = -4*dt*dt*l_s*(l_s+1)*souphi.c_cf->val_out_bound_jk(nz0-1, j, k) ;
00411       double multi = 8*R*R + dt*dt*(6+3*l_s*(l_s+1)) + 12*R*dt ;
00412       val = ( 16*R*R*(*phij)(k,j) -
00413           (multi-24*R*dt)*(*phijm1)(k,j) 
00414           + val)/multi ;
00415       phijm1->set(k,j) = (*phij)(k,j) ; 
00416       phij->set(k,j) = val ;
00417     }
00418       }
00419       Valeur bound3(mg) ;
00420       *bc1 = 3*R + 2*dt ;
00421       *bc2 = 2*R*dt ;
00422       bound3 = R*(4*fj_local.get_spectral_va() - fjm1_local.get_spectral_va()) ;
00423       if (bound3.get_etat() == ETATZERO) *tbc3 = 0 ;
00424       else {
00425     if (nz0 > 1) bound3.annule(0,nz0-2) ;
00426     bound3.coef() ;
00427     bound3.ylm() ;
00428     tbc3->set_etat_qcq() ;
00429     for (int k=0; k<np2; k++)
00430       for (int j=0; j<nt; j++) {
00431         val = 0. ;
00432         for (int i=0; i<nr; i++) 
00433           val += (*bound3.c_cf)(nz0-1,k,j,i) ;
00434         tbc3->set(k,j) = val + 2*R*dt*(*phij)(k,j);
00435       }
00436       }
00437       break ;
00438     }
00439     default:
00440       cout << "ERROR: Map_af::dalembert" << endl ;
00441       cout << "The boundary condition par.get_int(0) = "<< par.get_int(0) 
00442        << " is unknown!" << endl ;
00443       abort() ;
00444     }
00445 
00446     if (sigma.get_etat() == ETATZERO) {
00447       fjp1.set_etat_zero() ;
00448       return ;  
00449     }
00450 
00451     // Spherical harmonic expansion of the source
00452     // ------------------------------------------    
00453     Valeur& sourva = sigma.set_spectral_va() ; 
00454 
00455     // Spectral coefficients of the source
00456     assert(sourva.get_etat() == ETATQCQ) ; 
00457     sourva.ylm() ;          // spherical harmonic transforms 
00458 
00459     // Final result returned as a Scalar
00460     // ------------------------------
00461     fjp1.set_etat_zero() ;  // to call Scalar::del_t().
00462     fjp1.set_etat_qcq() ; 
00463     
00464     // Call to the Mtbl_cf version
00465     // ---------------------------
00466     fjp1.set_spectral_va() = sol_dalembert(par, *this, *(sourva.c_cf) ) ;
00467     fjp1.set_spectral_va().ylm_i() ; // Back to standard basis.  
00468 
00469     if (ced) {
00470         if (fj.get_etat() == ETATZERO) {
00471             fjp1.annule_domain(nz-1) ; 
00472         }
00473         else {
00474             fjp1.set_domain(nz-1) = fj.domain(nz-1) ;
00475         }
00476     fjp1.set_dzpuis(fj.get_dzpuis()) ;
00477     }
00478 }
00479 
00480 

Generated on Tue Feb 7 01:35:17 2012 for LORENE by  doxygen 1.4.6