How to implement an expr parameter with min/max bounds

351 views
Skip to first unread message

Nicholas Killerby-Smith

unread,
Mar 15, 2021, 4:35:28 AM3/15/21
to lmfit-py
Hi all,

Tl;Dr: How can i set a parameter to use an expression and have min/max bounds? Alternatively how can i use the value= syntax and have the bounds adjust dynamically through minimisation?
 
I am trying to solve a multi-gaussian decomposition of a line and as such have a multitude of interdependencies i'm trying to work around. The primary one here that's relevant is that the amplitude <=21.866*width^2*(1-e**(-tau)). (where tau is a constant for a given component).

Initially i solved this by setting the amplitude and width parameters separately, each with their respective physical min/max bounds but set the width to be limited by the amplitude parameter value

ATTEMPT 1
#set amplitude param
params.add(f'a{i}', value=emission_amps[i],
#min=0,
min=min_ts*(1-np.exp(-tau[i])),
max=max_tb_value)

#set width param
params.add(
f'w{i}',
value=emission_widths[i],
min=np.max([
(abs_widths[i] - np.abs(p_width * abs_widths[i])),
(np.sqrt((params[f'a{i}'].value)/(21.866*(1-np.exp(-tau[i])))))
]),
max=abs_widths[i] + np.abs(p_width * abs_widths[i]))

This is ideally how i would write express this problem but while this sort of worked the problem was that the bounds were set based on the parameters current value prior to minimisation. During minimisation the amplitude could hit it's own max bound and the width could hit it's lower bound and then the inequality amplitude <=21.866*width^2*(1-e**(-tau)) would be violated. Ideally in my situation the params.value would not be evaluated when the min/max bounds are set but left as a variable and constantly reevaluated throughout the minimisation, then it would behave as i want i think. Using .max instead of .value was a hacky workaround but not physically accurate as it was overly restrictive then.

