LORENE
app_hor_finder.C
1 /*
2  * Function ah_finder
3  *
4  * (see file app_hor.h for documentation)
5  */
6 
7 /*
8  * Copyright (c) 2005 Lap-Ming Lin & Jerome Novak
9  *
10  *
11  * This file is part of LORENE.
12  *
13  * LORENE is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2
15  * as published by the Free Software Foundation.
16  *
17  * LORENE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with LORENE; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  *
26  */
27 
28 
29 
30 /*
31  * $Id: app_hor_finder.C,v 1.13 2024/01/26 17:44:25 g_servignat Exp $
32  * $Log: app_hor_finder.C,v $
33  * Revision 1.13 2024/01/26 17:44:25 g_servignat
34  * Updated the Pseudopolytrope_1D class to be consistent with the paper (i.e. with a GPP in the middle)
35  *
36  * Revision 1.12 2016/12/05 16:17:44 j_novak
37  * Suppression of some global variables (file names, loch, ...) to prevent redefinitions
38  *
39  * Revision 1.11 2014/10/13 08:52:38 j_novak
40  * Lorene classes and functions now belong to the namespace Lorene.
41  *
42  * Revision 1.10 2014/10/06 15:12:56 j_novak
43  * Modified #include directives to use c++ syntax.
44  *
45  * Revision 1.9 2012/01/02 13:52:57 j_novak
46  * New parameter 'verbose' to get less output if needed.
47  *
48  * Revision 1.8 2008/01/08 13:56:54 j_novak
49  * Minor modif.
50  *
51  * Revision 1.7 2007/10/23 12:26:08 j_novak
52  * Added a test for the case where there is no AH, h(theta,phi) is then going out of the grid
53  *
54  * Revision 1.6 2005/12/09 09:35:06 lm_lin
55  *
56  * Add more information to screen output if no convergence.
57  *
58  * Revision 1.5 2005/12/07 14:16:36 lm_lin
59  *
60  * Add option to turn off screen output if no horizon is found
61  * (for performance reason in hydrodynamics simulation).
62  *
63  * Revision 1.4 2005/12/07 11:11:09 lm_lin
64  *
65  * Add option to turn off screen output during iterations.
66  *
67  * Revision 1.3 2005/11/17 15:53:28 lm_lin
68  *
69  * A tiny fix.
70  *
71  * Revision 1.2 2005/11/17 14:20:43 lm_lin
72  *
73  * Check the expansion function evaluated on the apparent horizon after the
74  * iteration of the 2-surface converges.
75  *
76  * Revision 1.1 2005/10/13 08:51:15 j_novak
77  * New stuff for apparent horizon finder. For the moment, there is only an
78  * external function. A class should come soon...
79  *
80  *
81  *
82  * $Header: /cvsroot/Lorene/C++/Source/App_hor/app_hor_finder.C,v 1.13 2024/01/26 17:44:25 g_servignat Exp $
83  *
84  */
85 
86 
87 // C headers
88 #include <cmath>
89 #include <cassert>
90 
91 // Lorene headers
92 #include "app_hor.h"
93 #include "graphique.h"
94 
95 
96 namespace Lorene {
97 bool ah_finder(const Metric& gamma, const Sym_tensor& k_dd, Valeur& h, Scalar& ex_fcn,
98  double a_axis, double b_axis, double c_axis, bool verbose, bool print,
99  double precis, double precis_exp, int step_max, int step_relax,
100  double relax)
101 {
102 
103  bool ah_flag = false ;
104 
105  //Get the mapping, grid, base vector...etc
106  const Map& map = gamma.get_mp() ;
107  const Mg3d* mg = map.get_mg() ;
108  const Mg3d* g_angu = mg->get_angu() ;
109  int nz = mg->get_nzone() ;
110 
111  const Base_vect_spher& bspher = map.get_bvect_spher() ;
112 
113  const Coord& rr = map.r ;
114  const Coord& theta = map.tet ;
115  const Coord& phi = map.phi ;
116  const Coord& costh = map.cost ;
117  const Coord& cosph = map.cosp ;
118  const Coord& sinth = map.sint ;
119  const Coord& sinph = map.sinp ;
120 
121  double r_min = min(+rr)(0) ;
122  double r_max = max(+rr)(nz-1) ;
123 
124  // Set up a triaxial ellipsoidal surface as the initial guess for h
125  //------------------------------------------------------------------
126 
127  double aa = a_axis ;
128  double bb = b_axis ;
129  double cc = c_axis ;
130 
131  Scalar ct(map) ;
132  ct = costh ;
133  ct.std_spectral_base() ;
134 
135  Scalar st(map) ;
136  st = sinth ;
137  st.std_spectral_base() ;
138 
139  Scalar cp(map) ;
140  cp = cosph ;
141  cp.std_spectral_base() ;
142 
143  Scalar sp(map) ;
144  sp = sinph ;
145  sp.std_spectral_base() ;
146 
147  Scalar h_tmp(map) ;
148 
149  h_tmp = st*st*( cp*cp/aa/aa + sp*sp/bb/bb ) + ct*ct/cc/cc ;
150  h_tmp = 1./sqrt( h_tmp ) ;
151  h_tmp.std_spectral_base() ;
152 
153  Valeur h_guess(g_angu) ;
154  h_guess.annule_hard() ;
155 
156  for (int l=0; l<nz; l++) {
157 
158  int jmax = mg->get_nt(l) ;
159  int kmax = mg->get_np(l) ;
160 
161  for (int k=0; k<kmax; k++) {
162  for (int j=0; j<jmax; j++) {
163  h_guess.set(l,k,j,0) = h_tmp.val_grid_point(l,k,j,0) ;
164  }
165  }
166  }
167 
168  h_guess.std_base_scal() ;
169 
170  h = h_guess ; // initialize h to h_guess
171  h.std_base_scal() ;
172 
173  //End setting initial guess for h
174  //------------------------------------
175 
176  const Metric_flat& fmets = map.flat_met_spher() ;
177 
178 
179  // Define the conformal factor
180  double one_third = double(1) / double(3) ;
181 
182  Scalar psi4 = gamma.determinant() / fmets.determinant() ;
183  psi4 = pow( psi4, one_third ) ;
184  psi4.std_spectral_base() ;
185 
186  // The expansion function at the n-1 iteration step
187  Scalar ex_fcn_old(map) ;
188  ex_fcn_old.set_etat_zero() ;
189 
190  // The expansion function evaulated on the 2 surface h
191  Valeur ex_AH(g_angu) ;
192  ex_AH.annule_hard() ;
193 
194  // Normal unit vector of the level set surface F = r - h(\theta,phi)
195  Vector s_unit(map, CON, bspher) ;
196 
197  double relax_prev = double(1) - relax ;
198  double diff_exfcn = 1. ;
199  Tbl diff_h(nz) ;
200  diff_h = 1. ;
201 
202  bool no_AH_in_grid = false ;
203 
204  //--------------------------------------------------------
205  // Start of iteration
206  //--------------------------------------------------------
207 
208  for (int step=0 ;
209  (max(diff_h) > precis) && (step < step_max) && (!no_AH_in_grid);
210  step++) {
211 
212 
213  // ***To be fixed: the function "set_grid_point" does not delete the derived
214  // quantities of F.
215  // Temporary fix: Define the level set F inside the iteration loop...
216  //----------------------------------------------------------------
217 
218  Scalar F(map) ; // level set function: F = r - h(theta,phi)
219  F.allocate_all() ;
220 
221  for (int l=0; l<nz; l++) {
222 
223  int imax = mg->get_nr(l) ;
224  int jmax = mg->get_nt(l) ;
225  int kmax = mg->get_np(l) ;
226 
227  for (int k=0; k<kmax; k++) {
228  for (int j=0; j<jmax; j++) {
229  for (int i=0; i<imax; i++) {
230 
231  // (+rr) converts rr to Mtbl
232  F.set_grid_point(l,k,j,i) = (+rr)(l,k,j,i) - h(l,k,j,0) ;
233 
234  }
235  }
236  }
237  }
238 
239  F.std_spectral_base() ;
240 
241  // Construct the unit normal vector s^i of the surface F
242  Scalar dF_norm(map) ;
243  dF_norm = contract( contract(gamma.con(), 0, F.derive_cov(gamma), 0),
244  0, F.derive_cov(gamma), 0) ;
245  dF_norm = sqrt( dF_norm ) ;
246  dF_norm.std_spectral_base() ;
247 
248  s_unit = F.derive_con(gamma) / dF_norm ;
249 
250  // The expansion function
251  ex_fcn = s_unit.divergence(gamma) - k_dd.trace(gamma) +
252  contract( s_unit, 0, contract(s_unit, 0, k_dd, 1), 0) ;
253 
254  // Construct the source term for the angular Laplace equation
255  //---------------------------------------------------------
256 
257  Sym_tensor sou_1(map, CON, bspher) ;
258  sou_1 = gamma.con() - fmets.con()/psi4 - s_unit*s_unit ;
259 
260  Scalar source_tmp(map) ;
261  source_tmp = contract( sou_1, 0, 1, F.derive_cov(fmets).derive_cov(fmets), 0, 1 ) ;
262  source_tmp = source_tmp / dF_norm ;
263 
264  Sym_tensor d_gam(map, COV, bspher) ;
265  d_gam = contract( gamma.connect().get_delta(), 0, F.derive_cov(fmets), 0) ;
266 
267  source_tmp -= contract( gamma.con() - s_unit*s_unit, 0, 1,
268  d_gam, 0, 1) / dF_norm ;
269 
270  source_tmp = psi4*dF_norm*( source_tmp - k_dd.trace(gamma) +
271  contract(s_unit, 0, contract(s_unit, 0, k_dd, 1), 0) ) ;
272 
273  source_tmp.std_spectral_base() ;
274 
275 
276  Valeur sou_angu(g_angu) ; // source defined on the angular grid
277  // S(theta, phi) = S(h(theta,phi),theta,phi)
278  sou_angu.annule_hard() ;
279 
280  double h_min = min(h)(0) ;
281  double h_max = max(h)(0) ;
282  // cout << "r_min : " << r_min << " h_min : " << h_min << " h_max : " << h_max << " r_max : " << r_max << endl;
283  // cout << "cdt : " << ( (r_min < h_min) && (h_max < r_max) ) << endl;
284  if ( (r_min < h_min) && (h_max < r_max) ) {
285 
286  for (int l=0; l<nz; l++) {
287 
288  int jmax = mg->get_nt(l) ;
289  int kmax = mg->get_np(l) ;
290  for (int k=0; k<kmax; k++) {
291  for (int j=0; j<jmax; j++) {
292  sou_angu.set(l,k,j,0) = source_tmp.val_point(h(l,k,j,0)
293  ,(+theta)(l,k,j,0) ,(+phi)(l,k,j,0)) ;
294  }
295  }
296  }
297  sou_angu = h*h*sou_angu ; // Final source term: psi4*dF_norm*h^2*(source_tmp)
298  }
299  else {
300  no_AH_in_grid = true ;
301  break ;
302  }
303  sou_angu.std_base_scal() ;
304 
305 
306  // Done with the source term
307  //-----------------------------------------
308 
309 
310  // Start solving the equation L^2h - 2h = source
311  //-----------------------------------------------
312 
313  sou_angu.ylm() ;
314 
315  Valeur h_new = sou_angu ;
316 
317  h_new.c_cf->poisson_angu(-2.) ;
318 
319  h_new.ylm_i() ;
320 
321  if (h_new.c != 0x0)
322  delete h_new.c ;
323  h_new.c = 0x0 ;
324  h_new.coef_i() ;
325 
326  // Convergence condition:
327  diff_h = max(abs(h - h_new)) ;
328 
329 
330  // Relaxations
331  if (step >= step_relax) {
332  h_new = relax * h_new + relax_prev * h ;
333  }
334 
335  // Recycling for the next step
336  h = h_new ;
337 
338 
339  if (print)
340  {
341 
342  cout << "-------------------------------------" << endl ;
343  cout << "App_hor iteration step: " << step << endl ;
344  cout << " " << endl ;
345 
346  cout << "Difference in h : " << diff_h << endl ;
347 
348  // Check: calculate the difference between ex_fcn and ex_fcn_old
349  Tbl diff_exfcn_tbl = diffrel( ex_fcn, ex_fcn_old ) ;
350  diff_exfcn = diff_exfcn_tbl(0) ;
351  for (int l=1; l<nz; l++) {
352  diff_exfcn += diff_exfcn_tbl(l) ;
353  }
354  diff_exfcn /= nz ;
355  cout << "diff_exfcn : " << diff_exfcn << endl ;
356 
357  ex_fcn_old = ex_fcn ; // recycling
358  // End check
359 
360  }
361 
362  if ( (step == step_max-1) && (max(diff_h) > precis) ) {
363 
364 
365  //Check: Evaluate the expansion function on the 2-surface
366 
367  for (int l=0; l<nz; l++) {
368 
369  int jmax = mg->get_nt(l) ;
370  int kmax = mg->get_np(l) ;
371 
372  for (int k=0; k<kmax; k++) {
373  for (int j=0; j<jmax; j++) {
374 
375  ex_AH.set(l,k,j,0) = ex_fcn.val_point(h(l,k,j,0),(+theta)(l,k,j,0)
376  ,(+phi)(l,k,j,0)) ;
377  }
378  }
379  }
380 
381  if (verbose) {
382  cout << " " << endl ;
383  cout << "###############################################" << endl ;
384  cout << "AH finder: maximum number of iteration reached!" << endl ;
385  cout << " No convergence in the 2-surface h! " << endl ;
386  cout << " max( difference in h ) > prescribed tolerance " << endl ;
387  cout << " " << endl ;
388  cout << " prescribed tolerance = " << precis << endl ;
389  cout << " max( difference in h ) = " << max(diff_h) << endl ;
390  cout << " max( expansion function on h ) = " << max(abs(ex_AH(0))) << endl ;
391  cout << "###############################################" << endl ;
392  cout << " " << endl ;
393 
394  }
395  }
396 
397 
398  } // End of iteration
399 
400  //Done with the AH finder
401 
402 
403 
404  //Check: Evaluate the expansion function on the 2-surface
405 
406  if (no_AH_in_grid) {
407  if (print) {
408  cout << " " << endl ;
409  cout << "###############################################" << endl ;
410  cout << " AH finder: no horizon found inside the grid!" << endl ;
411  cout << " Grid: rmin= " << r_min << ", rmax= " << r_max << endl ;
412  cout << "###############################################" << endl ;
413  cout << " " << endl ;
414  }
415  }
416  else {
417  for (int l=0; l<nz; l++) {
418 
419  int jmax = mg->get_nt(l) ;
420  int kmax = mg->get_np(l) ;
421 
422  for (int k=0; k<kmax; k++) {
423  for (int j=0; j<jmax; j++) {
424 
425  ex_AH.set(l,k,j,0) = ex_fcn.val_point(h(l,k,j,0),(+theta)(l,k,j,0)
426  ,(+phi)(l,k,j,0)) ;
427  }
428  }
429  }
430 
431 
432 
433  if ( (max(diff_h) < precis) && (max(abs(ex_AH(0))) < precis_exp) ) {
434 
435  ah_flag = true ;
436 
437  if (verbose) {
438  cout << " " << endl ;
439  cout << "################################################" << endl ;
440  cout << " AH finder: Apparent horizon found!!! " << endl ;
441  cout << " Max error of the expansion function on h: " << endl ;
442  cout << " max( expansion function on AH ) = " << max(abs(ex_AH(0))) << endl ;
443  cout << "################################################" << endl ;
444  cout << " " << endl ;
445  }
446 
447  }
448 
449  if ( (max(diff_h) < precis) && (max(abs(ex_AH(0))) > precis_exp) ) {
450 
451  if (print) {
452  cout << " " << endl ;
453  cout << "#############################################" << endl ;
454  cout << " AH finder: convergence in the 2 surface h. " << endl ;
455  cout << " But max error of the expansion function evaulated on h > precis_exp" << endl ;
456  cout << " max( expansion function on AH ) = " << max(abs(ex_AH(0))) << endl ;
457  cout << " Probably not an apparent horizon! " << endl ;
458  cout << "#############################################" << endl ;
459  cout << " " << endl ;
460  }
461 
462  }
463  }
464  return ah_flag ;
465 
466 } // End ah_finder
467 
468 }
Metric for tensor calculation.
Definition: metric.h:90
void poisson_angu(double lambda=0)
Resolution of the generalized angular Poisson equation.
Definition: mtbl_cf_pde.C:86
virtual const Sym_tensor & con() const
Read-only access to the contravariant representation.
Definition: metric.C:293
Mtbl_cf * c_cf
Coefficients of the spectral expansion of the function.
Definition: valeur.h:312
void ylm_i()
Inverse of ylm()
Definition: valeur_ylm_i.C:134
int get_np(int l) const
Returns the number of points in the azimuthal direction ( ) in domain no. l.
Definition: grilles.h:479
Cmp sqrt(const Cmp &)
Square root.
Definition: cmp_math.C:223
virtual void set_etat_zero()
Sets the logical state to ETATZERO (zero).
Definition: scalar.C:330
virtual const Scalar & determinant() const
Returns the determinant.
Definition: metric_flat.C:217
const Base_vect_spher & get_bvect_spher() const
Returns the orthonormal vectorial basis associated with the coordinates of the mapping.
Definition: map.h:795
Lorene prototypes.
Definition: app_hor.h:67
void ylm()
Computes the coefficients of *this.
Definition: valeur_ylm.C:141
void annule_hard()
Sets the Valeur to zero in a hard way.
Definition: valeur.C:726
const Mg3d * get_mg() const
Gives the Mg3d on which the mapping is defined.
Definition: map.h:777
Flat metric for tensor calculation.
Definition: metric.h:261
Tensor field of valence 0 (or component of a tensorial field).
Definition: scalar.h:393
void coef_i() const
Computes the physical value of *this.
Base class for coordinate mappings.
Definition: map.h:682
bool ah_finder(const Metric &gamma, const Sym_tensor &k_dd_in, Valeur &h, Scalar &ex_fcn, double a_axis, double b_axis, double c_axis, bool verbose=true, bool print=false, double precis=1.e-8, double precis_exp=1.e-6, int it_max=200, int it_relax=200, double relax_fac=1.)
Apparent horizon linked functions.
virtual void std_spectral_base()
Sets the spectral bases of the Valeur va to the standard ones for a scalar field. ...
Definition: scalar.C:790
Values and coefficients of a (real-value) function.
Definition: valeur.h:297
virtual void allocate_all()
Sets the logical state to ETATQCQ (ordinary state) and performs the memory allocation of all the elem...
Definition: scalar.C:371
Tbl min(const Cmp &)
Minimum values of a Cmp in each domain.
Definition: cmp_math.C:461
const Vector & derive_con(const Metric &gam) const
Returns the "contravariant" derivative of *this with respect to some metric , by raising the index of...
Definition: scalar_deriv.C:402
Tensor field of valence 1.
Definition: vector.h:188
const Tensor_sym & get_delta() const
Returns the tensor which defines the connection with respect to the flat one: is the difference bet...
Definition: connection.h:271
Tbl diffrel(const Cmp &a, const Cmp &b)
Relative difference between two Cmp (norme version).
Definition: cmp_math.C:507
void std_base_scal()
Sets the bases for spectral expansions (member base ) to the standard ones for a scalar.
Definition: valeur.C:827
const Map & get_mp() const
Returns the mapping.
Definition: metric.h:202
Coord tet
coordinate centered on the grid
Definition: map.h:731
Coord phi
coordinate centered on the grid
Definition: map.h:732
Coord sint
Definition: map.h:733
virtual const Sym_tensor & con() const
Read-only access to the contravariant representation.
Definition: metric_flat.C:156
const Mg3d * get_angu() const
Returns the pointer on the associated angular grid.
Definition: mg3d.C:604
virtual const Connection & connect() const
Returns the connection.
Definition: metric.C:304
Mtbl * c
Values of the function at the points of the multi-grid.
Definition: valeur.h:309
Coord sinp
Definition: map.h:735
int get_nzone() const
Returns the number of domains.
Definition: grilles.h:465
Tbl max(const Cmp &)
Maximum values of a Cmp in each domain.
Definition: cmp_math.C:438
const Scalar & divergence(const Metric &) const
The divergence of this with respect to a Metric .
Definition: vector.C:387
Cmp pow(const Cmp &, int)
Power .
Definition: cmp_math.C:351
Tenseur contract(const Tenseur &, int id1, int id2)
Self contraction of two indices of a Tenseur .
const Tensor & derive_cov(const Metric &gam) const
Returns the covariant derivative of this with respect to some metric .
Definition: tensor.C:1011
Active physical coordinates and mapping derivatives.
Definition: coord.h:90
virtual const Scalar & determinant() const
Returns the determinant.
Definition: metric.C:395
double val_point(double r, double theta, double phi) const
Computes the value of the field at an arbitrary point , by means of the spectral expansion.
Definition: scalar.C:896
Spherical orthonormal vectorial bases (triads).
Definition: base_vect.h:308
int get_nr(int l) const
Returns the number of points in the radial direction ( ) in domain no. l.
Definition: grilles.h:469
Multi-domain grid.
Definition: grilles.h:279
double & set_grid_point(int l, int k, int j, int i)
Setting the value of the field at a given grid point.
Definition: scalar.h:690
Cmp abs(const Cmp &)
Absolute value.
Definition: cmp_math.C:413
Coord cosp
Definition: map.h:736
Basic array class.
Definition: tbl.h:164
int get_nt(int l) const
Returns the number of points in the co-latitude direction ( ) in domain no. l.
Definition: grilles.h:474
const Vector & derive_cov(const Metric &gam) const
Returns the gradient (1-form = covariant vector) of *this
Definition: scalar_deriv.C:390
const Metric_flat & flat_met_spher() const
Returns the flat metric associated with the spherical coordinates and with components expressed in th...
Definition: map.C:324
Class intended to describe valence-2 symmetric tensors.
Definition: sym_tensor.h:226
Tensor trace(int ind1, int ind2) const
Trace on two different type indices.
Coord r
r coordinate centered on the grid
Definition: map.h:730
Tbl & set(int l)
Read/write of the value in a given domain (configuration space).
Definition: valeur.h:373
Coord cost
Definition: map.h:734