diff options
Diffstat (limited to 'src/driver/Newton.cc')
-rw-r--r-- | src/driver/Newton.cc | 694 |
1 files changed, 642 insertions, 52 deletions
diff --git a/src/driver/Newton.cc b/src/driver/Newton.cc index 2a54d17..62bab31 100644 --- a/src/driver/Newton.cc +++ b/src/driver/Newton.cc @@ -10,15 +10,19 @@ /// Newton_step - take the Newton step, scaling it down if it's too large // +#include <iostream> + #include <stdio.h> #include <assert.h> #include <limits.h> #include <float.h> #include <math.h> +#include <string.h> #include "util_Table.h" #include "cctk.h" #include "cctk_Arguments.h" +#include "cctk_Parameters.h" #include "config.h" #include "stdc.h" @@ -26,6 +30,7 @@ #include "../jtutil/array.hh" #include "../jtutil/cpm_map.hh" #include "../jtutil/linear_map.hh" +using jtutil::error_exit; #include "../patch/coords.hh" #include "../patch/grid.hh" @@ -48,7 +53,6 @@ // all the code in this file is inside this namespace namespace AHFinderDirect { -using jtutil::error_exit; //****************************************************************************** @@ -67,6 +71,7 @@ bool broadcast_status(const cGH* GH, struct iteration_status_buffers& isb); void broadcast_horizon_data(const cGH* GH, bool broadcast_flag, bool broadcast_horizon_shape, + struct AH_data& AH_data, struct BH_diagnostics& BH_diagnostics, patch_system& ps, struct horizon_buffers& horizon_buffers); @@ -106,22 +111,22 @@ void Newton(const cGH* GH, const struct verbose_info& verbose_info, struct iteration_status_buffers& isb) { +cGH const * const cctkGH = GH; +DECLARE_CCTK_ARGUMENTS; +DECLARE_CCTK_PARAMETERS; + const bool my_active_flag = hs.has_genuine_horizons(); -const int N_horizons = hs.N_horizons(); // print out which horizons we're finding on this processor -if (verbose_info.print_physics_details) - then { - if (hs.has_genuine_horizons()) - then CCTK_VInfo(CCTK_THORNSTRING, - "proc %d: searching for horizon%s %s/%d", - my_proc, - (hs.my_N_horizons() > 1 ? "s" : ""), - hs.sequence_string(","), N_horizons); - else CCTK_VInfo(CCTK_THORNSTRING, - "proc %d: dummy horizon(s) only", - my_proc); - } +if (hs.has_genuine_horizons()) + then CCTK_VInfo(CCTK_THORNSTRING, + "proc %d: searching for horizon%s %s/%d", + my_proc, + (hs.my_N_horizons() > 1 ? "s" : ""), + hs.sequence_string(","), N_horizons); + else CCTK_VInfo(CCTK_THORNSTRING, + "proc %d: dummy horizon(s) only", + my_proc); // // each pass through this loop finds a single horizon, @@ -138,7 +143,10 @@ if (verbose_info.print_physics_details) "Newton_solve(): processor %d working on horizon %d", my_proc, hn); - const bool horizon_is_genuine = hs.is_genuine(); + // only try to find horizons every find_every time steps + const bool horizon_is_genuine = + hs.is_genuine() && AH_data_array[hn]->search_flag; + // this is only a pessimistic approximation const bool there_is_another_genuine_horizon = hs.is_next_genuine(); if (verbose_info.print_algorithm_details) then { @@ -152,12 +160,262 @@ if (verbose_info.print_physics_details) struct AH_data* AH_data_ptr = horizon_is_genuine ? AH_data_array[hn] : NULL; + patch_system* const ps_ptr = horizon_is_genuine ? AH_data_ptr->ps_ptr : NULL; Jacobian* const Jac_ptr = horizon_is_genuine ? AH_data_ptr->Jac_ptr: NULL; - const fp add_to_expansion = horizon_is_genuine - ? -AH_data_ptr->surface_expansion : 0.0; + + if (horizon_is_genuine) { + // deal with dependent horizons + if (AH_data_ptr->depends_on > 0) { + assert (AH_data_ptr->depends_on != hn); + assert (AH_data_ptr->depends_on < hn); + // check that the other horizon is on the same processor! + AH_data *AH_other_ptr = AH_data_array[AH_data_ptr->depends_on]; + assert (AH_other_ptr); + AH_data_ptr->compute_info.desired_value + = AH_other_ptr->compute_info.desired_value + * AH_data_ptr->desired_value_factor + + AH_data_ptr->desired_value_offset; + const int gnp = ps_ptr->ghosted_N_grid_points(); + assert (AH_other_ptr->ps_ptr->ghosted_N_grid_points() == gnp); + memcpy (ps_ptr->ghosted_gridfn_data(gfns::gfn__h), + AH_other_ptr->ps_ptr->ghosted_gridfn_data(gfns::gfn__h), + gnp * sizeof(fp)); + ps_ptr->origin_x (AH_other_ptr->ps_ptr->origin_x()); + ps_ptr->origin_y (AH_other_ptr->ps_ptr->origin_y()); + ps_ptr->origin_z (AH_other_ptr->ps_ptr->origin_z()); + } + } + + if (horizon_is_genuine) { + if (AH_data_ptr->move_origins + && AH_data_ptr->depends_on == 0 + && AH_data_ptr->found_flag) + { + // move the origin to the centre + patch_system& ps = *ps_ptr; + fp cx=0, cy=0, cz=0; // change of origin + fp sx=0, sy=0, sz=0; // change of shape + if (! predict_origin_movement) { + size_t N=0; + for (int pn=0; pn<ps.N_patches(); ++pn) { + patch& p = ps.ith_patch(pn); + for (int irho = p.min_irho(); irho <= p.max_irho(); ++irho) { + for (int isigma = p.min_isigma(); isigma <= p.max_isigma(); ++isigma) { + const fp rho = p.rho_of_irho (irho); + const fp sigma = p.sigma_of_isigma (isigma); + const fp r = p.ghosted_gridfn (gfns::gfn__h, irho, isigma); + fp x, y, z; + p.xyz_of_r_rho_sigma (r, rho, sigma, x, y, z); + cx += x; + cy += y; + cz += z; + ++N; + } + } + } + assert (N > 0); + cx /= N; + cy /= N; + cz /= N; + sx=cx; sy=cy; sz=cz; + } else { // if predict_origin_movement + if (ah_centroid_valid[hn-1]) { + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF centroid x " << (ah_centroid_x[hn-1]) << " y " << (ah_centroid_y[hn-1]) << " z " << (ah_centroid_z[hn-1]) << " t " << (ah_centroid_t[hn-1]) << std::endl; + } + if (ah_centroid_valid_p[hn-1]) { + // have two previous origins: linear extrapolation + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF centroid_p x " << (ah_centroid_x_p[hn-1]) << " y " << (ah_centroid_y_p[hn-1]) << " z " << (ah_centroid_z_p[hn-1]) << " t " << (ah_centroid_t_p[hn-1]) << std::endl; + } + fp const dt = ah_centroid_t[hn-1] - ah_centroid_t_p[hn-1]; + fp const dt_n = cctk_time - ah_centroid_t [hn-1]; + fp const dt_p = cctk_time - ah_centroid_t_p[hn-1]; + fp const timescale = + fabs (dt) + fabs (dt_p) + fabs (dt_n) + + 0.001 * fabs (cctk_delta_time); + if (10 * fabs (dt ) < timescale || + 10 * fabs (dt_p) < timescale || + 10 * fabs (dt_n) < timescale) + { + // the times are too similar + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF toosim" << std::endl; + } + cx = ah_centroid_x[hn-1]; + cy = ah_centroid_y[hn-1]; + cz = ah_centroid_z[hn-1]; + } else { + fp const fact_n = + dt_p / dt; + fp const fact_p = - dt_n / dt; + if (fabs (fact_n) > 5 || fabs (fact_p) > 5) { + // don't trust a large extrapolation + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF notrust" << std::endl; + } + cx = ah_centroid_x[hn-1]; + cy = ah_centroid_y[hn-1]; + cz = ah_centroid_z[hn-1]; + } else { + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF extrap fn " << fact_n << " fp " << fact_p << std::endl; + } + cx = fact_n * ah_centroid_x[hn-1] + fact_p * ah_centroid_x_p[hn-1]; + cy = fact_n * ah_centroid_y[hn-1] + fact_p * ah_centroid_y_p[hn-1]; + cz = fact_n * ah_centroid_z[hn-1] + fact_p * ah_centroid_z_p[hn-1]; + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF xp " << (ah_centroid_x_p[hn-1]) << " x " << (ah_centroid_x[hn-1]) << " cx " << cx << std::endl; + } + } + } + } else { + // have one previous origin: constant extrapolation + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF const" << std::endl; + } + cx = ah_centroid_x[hn-1]; + cy = ah_centroid_y[hn-1]; + cz = ah_centroid_z[hn-1]; + } + if (verbose_info.print_algorithm_highlights) { + std::cout << "AHF predicted position cx " << cx << " cy " << cy << " cz " << cz << std::endl; + } + cx -= ps.origin_x(); + cy -= ps.origin_y(); + cz -= ps.origin_z(); + } + sx = ah_centroid_x[hn-1] - ps.origin_x(); + sy = ah_centroid_y[hn-1] - ps.origin_y(); + sz = ah_centroid_z[hn-1] - ps.origin_z(); + } // if predict_origin_movement + switch (ps.type()) { + case patch_system::patch_system__full_sphere: + break; // do nothing + case patch_system::patch_system__plus_z_hemisphere: + cz = 0; sz = 0; break; + case patch_system::patch_system__plus_xy_quadrant_mirrored: + cx = cy = 0; sx = sy = 0; break; + case patch_system::patch_system__plus_xy_quadrant_rotating: + cx = cy = 0; sx = sy = 0; break; + case patch_system::patch_system__plus_xz_quadrant_mirrored: + cx = cz = 0; sx = sz = 0; break; + case patch_system::patch_system__plus_xz_quadrant_rotating: + cx = cz = 0; sx = sz = 0; break; + case patch_system::patch_system__plus_xyz_octant_mirrored: + cx = cy = cz = 0; sx = sy = sz = 0; break; + case patch_system::patch_system__plus_xyz_octant_rotating: + cx = cy = cz = 0; sx = sy = sz = 0; break; + default: assert(0); + } + ps.origin_x (ps.origin_x() + cx); + ps.origin_y (ps.origin_y() + cy); + ps.origin_z (ps.origin_z() + cz); + if (reshape_while_moving) { + for (int pn=0; pn<ps.N_patches(); ++pn) { + patch& p = ps.ith_patch(pn); + for (int irho = p.min_irho(); irho <= p.max_irho(); ++irho) { + for (int isigma = p.min_isigma(); isigma <= p.max_isigma(); ++isigma) { + const fp rho = p.rho_of_irho (irho); + const fp sigma = p.sigma_of_isigma (isigma); + fp & r = p.ghosted_gridfn (gfns::gfn__h, irho, isigma); + fp x, y, z; + p.xyz_of_r_rho_sigma (r, rho, sigma, x, y, z); + fp const proj = (sx*x + sy*y + sz*z) / r; + r -= proj; + } + } + } + ps.synchronize(); + } + } + + // modify the initial guess + jtutil::norm<fp> norms; + ps_ptr->ghosted_gridfn_norms (gfns::gfn__h, norms); + // smoothing: + ps_ptr->scale_ghosted_gridfn + (1.0 - AH_data_ptr->smoothing_factor, gfns::gfn__h); + ps_ptr->add_to_ghosted_gridfn + (AH_data_ptr->smoothing_factor * norms.mean(), gfns::gfn__h); + // enlarging: + ps_ptr->scale_ghosted_gridfn + (AH_data_ptr->shiftout_factor, gfns::gfn__h); + } + + bool I_am_pretracking = horizon_is_genuine && AH_data_ptr->use_pretracking; + bool I_was_pretracking = false; + bool pretracking_have_upper_bound = false; + bool pretracking_have_lower_bound = false; + bool pretracking_was_successful = false; + fp const old_pretracking_value = I_am_pretracking ? AH_data_ptr->pretracking_value : 0.0; + fp pretracking_upper_bound; + fp pretracking_lower_bound; + bool pretracking_have_horizon_info; + fp pretracking_mean_expansion; + for (int pretracking_iter = 0; + I_am_pretracking + ? pretracking_iter < AH_data_ptr->pretracking_max_iterations + : true; + ++pretracking_iter) + { + bool found_this_horizon; + if (I_am_pretracking || I_was_pretracking) { + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: iteration %d", pretracking_iter); + if (pretracking_have_lower_bound) { + if (pretracking_have_upper_bound) { + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: looking for value %g in [%g,%g]", + double(AH_data_ptr->pretracking_value), + double(pretracking_lower_bound), + double(pretracking_upper_bound)); + } else { + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: looking for value %g in [%g,*]", + double(AH_data_ptr->pretracking_value), + double(pretracking_lower_bound)); + } + } else { + if (pretracking_have_upper_bound) { + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: looking for value %g in [*,%g]", + double(AH_data_ptr->pretracking_value), + double(pretracking_upper_bound)); + } else { + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: looking for value %g in [*,*]", + double(AH_data_ptr->pretracking_value)); + } + } + AH_data_ptr->compute_info.desired_value = AH_data_ptr->pretracking_value; + ps_ptr->ghosted_gridfn_copy (gfns::gfn__h, gfns::gfn__save_h); + pretracking_have_horizon_info = false; + } + + if (! I_am_pretracking) { + if (horizon_is_genuine) { + if (! AH_data_ptr->initial_guess_info.reset_horizon_after_not_finding) { + // save the surface for possible backtracking later + ps_ptr->ghosted_gridfn_copy (gfns::gfn__h, gfns::gfn__save_h); + } + } + } + + struct what_to_compute dummy_compute_info; + struct what_to_compute & compute_info = + horizon_is_genuine + ? AH_data_ptr->compute_info + : dummy_compute_info; + + if (horizon_is_genuine) { + if (ps_ptr->N_additional_points()) { + const int gnp = ps_ptr->ghosted_N_grid_points(); + ps_ptr->ghosted_gridfn_data(gfns::gfn__h)[gnp] = 0; + } + } const int max_iterations = horizon_is_genuine @@ -166,10 +424,16 @@ if (verbose_info.print_physics_details) : solver_info.max_Newton_iterations__subsequent) : INT_MAX; + int num_Theta_growth_iterations = 0; + fp previous_Theta_norm = 1.0e30; + int num_Theta_nonshrink_iterations = 0; + fp best_Theta_norm = 1.0e30; + // // each pass through this loop does a single Newton iteration // on the current horizon (which might be either genuine or dummy) // + bool do_return = false; for (int iteration = 1 ; ; ++iteration) { if (verbose_info.print_algorithm_debug) @@ -185,20 +449,136 @@ if (verbose_info.print_physics_details) if (horizon_is_genuine && solver_info.debugging_output_at_each_Newton_iteration) then output_gridfn(*ps_ptr, gfns::gfn__h, + "h", GH, IO_info, IO_info.h_base_file_name, + IO_info.h_min_digits, hn, verbose_info.print_algorithm_highlights, iteration); + // calculate the norms also for a surface a bit further out, + // so that we know how they vary in space. + // perform this calculation first, so that the real values + // do not have to be saved. + const fp epsilon = Jacobian_info.perturbation_amplitude; + jtutil::norm<fp> shifted_Theta_norms; + jtutil::norm<fp> shifted_expansion_Theta_norms; + jtutil::norm<fp> shifted_inner_expansion_Theta_norms; + jtutil::norm<fp> shifted_product_expansion_Theta_norms; + jtutil::norm<fp> shifted_mean_curvature_Theta_norms; + fp shifted_area; + jtutil::norm<fp> shifted2_Theta_norms; + jtutil::norm<fp> shifted2_expansion_Theta_norms; + jtutil::norm<fp> shifted2_inner_expansion_Theta_norms; + jtutil::norm<fp> shifted2_product_expansion_Theta_norms; + jtutil::norm<fp> shifted2_mean_curvature_Theta_norms; + fp shifted2_area; + if (solver_info.want_expansion_gradients) { + if (horizon_is_genuine) { + ps_ptr->add_to_ghosted_gridfn(epsilon, gfns::gfn__h); + // ps_ptr->scale_ghosted_gridfn(1.0+epsilon, gfns::gfn__h); + } + const enum expansion_status raw_shifted_expansion_status + = expansion(ps_ptr, compute_info, + cgi, gi, + error_info, (iteration == 1), + false, // no, we don't want Jacobian coeffs + false, + &shifted_Theta_norms, + &shifted_expansion_Theta_norms, + &shifted_inner_expansion_Theta_norms, + &shifted_product_expansion_Theta_norms, + &shifted_mean_curvature_Theta_norms); + if (horizon_is_genuine) { + shifted_area = ps_ptr->integrate_gridfn + (gfns::gfn__one, true, true, true, + gfns::gfn__h, + gfns::gfn__g_dd_11, gfns::gfn__g_dd_12, gfns::gfn__g_dd_13, + gfns::gfn__g_dd_22, gfns::gfn__g_dd_23, + gfns::gfn__g_dd_33, + BH_diagnostics_info.integral_method); + ps_ptr->add_to_ghosted_gridfn(-epsilon, gfns::gfn__h); + // ps_ptr->scale_ghosted_gridfn(1.0/(1.0+epsilon), gfns::gfn__h); + + ps_ptr->add_to_ghosted_gridfn(-epsilon, gfns::gfn__h); + // ps_ptr->scale_ghosted_gridfn(1.0/(1.0+epsilon), gfns::gfn__h); + } + const enum expansion_status raw_shifted2_expansion_status + = expansion(ps_ptr, compute_info, + cgi, gi, + error_info, (iteration == 1), + false, // no, we don't want Jacobian coeffs + false, + &shifted2_Theta_norms, + &shifted2_expansion_Theta_norms, + &shifted2_inner_expansion_Theta_norms, + &shifted2_product_expansion_Theta_norms, + &shifted2_mean_curvature_Theta_norms); + if (horizon_is_genuine) { + shifted2_area = ps_ptr->integrate_gridfn + (gfns::gfn__one, true, true, true, + gfns::gfn__h, + gfns::gfn__g_dd_11, gfns::gfn__g_dd_12, gfns::gfn__g_dd_13, + gfns::gfn__g_dd_22, gfns::gfn__g_dd_23, + gfns::gfn__g_dd_33, + BH_diagnostics_info.integral_method); + ps_ptr->add_to_ghosted_gridfn(epsilon, gfns::gfn__h); + // ps_ptr->scale_ghosted_gridfn(1.0+epsilon, gfns::gfn__h); + } + } // if want_expansion_gradients + + // now calculate the real values. jtutil::norm<fp> Theta_norms; + jtutil::norm<fp> expansion_Theta_norms; + jtutil::norm<fp> inner_expansion_Theta_norms; + jtutil::norm<fp> product_expansion_Theta_norms; + jtutil::norm<fp> mean_curvature_Theta_norms; const enum expansion_status raw_expansion_status - = expansion(ps_ptr, add_to_expansion, + = expansion(ps_ptr, compute_info, cgi, gi, error_info, (iteration == 1), true, // yes, we want Jacobian coeffs verbose_info.print_algorithm_details, - &Theta_norms); + &Theta_norms, + &expansion_Theta_norms, + &inner_expansion_Theta_norms, + &product_expansion_Theta_norms, + &mean_curvature_Theta_norms); + fp area; + if (horizon_is_genuine) + { + area = ps_ptr->integrate_gridfn + (gfns::gfn__one, true, true, true, + gfns::gfn__h, + gfns::gfn__g_dd_11, gfns::gfn__g_dd_12, gfns::gfn__g_dd_13, + gfns::gfn__g_dd_22, gfns::gfn__g_dd_23, + gfns::gfn__g_dd_33, + BH_diagnostics_info.integral_method); + } const bool Theta_is_ok = (raw_expansion_status == expansion_success); - const bool norms_are_ok = horizon_is_genuine && Theta_is_ok; + const bool norms_are_ok = horizon_is_genuine && Theta_is_ok; + + if (norms_are_ok) { + const fp this_norm = Theta_norms.infinity_norm(); + if (this_norm > previous_Theta_norm) { + ++ num_Theta_growth_iterations; + } else { + num_Theta_growth_iterations = 0; + } + previous_Theta_norm = this_norm; + + if (this_norm >= best_Theta_norm) { + ++ num_Theta_nonshrink_iterations; + } else { + num_Theta_nonshrink_iterations = 0; + best_Theta_norm = this_norm; + } + } + + if (I_am_pretracking && norms_are_ok) { + pretracking_mean_expansion = expansion_Theta_norms.mean(); + pretracking_have_horizon_info = true; + } + if (verbose_info.print_algorithm_debug) then { CCTK_VInfo(CCTK_THORNSTRING, @@ -212,27 +592,64 @@ if (verbose_info.print_physics_details) } if (horizon_is_genuine && Theta_is_ok && solver_info.debugging_output_at_each_Newton_iteration) - then output_gridfn(*ps_ptr, gfns::gfn__Theta, + then { + output_gridfn(*ps_ptr, gfns::gfn__Theta, + "Theta", GH, IO_info, IO_info.Theta_base_file_name, + IO_info.h_min_digits, + hn, verbose_info.print_algorithm_highlights, + iteration); + output_gridfn(*ps_ptr, gfns::gfn__mean_curvature, + "mean_curvature", GH, + IO_info, IO_info.mean_curvature_base_file_name, + IO_info.h_min_digits, hn, verbose_info.print_algorithm_highlights, iteration); + } // // have we found this horizon? // if so, compute and output BH diagnostics // - const bool found_this_horizon - = norms_are_ok && (Theta_norms.infinity_norm() - <= solver_info.Theta_norm_for_convergence); + found_this_horizon + = (norms_are_ok + && (I_was_pretracking + ? pretracking_was_successful + : Theta_norms.infinity_norm() <= solver_info.Theta_norm_for_convergence)); if (horizon_is_genuine) then AH_data_ptr->found_flag = found_this_horizon; - if (found_this_horizon) + if (found_this_horizon && ! I_am_pretracking) then { struct BH_diagnostics& BH_diagnostics = AH_data_ptr->BH_diagnostics; - BH_diagnostics.compute(*ps_ptr, BH_diagnostics_info); + const fp mean_expansion = expansion_Theta_norms.mean(); + const fp mean_inner_expansion = inner_expansion_Theta_norms.mean(); + const fp mean_product_expansion = product_expansion_Theta_norms.mean(); + const fp mean_mean_curvature = mean_curvature_Theta_norms.mean(); + // const fp area_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_area - area ) / epsilon; + // const fp mean_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_expansion_Theta_norms.mean() - expansion_Theta_norms.mean() ) / epsilon; + // const fp mean_inner_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_inner_expansion_Theta_norms.mean() - inner_expansion_Theta_norms.mean()) / epsilon; + // const fp mean_product_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_product_expansion_Theta_norms.mean() - product_expansion_Theta_norms.mean()) / epsilon; + // const fp mean_mean_curvature_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_mean_curvature_Theta_norms.mean() - mean_curvature_Theta_norms.mean() ) / epsilon; + const fp area_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_area - shifted2_area ) / (2*epsilon); + const fp mean_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_expansion_Theta_norms.mean() - shifted2_expansion_Theta_norms.mean() ) / (2*epsilon); + const fp mean_inner_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_inner_expansion_Theta_norms.mean() - shifted2_inner_expansion_Theta_norms.mean()) / (2*epsilon); + const fp mean_product_expansion_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_product_expansion_Theta_norms.mean() - shifted2_product_expansion_Theta_norms.mean()) / (2*epsilon); + const fp mean_mean_curvature_gradient = ! solver_info.want_expansion_gradients ? 0.0 : (shifted_mean_curvature_Theta_norms.mean() - shifted2_mean_curvature_Theta_norms.mean() ) / (2*epsilon); + BH_diagnostics.compute(*ps_ptr, + area, + mean_expansion, + mean_inner_expansion, + mean_product_expansion, + mean_mean_curvature, + area_gradient, + mean_expansion_gradient, + mean_inner_expansion_gradient, + mean_product_expansion_gradient, + mean_mean_curvature_gradient, + BH_diagnostics_info); if (IO_info.output_BH_diagnostics) then { if (AH_data_ptr->BH_diagnostics_fileptr == NULL) @@ -251,8 +668,13 @@ if (verbose_info.print_physics_details) // (if so, we'll give up on this horizon) // const bool expansion_is_too_large - = norms_are_ok && (Theta_norms.infinity_norm() - > solver_info.max_allowable_Theta); + = norms_are_ok + && ( Theta_norms.infinity_norm() > solver_info.max_allowable_Theta + || ( solver_info.max_allowable_Theta_growth_iterations > 0 + && num_Theta_growth_iterations > solver_info.max_allowable_Theta_growth_iterations) + || ( solver_info.max_allowable_Theta_nonshrink_iterations > 0 + && num_Theta_nonshrink_iterations > solver_info.max_allowable_Theta_nonshrink_iterations) + ); // @@ -260,10 +682,11 @@ if (verbose_info.print_physics_details) // then pretend expansion() returned a "surface too large" error status // jtutil::norm<fp> h_norms; - if (horizon_is_genuine) - then ps_ptr->ghosted_gridfn_norms(gfns::gfn__h, h_norms); - const fp mean_horizon_radius = horizon_is_genuine ? h_norms.mean() - : 0.0; + if (horizon_is_genuine) { + ps_ptr->ghosted_gridfn_norms(gfns::gfn__h, h_norms); + } + const fp mean_horizon_radius + = horizon_is_genuine ? h_norms.mean() : 0.0; const bool horizon_is_too_large = (mean_horizon_radius > solver_info .max_allowable_horizon_radius[hn]); @@ -279,7 +702,7 @@ if (verbose_info.print_physics_details) // does *this* horizon need more iterations? // i.e. has this horizon's Newton iteration not yet converged? - const bool this_horizon_needs_more_iterations + const bool this_horizon_needs_more_iterations = horizon_is_genuine && Theta_is_ok && !found_this_horizon && !expansion_is_too_large @@ -290,7 +713,8 @@ if (verbose_info.print_physics_details) // on this or a following horizon? const bool I_need_more_iterations = this_horizon_needs_more_iterations - || there_is_another_genuine_horizon; + || there_is_another_genuine_horizon + || I_am_pretracking; if (verbose_info.print_algorithm_details) then { @@ -305,7 +729,6 @@ if (verbose_info.print_physics_details) int(I_need_more_iterations)); } - // // broadcast iteration status from each active processor // to all processors, and inclusive-or the "we need more iterations" @@ -373,6 +796,7 @@ if (verbose_info.print_physics_details) broadcast_horizon_data(GH, my_proc == found_proc, broadcast_horizon_shape, + found_AH_data, found_AH_data.BH_diagnostics, *found_AH_data.ps_ptr, found_AH_data.horizon_buffers); @@ -387,8 +811,9 @@ if (verbose_info.print_physics_details) // // if we found our horizon, maybe output the horizon shape? // - if (found_this_horizon) + if (found_this_horizon && ! I_am_pretracking) then { + // printf("will output h/Th/mc: %d/%d/%d\n", IO_info.output_h, IO_info.output_Theta, IO_info.output_mean_curvature); //xxxxxxxxxxxx if (IO_info.output_h) then { // if this is the first time we've output h for this @@ -396,13 +821,24 @@ if (verbose_info.print_physics_details) if (!AH_data_ptr->h_files_written) then setup_h_files(*ps_ptr, IO_info, hn); output_gridfn(*ps_ptr, gfns::gfn__h, + "h", GH, IO_info, IO_info.h_base_file_name, + IO_info.h_min_digits, hn, verbose_info .print_algorithm_highlights); } if (IO_info.output_Theta) then output_gridfn(*ps_ptr, gfns::gfn__Theta, + "Theta", GH, IO_info, IO_info.Theta_base_file_name, + IO_info.h_min_digits, + hn, verbose_info + .print_algorithm_highlights); + if (IO_info.output_mean_curvature) + then output_gridfn(*ps_ptr, gfns::gfn__mean_curvature, + "mean_curvature", GH, + IO_info, IO_info.mean_curvature_base_file_name, + IO_info.h_min_digits, hn, verbose_info .print_algorithm_highlights); } @@ -417,7 +853,8 @@ if (verbose_info.print_physics_details) if (verbose_info.print_algorithm_details) then CCTK_VInfo(CCTK_THORNSTRING, "==> all processors are finished!"); - return; // *** NORMAL RETURN *** + do_return = true; + break; // *** LOOP EXIT *** } if ((N_procs == 1) && !this_horizon_needs_more_iterations) then { @@ -441,7 +878,7 @@ if (verbose_info.print_physics_details) = expansion_Jacobian (this_horizon_needs_more_iterations ? ps_ptr : NULL, this_horizon_needs_more_iterations ? Jac_ptr : NULL, - add_to_expansion, + compute_info, cgi, gi, Jacobian_info, error_info, (iteration == 1), verbose_info.print_algorithm_details); @@ -474,7 +911,7 @@ if (verbose_info.print_physics_details) verbose_info.print_algorithm_details); if ((rcond >= 0.0) && (rcond < 100.0*FP_EPSILON)) then { - CCTK_VWarn(SERIOUS_WARNING, __LINE__, __FILE__, CCTK_THORNSTRING, + CCTK_VWarn(1, __LINE__, __FILE__, CCTK_THORNSTRING, "Newton_solve: Jacobian matrix is numerically singular!"); // give up on this horizon break; // *** LOOP CONTROL *** @@ -491,7 +928,9 @@ if (verbose_info.print_physics_details) if (solver_info.debugging_output_at_each_Newton_iteration) then output_gridfn(*ps_ptr, gfns::gfn__Delta_h, + "Delta_h", GH, IO_info, IO_info.Delta_h_base_file_name, + IO_info.h_min_digits, hn, verbose_info.print_algorithm_details, iteration); @@ -507,6 +946,139 @@ if (verbose_info.print_physics_details) // end of this Newton iteration } + if (! I_am_pretracking) { + if (horizon_is_genuine) { + if (! AH_data_ptr->initial_guess_info.reset_horizon_after_not_finding) { + if (! found_this_horizon) { + // the surface failed; backtrack and continue + AH_data_ptr->ps_ptr->ghosted_gridfn_copy + (gfns::gfn__save_h, gfns::gfn__h); + } + } + } + } + + // exit + if (do_return) return; // *** NORMAL RETURN *** + + // break out of the pretracking loop if we are not pretracking + if (! I_am_pretracking) break; + + if (! found_this_horizon) { + // the surface failed; backtrack and continue + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: solving failed; backtracking"); + AH_data_ptr->ps_ptr->ghosted_gridfn_copy (gfns::gfn__save_h, gfns::gfn__h); + if (pretracking_have_lower_bound) { + assert (AH_data_ptr->pretracking_value >= pretracking_lower_bound - 1.0e-10 * fabs(pretracking_lower_bound)); + } + pretracking_have_lower_bound = true; + pretracking_lower_bound = AH_data_ptr->pretracking_value; + if (pretracking_have_upper_bound) { + AH_data_ptr->pretracking_delta = 0.5 * (pretracking_upper_bound - pretracking_lower_bound); + AH_data_ptr->pretracking_value = pretracking_lower_bound + 0.5 * (pretracking_upper_bound - pretracking_lower_bound); + } else { + AH_data_ptr->pretracking_delta = fabs(AH_data_ptr->pretracking_delta); + AH_data_ptr->pretracking_delta *= 2.0; + if (AH_data_ptr->pretracking_delta > AH_data_ptr->pretracking_maximum_delta) { + AH_data_ptr->pretracking_delta = AH_data_ptr->pretracking_maximum_delta; + } + AH_data_ptr->pretracking_value += AH_data_ptr->pretracking_delta; + if (AH_data_ptr->pretracking_value > AH_data_ptr->pretracking_maximum_value) { + AH_data_ptr->pretracking_value = AH_data_ptr->pretracking_maximum_value; + } + } + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: new value %g, delta %g", + double(AH_data_ptr->pretracking_value), + double(AH_data_ptr->pretracking_delta)); + if (pretracking_lower_bound >= AH_data_ptr->pretracking_maximum_value * 0.9999999999) { + // give up + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: upper bound reached, giving up."); + I_am_pretracking = false; + I_was_pretracking = true; + pretracking_was_successful = false; + // restore old pretracking goal + AH_data_ptr->pretracking_value = old_pretracking_value; + } else if (AH_data_ptr->pretracking_delta < AH_data_ptr->pretracking_minimum_delta) { + // give up + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: step size too small, giving up."); + I_am_pretracking = false; + I_was_pretracking = true; + pretracking_was_successful = true; + } + } else { + // the surface was okay + // get mean expansion + assert (pretracking_have_horizon_info); + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: solving succeeded; expansion is now %g", + double(pretracking_mean_expansion)); +// if (fabs(AH_data_ptr->pretracking_value) > 2.0 * AH_data_ptr->pretracking_minimum_delta) { + if (AH_data_ptr->pretracking_value > AH_data_ptr->pretracking_minimum_value + 1.0e-10 * AH_data_ptr->pretracking_minimum_delta) { + // it is not yet a horizon + if (pretracking_have_upper_bound) { + assert (AH_data_ptr->pretracking_value <= pretracking_upper_bound + 1.0e-10 * fabs(pretracking_upper_bound)); + } + pretracking_have_upper_bound = true; + pretracking_upper_bound = AH_data_ptr->pretracking_value; + if (pretracking_have_lower_bound) { +#if 1 + // TODO + // move lower bound further down + pretracking_lower_bound -= pretracking_upper_bound - pretracking_lower_bound; + if (pretracking_lower_bound < AH_data_ptr->pretracking_minimum_value) pretracking_lower_bound = AH_data_ptr->pretracking_minimum_value; +#endif + AH_data_ptr->pretracking_delta = 0.5 * (pretracking_lower_bound - pretracking_upper_bound); + AH_data_ptr->pretracking_value = pretracking_lower_bound + 0.5 * (pretracking_upper_bound - pretracking_lower_bound); + } else { + AH_data_ptr->pretracking_delta = - fabs(AH_data_ptr->pretracking_delta); + AH_data_ptr->pretracking_delta *= 2.0; + if (- AH_data_ptr->pretracking_delta > AH_data_ptr->pretracking_maximum_delta) { + AH_data_ptr->pretracking_delta = - AH_data_ptr->pretracking_maximum_delta; + } + AH_data_ptr->pretracking_value += AH_data_ptr->pretracking_delta; + if (AH_data_ptr->pretracking_value < AH_data_ptr->pretracking_minimum_value) { + AH_data_ptr->pretracking_value = AH_data_ptr->pretracking_minimum_value; + } + } + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: new value radius %g, delta %g", + double(AH_data_ptr->pretracking_value), + double(AH_data_ptr->pretracking_delta)); + if (pretracking_upper_bound <= AH_data_ptr->pretracking_minimum_value * 1.00000000001) { + // give up + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: lower bound reached, giving up."); + I_am_pretracking = false; + I_was_pretracking = true; + pretracking_was_successful = false; + // restore old pretracking goal + AH_data_ptr->pretracking_value = old_pretracking_value; + } else if (- AH_data_ptr->pretracking_delta < AH_data_ptr->pretracking_minimum_delta) { + // give up + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: step size too small, giving up."); + I_am_pretracking = false; + I_was_pretracking = true; + pretracking_was_successful = true; + } + } else { + // a true horizon was found; we are done + CCTK_VInfo(CCTK_THORNSTRING, + "Pretracking: done."); + I_am_pretracking = false; + I_was_pretracking = true; + pretracking_was_successful = true; + } + } // if surface found + + // end of pretracking loop + } + I_am_pretracking = false; + // end of this horizon } @@ -703,8 +1275,8 @@ return any_proc_needs_more_iterations; // // This function (which must be called on *every* processor) broadcasts -// the BH diagnostics and optionally also the (ghosted) horizon shape, -// from a specified processor to all processors. +// the BH diagnostics and (ghosted) horizon shape from a specified processor +// to all processors. // // The present implementation of this function uses the Cactus reduction // API. If AHFinderDirect is ported to some other software environment, @@ -715,15 +1287,11 @@ return any_proc_needs_more_iterations; // GH --> The Cactus grid hierarchy. // broadcast_flag = true on the broadcasting processor, // false on all other processors -// broadcast_horizon_shape = true to broadcast the (ghosted) horizon shape -// as well as the BH diagnostics -// false to only broadcast the BH diagnostics // BH_diagnostics = On the broadcasting processor, this is the BH diagnostics // to broadcast; on all other processors, it's set to the // broadcast BH diagnostics. -// ps = Used only if broadcast_horizon_shape; in this case... -// On the broadcasting processor, gfn__h is broadcast; -// on all other processors, gfn__h is set to the broadcast values. +// ps = On the broadcasting processor, gfn__h is broadcast; +// on all other processors, gfn__h is set to the broadcast values. // horizon_buffers = Internal buffers for use in the broadcast; // if N_buffer == 0 then we set N_buffer and allocate // the buffers. @@ -731,6 +1299,7 @@ return any_proc_needs_more_iterations; namespace { void broadcast_horizon_data(const cGH* GH, bool broadcast_flag, bool broadcast_horizon_shape, + struct AH_data& AH_data, struct BH_diagnostics& BH_diagnostics, patch_system& ps, struct horizon_buffers& horizon_buffers) @@ -751,7 +1320,8 @@ if (horizon_buffers.N_buffer == 0) // allocate the buffers horizon_buffers.N_buffer = BH_diagnostics::N_buffer - + (broadcast_horizon_shape ? ps.N_grid_points() : 0); + + (broadcast_horizon_shape ? ps.N_grid_points() : 0) + + 4; horizon_buffers.send_buffer = new CCTK_REAL[horizon_buffers.N_buffer]; horizon_buffers.receive_buffer @@ -762,9 +1332,9 @@ if (broadcast_flag) then { // pack the data to be broadcast into the send buffer BH_diagnostics.copy_to_buffer(horizon_buffers.send_buffer); + int posn = BH_diagnostics::N_buffer; if (broadcast_horizon_shape) then { - int posn = BH_diagnostics::N_buffer; for (int pn = 0 ; pn < ps.N_patches() ; ++pn) { const patch& p = ps.ith_patch(pn); @@ -782,8 +1352,12 @@ if (broadcast_flag) } } } - assert( posn == horizon_buffers.N_buffer ); } + horizon_buffers.send_buffer[posn++] = AH_data.initial_find_flag; + horizon_buffers.send_buffer[posn++] = AH_data.really_initial_find_flag; + horizon_buffers.send_buffer[posn++] = AH_data.search_flag; + horizon_buffers.send_buffer[posn++] = AH_data.found_flag; + assert( posn == horizon_buffers.N_buffer ); } else jtutil::zero_C_array(horizon_buffers.N_buffer, horizon_buffers.send_buffer); @@ -814,9 +1388,12 @@ if (!broadcast_flag) then { // unpack the data from the receive buffer BH_diagnostics.copy_from_buffer(horizon_buffers.receive_buffer); + ps.origin_x(BH_diagnostics.origin_x); + ps.origin_y(BH_diagnostics.origin_y); + ps.origin_z(BH_diagnostics.origin_z); + int posn = BH_diagnostics::N_buffer; if (broadcast_horizon_shape) then { - int posn = BH_diagnostics::N_buffer; for (int pn = 0 ; pn < ps.N_patches() ; ++pn) { patch& p = ps.ith_patch(pn); @@ -834,12 +1411,16 @@ if (!broadcast_flag) } } } - assert( posn == horizon_buffers.N_buffer ); // recover the full ghosted-grid horizon shape // (we only broadcast the nominal-grid shape) ps.synchronize(); } + AH_data.initial_find_flag = horizon_buffers.receive_buffer[posn++]; + AH_data.really_initial_find_flag = horizon_buffers.receive_buffer[posn++]; + AH_data.search_flag = horizon_buffers.receive_buffer[posn++]; + AH_data.found_flag = horizon_buffers.receive_buffer[posn++]; + assert( posn == horizon_buffers.N_buffer ); } } } @@ -918,6 +1499,7 @@ const fp scale = (max_Delta_h <= max_allowable_Delta_h) if (verbose_info.print_algorithm_details) then { + if (scale == 1.0) then CCTK_VInfo(CCTK_THORNSTRING, "h += Delta_h (rms-norm=%.1e, infinity-norm=%.1e)", @@ -948,6 +1530,14 @@ if (verbose_info.print_algorithm_details) } } } + +if (ps.N_additional_points()) + { + const int np = ps.N_grid_points(); + const int gnp = ps.ghosted_N_grid_points(); + ps.ghosted_gridfn_data(gfns::gfn__h)[gnp] + -= scale * ps.gridfn_data(gfns::gfn__Delta_h)[np]; + } } } |