I rewrote a bunch of code to allow me to instead rewrite it with an expression (as outlined here: https://lmfit.github.io/lmfit-py/constraints.html#using-inequality-constraints). It currently looks like this:

ATTEMPT 2
#set amplitude param
params.add(f'a{i}', 
value=emission_amps[i],
min=min_ts*(1-np.exp(-tau[i])),
max=max_tb_value)

#set delta param
params.add(f'd{i}', 
value=0.00001, #guess that's in bounds
min=0,
max=21.866*(1-np.exp(-tau[i])),vary=True)

#set width param
params.add(f'w{i}',
expr=f'sqrt(a{i}/d{i})',
min=abs_widths[i] - np.abs(p_width * abs_widths[i]),
max=abs_widths[i] + np.abs(p_width * abs_widths[i]))

This would also do what i want but the min/max kwargs aren't supported for expr parameters as far as i can tell.

In summary i have a width parameter that has bounds defined by the current value of the amplitude during minimisation but it has other bounds that also need to be satisfied which makes expressing this parameter using expressions troublesome.

Any solutions? Happy to explain further if something was unclear.

Cheers,

Nick

Matt Newville

unread,
Mar 15, 2021, 6:03:17 PM3/15/21
to lmfit-py
Hi Nicholas,



On Mon, Mar 15, 2021 at 3:35 AM Nicholas Killerby-Smith <nickille...@gmail.com> wrote:
Hi all,

Tl;Dr: How can i set a parameter to use an expression and have min/max bounds? Alternatively how can i use the value= syntax and have the bounds adjust dynamically through minimisation?
 

Mathematical expressions are not supported for Parameter boundaries.  

I am trying to solve a multi-gaussian decomposition of a line and as such have a multitude of interdependencies i'm trying to work around. The primary one here that's relevant is that  the amplitude <=21.866*width^2*(1-e**(-tau)). (where tau is a constant for a given component).

Initially i solved this by setting the amplitude and width parameters separately, each with their respective physical min/max bounds but set the width to be limited by the amplitude parameter value

ATTEMPT 1
#set amplitude param
params.add(f'a{i}', value=emission_amps[i],
#min=0,
min=min_ts*(1-np.exp(-tau[i])),
max=max_tb_value)

#set width param
params.add(
f'w{i}',
value=emission_widths[i],
min=np.max([
(abs_widths[i] - np.abs(p_width * abs_widths[i])),
(np.sqrt((params[f'a{i}'].value)/(21.866*(1-np.exp(-tau[i])))))
]),
max=abs_widths[i] + np.abs(p_width * abs_widths[i]))

This is ideally how i would write express this problem but while this sort of worked the problem was that the bounds were set based on the parameters current value prior to minimisation.


Yes, that sets the bounds to be the current values of those expressions, not the expressions themselves.   
 
During minimisation the amplitude could hit it's own max bound and the width could hit it's lower bound and then the inequality amplitude <=21.866*width^2*(1-e**(-tau)) would be violated. Ideally in my situation the params.value would not be evaluated when the min/max bounds are set but left as a variable and constantly reevaluated throughout the minimisation, then it would behave as i want i think. Using .max instead of .value was a hacky workaround but not physically accurate as it was overly restrictive then.

 A Parameter's "min" and "max" attributes are floats that cannot be changed during the fit.

I rewrote a bunch of code to allow me to instead rewrite it with an expression (as outlined here: https://lmfit.github.io/lmfit-py/constraints.html#using-inequality-constraints). It currently looks like this:

ATTEMPT 2
#set amplitude param
params.add(f'a{i}', 
value=emission_amps[i],
min=min_ts*(1-np.exp(-tau[i])),
max=max_tb_value)

#set delta param
params.add(f'd{i}', 
value=0.00001, #guess that's in bounds
min=0,
max=21.866*(1-np.exp(-tau[i])),vary=True)

#set width param
params.add(f'w{i}',
expr=f'sqrt(a{i}/d{i})',
min=abs_widths[i] - np.abs(p_width * abs_widths[i]),
max=abs_widths[i] + np.abs(p_width * abs_widths[i]))


that is still setting the "min" and "max" attributes to have the values evaluated by those Python expressions.  I don't see an inequality constraint here.
This would also do what i want but the min/max kwargs aren't supported for expr parameters as far as i can tell.

That is not correct.  The `min` and `max` attributes are supported for parameters constrained by an expression.

In summary i have a width parameter that has bounds defined by the current value of the amplitude during minimisation but it has other bounds that also need to be satisfied which makes expressing this parameter using expressions troublesome.

Any solutions? Happy to explain further if something was unclear.


The bounds of a "width" Parameter cannot be dynamically based on the value of another Parameter.   Just to be clear, I expect it will not ever be allowed. 


I think you want to revisit the topic of "inequality constraints".   

As we say here often, it is much better if you post a minimal and complete code example that shows what you are trying to do.  You did not post a complete example, you posted incomplete code snippets.  Consequently, my response will be based on conjecture and code snippets. 

If you have a `width` parameter and a `tau` parameter:

    params = Parameters()
    params.add('width', value=0.5, min=0)
    params.add('tau', value=2, min=0)

and then want to have an `amplitude` parameter that cannot exceed "21.866*width^2*(1-e**(-tau))", then you can do something like:

   params.add('amp_delta', value=-1, max=0)
   params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))")


With that, `amp_delta` will be adjusted in the fit but remain negative.  As `amp_delta`, 'tau`, and `width` vary in the fit, the value of `amplitude` will be updated to respect the constraint.   If you want to impose bounds on the amplitude, perhaps to ensure that the amplitude is positive, you could say something like

   params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))", min=0)

The lower bound there will be applied after the evaluation of the expression. 

--Matt

Nicholas Killerby-Smith

unread,
Mar 16, 2021, 1:06:24 AM3/16/21
to lmfit-py
Hi Matt,

Thanks for the reply.

I rewrote a bunch of code to allow me to instead rewrite it with an expression (as outlined here: https://lmfit.github.io/lmfit-py/constraints.html#using-inequality-constraints). It currently looks like this:

ATTEMPT 2
#set amplitude param
params.add(f'a{i}', 
value=emission_amps[i],
min=min_ts*(1-np.exp(-tau[i])),
max=max_tb_value)

#set delta param
params.add(f'd{i}', 
value=0.00001, #guess that's in bounds
min=0,
max=21.866*(1-np.exp(-tau[i])),vary=True)

#set width param
params.add(f'w{i}',
expr=f'sqrt(a{i}/d{i})',
min=abs_widths[i] - np.abs(p_width * abs_widths[i]),
max=abs_widths[i] + np.abs(p_width * abs_widths[i]))


that is still setting the "min" and "max" attributes to have the values evaluated by those Python expressions.  I don't see an inequality constraint here.

so in this section i have used the example from the inequality constraints page to rewrite my parameters using a delta parameter as an expression for one of the two bounds i had in the ATTEMPT 1 width minimum bound (note i called np.max() and take the larger of the two values to set as the minimum bound. By pulling it out as a delta function and setting the width to be a function of delta i believe i have constrained it appropriately with that bound) however this leaves the min/max bounds from ATTEMPT 1 still to be accounted for. Fortunately these do not actually need to vary dynamically like the other bound did and can be input as floats for lmfit minimisation.
 
This would also do what i want but the min/max kwargs aren't supported for expr parameters as far as i can tell.

That is not correct.  The `min` and `max` attributes are supported for parameters constrained by an expression.

I was led to believe they weren't supported as i was getting the following error and hadn't seen any expr parameters in examples used in conjunction with min/max (maybe a bit presumptive sorry):

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-9fb35eaeab99> in <module> 10 expr=f'sqrt(a{i}/d{i})', 11 min=(abs_widths[i] - 1), ---> 12 max=(abs_widths[i] + 1))   ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 592 self.from_internal = lambda val: self.min + (sin(val) + 1) * \ 593 (self.max - self.min) / 2.0 --> 594 _val = arcsin(2*(self._val - self.min)/(self.max - self.min) - 1) 595 return _val 596 TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

