This PR fixes #92, and replaces a call to numpy.seterr, which changes the error handling behavior of numpy globally whenever gctree is imported, with appropriate calls to the numpy.errstate context manager.
There are two strategies for wrapping all numerically sensitive code in a numpy.errstate context. One option is to wrap specifically the numpy-calling code blocks in a with block, in each function where such code blocks exist. The other option is to wrap larger chunks of code, e.g. entire functions, using numpy.errstate as a decorator.
I chose the second option, since the first involves possibly orders of magnitude more invocations of numpy.errstate (e.g. every call to _ll_genotype). *The policy will be that each public function or method which contains numerically sensitive computations shall be decorated with numpy.errstate(all='raise'), or if appropriate use a with block.
This approach has two disadvantages:
In the case of nested function/method calls, it may be difficult to trace which code is executed in the appropriate numpy context
There may be nested calls to numpy.errstate, where decorated functions call other decorated functions.
I think both of these are acceptable.
Testing:
Exactly which methods are decorated may need to be tweaked. To test, I sprinkled assert set(numpy.geterr().values()) == {'raise'} in appropriate places in gctree.branching_processes, and ran all tests and pipelines.
This PR fixes #92, and replaces a call to
numpy.seterr
, which changes the error handling behavior of numpy globally whenever gctree is imported, with appropriate calls to thenumpy.errstate
context manager.There are two strategies for wrapping all numerically sensitive code in a
numpy.errstate
context. One option is to wrap specifically the numpy-calling code blocks in awith
block, in each function where such code blocks exist. The other option is to wrap larger chunks of code, e.g. entire functions, usingnumpy.errstate
as a decorator.I chose the second option, since the first involves possibly orders of magnitude more invocations of
numpy.errstate
(e.g. every call to_ll_genotype
). *The policy will be that each public function or method which contains numerically sensitive computations shall be decorated withnumpy.errstate(all='raise')
, or if appropriate use awith
block.This approach has two disadvantages:
numpy.errstate
, where decorated functions call other decorated functions.I think both of these are acceptable.
Testing:
Exactly which methods are decorated may need to be tweaked. To test, I sprinkled
assert set(numpy.geterr().values()) == {'raise'}
in appropriate places ingctree.branching_processes
, and ran all tests and pipelines.