4
$\begingroup$

Really stuck with this.

When I use NIntegrate, it sometimes prints a message like

NIntegrate::ncvb: "NIntegrate failed to converge to prescribed accuracy after 18 recursive bisections in y near {x,y} = {-0.974847,-0.999994}. NIntegrate obtained 1.6208370249645834`*^-13 and 4.441318688929174`*^-16 for the integral and error estimates."

What I want to do is to return 0 when such a message is produced. I tried wrapping in Check, e.g. Check[NIntegrate[...], 0], but that doesn't stop the integration and the program just hangs. Also, it would be perfect if I could somehow extract the last obtained value from the message (1.6208370249645834`*^-13)

The problem

F11[x_, y_] := -((16 (3 x^4 + 6 x^2 y^2 - 5 y^4))/(9 (x^2 + y^2)^3));
F12[x_,y_] := -((32 x (x^4 - 6 x^2 y^2 + y^4))/(3 (x^2 + y^2)^4));
F21[x_, y_] := (32 x (x^4 - 6 x^2 y^2 + y^4))/(3 (x^2 + y^2)^4);
F22[x_, y_] := 
  (16 (33 x^6 - 180 x^5 y - 505 x^4 y^2 + 600 x^3 y^3 + 180 x y^5 - 
     515 x^2 y^4 - 35 y^6))/(3 (x^2 + y^2)^5);

K[x_, y_, i_, j_] := 
  Which[
    i == 1 && j==1, F11[x,y],
    i==1 && j==2, F12[x,y], 
    i==2 && j==1, F21[x,y], 
    i==2 && j==2, F22[x,y], 
    True, -12]; 

A[a_, i_, j_,n_,k_] := 
  NIntegrate[
    Sqrt[1 - x^2]*Sqrt[1 - y^2]*JacobiP[n, 1/2, 1/2, x]*JacobiP[k, 1/2, 1/2, y]*
      K[-2*a, x - y, i, j], 
    {x, -1, 1}, {y, -1, 1}, 
    AccuracyGoal -> 3, Method -> "LocalAdaptive"];

I get the error message when evaluating A[0.01, 1, 2, 1, 3].

$\endgroup$
11
  • 1
    $\begingroup$ The methods mentioned in question 1512 should help somewhat towards aborting the computation. As for the rest of your question, could you post a code snippet to get some context for your problem? $\endgroup$
    – MarcoB
    Commented May 6, 2015 at 8:30
  • 1
    $\begingroup$ Try this : Quiet[Check[ NIntegrate[Sin[x], {x, 0, 10000}, Method -> { Automatic, "SymbolicProcessing" -> False}] , "invalid"] ] . Its pretty much what you say you tried though.. $\endgroup$
    – george2079
    Commented May 6, 2015 at 18:19
  • 1
    $\begingroup$ To the second part, see $MessagePrePrint for extracting the numbers.. they are often garbage though so I'm not sure thats a worthwhile thing to do. $\endgroup$
    – george2079
    Commented May 6, 2015 at 18:34
  • 1
    $\begingroup$ Related: mathematica.stackexchange.com/questions/20367/… $\endgroup$
    – Michael E2
    Commented May 6, 2015 at 22:11
  • 1
    $\begingroup$ Also avoid initial capital letters -- no really, you should avoid initial capital letters. Also K is used the by system (see ?K). $\endgroup$
    – Michael E2
    Commented May 6, 2015 at 22:19

1 Answer 1

2
$\begingroup$

This was not closed as being unreproducible, so I've decided to answer it, since I think this method may be useful to some. I can adapt something I wrote for other purposes to address the outcome desired by the OP. I had occasion to write an extended version of NIntegrateProfile found in Needs["Integration`NIntegrateUtilities`"] (see, for example, the tutorial NIntegrate Integration Strategies). I adapted the Internal`AddHandler solution of Szabolcs to How to abort on any message generated? to capture the error estimate of NIntegrate. I think it might be of general interest, so I will include it as well as adapt it to the OP's situation; it may also be helpful in the OP's case, depending on what exactly is desired. It only catches the error estimate when NIntegrate::ncvb is produced, so it is not a (complete) solution to Obtaining an NIntegrate error estimate.