which occurs in the following (minimal and complete :) ) example:

params = Parameters()

abs_widths=[1,2,3,4,5]
tau=[0.1,0.2,0.3,0.4,0.5]

for i in range(len(abs_widths)):
    params.add(f'amplitude{i}',value=8,min=5,max=20)
    params.add(f'delta{i}', value=0.00001,min=0,max=21.866*(1-np.exp(-tau[i])),vary=True)
    params.add(f'w{i}', 
            expr=f'sqrt(a{i}/d{i})',
            min=(abs_widths[i] - 1), 
            max=(abs_widths[i] + 1))

What made me assume that it wasn't supported is that the list isn't NoneType, a numpy array also doesn't work but the expression independent of Parameters() evaluates fine. So not sure what's causing this. 

The bounds of a "width" Parameter cannot be dynamically based on the value of another Parameter.   Just to be clear, I expect it will not ever be allowed. 

Fair enough, i think i worked around the need for that by expressing one of the bounds through a delta parameter and making the width an expression of delta and amplitude. But would need the min/max bounds on the expr syntax for me to be able to do what i want i think.

I think you want to revisit the topic of "inequality constraints".   

As we say here often, it is much better if you post a minimal and complete code example that shows what you are trying to do.  You did not post a complete example, you posted incomplete code snippets.  Consequently, my response will be based on conjecture and code snippets. 

Sorry i thought to give one but wasn't sure if i could appropriately simplify it but evidently just didn't think about it enough. The above code i think should simplistically represent the key parts of my question. I'm wondering if maybe i'm running a different version to you or my install is broken because this line below doesn't run for me and throws the same error as above (slightly different traceback posted below, i get the same result changing all the variables in the expression to constants too).
 
If you want to impose bounds on the amplitude, perhaps to ensure that the amplitude is positive, you could say something like

   params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))", min=0)

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-22-a21cce017c92> in <module> 1 params.add('amplitude', 2 expr="amp_delta + 21.866*width*(1-exp(-tau))", ----> 3 min=0) ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 585 elif self.max == inf: 586 self.from_internal = lambda val: self.min - 1.0 + sqrt(val*val + 1) --> 587 _val = sqrt((self._val - self.min + 1.0)**2 - 1) 588 elif self.min == -inf: 589 self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1) TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'
 
The lower bound there will be applied after the evaluation of the expression. 
so it will evaluate then if it's lower than the minimum it will cycle again and keep re-evaluating until it's above the minimum?  

Thanks!
-Nick

Matt Newville

unread,
Mar 16, 2021, 12:29:05 PM3/16/21
to lmfit-py
I don't know what led you to believe that, but it is not correct.

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-9fb35eaeab99> in <module> 10 expr=f'sqrt(a{i}/d{i})', 11 min=(abs_widths[i] - 1), ---> 12 max=(abs_widths[i] + 1))   ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 592 self.from_internal = lambda val: self.min + (sin(val) + 1) * \ 593 (self.max - self.min) / 2.0 --> 594 _val = arcsin(2*(self._val - self.min)/(self.max - self.min) - 1) 595 return _val 596 TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

which occurs in the following (minimal and complete :) ) example:

params = Parameters()

abs_widths=[1,2,3,4,5]
tau=[0.1,0.2,0.3,0.4,0.5]

for i in range(len(abs_widths)):
    params.add(f'amplitude{i}',value=8,min=5,max=20)
    params.add(f'delta{i}', value=0.00001,min=0,max=21.866*(1-np.exp(-tau[i])),vary=True)
    params.add(f'w{i}', 
            expr=f'sqrt(a{i}/d{i})',
            min=(abs_widths[i] - 1), 
            max=(abs_widths[i] + 1))


