From 93f57bd71fa954c2d19b83b81ea5114339038df8 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Fri, 15 Nov 2019 17:49:08 +0100 Subject: [PATCH 01/18] [Issue #252] added functions to check if user given is rightly defined --- tofu/geom/_GG.pyx | 77 ++---------------------------------------- tofu/geom/_core.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 74 deletions(-) diff --git a/tofu/geom/_GG.pyx b/tofu/geom/_GG.pyx index 0462264b8..1455969a4 100644 --- a/tofu/geom/_GG.pyx +++ b/tofu/geom/_GG.pyx @@ -9,10 +9,7 @@ from warnings import warn import numpy as np import scipy.integrate as scpintg from matplotlib.path import Path -if sys.version[0]=='3': - from inspect import signature as insp -elif sys.version[0]=='2': - from inspect import getargspec as insp + # -- Cython libraries imports -------------------------------------------------- from cpython cimport bool from cpython.array cimport array, clone @@ -851,7 +848,7 @@ def discretize_vpoly(double[:,::1] VPoly, double dL, reference Radius coordinates, not shifted even if DIn <> 0. If DIn == 0, then Rref_arr = PtsCross[0, ...] VPolybis : - + """ cdef int NP=VPoly.shape[1] cdef int[1] sz_vb, sz_ot @@ -2771,74 +2768,6 @@ def LOS_get_sample(int nlos, dL, double[:,::1] los_lims, str dmethod='abs', ###################################################################### # Signal calculation ###################################################################### -cdef get_insp(ff): - out = insp(ff) - if sys.version[0]=='3': - pars = out.parameters.values() - na = np.sum([(pp.kind==pp.POSITIONAL_OR_KEYWORD - and pp.default is pp.empty) for pp in pars]) - kw = [pp.name for pp in pars if (pp.kind==pp.POSITIONAL_OR_KEYWORD - and pp.default is not pp.empty)] - else: - nat, nak = len(out.args), len(out.defaults) - na = nat-nak - kw = [out.args[ii] for ii in range(nat-1,na-1,-1)][::-1] - return na, kw - - - -def check_ff(ff, t=None, Ani=None, bool Vuniq=False): - cdef bool ani - cdef int nt = -1 - # ... - stre = "Input emissivity function (ff)" - assert hasattr(ff,'__call__'), stre+" must be a callable (function)!" - na, kw = get_insp(ff) - assert na==1, stre+" must take only one positional argument: ff(Pts)!" - assert 't' in kw, stre+" must have kwarg 't=None' for time vector!" - C = type(t) in [int,float,np.int64,np.float64] or hasattr(t,'__iter__') - assert t is None or C, "Arg t must be None, a scalar or an iterable!" - Pts = np.array([[1,2],[3,4],[5,6]]) - NP = Pts.shape[1] - try: - out = ff(Pts, t=t) - except Exception: - Str = stre+" must take one positional arg: a (3,N) np.ndarray" - assert False, Str - if hasattr(t,'__iter__'): - nt = len(t) - Str = ("ff(Pts,t=t), where Pts is a (3,N) np.array and " - +"t a len()=nt iterable, must return a (nt,N) np.ndarray!") - assert type(out) is np.ndarray and out.shape==(nt,NP), Str - else: - Str = ("When fed a (3,N) np.array only, or if t is a scalar," - +" ff must return a (N,) np.ndarray!") - assert type(out) is np.ndarray and out.shape==(NP,), Str - - ani = ('Vect' in kw) if Ani is None else Ani - if ani: - Str = "If Ani=True, ff must take a keyword argument 'Vect=None'!" - assert 'Vect' in kw, Str - Vect = np.array([1,2,3]) if Vuniq else np.ones(Pts.shape) - try: - out = ff(Pts, Vect=Vect, t=t) - except Exception: - Str = "If Ani=True, ff must handle multiple points Pts (3,N) with " - if Vuniq: - Str += "a unique common vector (Vect as a len()=3 iterable)" - else: - Str += "multiple vectors (Vect as a (3,N) np.ndarray)" - assert False, Str - if hasattr(t,'__iter__'): - Str = ("If Ani=True, ff must return a (nt,N) np.ndarray when " - +"Pts is (3,N), Vect is provided and t is (nt,)") - assert type(out) is np.ndarray and out.shape==(nt,NP), Str - else: - Str = ("If Ani=True, ff must return a (nt,N) np.ndarray when " - +"Pts is (3,N), Vect is provided and t is (nt,)") - assert type(out) is np.ndarray and out.shape==(NP,), Str - return ani - def integrate1d(y, double dx, t=None, str method='sum'): """ Generic integration method ['sum','simps','romb'] @@ -3385,7 +3314,7 @@ cdef inline void NEW_LOS_sino_Tor(double orig0, double orig1, double orig2, kPMin = res[0] if is_LOS_Mode and kPMin > kOut: kPMin = kOut - + # Computing the point's coordinates......................................... cdef double PMin0 = orig0 + kPMin * dirv0 cdef double PMin1 = orig1 + kPMin * dirv1 diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 103d3dc77..b132d5214 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5760,6 +5760,90 @@ def calc_min_rho_from_Plasma2D(self, plasma, t=None, log='min', for vv in np.split(val, lind, axis=-1)]) return vals, pts, t + def get_inspector(self, ff): + out = inspect.signature(ff) + pars = out.parameters.values() + na = np.sum([(pp.kind==pp.POSITIONAL_OR_KEYWORD + and pp.default is pp.empty) for pp in pars]) + kw = [pp.name for pp in pars if (pp.kind==pp.POSITIONAL_OR_KEYWORD + and pp.default is not pp.empty)] + return na, kw + + def check_ff(self, ff, t=None, ani=None, vuniq=False): + time_steps = -1 + # .. Checking basic definition of function ............................. + str_error = "Input emissivity function (ff): " + assert hasattr(ff, '__call__'), (str_error + + " must be a callable (function)!") + npos_args, kw = self.get_inspector(ff) + assert npos_args==1, (str_error + + " must take only one positional argument:" + + " ff(Pts)!") + assert 't' in kw, (str_error + + " must have kwarg 't=None' for time vector!") + is_t_type_valid = (type(t) in [int, float, np.int64, np.float64] + or hasattr(t, '__iter__')) + assert t is None or is_t_type_valid, (str_error + + "Arg t must be None," + + " a scalar or an iterable!") + # .. Testing outputs ................................................... + test_pts = np.array([[1, 2], [3, 4], [5, 6]]) + npts = test_pts.shape[1] + try: + out = ff(test_pts, t=t) + except Exception: + assert False, (str_error + + " must take one positional arg:" + + " a (3, npts) np.ndarray") + if hasattr(t, '__iter__'): + time_steps = len(t) + err_msg = (str_error + + " ff(Pts, t=t), where Pts is a (3, npts) np.array and" + + " t a len()=nt iterable," + + " must return a (nt, npts) np.ndarray!") + assert (type(out) is np.ndarray + and out.shape==(time_steps, npts)), err_msg + else: + err_msg = (str_error + + " When t=None or t is a scalar," + + " ff must return a 2D (1, npts) np.ndarray!") + assert type(out) is np.ndarray and out.shape==(1, npts), err_msg + + is_ani = ('vect' in kw) if ani is None else ani + if is_ani: + err_msg = (str_error + + " If ani=True, ff must take a keyword argument:" + + " 'vect=None'!") + assert 'vect' in kw, err_msg + vect = np.array([1, 2, 3]) if vuniq else np.ones(test_pts.shape) + try: + out = ff(test_pts, vect=vect, t=t) + except Exception: + err_msg = (str_error + + " If ani=True, ff must handle multiple" + + " points Pts (3, npts) with ") + if vuniq: + err_msg += ("a unique common vector" + + " (vect as a len()=3 iterable)") + else: + err_msg += ("multiple vectors (vect as a" + + " (3, npts) np.ndarray)") + assert False, err_msg + if hasattr(t, '__iter__'): + err_msg = (str_error + + " If ani=True, ff must return a (nt, npts)" + + " np.ndarray when Pts is (3,N), vect is provided" + + " and t is a list (nt,)") + assert (type(out) is np.ndarray + and out.shape==(time_steps, npts)), err_msg + else: + err_msg = (str_error + + "If ani=True, ff must return a (1, npts)" + + " np.ndarray when Pts is (3, npts), vect is" + + " provided and t is None or a scalar") + assert type(out) is np.ndarray and out.shape==(1, npts), err_msg + return + def _calc_signal_preformat(self, ind=None, DL=None, t=None, out=object, Brightness=True): msg = "Arg out must be in [object,np.ndarray]" From 27cea6dafe16149d50bb053d6236ddde4e61a2f2 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Fri, 15 Nov 2019 17:53:38 +0100 Subject: [PATCH 02/18] [Issue #252] added call to check function got rid of old param --- tofu/geom/_core.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index b132d5214..d0d9842ea 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5769,7 +5769,7 @@ def get_inspector(self, ff): and pp.default is not pp.empty)] return na, kw - def check_ff(self, ff, t=None, ani=None, vuniq=False): + def check_ff(self, ff, t=None, ani=None): time_steps = -1 # .. Checking basic definition of function ............................. str_error = "Input emissivity function (ff): " @@ -5815,19 +5815,15 @@ def check_ff(self, ff, t=None, ani=None, vuniq=False): + " If ani=True, ff must take a keyword argument:" + " 'vect=None'!") assert 'vect' in kw, err_msg - vect = np.array([1, 2, 3]) if vuniq else np.ones(test_pts.shape) + vect = np.ones(test_pts.shape) try: out = ff(test_pts, vect=vect, t=t) except Exception: err_msg = (str_error + " If ani=True, ff must handle multiple" - + " points Pts (3, npts) with ") - if vuniq: - err_msg += ("a unique common vector" - + " (vect as a len()=3 iterable)") - else: - err_msg += ("multiple vectors (vect as a" - + " (3, npts) np.ndarray)") + + " points Pts (3, npts) with " + + "multiple vectors (vect as a" + + " (3, npts) np.ndarray)") assert False, err_msg if hasattr(t, '__iter__'): err_msg = (str_error @@ -6050,6 +6046,7 @@ def calc_signal( # Launch # NB : find a way to exclude cases with DL[0,:]>=DL[1,:] !! # Exclude Rays not seeing the plasma if newcalc: + self.check_ff(func, t=t, ani=ani): s = _GG.LOS_calc_signal( func, Ds, From ae691535c2eef113877b73f13dc3a6159b9150c5 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Fri, 15 Nov 2019 18:08:02 +0100 Subject: [PATCH 03/18] [Issue #252] bf: let a semicolon by mistake --- tofu/geom/_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index d0d9842ea..487c9d149 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -6046,7 +6046,7 @@ def calc_signal( # Launch # NB : find a way to exclude cases with DL[0,:]>=DL[1,:] !! # Exclude Rays not seeing the plasma if newcalc: - self.check_ff(func, t=t, ani=ani): + self.check_ff(func, t=t, ani=ani) s = _GG.LOS_calc_signal( func, Ds, From 565d736569017f3ef836ee3d65b3bf274a9d32da Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Fri, 15 Nov 2019 18:59:55 +0100 Subject: [PATCH 04/18] [Issue #252] trying something --- examples/tutorials/plot_custom_emissivity.py | 9 ++++- tofu/geom/_core.py | 39 +++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/tutorials/plot_custom_emissivity.py b/examples/tutorials/plot_custom_emissivity.py index 349aa3d45..0cb041359 100644 --- a/examples/tutorials/plot_custom_emissivity.py +++ b/examples/tutorials/plot_custom_emissivity.py @@ -51,6 +51,11 @@ def emissivity(pts, t=None, vect=None): e = np.reshape(e, (1, -1)) return e +def ff(Pts, t=None): + print("pts =", Pts) + print("t=", t) + print("--------") + return np.zeros(Pts.shape[1])+1 y = np.linspace(2, 3, num=90) z = np.linspace(-0.5, 0.5, num=100) @@ -81,11 +86,11 @@ def project_to_2D(xyz): time_vector = np.linspace(0, 2 * np.pi, num=100) -sig, units = cam2d.calc_signal(emissivity, +sig, units = cam2d.calc_signal(ff, res=0.01, reflections=False, newcalc=True, plot=False, - t=time_vector) + t=None) sig.plot(ntMax=1) plt.show() diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 487c9d149..874c0b8fc 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5763,22 +5763,22 @@ def calc_min_rho_from_Plasma2D(self, plasma, t=None, log='min', def get_inspector(self, ff): out = inspect.signature(ff) pars = out.parameters.values() - na = np.sum([(pp.kind==pp.POSITIONAL_OR_KEYWORD + na = np.sum([(pp.kind == pp.POSITIONAL_OR_KEYWORD and pp.default is pp.empty) for pp in pars]) - kw = [pp.name for pp in pars if (pp.kind==pp.POSITIONAL_OR_KEYWORD + kw = [pp.name for pp in pars if (pp.kind == pp.POSITIONAL_OR_KEYWORD and pp.default is not pp.empty)] return na, kw def check_ff(self, ff, t=None, ani=None): time_steps = -1 - # .. Checking basic definition of function ............................. + # .. Checking basic definition of function ............................ str_error = "Input emissivity function (ff): " assert hasattr(ff, '__call__'), (str_error + " must be a callable (function)!") npos_args, kw = self.get_inspector(ff) - assert npos_args==1, (str_error - + " must take only one positional argument:" - + " ff(Pts)!") + assert npos_args == 1, (str_error + + " must take only one positional argument:" + + " ff(Pts)!") assert 't' in kw, (str_error + " must have kwarg 't=None' for time vector!") is_t_type_valid = (type(t) in [int, float, np.int64, np.float64] @@ -5786,7 +5786,7 @@ def check_ff(self, ff, t=None, ani=None): assert t is None or is_t_type_valid, (str_error + "Arg t must be None," + " a scalar or an iterable!") - # .. Testing outputs ................................................... + # .. Testing outputs .................................................. test_pts = np.array([[1, 2], [3, 4], [5, 6]]) npts = test_pts.shape[1] try: @@ -5802,13 +5802,18 @@ def check_ff(self, ff, t=None, ani=None): + " t a len()=nt iterable," + " must return a (nt, npts) np.ndarray!") assert (type(out) is np.ndarray - and out.shape==(time_steps, npts)), err_msg + and out.shape == (time_steps, npts)), err_msg else: err_msg = (str_error + " When t=None or t is a scalar," + " ff must return a 2D (1, npts) np.ndarray!") - assert type(out) is np.ndarray and out.shape==(1, npts), err_msg - + assert ((out.shape == (1, npts) or out.shape == (npts,)) + and type(out) is np.ndarray), err_msg + if out.shape == (npts,): + def wrapped(ff, *args, **kwargs): + return np.reshape(ff(*args, **kwargs), (1,npts)) + loc_ff = wrapped(ff, *args, **kwargs) + return loc_ff is_ani = ('vect' in kw) if ani is None else ani if is_ani: err_msg = (str_error @@ -5831,14 +5836,20 @@ def check_ff(self, ff, t=None, ani=None): + " np.ndarray when Pts is (3,N), vect is provided" + " and t is a list (nt,)") assert (type(out) is np.ndarray - and out.shape==(time_steps, npts)), err_msg + and out.shape == (time_steps, npts)), err_msg else: err_msg = (str_error + "If ani=True, ff must return a (1, npts)" + " np.ndarray when Pts is (3, npts), vect is" + " provided and t is None or a scalar") - assert type(out) is np.ndarray and out.shape==(1, npts), err_msg - return + assert (type(out) is np.ndarray + and (out.shape == (1, npts) + or out.shape == (npts,))), err_msg + if out.shape == (npts,): + def wrapped(*args, **kwargs): + return np.reshape(ff(*args, **kwargs), (1,npts)) + return wrapped(ff) + return ff def _calc_signal_preformat(self, ind=None, DL=None, t=None, out=object, Brightness=True): @@ -6046,7 +6057,7 @@ def calc_signal( # Launch # NB : find a way to exclude cases with DL[0,:]>=DL[1,:] !! # Exclude Rays not seeing the plasma if newcalc: - self.check_ff(func, t=t, ani=ani) + func = self.check_ff(func, t=t, ani=ani) s = _GG.LOS_calc_signal( func, Ds, From 136c54ce76b0e5e0306a90a53ad9932013879b9b Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Mon, 18 Nov 2019 10:07:44 +0100 Subject: [PATCH 05/18] [Issue252] PEP8 Compliance --- tofu/geom/_core.py | 26 +++++++++++++------------- tofu/version.py | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 487c9d149..a5f2a301f 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5763,20 +5763,20 @@ def calc_min_rho_from_Plasma2D(self, plasma, t=None, log='min', def get_inspector(self, ff): out = inspect.signature(ff) pars = out.parameters.values() - na = np.sum([(pp.kind==pp.POSITIONAL_OR_KEYWORD + na = np.sum([(pp.kind == pp.POSITIONAL_OR_KEYWORD and pp.default is pp.empty) for pp in pars]) - kw = [pp.name for pp in pars if (pp.kind==pp.POSITIONAL_OR_KEYWORD + kw = [pp.name for pp in pars if (pp.kind == pp.POSITIONAL_OR_KEYWORD and pp.default is not pp.empty)] return na, kw def check_ff(self, ff, t=None, ani=None): time_steps = -1 - # .. Checking basic definition of function ............................. + # .. Checking basic definition of function .......................... str_error = "Input emissivity function (ff): " assert hasattr(ff, '__call__'), (str_error + " must be a callable (function)!") npos_args, kw = self.get_inspector(ff) - assert npos_args==1, (str_error + assert npos_args == 1, (str_error + " must take only one positional argument:" + " ff(Pts)!") assert 't' in kw, (str_error @@ -5786,7 +5786,7 @@ def check_ff(self, ff, t=None, ani=None): assert t is None or is_t_type_valid, (str_error + "Arg t must be None," + " a scalar or an iterable!") - # .. Testing outputs ................................................... + # .. Testing outputs ............................................... test_pts = np.array([[1, 2], [3, 4], [5, 6]]) npts = test_pts.shape[1] try: @@ -5802,12 +5802,12 @@ def check_ff(self, ff, t=None, ani=None): + " t a len()=nt iterable," + " must return a (nt, npts) np.ndarray!") assert (type(out) is np.ndarray - and out.shape==(time_steps, npts)), err_msg + and out.shape == (time_steps, npts)), err_msg else: err_msg = (str_error + " When t=None or t is a scalar," + " ff must return a 2D (1, npts) np.ndarray!") - assert type(out) is np.ndarray and out.shape==(1, npts), err_msg + assert type(out) is np.ndarray and out.shape == (1, npts), err_msg is_ani = ('vect' in kw) if ani is None else ani if is_ani: @@ -5831,13 +5831,13 @@ def check_ff(self, ff, t=None, ani=None): + " np.ndarray when Pts is (3,N), vect is provided" + " and t is a list (nt,)") assert (type(out) is np.ndarray - and out.shape==(time_steps, npts)), err_msg + and out.shape == (time_steps, npts)), err_msg else: - err_msg = (str_error - + "If ani=True, ff must return a (1, npts)" - + " np.ndarray when Pts is (3, npts), vect is" - + " provided and t is None or a scalar") - assert type(out) is np.ndarray and out.shape==(1, npts), err_msg + msg = (str_error + + "If ani=True, ff must return a (1, npts)" + + " np.ndarray when Pts is (3, npts), vect is" + + " provided and t is None or a scalar") + assert type(out) is np.ndarray and out.shape == (1, npts), msg return def _calc_signal_preformat(self, ind=None, DL=None, t=None, diff --git a/tofu/version.py b/tofu/version.py index 1fc557b2f..f30369d36 100644 --- a/tofu/version.py +++ b/tofu/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '1.4.1-217-g754c8bb' +__version__ = '1.4.1-233-gae69153' From d272f2f245d2a14d5eaf6c7e787a673e088d7ac6 Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Mon, 18 Nov 2019 10:58:17 +0100 Subject: [PATCH 06/18] [Issue252] All assert if check_ff() replaced by if / raise statements --- tofu/geom/_core.py | 121 +++++++++++++++++++++++++++------------------ tofu/version.py | 2 +- 2 files changed, 73 insertions(+), 50 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index a5f2a301f..a33e31ff1 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5771,73 +5771,96 @@ def get_inspector(self, ff): def check_ff(self, ff, t=None, ani=None): time_steps = -1 + # .. Checking basic definition of function .......................... - str_error = "Input emissivity function (ff): " - assert hasattr(ff, '__call__'), (str_error - + " must be a callable (function)!") + str_err = "Input emissivity function (ff):\n\t" + if not hasattr(ff, '__call__'): + msg = str_err + "must be a callable (function)!" + raise Exception(msg) + npos_args, kw = self.get_inspector(ff) - assert npos_args == 1, (str_error - + " must take only one positional argument:" - + " ff(Pts)!") - assert 't' in kw, (str_error - + " must have kwarg 't=None' for time vector!") - is_t_type_valid = (type(t) in [int, float, np.int64, np.float64] - or hasattr(t, '__iter__')) - assert t is None or is_t_type_valid, (str_error - + "Arg t must be None," - + " a scalar or an iterable!") + if npos_args != 1: + msg = str_err + "must take only one positional argument: ff(pts)!" + raise Exception(msg) + + if 't' not in kw: + msg = str_err + "must have kwarg 't=None' for time vector!" + raise Exception(msg) + + # .. Checking time vector ......................................... + ltypeok = [int, float, np.int64, np.float64] + is_t_type_valid = (type(t) in ltypeok or hasattr(t, '__iter__')) + if not (t is None or is_t_type_valid): + msg = (str_error + "Arg t must be either:\n" + + "\t\t- None\n" + + "\t\ŧ- a scalar (type in {})\n".format(str(ltypeok)) + + "\t\t- an iterable (1d np.ndarray)\n" + + "\tProvided type(t) = {}".format(type(t))) + raise Exception(msg) + # .. Testing outputs ............................................... test_pts = np.array([[1, 2], [3, 4], [5, 6]]) npts = test_pts.shape[1] try: out = ff(test_pts, t=t) except Exception: - assert False, (str_error - + " must take one positional arg:" - + " a (3, npts) np.ndarray") + msg = (str_err + + "must take a (3, npts) np.ndarray as positional arg") + raise Exception(msg) + if hasattr(t, '__iter__'): - time_steps = len(t) - err_msg = (str_error - + " ff(Pts, t=t), where Pts is a (3, npts) np.array and" - + " t a len()=nt iterable," - + " must return a (nt, npts) np.ndarray!") - assert (type(out) is np.ndarray - and out.shape == (time_steps, npts)), err_msg + nt = len(t) + if not (isinstance(out, np.ndarray) and out.shape == (nt, npts)): + msg = (str_err + + "ff(pts, t=t), where pts is a (3, npts) np.array and" + + "t a len() = nt iterable, " + + "must return a (nt, npts) np.ndarray!") + raise Exception(msg) else: - err_msg = (str_error - + " When t=None or t is a scalar," - + " ff must return a 2D (1, npts) np.ndarray!") - assert type(out) is np.ndarray and out.shape == (1, npts), err_msg + if not (isinstance(out, np.ndarray) and out.shape == (1, npts)): + msg = (str_err + + "ff(pts, t=t), where pts is a (3, npts) np.array and" + + "t is None or a scalar, " + + "must return a (1, npts) np.ndarray!") + raise Exception(msg) + # .. Test anisotropic case ....................................... is_ani = ('vect' in kw) if ani is None else ani if is_ani: - err_msg = (str_error - + " If ani=True, ff must take a keyword argument:" - + " 'vect=None'!") - assert 'vect' in kw, err_msg + if vect not in kw: + msg = (str_error + + "If ani=True, ff must take a keyword argument:" + + "'vect=None'!") + vect = np.ones(test_pts.shape) try: out = ff(test_pts, vect=vect, t=t) - except Exception: - err_msg = (str_error - + " If ani=True, ff must handle multiple" - + " points Pts (3, npts) with " - + "multiple vectors (vect as a" - + " (3, npts) np.ndarray)") - assert False, err_msg + except Exception:i + msg = (str_error + + "If ani=True, ff must handle both:\n" + + "\t\t- multiple points pts (3, npts) np.darray\n" + + "\t\t- multiple vectors(vect (3, npts) np.ndarray)\n" + + "\t vect is the photon emission direction from pts") + raise Exception(msg) + if hasattr(t, '__iter__'): - err_msg = (str_error - + " If ani=True, ff must return a (nt, npts)" - + " np.ndarray when Pts is (3,N), vect is provided" - + " and t is a list (nt,)") - assert (type(out) is np.ndarray - and out.shape == (time_steps, npts)), err_msg + if not (isinstance(out, np.ndarray) + and out.shape == (nt, npts)): + msg = (str_error + + "ff(pts, vect=vect, t=t), where " + + "pts and vect are both (3, npts) np.ndarrays " + + "and t is an iterable of len() = nt, must return " + + "a (nt, npts) np.ndarray" + raise Exception(msg) else: - msg = (str_error - + "If ani=True, ff must return a (1, npts)" - + " np.ndarray when Pts is (3, npts), vect is" - + " provided and t is None or a scalar") - assert type(out) is np.ndarray and out.shape == (1, npts), msg + if not (isinstance(out, np.ndarray) + and out.shape == (nt, npts)): + msg = (str_error + + "ff(pts, vect=vect, t=t), where " + + "pts and vect are both (3, npts) np.ndarrays " + + "and t is iNone or a scalar must return " + + "a (1, npts) np.ndarray" + raise Exception(msg) return def _calc_signal_preformat(self, ind=None, DL=None, t=None, diff --git a/tofu/version.py b/tofu/version.py index f30369d36..eebff2ef2 100644 --- a/tofu/version.py +++ b/tofu/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '1.4.1-233-gae69153' +__version__ = '1.4.1-234-g136c54c' From fb4b530880356b6056615bd6d36ee67bdcc30527 Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Mon, 18 Nov 2019 12:25:53 +0100 Subject: [PATCH 07/18] [Issue252] Unique full error msg in check_ff(), complemented by error-specific line --- tofu/geom/_core.py | 104 +++++++++++++++++---------------------------- tofu/version.py | 2 +- 2 files changed, 40 insertions(+), 66 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index a33e31ff1..1ee7a3b27 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5770,98 +5770,72 @@ def get_inspector(self, ff): return na, kw def check_ff(self, ff, t=None, ani=None): - time_steps = -1 + + # Define unique error message giving all info in a concise way + # Optionnally add error-specific line afterwards + msg = ("User-defined ieemissivity function ff must:\n" + + "\t- be a callable (function)\n" + + "\t- take only one positional arg" + + "and at least one keyword arg:\n" + + "\t\t - ff(pts, t=None), where:\n" + + "\t\t\t - pts is a (3, npts) of (x, y, z) coordinates\n" + + "\t\t\t - t can be None / scalar / iterable of len(t) = nt\n" + + "\t- Always return a 2d (nt, npts) np.ndarray, where:\n" + + "\t\t - nt = len(t) or nt = 1 if t is None or scalar\n" + + "\t\t - npts is the number of pts (shape[1])\n\n" + + "\t- Optionally, ff can take an extra keyword arg:\n" + + "\t\t - ff(pts, vect=None, t=None), where:\n" + + "\t\t\t - vect is a (3, npts) of the (x, y, z) coordinates" + + "of the units vectors of the direction of emission" + + "of photons for each pts. Used for anisotropic emissivity.\n" + + "\t\t\tDoes not affect the outpout shape (still (nt, npts))") # .. Checking basic definition of function .......................... - str_err = "Input emissivity function (ff):\n\t" if not hasattr(ff, '__call__'): - msg = str_err + "must be a callable (function)!" + msg += "\n\n => ff must be a callable (function)!" raise Exception(msg) npos_args, kw = self.get_inspector(ff) if npos_args != 1: - msg = str_err + "must take only one positional argument: ff(pts)!" + msg += "\n\n => ff must take only one positional argument: ff(pts)!" raise Exception(msg) if 't' not in kw: - msg = str_err + "must have kwarg 't=None' for time vector!" + msg += "\n\n => ff must have kwarg 't=None' for time vector!" raise Exception(msg) # .. Checking time vector ......................................... ltypeok = [int, float, np.int64, np.float64] is_t_type_valid = (type(t) in ltypeok or hasattr(t, '__iter__')) if not (t is None or is_t_type_valid): - msg = (str_error + "Arg t must be either:\n" - + "\t\t- None\n" - + "\t\ŧ- a scalar (type in {})\n".format(str(ltypeok)) - + "\t\t- an iterable (1d np.ndarray)\n" - + "\tProvided type(t) = {}".format(type(t))) + msg += "\n\n => t must be None, scalar or iterable !" raise Exception(msg) + nt = len(t) if hasattr(t, '__iter__') else 1 + + # .. Test anisotropic case ....................................... + is_ani = ('vect' in kw) if ani is None else ani # .. Testing outputs ............................................... test_pts = np.array([[1, 2], [3, 4], [5, 6]]) npts = test_pts.shape[1] - try: - out = ff(test_pts, t=t) - except Exception: - msg = (str_err - + "must take a (3, npts) np.ndarray as positional arg") - raise Exception(msg) - - if hasattr(t, '__iter__'): - nt = len(t) - if not (isinstance(out, np.ndarray) and out.shape == (nt, npts)): - msg = (str_err - + "ff(pts, t=t), where pts is a (3, npts) np.array and" - + "t a len() = nt iterable, " - + "must return a (nt, npts) np.ndarray!") - raise Exception(msg) - else: - if not (isinstance(out, np.ndarray) and out.shape == (1, npts)): - msg = (str_err - + "ff(pts, t=t), where pts is a (3, npts) np.array and" - + "t is None or a scalar, " - + "must return a (1, npts) np.ndarray!") - raise Exception(msg) - - # .. Test anisotropic case ....................................... - is_ani = ('vect' in kw) if ani is None else ani if is_ani: - if vect not in kw: - msg = (str_error - + "If ani=True, ff must take a keyword argument:" - + "'vect=None'!") - vect = np.ones(test_pts.shape) try: out = ff(test_pts, vect=vect, t=t) - except Exception:i - msg = (str_error - + "If ani=True, ff must handle both:\n" - + "\t\t- multiple points pts (3, npts) np.darray\n" - + "\t\t- multiple vectors(vect (3, npts) np.ndarray)\n" - + "\t vect is the photon emission direction from pts") + except Exception: + msg += "\n\n => ff must take ff(pts, vect=vect, t=t) !" + raise Exception(msg) + else: + try: + out = ff(test_pts, t=t) + except Exception: + msg += "\n\n => ff must take a ff(pts, t=t) !" raise Exception(msg) - if hasattr(t, '__iter__'): - if not (isinstance(out, np.ndarray) - and out.shape == (nt, npts)): - msg = (str_error - + "ff(pts, vect=vect, t=t), where " - + "pts and vect are both (3, npts) np.ndarrays " - + "and t is an iterable of len() = nt, must return " - + "a (nt, npts) np.ndarray" - raise Exception(msg) - else: - if not (isinstance(out, np.ndarray) - and out.shape == (nt, npts)): - msg = (str_error - + "ff(pts, vect=vect, t=t), where " - + "pts and vect are both (3, npts) np.ndarrays " - + "and t is iNone or a scalar must return " - + "a (1, npts) np.ndarray" - raise Exception(msg) - return + if not (isinstance(out, np.ndarray) and out.shape == (nt, npts)): + msg += "\n\n => wrong output (always 2d np.ndarray) !" + raise Exception(msg) + return is_ani def _calc_signal_preformat(self, ind=None, DL=None, t=None, out=object, Brightness=True): diff --git a/tofu/version.py b/tofu/version.py index eebff2ef2..2672576d0 100644 --- a/tofu/version.py +++ b/tofu/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '1.4.1-234-g136c54c' +__version__ = '1.4.1-235-gd272f2f' From 1f4978166c59d2dadee0a8626cfea45ec755f9dd Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Mon, 18 Nov 2019 12:50:50 +0100 Subject: [PATCH 08/18] [Issue252] PEP8 Compliance and more robust check on ani in check_ff() --- tofu/geom/_core.py | 28 +++++++++++++++++----------- tofu/version.py | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index e47274996..03f76e79c 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5773,21 +5773,23 @@ def check_ff(self, ff, t=None, ani=None): # Define unique error message giving all info in a concise way # Optionnally add error-specific line afterwards - msg = ("User-defined ieemissivity function ff must:\n" + msg = ("User-defined emissivity function ff must:\n" + "\t- be a callable (function)\n" - + "\t- take only one positional arg" + + "\t- take only one positional arg " + "and at least one keyword arg:\n" + "\t\t - ff(pts, t=None), where:\n" + "\t\t\t - pts is a (3, npts) of (x, y, z) coordinates\n" + "\t\t\t - t can be None / scalar / iterable of len(t) = nt\n" + "\t- Always return a 2d (nt, npts) np.ndarray, where:\n" - + "\t\t - nt = len(t) or nt = 1 if t is None or scalar\n" - + "\t\t - npts is the number of pts (shape[1])\n\n" + + "\t\t - nt = len(t) if t is an iterable\n" + + "\t\t - nt = 1 if t is None or scalar\n" + + "\t\t - npts is the number of pts (pts.shape[1])\n\n" + "\t- Optionally, ff can take an extra keyword arg:\n" + "\t\t - ff(pts, vect=None, t=None), where:\n" - + "\t\t\t - vect is a (3, npts) of the (x, y, z) coordinates" - + "of the units vectors of the direction of emission" - + "of photons for each pts. Used for anisotropic emissivity.\n" + + "\t\t\t - vect is a (3, npts) np.ndarray\n" + + "\t\t\t - vect contains the (x, y, z) coordinates " + + "of the units vectors of the photon emission directions" + + "for each pts. Used for anisotropic emissivity.\n" + "\t\t\tDoes not affect the outpout shape (still (nt, npts))") # .. Checking basic definition of function .......................... @@ -5797,7 +5799,7 @@ def check_ff(self, ff, t=None, ani=None): npos_args, kw = self.get_inspector(ff) if npos_args != 1: - msg += "\n\n => ff must take only one positional argument: ff(pts)!" + msg += "\n\n => ff must take only 1 positional arg: ff(pts)!" raise Exception(msg) if 't' not in kw: @@ -5813,7 +5815,11 @@ def check_ff(self, ff, t=None, ani=None): nt = len(t) if hasattr(t, '__iter__') else 1 # .. Test anisotropic case ....................................... - is_ani = ('vect' in kw) if ani is None else ani + if ani is None: + is_ani = ('vect' in kw) + else: + assert isinstance(ani, bool) + is_ani = ani # .. Testing outputs ............................................... test_pts = np.array([[1, 2], [3, 4], [5, 6]]) @@ -5963,7 +5969,7 @@ def calc_signal( self, func, t=None, - ani=False, + ani=None, fkwdargs={}, Brightness=True, res=None, @@ -6043,7 +6049,7 @@ def calc_signal( # Launch # NB : find a way to exclude cases with DL[0,:]>=DL[1,:] !! # Exclude Rays not seeing the plasma if newcalc: - self.check_ff(func, t=t, ani=ani) + ani = self.check_ff(func, t=t, ani=ani) s = _GG.LOS_calc_signal( func, Ds, diff --git a/tofu/version.py b/tofu/version.py index 90100a844..6c0d5bf20 100644 --- a/tofu/version.py +++ b/tofu/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '1.4.1-236-gfb4b530' +__version__ = '1.4.1-263-ga19ccfe' From 3cf115dc749b58cfbfb13b268256b9a01d37b6c9 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Mon, 18 Nov 2019 14:44:00 +0100 Subject: [PATCH 09/18] [#252] right definition of wrapped function --- tofu/geom/_core.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 874c0b8fc..756aa0a6b 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5771,6 +5771,7 @@ def get_inspector(self, ff): def check_ff(self, ff, t=None, ani=None): time_steps = -1 + wrapped_ff = ff # .. Checking basic definition of function ............................ str_error = "Input emissivity function (ff): " assert hasattr(ff, '__call__'), (str_error @@ -5810,10 +5811,10 @@ def check_ff(self, ff, t=None, ani=None): assert ((out.shape == (1, npts) or out.shape == (npts,)) and type(out) is np.ndarray), err_msg if out.shape == (npts,): - def wrapped(ff, *args, **kwargs): - return np.reshape(ff(*args, **kwargs), (1,npts)) - loc_ff = wrapped(ff, *args, **kwargs) - return loc_ff + def wrapped_ff(*args, **kwargs): + res_ff = ff(*args, **kwargs) + npts_loc = res_ff.size + return np.reshape(res_ff, (1, npts_loc)) is_ani = ('vect' in kw) if ani is None else ani if is_ani: err_msg = (str_error @@ -5846,10 +5847,11 @@ def wrapped(ff, *args, **kwargs): and (out.shape == (1, npts) or out.shape == (npts,))), err_msg if out.shape == (npts,): - def wrapped(*args, **kwargs): - return np.reshape(ff(*args, **kwargs), (1,npts)) - return wrapped(ff) - return ff + def wrapped_ff(*args, **kwargs): + res_ff = ff(*args, **kwargs) + npts_loc = res_ff.size + return np.reshape(res_ff, (1, npts_loc)) + return wrapped_ff def _calc_signal_preformat(self, ind=None, DL=None, t=None, out=object, Brightness=True): From cf892fedcce860d34729eebb09f007520e451c23 Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Mon, 18 Nov 2019 15:22:11 +0100 Subject: [PATCH 10/18] [Issue252] Solved remaining issue with Rays.calc_signal(plot=True): squeeze if necessary (but only if necessary) --- tofu/tests/tests09_tutorials/tests01_runall.py | 11 +++++++++-- tofu/utils.py | 3 ++- tofu/version.py | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tofu/tests/tests09_tutorials/tests01_runall.py b/tofu/tests/tests09_tutorials/tests01_runall.py index 969554fa6..c47de7fdd 100644 --- a/tofu/tests/tests09_tutorials/tests01_runall.py +++ b/tofu/tests/tests09_tutorials/tests01_runall.py @@ -148,13 +148,20 @@ def _test_tuto(cls, tuto=None, pathtuto=_HERE, root=_TFROOT): src = os.path.join(pathtuto, tuto + '.py') target = os.path.join(root, tuto + '.py') shutil.copyfile(src, target) + error = None try: cmd = 'python ' + target - out = subprocess.run(cmd, shell=True, check=True, + out = subprocess.run(cmd, shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if 'error' in out.stderr.decode().lower(): + error = out.stderr.decode() except Exception as err: - raise err + error = err + + if error is not None: + msg = str(error) + raise Exception(msg) plt.close('all') # Remove temporary files and saved files diff --git a/tofu/utils.py b/tofu/utils.py index f727a83ca..475b6a338 100644 --- a/tofu/utils.py +++ b/tofu/utils.py @@ -2484,7 +2484,8 @@ def func(li, val=val, n1=n1, n2=n2): else: assert type(val) is np.ndarray - # val = np.atleast_1d(val.squeeze()) + if val.ndim > len(lrids) and val.ndim > ninds: + val = np.atleast_1d(np.squeeze(val)) ndim = val.ndim c0 = ndim >= len(lrids) and len(lrids) >= ninds and ndim >= ninds if not c0: diff --git a/tofu/version.py b/tofu/version.py index 6c0d5bf20..31088c3e2 100644 --- a/tofu/version.py +++ b/tofu/version.py @@ -1,2 +1,2 @@ # Do not edit, pipeline versioning governed by git tags! -__version__ = '1.4.1-263-ga19ccfe' +__version__ = '1.4.1-264-g1f49781' From 677d6496883ef1df263a9f04cc7e04ee0f0b3209 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Mon, 18 Nov 2019 16:12:52 +0100 Subject: [PATCH 11/18] [bisect 252] undid changes in tuto --- examples/tutorials/tuto_plot_custom_emissivity.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/tutorials/tuto_plot_custom_emissivity.py b/examples/tutorials/tuto_plot_custom_emissivity.py index 710f82080..2b63672da 100644 --- a/examples/tutorials/tuto_plot_custom_emissivity.py +++ b/examples/tutorials/tuto_plot_custom_emissivity.py @@ -31,6 +31,7 @@ # Now, we define an emissivity function that depends on r and z coordinates. # We can plot its profile in the (0, X, Z) plane. + def emissivity(pts, t=None, vect=None): """Custom emissivity as a function of geometry. @@ -51,11 +52,6 @@ def emissivity(pts, t=None, vect=None): e = np.reshape(e, (1, -1)) return e -def ff(Pts, t=None): - print("pts =", Pts) - print("t=", t) - print("--------") - return np.zeros(Pts.shape[1])+1 y = np.linspace(2, 3, num=90) z = np.linspace(-0.5, 0.5, num=100) @@ -86,7 +82,7 @@ def project_to_2D(xyz): time_vector = np.linspace(0, 2 * np.pi, num=100) -sig, units = cam2d.calc_signal(ff, +sig, units = cam2d.calc_signal(emissivity, res=0.01, reflections=False, minimize="hybrid", From 67fdeeec76a121ee89b50df7dfce9fcac7822801 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Mon, 18 Nov 2019 16:53:00 +0100 Subject: [PATCH 12/18] [feature] cleaner way of defining 2nd dim --- tofu/geom/_core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index a763c25d3..13357a8c9 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5848,8 +5848,7 @@ def check_ff(self, ff, t=None, ani=None): if nt == 1 and out.shape == (npts,): def wrapped_ff(*args, **kwargs): res_ff = ff(*args, **kwargs) - npts_loc = res_ff.size - return np.reshape(res_ff, (1, npts_loc)) + return np.reshape(res_ff, (1, -1)) return is_ani, wrapped_ff From 11ab20c2830996144994cd01cbc519958ebfd697 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Mon, 18 Nov 2019 18:06:06 +0100 Subject: [PATCH 13/18] [bug fix #255] found bug --- tofu/geom/_GG.pyx | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tofu/geom/_GG.pyx b/tofu/geom/_GG.pyx index b2c54e936..4ffa3a155 100644 --- a/tofu/geom/_GG.pyx +++ b/tofu/geom/_GG.pyx @@ -2860,7 +2860,6 @@ def LOS_calc_signal(func, double[:,::1] ray_orig, double[:,::1] ray_vdir, res, cdef double[1] loc_eff_res cdef double[::1] reseff_mv cdef double[::1] res_mv - cdef double[::1,:] sig_mv cdef double[:,::1] val_mv cdef double[:,::1] pts_mv cdef double[:,::1] usbis_mv @@ -2928,7 +2927,6 @@ def LOS_calc_signal(func, double[:,::1] ray_orig, double[:,::1] ray_vdir, res, n_imode = _st.get_nb_imode(imode) # Initialization result sig = np.empty((nt, nlos), dtype=float, order='F') - sig_mv = sig # If the resolution is the same for every LOS, we create a tab if res_is_list : res_arr = np.asarray(res) @@ -3025,11 +3023,12 @@ def LOS_calc_signal(func, double[:,::1] ray_orig, double[:,::1] ray_vdir, res, pts, usbis = _st.call_get_sample_single_ani(lims[0, ii], lims[1, ii], res_mv[ii], - n_dmode, n_imode, + n_dmode, + n_imode, &loc_eff_res[0], &nb_rows[0], - ray_orig[:,ii:ii+1], - ray_vdir[:,ii:ii+1]) + ray_orig[:, ii:ii+1], + ray_vdir[:, ii:ii+1]) # loop over time for calling and integrating for jj in range(nt): val = func(pts, t=ltime[jj], vect=-usbis, **fkwdargs) @@ -3129,7 +3128,7 @@ def LOS_calc_signal(func, double[:,::1] ray_orig, double[:,::1] ray_vdir, res, ray_orig[:, ii:ii+1], ray_vdir[:, ii:ii+1]) val_2d = func(pts, t=t, vect=-usbis, **fkwdargs) - sig_mv[:, ii] = np.sum(val_2d, axis=-1)*loc_eff_res[0] + sig[:, ii] = np.sum(val_2d, axis=-1)*loc_eff_res[0] elif n_imode == 1: # simpson integration mode for ii in range(nlos): pts, usbis = _st.call_get_sample_single_ani(lims[0, ii], @@ -3162,39 +3161,42 @@ def LOS_calc_signal(func, double[:,::1] ray_orig, double[:,::1] ray_vdir, res, # -- not anisotropic ----------------------------------------------- if n_imode == 0: # "sum" integration mode for ii in range(nlos): - pts = _st.call_get_sample_single(lims[0,ii], lims[1,ii], + pts = _st.call_get_sample_single(lims[0, ii], + lims[1, ii], res_mv[ii], n_dmode, n_imode, &loc_eff_res[0], &nb_rows[0], - ray_orig[:,ii:ii+1], - ray_vdir[:,ii:ii+1]) + ray_orig[:, ii:ii+1], + ray_vdir[:, ii:ii+1]) val_2d = func(pts, t=t, **fkwdargs) - sig[:, ii] = np.sum(val_2d,axis=-1)*loc_eff_res[0] + sig[:, ii] = np.sum(val_2d, axis=-1)*loc_eff_res[0] elif n_imode == 1: # "simpson" integration mode for ii in range(nlos): - pts = _st.call_get_sample_single(lims[0,ii], lims[1,ii], + pts = _st.call_get_sample_single(lims[0, ii], + lims[1, ii], res_mv[ii], n_dmode, n_imode, &loc_eff_res[0], &nb_rows[0], - ray_orig[:,ii:ii+1], - ray_vdir[:,ii:ii+1]) + ray_orig[:, ii:ii+1], + ray_vdir[:, ii:ii+1]) val = func(pts, t=t, **fkwdargs) sig[:, ii] = scpintg.simps(val, x=None, axis=-1, dx=loc_eff_res[0]) elif n_imode == 2: # "romberg" integration mode for ii in range(nlos): - pts = _st.call_get_sample_single(lims[0,ii], lims[1,ii], + pts = _st.call_get_sample_single(lims[0, ii], + lims[1, ii], res_mv[ii], n_dmode, n_imode, &loc_eff_res[0], &nb_rows[0], - ray_orig[:,ii:ii+1], - ray_vdir[:,ii:ii+1]) + ray_orig[:, ii:ii+1], + ray_vdir[:, ii:ii+1]) val = func(pts, t=t, **fkwdargs) sig[:, ii] = scpintg.romb(val, show=False, axis=1, - dx=loc_eff_res[0]) + dx=loc_eff_res[0]) return sig From a667bec973a1d1a343c3dabdf5482ce67f974b20 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Tue, 19 Nov 2019 10:14:32 +0100 Subject: [PATCH 14/18] [bf #255] added doc for ani/vect definition --- .../tutorials/tuto_plot_custom_emissivity.py | 5 +++- tofu/geom/_core.py | 24 ++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/examples/tutorials/tuto_plot_custom_emissivity.py b/examples/tutorials/tuto_plot_custom_emissivity.py index dc8676037..9d05cdb2c 100644 --- a/examples/tutorials/tuto_plot_custom_emissivity.py +++ b/examples/tutorials/tuto_plot_custom_emissivity.py @@ -31,13 +31,15 @@ # Now, we define an emissivity function that depends on r and z coordinates. # We can plot its profile in the (0, X, Z) plane. + def emissivity(pts, t=None, vect=None): """Custom emissivity as a function of geometry. :param pts: ndarray of shape (3, n_points) (each column is a xyz coordinate) :param t: optional, time parameter to add a time dependency to the emissivity function - :param vect: + :param vect: optional, ndarray of shape (3, n_points), if anisotropic + emissivity, unit direction vectors (X,Y,Z) :return: - emissivity -- 2D array holding the emissivity for each point in the input grid @@ -88,6 +90,7 @@ def project_to_2D(xyz): method="sum", newcalc=True, plot=False, + ani=False, t=time_vector) sig.plot(ntMax=1) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 03f76e79c..931baf7d9 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5769,7 +5769,7 @@ def get_inspector(self, ff): and pp.default is not pp.empty)] return na, kw - def check_ff(self, ff, t=None, ani=None): + def check_ff(self, ff, t=None, ani=False): # Define unique error message giving all info in a concise way # Optionnally add error-specific line afterwards @@ -5789,7 +5789,9 @@ def check_ff(self, ff, t=None, ani=None): + "\t\t\t - vect is a (3, npts) np.ndarray\n" + "\t\t\t - vect contains the (x, y, z) coordinates " + "of the units vectors of the photon emission directions" - + "for each pts. Used for anisotropic emissivity.\n" + + "for each pts. Present only for anisotropic emissivity, " + + "unless specifically indicated otherwise " + + "(with ani=False in LOS_calc_signal).\n" + "\t\t\tDoes not affect the outpout shape (still (nt, npts))") # .. Checking basic definition of function .......................... @@ -5815,7 +5817,7 @@ def check_ff(self, ff, t=None, ani=None): nt = len(t) if hasattr(t, '__iter__') else 1 # .. Test anisotropic case ....................................... - if ani is None: + if ani is False: is_ani = ('vect' in kw) else: assert isinstance(ani, bool) @@ -5969,7 +5971,7 @@ def calc_signal( self, func, t=None, - ani=None, + ani=False, fkwdargs={}, Brightness=True, res=None, @@ -6005,11 +6007,6 @@ def calc_signal( => the method returns W/m2 (resp. W/m2/sr) The line is sampled using :meth:`~tofu.geom.LOS.get_sample`, - The integral can be computed using three different methods: - - 'sum': A numpy.sum() on the local values (x segments lengths) - - 'simps': using :meth:`scipy.integrate.simps` - - 'romb': using :meth:`scipy.integrate.romb` - Except func, arguments common to :meth:`~tofu.geom.LOS.get_sample` Parameters @@ -6024,6 +6021,15 @@ def calc_signal( - vect: None / (3,N) np.ndarray, unit direction vectors (X,Y,Z) Should return at least: - val : (N,) np.ndarray, local emissivity values + method : string, the integral can be computed using 3 different methods: + - 'sum': A numpy.sum() on the local values (x segments) DEFAULT + - 'simps': using :meth:`scipy.integrate.simps` + - 'romb': using :meth:`scipy.integrate.romb` + minimize : string, method to minimize for computation optimization + - "calls": minimal number of calls to `func` (default) + - "memory": slowest method, to use only if "out of memory" error + - "hybrid": mix of before mentioned method. + Returns ------- From fcc95f0da9074d7d1bb94c452e422b8fc0772926 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Tue, 19 Nov 2019 10:20:57 +0100 Subject: [PATCH 15/18] [pep8] changes for flake --- tofu/geom/_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 931baf7d9..f995c434f 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -6021,7 +6021,7 @@ def calc_signal( - vect: None / (3,N) np.ndarray, unit direction vectors (X,Y,Z) Should return at least: - val : (N,) np.ndarray, local emissivity values - method : string, the integral can be computed using 3 different methods: + method : string, the integral can be computed using 3 different methods - 'sum': A numpy.sum() on the local values (x segments) DEFAULT - 'simps': using :meth:`scipy.integrate.simps` - 'romb': using :meth:`scipy.integrate.romb` From 820e73fe7937d5f1603193f44b48b9ddd2daddfb Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Tue, 19 Nov 2019 10:22:25 +0100 Subject: [PATCH 16/18] [doc] typo corrections --- tofu/geom/_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index f995c434f..7a93bf6e4 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -6028,7 +6028,7 @@ def calc_signal( minimize : string, method to minimize for computation optimization - "calls": minimal number of calls to `func` (default) - "memory": slowest method, to use only if "out of memory" error - - "hybrid": mix of before mentioned method. + - "hybrid": mix of before-mentioned methods. Returns From 6b2afd45cbd4639552650cd8bcdbeed806d71478 Mon Sep 17 00:00:00 2001 From: Laura Mendoza Date: Tue, 19 Nov 2019 11:18:03 +0100 Subject: [PATCH 17/18] [bf #255] ani=None by default --- tofu/geom/_core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tofu/geom/_core.py b/tofu/geom/_core.py index 7a93bf6e4..1cd9886a2 100644 --- a/tofu/geom/_core.py +++ b/tofu/geom/_core.py @@ -5769,7 +5769,7 @@ def get_inspector(self, ff): and pp.default is not pp.empty)] return na, kw - def check_ff(self, ff, t=None, ani=False): + def check_ff(self, ff, t=None, ani=None): # Define unique error message giving all info in a concise way # Optionnally add error-specific line afterwards @@ -5817,7 +5817,7 @@ def check_ff(self, ff, t=None, ani=False): nt = len(t) if hasattr(t, '__iter__') else 1 # .. Test anisotropic case ....................................... - if ani is False: + if ani is None: is_ani = ('vect' in kw) else: assert isinstance(ani, bool) @@ -5971,7 +5971,7 @@ def calc_signal( self, func, t=None, - ani=False, + ani=None, fkwdargs={}, Brightness=True, res=None, From 8ab1c43e89cdcf48a59d43c7a423fa80683b099b Mon Sep 17 00:00:00 2001 From: VEZINET Didier Date: Tue, 19 Nov 2019 18:32:58 +0100 Subject: [PATCH 18/18] [bf-#255] Fixed unit tests for tutorials --- tofu/tests/tests09_tutorials/tests01_runall.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tofu/tests/tests09_tutorials/tests01_runall.py b/tofu/tests/tests09_tutorials/tests01_runall.py index c47de7fdd..e20341724 100644 --- a/tofu/tests/tests09_tutorials/tests01_runall.py +++ b/tofu/tests/tests09_tutorials/tests01_runall.py @@ -154,8 +154,10 @@ def _test_tuto(cls, tuto=None, pathtuto=_HERE, root=_TFROOT): out = subprocess.run(cmd, shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if 'error' in out.stderr.decode().lower(): - error = out.stderr.decode() + ls = out.stderr.decode().split('\n') + if any(['Error' in ss and not 'ModuleNotFoundError' in ss + for ss in ls]): + error = '\n'.join(ls) except Exception as err: error = err