Hi!
I want to see what happens when we build a surrogate model while ignoring some of the observations which lead to failures in the model evaluation. This can be emulated by considering a toy model and raising an exception when appropriate. Unfortunately, I am not able to catch the exception produced by the PythonFunction.
To see this, please consider the code:
import openturns as ot
def rungeWithFailurePy(x):
x0 = x[0]
y = 1.0 / (1.0 + 25.0 * x0 ** 2)
yThresholdRunge = 0.8
if y > yThresholdRunge:
raise ValueError(f"Cannot evaluate y at input {x0:.4f}")
return [y]
rungeModelWithFailure = ot.PythonFunction(1, 1, rungeWithFailurePy)
sampleSize = 50
inputDistribution = ot.Uniform(-1.0, 1.0)
inputSample = inputDistribution.getSample(sampleSize)
outputSample = ot.Sample(sampleSize, 1)
outputSampleLabel = [True] * sampleSize
for i in range(sampleSize):
try:
# outputSample[i] = rungeWithFailurePy(inputSample[i]) # OK
outputSample[i] = rungeModelWithFailure(inputSample[i]) # Fails
except ValueError:
outputSampleLabel[i] = False
print(f"Cannot evaluate y at input {inputSample[i, 0]:.4f}")
When I use rungeModelWithFailure (i.e. the ot.PythonFunction), this prints:
[...]
ValueError: Cannot evaluate y at input 0.0484
RuntimeError: InternalException : Python exception: ValueError: Cannot evaluate y at input 0.0484
When I use rungeWithFailurePy (i.e. the Python function), this prints:
Cannot evaluate y at input -0.0133
Cannot evaluate y at input -0.0905
Cannot evaluate y at input 0.0900
Cannot evaluate y at input -0.0374
Cannot evaluate y at input -0.0302
So I can catch the exception raised by the basic Python function, but I cannot catch the exception raised by the OpenTURNS PythonFunction. Why is that?
Regards,
Michaël
OpenTURNS raises a “RuntimeError”, you can catch this type of error but I do not why it does not raise the initial error. But still the output is strange.
sampleSize = 50
inputDistribution = ot.Uniform(-1.0, 1.0)
inputSample = inputDistribution.getSample(sampleSize)
outputSample = ot.Sample(sampleSize, 1)
outputSampleLabel = [True] * sampleSize
for i in range(sampleSize):
try:
# outputSample[i] = rungeWithFailurePy(inputSample[i]) # OK
outputSample[i] = rungeModelWithFailure(inputSample[i]) # Fails
except RuntimeError:
outputSampleLabel[i] = False
print(f"Cannot evaluate y at input {inputSample[i, 0]:.4f}")
except ValueError:
outputSampleLabel[i] = False
print(f"Cannot evaluate y at input {inputSample[i, 0]:.4f}")
But then the ValueError exception is raised:
ValueError: Cannot evaluate y at input 0.0491
ValueError: Cannot evaluate y at input 0.0606
etc.
It seems to me that it should not and should be catched by the except ValueError. Should I organize my “try/catch” statements in some other way?
Regards,
Michaël
Maybe to check if this is really the ValueError you want to catch, you can test the text in the error. But the original print is still here because it comes frome OT, you can redirect the stdout. It is not really elegant but it works:
import sys
import os
f_origin = sys.stdout
print_null = open(os.devnull, 'w')
sampleSize = 50
inputDistribution = ot.Uniform(-1.0, 1.0)
inputSample = inputDistribution.getSample(sampleSize)
outputSample = ot.Sample(sampleSize, 1)
outputSampleLabel = [True] * sampleSize
for i in range(sampleSize):
try:
# outputSample[i] = rungeWithFailurePy(inputSample[i]) # OK
sys.stdout = print_null
outputSample[i] = rungeModelWithFailure(inputSample[i]) # Fails
sys.stdout = f_origin
except RuntimeError as err:
sys.stdout = f_origin
outputSampleLabel[i] = False
if 'ValueError' in err.args[0]:
outputSampleLabel[i] = False
print(f"Cannot evaluate y at input {inputSample[i, 0]:.4f}")