Running this code gives 
    NameError
       <_ast.Module object at 0x7fd5ccb14370>
             ^^^
    name 'a0' is not defined
which seems sensible to me.  'a0' is indeed not defined.


What made me assume that it wasn't supported is that the list isn't NoneType, a numpy array also doesn't work but the expression independent of Parameters() evaluates fine. So not sure what's causing this. 

The bounds of a "width" Parameter cannot be dynamically based on the value of another Parameter.   Just to be clear, I expect it will not ever be allowed. 

Fair enough, i think i worked around the need for that by expressing one of the bounds through a delta parameter and making the width an expression of delta and amplitude. But would need the min/max bounds on the expr syntax for me to be able to do what i want i think.

I think you want to revisit the topic of "inequality constraints".   

As we say here often, it is much better if you post a minimal and complete code example that shows what you are trying to do.  You did not post a complete example, you posted incomplete code snippets.  Consequently, my response will be based on conjecture and code snippets. 

Sorry i thought to give one but wasn't sure if i could appropriately simplify it but evidently just didn't think about it enough. The above code i think should simplistically represent the key parts of my question. I'm wondering if maybe i'm running a different version to you or my install is broken because this line below doesn't run for me and throws the same error as above (slightly different traceback posted below, i get the same result changing all the variables in the expression to constants too).
 
If you want to impose bounds on the amplitude, perhaps to ensure that the amplitude is positive, you could say something like

   params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))", min=0)

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-22-a21cce017c92> in <module> 1 params.add('amplitude', 2 expr="amp_delta + 21.866*width*(1-exp(-tau))", ----> 3 min=0) ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 585 elif self.max == inf: 586 self.from_internal = lambda val: self.min - 1.0 + sqrt(val*val + 1) --> 587 _val = sqrt((self._val - self.min + 1.0)**2 - 1) 588 elif self.min == -inf: 589 self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1) TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'
 
The lower bound there will be applied after the evaluation of the expression. 
so it will evaluate then if it's lower than the minimum it will cycle again and keep re-evaluating until it's above the minimum?  


Again, I cannot stress strongly enough how important it is to always include a complete, minimal example that shows any problem you are having.  Post the code you actually ran, and any messages you get from that code. 

Try this:

##
import numpy as np
from lmfit import Parameters


params = Parameters()

params.add('width', value=0.5, min=0)
params.add('tau', value=2, min=0)
params.add('amp_delta', value=-1, max=0)
params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))", min=0)


print("tau     width  amp_delta amplitude")
for tau_value in (1, 2, 3):
    params['tau'].value = tau_value
    for width_value in (0.2, 0.5, 1.0):
        params['width'].value = width_value
        for ampd_value in (-10, -5, -2):
            params['amp_delta'].value = ampd_value
            amp_value = params['amplitude'].value
            print("%5.1f   %5.1f   %5.1f  %7.2f" % (tau_value, width_value, ampd_value, amp_value))

###

For me, this gives:

tau     width  amp_delta amplitude
  1.0     0.2   -10.0     0.00
  1.0     0.2    -5.0     0.00
  1.0     0.2    -2.0     0.76
  1.0     0.5   -10.0     0.00
  1.0     0.5    -5.0     1.91
  1.0     0.5    -2.0     4.91
  1.0     1.0   -10.0     3.82
  1.0     1.0    -5.0     8.82
  1.0     1.0    -2.0    11.82
  2.0     0.2   -10.0     0.00
  2.0     0.2    -5.0     0.00
  2.0     0.2    -2.0     1.78
  2.0     0.5   -10.0     0.00
  2.0     0.5    -5.0     4.45
  2.0     0.5    -2.0     7.45
  2.0     1.0   -10.0     8.91
  2.0     1.0    -5.0    13.91
  2.0     1.0    -2.0    16.91
  3.0     0.2   -10.0     0.00
  3.0     0.2    -5.0     0.00
  3.0     0.2    -2.0     2.16
  3.0     0.5   -10.0     0.39
  3.0     0.5    -5.0     5.39
  3.0     0.5    -2.0     8.39
  3.0     1.0   -10.0    10.78
  3.0     1.0    -5.0    15.78
  3.0     1.0    -2.0    18.78


--Matt



  

Nicholas Killerby-Smith

