try catch of "ExcDereferenceInvalidCell"

51 views
Skip to first unread message

Simon

unread,
Jul 27, 2023, 10:34:30 AM7/27/23
to deal.II User Group
Dear all,

I want to catch exceptions thrown by fePointEval.reinit(...), 
where fePointEval is an object of type FEPointEvaluation.

Here is a snippet of code demonstrating the issue:

try
{
     fePointEval.reinit(...);
}
catch(dealii::ExceptionBase & exception)
{
       std::cout<<"exception is catched"<<std::endl;
       throw MyClass(...);
}

where MyClass is derived from dealii::ExceptionBase.

The exception ExcDereferenceInvalidCell is definitely thrown because the message
" You tried to dereference a cell iterator.... "
is printed on my screen, if I try to evaluate the function attached to the FEPointEvaluation
object outside its domain.
I am also convinced that the exception is not catched by the code above, because the
dummy print statement in the catch block is not printed on my screen.

According to the documentation (v9.3.2), ExcDereferenceInvalidCell throws an exception
of type dealii::ExceptionBase, i.e., I would have expected that my snippet above catches it. 
What do I miss here?

Best,
Simon

Wolfgang Bangerth

unread,
Jul 30, 2023, 12:33:41 PM7/30/23
to dea...@googlegroups.com

Simon,

> I want to catch exceptions thrown by fePointEval.reinit(...),
> where fePointEval is an object of type FEPointEvaluation.
>
> Here is a snippet of code demonstrating the issue:
>
> try
> {
>      fePointEval.reinit(...);
> }
> catch(dealii::ExceptionBase & exception)
> {
>        std::cout<<"exception is catched"<<std::endl;
>        throw MyClass(...);
> }
>
> where MyClass is derived from dealii::ExceptionBase.
>
> The exception ExcDereferenceInvalidCell is definitely thrown because the message
> " You tried to dereference a cell iterator.... "
> is printed on my screen, if I try to evaluate the function attached to the
> FEPointEvaluation
> object outside its domain.

