LORENE
wave_utilities.C
1 /*
2  * Miscellaneous functions for the wave equation
3  *
4  */
5 
6 /*
7  * Copyright (c) 2008 Jerome Novak
8  *
9  * This file is part of LORENE.
10  *
11  * LORENE is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2
13  * as published by the Free Software Foundation.
14  *
15  * LORENE is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with LORENE; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  */
25 
26 
27 
28 /*
29  * $Id: wave_utilities.C,v 1.14 2019/04/25 13:52:52 j_novak Exp $
30  * $Log: wave_utilities.C,v $
31  * Revision 1.14 2019/04/25 13:52:52 j_novak
32  * Considering also l_q + dl = 0 momenta in evolve_BC.
33  *
34  * Revision 1.13 2018/12/04 16:36:02 j_novak
35  * Changed test on l_q in evolve_outgoing_BC to treat cases l=0 & 1
36  *
37  * Revision 1.12 2016/12/05 16:18:10 j_novak
38  * Suppression of some global variables (file names, loch, ...) to prevent redefinitions
39  *
40  * Revision 1.11 2014/10/13 08:53:31 j_novak
41  * Lorene classes and functions now belong to the namespace Lorene.
42  *
43  * Revision 1.10 2008/12/05 13:09:10 j_novak
44  * Minor change in tilde_laplacian.
45  *
46  * Revision 1.9 2008/12/04 18:20:41 j_novak
47  * Better treatment of the case ETATZERO in BC initialization, and of dzpuis for
48  * evolution.
49  *
50  * Revision 1.8 2008/11/27 12:12:38 j_novak
51  * New function to initialize parameters for wave equation.
52  *
53  * Revision 1.7 2008/10/29 08:22:58 jl_cornou
54  * Compatibility conditions in the vector wave-equation case added
55  *
56  * Revision 1.6 2008/10/14 13:10:58 j_novak
57  * New function Dirichlet_BC_AtB, to compute Dirichlet boundary conditions on A and B potentials knowing them on the tensor h^{ij}.
58  *
59  * Revision 1.5 2008/08/27 08:11:47 j_novak
60  * Correction of a mistake in the index in evolve_outgoing_BC.
61  *
62  * Revision 1.4 2008/08/19 06:42:00 j_novak
63  * Minor modifications to avoid warnings with gcc 4.3. Most of them concern
64  * cast-type operations, and constant strings that must be defined as const char*
65  *
66  * Revision 1.3 2008/07/18 12:28:41 j_novak
67  * Corrected some mistakes.
68  *
69  * Revision 1.2 2008/07/18 09:17:35 j_novak
70  * New function tilde_laplacian().
71  *
72  * Revision 1.1 2008/07/11 13:20:54 j_novak
73  * Miscellaneous functions for the wave equation.
74  *
75  *
76  * $Header $
77  *
78  */
79 
80 #include"tensor.h"
81 #include"evolution.h"
82 
83 namespace Lorene {
84 void tilde_laplacian(const Scalar& B_in, Scalar& tilde_lap, int dl) {
85 
86  if (B_in.get_etat() == ETATZERO) {
87  tilde_lap.set_etat_zero() ;
88  return ;
89  }
90  assert(B_in.check_dzpuis(0)) ; ;
91  if (dl == 0) {
92  tilde_lap = B_in.laplacian(0) ;
93  return ;
94  }
95  assert(B_in.get_etat() != ETATNONDEF) ;
96  const Map_af* map =dynamic_cast<const Map_af*>(&B_in.get_mp()) ;
97  assert(map != 0x0) ;
98 
99  tilde_lap = 2*B_in.dsdr() ;
100  tilde_lap.div_r_dzpuis(3) ;
101  tilde_lap += B_in.dsdr().dsdr() ;
102  tilde_lap.dec_dzpuis() ;
103  tilde_lap.set_spectral_va().ylm() ;
104  Scalar B_over_r2 = B_in ;
105  B_over_r2.div_r_dzpuis(1) ;
106  B_over_r2.div_r_dzpuis(2) ;
107  B_over_r2.set_spectral_va().ylm() ;
108 
109  const Base_val& base = B_in.get_spectral_base() ;
110  const Mg3d& mg = *map->get_mg() ;
111  int nz = mg.get_nzone() ;
112  int l_q, m_q, base_r ;
113  for (int lz=0; lz<nz; lz++) {
114  if (B_in.domain(lz).get_etat() == ETATZERO) {
115  tilde_lap.set_spectral_va().c_cf->set(lz).set_etat_zero() ;
116  }
117  else {
118  for (int k=0; k<mg.get_np(lz)+2; k++)
119  for (int j=0; j<mg.get_nt(lz); j++) {
120  base.give_quant_numbers(lz, k, j, m_q, l_q, base_r) ;
121  if (l_q > 1) {
122  l_q += dl ;
123  for (int i=0; i<mg.get_nr(lz); i++)
124  tilde_lap.set_spectral_va().c_cf->set(lz, k, j, i)
125  -= l_q*(l_q+1)*
126  (*B_over_r2.get_spectral_va().c_cf)(lz, k, j, i) ;
127  }
128  }
129  }
130  }
131  if (tilde_lap.get_spectral_va().c != 0x0) {
132  delete tilde_lap.set_spectral_va().c ;
133  tilde_lap.set_spectral_va().c = 0x0 ;
134  }
135  tilde_lap.dec_dzpuis(2) ;
136  return ;
137 }
138 
139 /* Performs one time-step integration of the wave equation, using
140  * a third-order Runge-Kutta scheme.
141  * phi = d fff / dt
142  * \Delta fff = d phi / dt
143  * Inputs are dt, fff, phi; outputs fnext, phinext.
144  */
145 void runge_kutta3_wave_sys(double dt, const Scalar& fff, const Scalar& phi,
146  Scalar& fnext, Scalar& phinext, int dl) {
147 
148  const Map& map = fff.get_mp() ;
149  Scalar k1 = phi ;
150  Scalar dk1(map) ; tilde_laplacian(fff, dk1, dl) ;
151  Scalar y1 = fff + 0.5*dt*k1 ;
152  Scalar dy1 = phi + 0.5*dt*dk1 ;
153  Scalar k2 = dy1 ; Scalar dk2(map) ; tilde_laplacian(y1, dk2, dl) ;
154  Scalar y2 = fff - dt*k1 + 2*dt*k2 ;
155  Scalar dy2 = phi - dt*dk1 + 2*dt*dk2 ;
156  Scalar k3 = dy2 ;
157  Scalar dk3(map) ; tilde_laplacian(y2, dk3, dl) ;
158  fnext = fff + dt*(k1 + 4*k2 + k3)/6. ;
159  phinext = phi + dt*(dk1 + 4*dk2 + dk3)/6. ;
160 
161  return ;
162 }
163 
164 void initialize_outgoing_BC(int nz_bound, const Scalar& phi, const Scalar& dphi,
165  Tbl& xij)
166 {
167  Scalar source_xi = phi ;
168  source_xi.div_r_dzpuis(2) ;
169  source_xi += phi.dsdr() ;
170  source_xi.dec_dzpuis(2) ;
171  source_xi += dphi ;
172  if (source_xi.get_etat() == ETATZERO)
173  xij.annule_hard() ;
174  else {
175  source_xi.set_spectral_va().ylm() ;
176 
177  const Base_val& base_x = source_xi.get_spectral_base() ;
178  int np2 = xij.get_dim(1) ;
179  int nt = xij.get_dim(0) ;
180  assert (source_xi.get_mp().get_mg()->get_np(nz_bound) + 2 == np2 ) ;
181  assert (source_xi.get_mp().get_mg()->get_nt(nz_bound) == nt ) ;
182 
183  int l_q, m_q, base_r ;
184  for (int k=0; k<np2; k++)
185  for (int j=0; j<nt; j++) {
186  base_x.give_quant_numbers(nz_bound, k, j, m_q, l_q, base_r) ;
187  xij.set(k, j)
188  = source_xi.get_spectral_va().c_cf->val_out_bound_jk(nz_bound, j, k) ;
189  if (l_q == 0)
190  xij.set(k,j) = 0 ;
191  }
192  }
193 }
194 
195 
196 /* Performs one time-step integration of the quantities needed for the
197  * enhanced outgoing-wave boundary condition. It DOES NOT impose the BC
198  * d phi / dr + d phi / dt + phi / r = xi(theta, varphi).
199  * nz_bound: index of the domain on which to impose the BC
200  * phi: the field that should leave the grid
201  * sphi: source of the Robin BC, without xi : a phi + b d phi / dr = sphi + xi
202  * ccc: (output) total source of the Robin BC
203  */
204 void evolve_outgoing_BC(double dt, int nz_bound, const Scalar& phi, Scalar& sphi,
205  Tbl& xij, Tbl& xijm1, Tbl& ccc, int dl) {
206 
207  const Map* map = &phi.get_mp() ;
208  const Map_af* mp_aff = dynamic_cast<const Map_af*>(map) ;
209  assert(mp_aff != 0x0) ;
210 
211  const Mg3d& grid = *mp_aff->get_mg() ;
212 #ifndef NDEBUG
213  int nz = grid.get_nzone() ;
214  assert(nz_bound < nz) ;
215  assert(phi.get_etat() != ETATZERO) ;
216  assert(sphi.get_etat() != ETATZERO) ;
217 #endif
218  int np2 = grid.get_np(nz_bound) + 2 ;
219  int nt = grid.get_nt(nz_bound) ;
220  assert(xij.get_ndim() == 2) ;
221  assert(xijm1.get_ndim() == 2) ;
222  assert(ccc.get_ndim() == 2) ;
223  assert(xij.get_dim(0) == nt) ;
224  assert(xij.get_dim(1) == np2) ;
225  assert(xijm1.get_dim(0) == nt) ;
226  assert(xijm1.get_dim(1) == np2) ;
227  assert(ccc.get_dim(0) == nt) ;
228  assert(ccc.get_dim(1) == np2) ;
229 
230  double Rmax = mp_aff->get_alpha()[nz_bound] + mp_aff->get_beta()[nz_bound] ;
231 
232  Scalar source_xi = phi ;
233  int dzp = ( source_xi.get_dzpuis() == 0 ? 2 : source_xi.get_dzpuis()+1 ) ;
234  source_xi.div_r_dzpuis(dzp) ;
235  source_xi -= phi.dsdr() ;
236  source_xi.set_spectral_va().ylm() ;
237  sphi.set_spectral_va().ylm() ;
238  const Base_val& base = sphi.get_spectral_base() ;
239  int l_q, m_q, base_r ;
240  for (int k=0; k<np2; k++)
241  for (int j=0; j<nt; j++) {
242  base.give_quant_numbers(nz_bound, k, j, m_q, l_q, base_r) ;
243  if (l_q + dl >= 0) {
244  l_q += dl ;
245  double fact = 8*Rmax*Rmax + dt*dt*(6+3*l_q*(l_q+1)) + 12*Rmax*dt ;
246  double souphi = -4*dt*dt*l_q*(l_q+1)*
247  source_xi.get_spectral_va().c_cf->val_out_bound_jk(nz_bound, j, k) ;
248  double xijp1 = ( 16*Rmax*Rmax*xij(k,j) -
249  (fact - 24*Rmax*dt)*xijm1(k,j)
250  + souphi) / fact ;
251  ccc.set(k, j) = xijp1
252  + sphi.get_spectral_va().c_cf->val_out_bound_jk(nz_bound, j, k) ;
253  xijm1.set(k,j) = xij(k,j) ;
254  xij.set(k,j) = xijp1 ;
255  }
256  }
257 
258 }
259 
260 void Dirichlet_BC_AtB(const Evolution_std<Sym_tensor>& hb_evol,
261  const Evolution_std<Sym_tensor>& dhb_evol, Tbl& ccA, Tbl& ccB) {
262 
263  int iter = hb_evol.j_max() ;
264  assert(dhb_evol.j_max() == iter) ;
265 
266  Scalar mu_ddot = dhb_evol.time_derive(iter,3).mu() ;
267 
268  Tbl ddmu = mu_ddot.tbl_out_bound(0, true) ;
269  int nt = ddmu.get_dim(0) ;
270  int np2 = ddmu.get_dim(1) ;
271  const Base_val& base = mu_ddot.get_spectral_base() ;
272  int l_q, m_q, base_r ;
273  ccA.annule_hard() ;
274  for (int k=0; k<np2; k++) {
275  for (int j=0; j<nt; j++) {
276  base.give_quant_numbers(0, k, j, m_q, l_q, base_r) ;
277  if (l_q>1)
278  ccA.set(k,j) = ddmu(k,j) / double(l_q*(l_q+1)-2) ;
279  }
280  }
281 
282  Scalar hrr_ddot = dhb_evol.time_derive(iter,3)(1,1) ;
283  Tbl ddhrr = hrr_ddot.tbl_out_bound(0, true) ;
284  Scalar eta_ddot = dhb_evol.time_derive(iter,3).eta() ;
285  Tbl ddeta = eta_ddot.tbl_out_bound(0, true) ;
286  const Base_val& base2 = hrr_ddot.get_spectral_base() ;
287 
288  const Map& map = hrr_ddot.get_mp() ;
289  const Map_radial* mp_rad = dynamic_cast<const Map_radial*>(&map) ;
290  assert(mp_rad != 0x0) ;
291  for (int k=0; k<np2; k++) {
292  for (int j=0; j<nt; j++) {
293  base2.give_quant_numbers(0, k, j, m_q, l_q, base_r) ;
294  if (l_q>1) {
295  ccB.set(k,j) = (double(l_q+1)*ddeta(k,j)
296  + ddhrr(k,j)*mp_rad->val_r_jk(0, 1., j, k))
297  / double((l_q+1)*(l_q-1)) ;
298  }
299  }
300  }
301 
302 }
303 
304 
305 void Dirichlet_BC_Amu(const Evolution_std<Vector>& vb_evol,
306  const Evolution_std<Vector>& dvb_evol, Tbl& ccA, Tbl& ccmu) {
307 
308  int iter = vb_evol.j_max() ;
309  assert(dvb_evol.j_max() == iter) ;
310 
311  Scalar vr_ddot = dvb_evol.time_derive(iter,3)(1) ;
312 
313  Tbl ddvr = vr_ddot.tbl_out_bound(0, true) ;
314  int nt = ddvr.get_dim(0) ;
315  int np2 = ddvr.get_dim(1) ;
316  const Base_val& base = vr_ddot.get_spectral_base() ;
317  int l_q, m_q, base_r ;
318  ccA.annule_hard() ;
319  ccmu.annule_hard() ;
320  Scalar mu_b = vb_evol[iter].mu();
321  ccmu = mu_b.tbl_out_bound(0,true);
322  const Map& map = vr_ddot.get_mp();
323  const Map_radial* mp_rad = dynamic_cast<const Map_radial*>(&map);
324  assert(mp_rad != 0x0) ;
325  for (int k=0; k<np2; k++) {
326  for (int j=0; j<nt; j++) {
327  base.give_quant_numbers(0, k, j, m_q, l_q, base_r) ;
328  if (l_q>0) {
329  ccA.set(k,j) = ddvr(k,j)*mp_rad->val_r_jk(0, 1., j, k) / double(l_q*(l_q+1)) ;
330  }
331  }
332  }
333  }
334 
335 
336 
337 
338 
339 }
Lorene prototypes.
Definition: app_hor.h:67