unread,
Mar 16, 2021, 11:36:37 PM3/16/21
to lmfi...@googlegroups.com
Sorry about the first example i picked up on a0 not getting defined and changed it but forgot to switch out what i had pasted in my reply. I got the same error before and after the change. In a new terminal the following code:

import numpy as np
from lmfit import Parameters, minimize
params = Parameters()
abs_widths=np.array([1,2,3,4,5])
tau=[0.1,0.2,0.3,0.4,0.5]
print(type(abs_widths))
for i in range(len(abs_widths)):
    params.add(f'amplitude{i}',value=8,min=5,max=20)
    params.add(f'delta{i}'value=0.00001,min=0,max=21.866*(1-np.exp(-tau[i])),vary=True)
    
    minimum=(abs_widths[i] - 1)
    maximum=(abs_widths[i] + 1)
    print(minimum)
    params.add(f'width{i}'
            expr=f'sqrt(amplitude{i}/delta{i})',min=0)

returns:

<class 'numpy.ndarray'> 0
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-2-406ddcb4e480> in <module> 15 print(minimum) 16 params.add(f'width{i}', ---> 17 expr=f'sqrt(amplitude{i}/delta{i})',min=0) ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 585 elif self.max == inf: 586 self.from_internal = lambda val: self.min - 1.0 + sqrt(val*val + 1) --> 587 _val = sqrt((self._val - self.min + 1.0)**2 - 1) 588 elif self.min == -inf: 589 self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1) TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

similarly running the code you pasted in a new session (which i just copied and pasted but have re-copied from the cell to here just to remove all doubt):

##
import numpy as np
from lmfit import Parameters

params = Parameters()

params.add('width'value=0.5min=0)
params.add('tau'value=2min=0)
params.add('amp_delta'value=-1max=0)
params.add('amplitude'expr="amp_delta + 21.866*width*(1-exp(-tau))"min=0)


print("tau     width  amp_delta amplitude")
for tau_value in (123):
    params['tau'].value = tau_value
    for width_value in (0.20.51.0):
        params['width'].value = width_value
        for ampd_value in (-10-5-2):
            params['amp_delta'].value = ampd_value
            amp_value = params['amplitude'].value
            print("%5.1f   %5.1f   %5.1f  %7.2f" % (tau_value, width_value, ampd_value, amp_value))

###

returns:

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-7b3675d1fc9b> in <module> 8 params.add('tau', value=2, min=0) 9 params.add('amp_delta', value=-1, max=0) ---> 10 params.add('amplitude', expr="amp_delta + 21.866*width*(1-exp(-tau))", min=0) 11 12 ~/software/python/lmfit/parameter.py in add(self, name, value, vary, min, max, expr) 291 else: 292 self.__setitem__(name, Parameter(value=value, name=name, vary=vary, --> 293 min=min, max=max, expr=expr)) 294 295 def add_many(self, *parlist): ~/software/python/lmfit/parameter.py in __init__(self, name, value, vary, min, max, expr) 473 self.correl = None 474 self.from_internal = lambda val: val --> 475 self._init_bounds() 476 477 def set(self, value=None, vary=None, min=-inf, max=inf, expr=None): ~/software/python/lmfit/parameter.py in _init_bounds(self) 525 elif self._expr is None: 526 self._val = self.min --> 527 self.setup_bounds() 528 529 def __getstate__(self): ~/software/python/lmfit/parameter.py in setup_bounds(self) 585 elif self.max == inf: 586 self.from_internal = lambda val: self.min - 1.0 + sqrt(val*val + 1) --> 587 _val = sqrt((self._val - self.min + 1.0)**2 - 1) 588 elif self.min == -inf: 589 self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1) TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

This seems to be atypical given you get your output, here is the python version info:

Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.

and the lmfit version info:
0.9.5
Since this is now a few versions out of date (although i couldn't see any relevant bug fix info from a skim read) i ran:
pip uninstall lmfit
conda install -c conda-forge lmfit
which installed version 1.0.2 (used conda install since i have a long running problem with a network wide install of pip and various python2 libraries that cause me constant trouble which reappeared when trying to pip install here) and the above code you posted ran successfully with the same output you posted.

So not sure if the problem was a broken install or version specific but in either case it's fixed now.

Thanks for your help!

-Nick

--
You received this message because you are subscribed to a topic in the Google Groups "lmfit-py" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/lmfit-py/qMxvYDD7uB8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to lmfit-py+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lmfit-py/CA%2B7ESbos2BXVKBOPBuRTkuX%2B2bX7btFmUL4RDjKxBWVZWi6pRQ%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages