Dear Kostas,

Indeed, it would be better to have a convergence threshold on a relative residual, so your suggestion to scale the convergence threshold with gmm::mat_maxnorm(G) is a very good idea.

There is a sharper convergence threshold for the Newton algorithm in invert_nonlin() in order to have a sufficient accuracy to ensure a consistent result of point_in_convex(*pgt, x, res, IN_EPS).

With a scaled convergence threshold, this ratio can probably be reduced, but a certain safety factor has to be kept, in my opinion.


Best regards,

Yves


Le 06/04/2022 à 15:20, Konstantinos Poulios a écrit :
Dear Yves,

Thanks for the feedback. Still the check if the point lies in the convex is combined with a convergence check in the returned value. And this convergence check is less strict than the convergence result returned in the "converged" flag. So we have two different convergence criteria which is a bit confusing.

Anyway, at some point, you had reduced the convergence threshold from IN_EPS to IN_EPS/1000 and then you increased it to the current value of IN_EPS/100. Do you remember the motivation for reducing the threshold? The problem is that the current threshold value works well for elements that are 1x1x1 or smaller and they are placed relatively close to the origin of the coordinates. If one needs to work with large elements e.g. 100x100x100, or small elements 1x1x1, which are far away from the origin, let's say at a distance of 1000 from (0,0,0), then the requested precision can never be achieved because of floating point arithmetics. Ideally, the geometric inversion should be done with the real element moved to the origin and normalized, but this would require quite some changes in this function. Another quick fix would be to multiply the convergence threshold with gmm::mat_maxnorm(G). I will think a bit about it.

Best regards
Kostas



On Mon, Apr 4, 2022 at 3:18 PM Renard Yves <yves.ren...@insa-lyon.fr> wrote:


    Dear Kostas,


    You are right of course. This change has been done after
    experiencing some difficulties of convergence for the pyramid
    element. I think the test (factor < 1.0-IN-EPS) does not change a
    lot of things but may be it is slightly more robust in some
    situations, but the change "factor *= 2.0" in "factor = 2.0" is
    simply a nonsense.

    Concerning the returned value and the convergence flag it has a
    different meaning : the inversion is sometimes used for
    extrapolation outside the element. The returned value indicates
    only if the point is inside the element (with possibly a
    successful convergence) and the flag returns whether or not the
    convergence was successful.

    This portion of code can probably be improved, yes !


    Best regards,


    Yves



    Le 03/04/2022 à 11:05, Konstantinos Poulios a écrit :
    Dear Yves,

    Another thing that seems illogical to me is that
    geotrans_inv_convex::invert() returns convergence information,
    both as a return value and through a boolean argument
    "converged", with two possibly different values. Shouldn't we
    simplify this?

    The reason that I am looking into this is because I am
    experiencing some geometric inversion failures which are due to
    too strict checks with IN_EPS/100. But I don't want to just
    change the threshold value, I would like to improve the
    robustness of this quite central function in general.

    Best regards
    Kostas

    On Sun, Apr 3, 2022 at 9:36 AM Konstantinos Poulios
    <logar...@googlemail.com> wrote:

        Dear Yves,

        I assume this change
        image.png
        was not intentional, right? I cannot imagine why one would
        use a factor equal to 2.

        Best regards
        Kostas

        On Fri, Jun 15, 2018 at 5:14 PM Yves Renard
        <yves.ren...@insa-lyon.fr> wrote:

            branch: master
            commit 93ea20ccf0e03d841f600d928764a694a0047ab8
            Author: Yves Renard <yves.ren...@insa-lyon.fr>
            Date:   Fri Jun 15 16:34:52 2018 +0200

                fix a problem in inverting transformation for pyramids
            ---
             src/bgeot_geotrans_inv.cc                       | 10 +++----
             src/getfem/getfem_generic_assembly_tree.h  |  5 ----
             src/getfem_generic_assembly_compile_and_exec.cc | 35
            ++++++++++++++++++-------
             3 files changed, 29 insertions(+), 21 deletions(-)

            diff --git a/src/bgeot_geotrans_inv.cc
            b/src/bgeot_geotrans_inv.cc
            index f87e9df..f3fb9d0 100644
            --- a/src/bgeot_geotrans_inv.cc
            +++ b/src/bgeot_geotrans_inv.cc
            @@ -227,6 +227,7 @@ namespace bgeot
                 }

                 if (res < res0) copy(storage.x_ref, x);
            +    x *= 0.999888783; // For pyramid element to avoid
            the singularity
               }


            @@ -242,12 +243,11 @@ namespace bgeot
                 auto res = vect_norm2(nonlinear_storage.diff);
                 auto res0 = std::numeric_limits<scalar_type>::max();
                 double factor = 1.0;
            -    auto cnt = 0;

                 while (res > IN_EPS) {
                   if ((abs(res - res0) < IN_EPS) || (factor < IN_EPS)) {
            -        converged = false;
            -        return point_in_convex(*pgt, x, res, IN_EPS);
            +       converged = false;
            +       return point_in_convex(*pgt, x, res, IN_EPS);
                   }

                   if (res > res0) {
            @@ -258,10 +258,9 @@ namespace bgeot
                     factor *= 0.5;
                   }
                   else {
            -        if (factor < 1.0) factor *= 2.0;
            +        if (factor < 1.0-IN_EPS) factor = 2.0;
                     res0 = res;
                   }
            -
                   pgt->poly_vector_grad(x, pc);
                   update_B();
                   mult(transposed(B), nonlinear_storage.diff,
            nonlinear_storage.x_ref);
            @@ -271,7 +270,6 @@ namespace bgeot
                   add(nonlinear_storage.x_real, scaled(xreal, -1.0),
                       nonlinear_storage.diff);
                   res = vect_norm2(nonlinear_storage.diff);
            -      ++cnt;
                 }

                 return point_in_convex(*pgt, x, res, IN_EPS);
            diff --git a/src/getfem/getfem_generic_assembly_tree.h
            b/src/getfem/getfem_generic_assembly_tree.h
            index 9ca3bd9..18682c0 100644
            --- a/src/getfem/getfem_generic_assembly_tree.h
            +++ b/src/getfem/getfem_generic_assembly_tree.h
            @@ -54,11 +54,6 @@ extern "C"{
             }
             #endif

            -// #define GA_USES_BLAS // not so interesting, at least
            for debian blas
            -
            -// #define GA_DEBUG_INFO(a) { cout << a << endl; }
            -#define GA_DEBUG_INFO(a)
            -
             #define GA_DEBUG_ASSERT(a, b) GMM_ASSERT1(a, b)
             // #define GA_DEBUG_ASSERT(a, b)

            diff --git
            a/src/getfem_generic_assembly_compile_and_exec.cc
            b/src/getfem_generic_assembly_compile_and_exec.cc
            index 3212b25..5a77635 100644
            --- a/src/getfem_generic_assembly_compile_and_exec.cc
            +++ b/src/getfem_generic_assembly_compile_and_exec.cc
            @@ -25,6 +25,13 @@
             #include "getfem/getfem_generic_assembly_compile_and_exec.h"
             #include
            "getfem/getfem_generic_assembly_functions_and_operators.h"

            +// #define GA_USES_BLAS // not so interesting, at least
            for debian blas
            +
            +// #define GA_DEBUG_INFO(a) { cout << a << endl; }
            +#define GA_DEBUG_INFO(a)
            +
            +
            +
             namespace getfem {


            @@ -766,6 +773,7 @@ namespace getfem {
                 virtual int exec() {
                   GA_DEBUG_INFO("Instruction: value of test functions");
                   if (qdim == 1) {
            +       GA_DEBUG_ASSERT(t.size() == Z.size(), "Wrong size
            for base vector");
                     std::copy(Z.begin(), Z.end(), t.begin());
                   } else {
                     size_type target_dim = Z.sizes()[1];
            @@ -3781,7 +3789,7 @@ namespace getfem {
                   if (inin.pt_type) {
                     if (cv != size_type(-1)) {
                       inin.m->points_of_convex(cv, inin.G);
            - inin.ctx.change((inin.m)->trans_of_convex(cv),
            +  inin.ctx.change((inin.m)->trans_of_convex(cv),
                                       0, P_ref, inin.G, cv, face_num);
                       inin.has_ctx = true;
                       if (face_num != short_type(-1)) {
            @@ -3826,7 +3834,7 @@ namespace getfem {

                 virtual int exec() {
                   bool cancel_optimization = false;
            -      GA_DEBUG_INFO("Instruction: call interpolate
            transformation");
            +      GA_DEBUG_INFO("Instruction: call interpolate
            neighbour transformation");
                   if (ipt == 0) {
                     if (!(ctx.have_pgp()) || !pai ||
            pai->is_built_on_the_fly()
                         || cancel_optimization) {
            @@ -3873,7 +3881,7 @@ namespace getfem {
                           gic.init(m.points_of_convex(adj_face.cv
            <http://adj_face.cv>), gpc.pgt2);
                           size_type first_ind =
            pai->ind_first_point_on_face(f);
                           const bgeot::stored_point_tab
            -                &spt = *(pai->pintegration_points());
            +               &spt = *(pai->pintegration_points());
                           base_matrix G;
                           m.points_of_convex(cv, G);
                           fem_interpolation_context ctx_x(gpc.pgt1,
            0, spt[0], G, cv, f);
            @@ -3882,7 +3890,8 @@ namespace getfem {
                           for (size_type i = 0; i < nbpt; ++i) {
                             ctx_x.set_xref(spt[first_ind+i]);
                             bool converged = true;
            -                bool is_in = gic.invert(ctx_x.xreal(),
            P_ref[i],converged,1E-4);
            +                gic.invert(ctx_x.xreal(), P_ref[i],
            converged);
            +               bool is_in =
            (gpc.pgt2->convex_ref()->is_in(P_ref[i]) < 1E-4);
                             GMM_ASSERT1(is_in &&
            converged,"Geometric transformation "
                                         "inversion has failed in
            neighbour transformation");
                           }
            @@ -3936,7 +3945,8 @@ namespace getfem {
                       inin.has_ctx = false;
                     }
                   }
            -      GA_DEBUG_INFO("Instruction: end of call
            interpolate transformation");
            +      GA_DEBUG_INFO("Instruction: end of call neighbour
            interpolate "
            +                   "transformation");
                   return 0;
                 }
                 ga_instruction_neighbour_transformation_call
            @@ -4746,6 +4756,7 @@ namespace getfem {
                 const mesh_fem **mfg1 = 0, **mfg2 = 0;
                 fem_interpolation_context *pctx1 = 0, *pctx2 = 0;
                 bool tensor_to_clear = false;
            +    bool tensor_to_adapt = false;

                 if (pnode->test_function_type) {
                   if (pnode->name_test1.size())
            @@ -4754,6 +4765,7 @@ namespace getfem {
                     pctx1 = &(gis.ctx);
                     const std::string &intn1 =
            pnode->interpolate_name_test1;
                     if (intn1.size()) {
            +         tensor_to_adapt = true;
                       pctx1 = &(rmi.interpolate_infos[intn1].ctx);
                       if
            (workspace.variable_group_exists(pnode->name_test1)) {
             ga_instruction_set::variable_group_info &vgi =
            @@ -4769,6 +4781,7 @@ namespace getfem {
                     pctx2 = &(gis.ctx);
                     const std::string &intn2 =
            pnode->interpolate_name_test2;
                     if (intn2.size()) {
            +         tensor_to_adapt = true;
                       pctx2 = &(rmi.interpolate_infos[intn2].ctx);
                       if
            (workspace.variable_group_exists(pnode->name_test2)) {
             ga_instruction_set::variable_group_info &vgi =
            @@ -4781,7 +4794,7 @@ namespace getfem {
                 }

                 // Produce a resize instruction which is stored if
            no equivalent node is
            -    // detected and is the mesh is not uniform.
            +    // detected and if the mesh is not uniform.
                 pnode->t.set_to_original(); pnode->t.set_sparsity(0, 0);
                 bool is_uniform = false;
                 if (pnode->test_function_type == 1) {
            @@ -4825,9 +4838,9 @@ namespace getfem {
                   std::list<pga_tree_node> &node_list =
            rmi.node_list[pnode->hash_value];
                   for (std::list<pga_tree_node>::iterator it =
            node_list.begin();
                        it != node_list.end(); ++it) {
            -        // cout << "found potential equivalent nodes ";
            -        // ga_print_node(pnode, cout);
            -        // cout << " and "; ga_print_node(*it, cout);
            cout << endl;
            +       // cout << "found potential equivalent nodes ";
            +       // ga_print_node(pnode, cout);
            +       // cout << " and "; ga_print_node(*it, cout);
            cout << endl;
                     if (sub_tree_are_equal(pnode, *it, workspace, 1)) {
                       pnode->t.set_to_copy((*it)->t);
                       return;
            @@ -4843,6 +4856,8 @@ namespace getfem {
                         pgai =
            std::make_shared<ga_instruction_transpose_test>
                           (pnode->tensor(), (*it)->tensor());
             rmi.instructions.push_back(std::move(pgai));
            +           GMM_ASSERT1(false,
            +                  "No use of X is allowed in scalar
            functions");
                       } else {
                         pnode->t.set_to_copy((*it)->t);
                       }
            @@ -4860,7 +4875,7 @@ namespace getfem {
                 if (pgai) { // resize instruction if needed and no
            equivalent node detected
                   if (is_uniform) { pgai->exec(); }
                   else {
            -        if (mfg1 || mfg2)
            +        if (tensor_to_adapt)
             rmi.instructions.push_back(std::move(pgai));
                     else
             rmi.elt_instructions.push_back(std::move(pgai));

Reply via email to