I am solving a large problem where the location of the root to my equation changes very rapidly from one value to another. However the function is close to 0, and so Newton method thinks there is a root there, but iterates itself out. I would like to be able to ask the root finder to try again, but with a different initial guess if it can not converge the first time, but I am unsure how to handle this error. It is worth noting that I would like to use Newton/Secant method as Bisection method will not be very useful due to the problem I am solving. I have an example below which illustrates my problem.
I have searched on how to handle errors and looked at the documentation for scipy.optimize.newton but cannot find how to handle the error and ask it to try again. I keep having to manually input the new guess.
from numpy import *
from scipy import optimize
# Define a function that passes 1, but grazes it at another point
def f(x):
y = log(exp(-0.8*x)*cos(5*x) + 0.62)
return(y)
# Try find the root
root= optimize.newton(f, x0, tol = 1e-7, maxiter=80)
If I run this with some x0 value reasonably close to the true root (~0.2201), it finds it quickly. However, the function approaches 0 quite close around 1.25, but then turns back around. If i put x0 in as 1.25, the root finder fails to converge and the error reads 'Failed to converge after 80 iterations, value is nan'. I just want a way to handle this error and ask it to try again with another guess. I have a root finder as part of a big function which I know has a root, it has just moved. So when I get this error, it just terminates my whole code which I'd like to avoid.
What is happening is that your root finder is throwing an exception and you are not doing anything about it, which is why you see an error message.
Even if a statement or expression is syntactically correct, it may cause an error
...
Errors detected during execution are called exceptions
...
Most exceptions are not handled ... and result in error messages
From this we can see that the error message is caused because an exception happened and it wasn't handled.
The next section in defines how you should handle errors.
From the Python 3.7.4 spec (Section 8.3):
It is possible to write programs that handle selected exceptions.
...
The try statement works as follows.
• First, the try clause ... is executed.
• If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, [then the program skips the rest of the try clause and continues after the except clause]
• If an exception occurs which does not match the exception named in the except clause, [the exception is thrown and can be caught by try-catch clauses wrapping around the current one]
Using this information, we can solve your problem.
try
clause:
try:
root = optimize.newton(f, x0, tol = 1e-7, maxiter=80)
...
Since root
is now local to the scope of the try
clause, we need to declare it outside:
root = x0
try:
root = optimize.newton(f, x0, tol = 1e-7, maxiter=80)
...
We now need to add the except clause to try it with a different value:
root = x0
try:
root = optimize.newton(f, x0, tol = 1e-7, maxiter=80)
except YOUR EXCEPTION:
root = optimizes.newton(f, other_x0, tol = 1e-7, maxiter=80)
You need to replace YOUR EXCEPTION
with the name of the exception that is thrown when you reach the maximum amount of iterations.
Alternatively, you could replace it with Exception
to catch any exception that is thrown but this isn't recommended because you might catch another exception that you won't know you have to fix.