Hooking the NIntegrate::ncvb message. As shown by Szabolcs', we can use Internal`AddHandler to capture the parameters passed to Message. In the case of NIntegrate::ncvb, some of the arguments are wrapped in HoldForm. I do not recall the numeric parameters (e.g., the integral estimate) ever not being numeric, so I released the hold. The potential for an evaluation leak might be introduced by this.

ClearAll[sowMessageData];
sowMessageData[
  Hold[Message[NIntegrate::ncvb, recur_, rvar_, vars_, vars0_, integral_, error_], _]] := 
    Sow[{"ErrorEstimate" -> ReleaseHold@error, 
      "PossibleSingularity" -> Thread[Map[HoldPattern, vars, {2}] -> vars0 // ReleaseHold]}, 
     sowNIntegrateData];

ClearAll[nintegrateProfile];
SetAttributes[nintegrateProfile, HoldAll];
nintegrateProfile[NIntegrate[args__]] := 
 Module[{evaluations = 0},
  Internal`WithLocalSettings[
   Internal`AddHandler["Message", sowMessageData],
   Flatten[{
     Reap[Thread[{"Timing", "IntegralEstimate"} -> 
        AbsoluteTiming@ NIntegrate[args, EvaluationMonitor :> evaluations++]]],
     "Evaluations" -> evaluations}],
   Internal`RemoveHandler["Message", sowMessageData]
   ]]

nintegrateProfile[NIntegrate[1/x, {x, -0.5, 1}]]
nintegrateProfile[NIntegrate[1/x, {x, 0.5, 1}]]

NIntegrate::slwcon: Numerical integration converging too slowly; suspect one of the following: singularity, value of the integration is 0, highly oscillatory integrand, or WorkingPrecision too small. >>

NIntegrate::ncvb: NIntegrate failed to converge to prescribed accuracy after 9 recursive bisections in x near {x} = {0.00095325}. NIntegrate obtained -3.67657 and 5.363161650917478` for the integral and error estimates. >>

(*
  {"Timing" -> 0.088606, "IntegralEstimate" -> -3.67657, 
   "ErrorEstimate" -> 5.36316, "PossibleSingularity" -> {HoldPattern[x] -> 0.00095325}, 
   "Evaluations" -> 209}

  {"Timing" -> 0.002897, "IntegralEstimate" -> 0.693147, "Evaluations" -> 11}
*)

The OP's goals. The first goal mentioned by the OP is to return 0 in case of NIntegrate::ncvb. That's straightforward:

ClearAll[returnZeroOnNonconvergence];
returnZeroOnNonconvergence[
  Hold[Message[NIntegrate::ncvb, recur_, rvar_, vars_, vars0_, integral_, error_], _]] :=
     Return[0, NIntegrate];

Internal`WithLocalSettings[
 Internal`AddHandler["Message", returnZeroOnNonconvergence],
 NIntegrate[1/x, {x, -0.5, 1}],
 Internal`RemoveHandler["Message", returnZeroOnNonconvergence]
 ]

NIntegrate::slwcon: Numerical integration converging too slowly; suspect one of the following: singularity, value of the integration is 0, highly oscillatory integrand, or WorkingPrecision too small. >>

NIntegrate::ncvb: NIntegrate failed to converge to prescribed accuracy after 9 recursive bisections in x near {x} = {0.00095325}. NIntegrate obtained -3.67657 and 5.363161650917478` for the integral and error estimates. >>

(*  0  *)

I'm a little confused by the OP's request to be able to "extract the last obtained value," because that is the value returned by NIntegrate. In any case, the value is the argument integral to sowMessageData and maybe returned in whatever way desired (e.g. Return[{0, integral}, NIntegrate]). And my first example nintegrateProfile can be adapted to return all of the parameters, if desired.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.