The documentation of deal.II rarely is clear about what "throwing an
exception" means. That depends on whether you use Assert or AssertThrow. The
former is for logic errors inherent in the program that cannot be recovered
from -- say, trying to dereference triangulation.end(). You need to fix the
program to deal with this, and so we use Assert which simply aborts the
program (even though perhaps the documentation may say that it "throws the
exception") after showing the error message.

We use AssertThrow (which really does 'throw' an exception) for situations
that are run-time errors. Say the file you opened cannot be read, or you're
out of memory -- in general, for situations where the *program* is correct,
but perhaps its *input* is not.

Best
W.

--
------------------------------------------------------------------------
Wolfgang Bangerth email: bang...@colostate.edu
www: http://www.math.colostate.edu/~bangerth/


Simon Wiesheier

unread,
Jul 30, 2023, 1:21:53 PM7/30/23
to dea...@googlegroups.com
"
The
former is for logic errors inherent in the program that cannot be recovered
from -- say, trying to dereference triangulation.end()"

Of course, it does not make sense to dereference such an iterator. 
That's the reason why I wanted to catch this operation, and do something else instead. In my case, aborting the program is absolutely not necessary as I would have a workaround. 

But, if I understand you, there is no way for me to catch the exception from my question, right? 

Best 
Simon 

--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dealii/e3b7f84f-d4ee-5854-83a4-add287e86415%40colostate.edu.

Wolfgang Bangerth

unread,
Aug 2, 2023, 12:51:18 PM8/2/23
to dea...@googlegroups.com
On 7/30/23 11:20, Simon Wiesheier wrote:
>
> Of course, it does not make sense to dereference such an iterator.
> That's the reason why I wanted to catch this operation, and do something else
> instead. In my case, aborting the program is absolutely not necessary as I
> would have a workaround.
>
> But, if I understand you, there is no way for me to catch the exception from
> my question, right?

You can call
deal_II_exceptions::disable_abort_on_exception();
which converts the call to abort() to raising an actual exception.

But I do want to ask what you plan to do if you derefernce an end-iterator.
That should simply never happen -- it's a bug in the program to do this,
comparable to a segmentation fault when dereferencing a NULL pointer. The
right approach is to ensure that that doesn't happen, not to come up with a
backup plan to do something else if it does happen.

Simon Wiesheier

unread,
Aug 2, 2023, 5:53:36 PM8/2/23
to dea...@googlegroups.com
" You can call
   deal_II_exceptions::disable_abort_on_exception();
which converts the call to abort() to raising an actual exception.  "
This worked indeed.

" But I do want to ask what you plan to do if you derefernce an end-iterator. "

I see your point, let me briefly sketch what I want to do:
I have an interpoland to which I attach a triangulation.
When I want to evaluate the interpoland at a real point,
I first call GridTools::find_active_cell_around_point
to find the cell where the point lives along with the
unit cell coordinates.
Then, I call the .reinit function to actually evaluate
values, gradients, ... of the interpoland.
However, it may be the case that the evaluation point is
outside the domain of the triangulation, in which case
.reinit aborts the program, for the reasons you mentioned.
In those cases, I also want to abort the program but with a more
meaningfull message.
In particular, I want to inform the user about the domain of
the interpoland, the point where evaluation failed, and
workarounds how to circumvent such out-of-bound evaluations,...
I want to do this by throwing on instance of a class that derives from 
dealii::ExceptionBase
in the catch block.

Does that make sense?
Or do you see a better solution, like checking
cell->status() right after GridTools::find_active_cell_around_point?

Best,
Simon



--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.

Wolfgang Bangerth

unread,
Aug 3, 2023, 8:21:52 AM8/3/23
to dea...@googlegroups.com
On 8/2/23 15:58, Simon Wiesheier wrote:
>
> Does that make sense?
> Or do you see a better solution, like checking
> cell->status() right after GridTools::find_active_cell_around_point?

This. If the function you call returns an error code in the form of an end
iterator, just test for that rather than doing something with this iterator
and wait to see what happens. It is always worth checking errors as early as
possible.

Simon Wiesheier

unread,
Aug 3, 2023, 1:20:42 PM8/3/23
to dea...@googlegroups.com
Let me please clarify my last concerns in this regard:

The operations
GridTools::find_active_cell_around_point and
feValues.reinit
are executed at quadrature point level and performance
is really important in our application.

The reason why I wanted to use an
try/catch block is to surrogate the use of an if-statement.
Consider these two variants:

Variant 1:

disable_abort_on_exception();
try
{
   feValues.reinit(cell,...);
}
catch(dealii::Exception Base exception & )
{
   Assert(checkSecondRunTimeCondition, ...)
   // do something
}

Variant 2:

if(cell->state()==-1)
{    
    Assert(checkSecondRunTimeCondition, ...)
   // do something 
}
else
{
     feValues.reinit(cell,...);
}

As you can see, there are two conditions I have to check at every quadrature point.
Clearly, Variant 2 implements an if-requests and is probably not the way to go.


1. So with regard to performance, would you prefer Variant 1 
(as the try/catch introduces less overhead compared to the if-statement)?
2. If so, is the call of "disable_abort_on_exception()" good
coding practice or would you refrain from doing so?
In the main function of our program, we have a try/catch with
catch(dealii::ExceptionBase exception &). 
Given that, in my opinion  "disable_abort_on_exception()"
should cause any undue behavior.

Best,
Simon


--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.

Matthias Maier

unread,
Aug 3, 2023, 5:57:21 PM8/3/23
to dea...@googlegroups.com
I am a bit confused.


In optimized release mode the `Assert` are reduced to a nnop and will
not abort (or throw an exception). For user-visible/induced runtime
errors we have `AssertThrow` which will throw an exception (and not
abort a program). In summary:

- we use `Assert(...)` in the library to check for logical error
conditions in *debug* mode. These are optimized out in optimized
release mode.

The reasoning behind this is that these asserts are "static", logical
mistakes in the library / user code.

- we use `AssertThrow(...)` to check for error conditions in *debug*
and *release* mode. These checks are always run and used to validate
user-controlled input.

(and catchable to do something in case such an error is encountered).

So I am not sure how you would ever use an `Assert(...)` in optimized
release mode (where you want to run your program to get any
performance).


Regarding the additional if statement: If this is performance critical I
suggest to not use the c++ exception mechanism in this way. Stack
unwinding is very, very slow.


On the other hand, if you have a very unlikely error path and handled in
an if-statement (c++20 style):

if (/* error condition */) [[unlikely]] {
// ... handle error
}

then we have often made the observation that this leads to very acceptable
performance - even in hot execution paths.


Best,
Matthias

Matthias Maier

unread,
Aug 3, 2023, 6:02:11 PM8/3/23
to dea...@googlegroups.com
Have you considered looking into our FEPointEvaluation [1] and related
"nonmatching" facilities?

I have the feeling that we already provide the right data structures for
your interpolation/evaluation needs - in particular with an efficient
and fast implementation. An example usage can be found in step-19.

Best,
Matthias

[1] https://www.dealii.org/current/doxygen/deal.II/classFEPointEvaluation.html

Simon Wiesheier

unread,
Aug 3, 2023, 6:58:18 PM8/3/23
to dea...@googlegroups.com
" So I am not sure how you would ever use an `Assert(...)` in optimized
release mode (where you want to run your program to get any
performance). "

I was indeed considering my program in debug mode.
Based on what you said, there is no way for me to catch
the failed .reinit call in optimized released mode
and using if-statements is the proper way for me
to handle my conditions.
Is that correct?

" Have you considered looking into our FEPointEvaluation [1] and related
"nonmatching" facilities?"

Yes, I already use FEPointEvaluation to evaluate the interpoland
at arbitrary points.
What other "nonmatching" facilities do you think may be helpful?
As said, I have to evaluate the interpoland (first and second derivatives)
at arbitrary points in real space --
as often as there are quadrature points on my geometry in each assembly.

Best,
Simon



--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dealii/87zg37bx9e.fsf%4043-1.org.



Wolfgang Bangerth

unread,
Aug 4, 2023, 8:19:11 AM8/4/23
to dea...@googlegroups.com
On 8/3/23 11:25, Simon Wiesheier wrote:
>
> The reason why I wanted to use an
> try/catch block is to surrogate the use of an if-statement.
> Consider these two variants:
>
> Variant 1:
>
> disable_abort_on_exception();
> try
> {
>    feValues.reinit(cell,...);
> }
> catch(dealii::Exception Base exception & )
> {
>    Assert(checkSecondRunTimeCondition, ...)
>    // do something
> }
>
> Variant 2:
>
> if(cell->state()==-1)
> {
>     Assert(checkSecondRunTimeCondition, ...)
>    // do something
> }
> else
> {
>      feValues.reinit(cell,...);
> }
>
> As you can see, there are two conditions I have to check at every quadrature
> point.
> Clearly, Variant 2 implements an if-requests and is probably not the way to go.

Variant 2 is what I would have done.

Why do you care about the 'if'? Are you worried of the run time overhead? If
that's the case, consider the equivalent cost of a 'throw' and 'catch' -- I
would not be surprised if that were two order of magnitude more expensive than
the 'if'.


> 1. So with regard to performance, would you prefer Variant 1
> (as the try/catch introduces less overhead compared to the if-statement)?

That's something you can test. There is a general rule that even good
programmers cannot tell where the bottlenecks of their code are unless they
benchmark them. I would suggest writing a small test program that checks these
two options!


> 2. If so, is the call of "disable_abort_on_exception()" good
> coding practice or would you refrain from doing so?
> In the main function of our program, we have a try/catch with
> catch(dealii::ExceptionBase exception &).
> Given that, in my opinion  "disable_abort_on_exception()"
> should cause any undue behavior.

It's not good practice. As Matthias already pointed out, it doesn't work in
release mode. It's a tool we only use in the test suite.
Reply all
Reply to author
Forward
0 new messages