Passing a list of fitting parameters

242 views
Skip to first unread message

jensen...@gmail.com

unread,
Aug 9, 2021, 2:37:08 PM8/9/21
to lmfit-py
Hello,

I am a physicist, so I am leaving out some details since they may just cause confusion.

I am using LMFIT in conjunction with another object oriented package.

The package calculates a spectrum of data based on a series of parameters.
I am holding all parameters as independent except for one (these we'll call B coefficients). The B coefficients are retrieved from the other package as a list; I wish to pass this list as dependent parameters to be fitted in my self defined model.

Below is the outputted error:

TypeError Traceback (most recent call last) <ipython-input-95-1d072fa33f0a> in <module> 5 6 bFitModel = Model(bFit, independent_vars=['CF', 'energy', 'Ei','T','res']) ----> 7 params = bFitModel.make_params(B = Pr.B) 8 bFittedSpectrum = bFitModel.fit(np.array(signal), energy = energy, Ei = Ei, T = T, CF = Pr, res = 30) 9 print('parameter names: {}'.format(bFitModel.param_names)) c:\users\jense\appdata\local\programs\python\python38\lib\site-packages\lmfit\model.py in make_params(self, verbose, **kwargs) 669 if basename in kwargs: 670 # kw parameter names with no prefix --> 671 par.value = kwargs[basename] 672 if name in kwargs: 673 # kw parameter names with prefix c:\users\jense\appdata\local\programs\python\python38\lib\site-packages\lmfit\parameter.py in value(self, val) 827 self._val = val 828 if self._val is not None: --> 829 if self._val > self.max: 830 self._val = self.max 831 elif self._val < self.min: TypeError: '>' not supported between instances of 'list' and 'float'

Since this error output is formatted poorly I am also including a picture of it.

Pr.B is the list of B coefficients (retrieved from the other package) that I would like to use as fitting parameters.

I have not included a minimal working code since it would require the use of the other package. But if that is what's required to understand the issue. I can create a minimal working code and include the data sets required.

Thank you,
Jensen


lmfithelp.PNG

Renee Otten

unread,
Aug 9, 2021, 5:33:07 PM8/9/21
to lmfi...@googlegroups.com
Hi Jensen,


well… we ask for a “minimal, working example” for a reason…. Leaving details out here is likely not the best approach as we now, for example, have no idea what the actual function is you’re trying to minimize. I don’t know what you mean with "I am holding all parameters as independent except for one” that seems kind of odd to me, but again I don’t know what you’re attempting to do.

Just looking at the Traceback you do show, the problem and error message are pretty clear: when you do “make_params” in the way you do, it expects an initial value and does some checking on that (e.g., is the value within the min/max bounds). You’re giving a list instead of a float and Python tells you correctly that it cannot compare a list and a float.

Hope that helps,
Renee

jensen...@gmail.com

unread,
Aug 10, 2021, 11:12:02 AM8/10/21
to lmfit-py
Hello Renee,

Before attempting to tackle the list problem, I've decided to individually pass the dependent parameters (the ones that would normally be in the list).

I've attached a zip file that contains a Jupyter Notebook and the required data files, as an example of the error I'm having.

I appreciate the help, and I'm sorry for not initially including more details.

Cheers,
Jensen
lmfit_help.zip

Renee Otten

unread,
Aug 11, 2021, 9:54:51 AM8/11/21
to lmfi...@googlegroups.com
It’s not really a minimal, working example if I first need to download another random package (that doesn’t have a proper installer and fix their imports for numba) before I can run your code - but that’s not really your fault ;) Also, plotting stuff and other things do should not be part of a minimal example; it should be pretty much only (i) reading in data, (ii) defining a function, and (iii) doing a fit. Finally, please do not send Jupyter notebooks as not everyone is using these; plain-old Python code is preferred (at least by me). 

Having said that, the error message is: "ValueError: array must not contain infs or NaNs”. That can indeed not happen and you need to make sure that your model function doesn’t do that - perhaps by making sure that your variables cannot wonder off to unphysical values. I didn’t spend time understanding exactly what you’re doing and what the physical meaning of your fitting parameters is, but perhaps if some/any of them become negative you’d run into NaNs or Infs? If so, you can set boundaries on the parameters. This is described in the documentation and there is a FAQ about the problem you’re seeing: https://lmfit.github.io/lmfit-py/faq.html#i-get-errors-from-nan-in-my-fit-what-can-i-do



-- 
You received this message because you are subscribed to the Google Groups "lmfit-py" group.
To unsubscribe from this group and stop receiving emails from it, 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/3593f537-caef-4afc-bbd6-539e543a7006n%40googlegroups.com.
<lmfit_help.zip>

jensen...@gmail.com

unread,
Aug 11, 2021, 10:33:55 AM8/11/21
to lmfit-py
I'm sorry for the hassle.
I've converted the code to Python (as opposed to Jupyter), I've taken out the plotting, and I've included the two WORKING PyCrystalField files needed for the package to run.
'pcf_lib' and 'PyCrystalField.py' just need to be dragged into your 'site-packages' folder.

It's crucial to my project that LMFIT is used in conjunction with this PyCrystalField package, since PyCrystalField is doing the intensive math needed to create the model.

The fitting parameters (which I have called B) can indeed be positive or negative, as prescribed by the theory behind the model.

So if they are supposed to be able to be pos/neg does that mean I should NOT be using LMFIT to begin with?

The zip I've attached is the updated associated files.
forgooglegroup.zip

Renee Otten

unread,
Aug 11, 2021, 11:13:57 AM8/11/21
to lmfi...@googlegroups.com
Hi Jensen,

Of course you can use lmfit if parameters can be both positive/negative; that’s the case in 99.999% of the cases. What you need to figure out is why your function gives values that are Infs and/or NaNs and make sure that these don’t happen. What I meant is that sometimes restricting fitting parameters to meaningful values can help with that - this is described in the FAQ entry I linked in my previous answer.

Here, if you look at the Traceback (pasted below) you’ll see that the actual error is coming from "PyCrystalField.py in diagonalize(self, CEF_Hamiltonian)”. I am afraid there is nothing we can do about that and/or the issue you’re currently having with lmfit. Unless, I am missing something here and other spot something else of course. Fitting algorithms cannot deal with NaNs and/or Infs and whatever PyCrystalField exactly does (presumably diagonalizing a matrix) neither. My advice would be to explore your model function a bit and/or using an “iteration callback” (https://lmfit.github.io/lmfit-py/fitting.html#using-a-iteration-callback-function and an example here: https://lmfit.github.io/lmfit-py/examples/documentation/model_with_iter_callback.html) to print out what your fitting parameters are when it throws this error and see how to resolve that. 

Best, 
Renee



---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/var/folders/qn/5bwbztqn3kqd3sd888hb_llm0000gn/T/ipykernel_68423/3139038664.py in <module>
----> 1 bFittedSpectrum = bFitModel.fit(np.array(signal), energy = energy, Ei = Ei, T = T, CF = Pr, res = 30, weights = error)

~/Library/Python/3.9/lib/python/site-packages/lmfit-1.0.2.post73+g1925ecd-py3.9.egg/lmfit/model.py in fit(self, data, params, weights, method, iter_cb, scale_covar, verbose, fit_kws, nan_policy, calc_covar, max_nfev, **kwargs)
   1036                              nan_policy=self.nan_policy, calc_covar=calc_covar,
   1037                              max_nfev=max_nfev, **fit_kws)
-> 1038         output.fit(data=data, weights=weights)
   1039         output.components = self.components
   1040         return output

~/Library/Python/3.9/lib/python/site-packages/lmfit-1.0.2.post73+g1925ecd-py3.9.egg/lmfit/model.py in fit(self, data, params, weights, method, nan_policy, **kwargs)
   1393         self.userargs = (self.data, self.weights)
   1394         self.userkws.update(kwargs)
-> 1395         self.init_fit = self.model.eval(params=self.params, **self.userkws)
   1396         _ret = self.minimize(method=self.method)
   1397 

~/Library/Python/3.9/lib/python/site-packages/lmfit-1.0.2.post73+g1925ecd-py3.9.egg/lmfit/model.py in eval(self, params, **kwargs)
    854 
    855         """
--> 856         return self.func(**self.make_funcargs(params, kwargs))
    857 
    858     @property

/var/folders/qn/5bwbztqn3kqd3sd888hb_llm0000gn/T/ipykernel_68423/1566982752.py in bFit(CF, energy, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, Ei, T, res)
      1 def bFit (CF, energy, b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15, Ei, T, res):
----> 2     CF.newCoeff([b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15])
      3     CalculatedSpectrum = CF.neutronSpectrum(energy, Temp=T, Ei=Ei, ResFunc = lambda x: res)
      4     return CalculatedSpectrum

/private/tmp/1/PyCrystalField.py in newCoeff(self, newcoeff)
   1483         self.B = np.array(newcoeff)
   1484         newH = np.sum([a*b for a,b in zip(self.O, newcoeff)], axis=0)
-> 1485         self.diagonalize(newH)
   1486 
   1487 

/private/tmp/1/PyCrystalField.py in diagonalize(self, CEF_Hamiltonian)
   1494 
   1495         bands = self._findbands(CEF_Hamiltonian + self.H_SOC.O)
-> 1496         diagonalH = LA.eig_banded(bands, lower=True)
   1497 
   1498         #self.eigenvaluesNoNorm = diagonalH[0]

/opt/local/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/scipy/linalg/decomp.py in eig_banded(a_band, lower, eigvals_only, overwrite_a_band, select, select_range, max_ev, check_finite)
    755         a1 = array(a_band)
    756         if issubclass(a1.dtype.type, inexact) and not isfinite(a1).all():
--> 757             raise ValueError("array must not contain infs or NaNs")
    758         overwrite_a_band = 1
    759 

ValueError: array must not contain infs or NaNs

jensen...@gmail.com

unread,
Aug 11, 2021, 11:39:06 AM8/11/21
to lmfit-py
Hi Renee,

I think I have an idea as to what's going on.
In my fitting function I return "CalculatedSpectrum" which is an array of values (which is a lineshape) since I want the line shape to be optimized to my data.

However, by returning a lineshape, I'm losing all of the information of the "CF" object (which contains the B values).
So I'm wondering if there's a way to have my fitting function return the "CF" object (so that the B values can be iteratively varied) but have LMFIT optimize the CalculatedSpectrum.

Can I have LMFIT call "CF.neutronSpectrum()" each iteration if I'm returning a "CF" object?

I really appreciate your help,

Jensen

jensen...@gmail.com

unread,
Aug 11, 2021, 12:24:28 PM8/11/21
to lmfit-py
Nevermind!

I've found what's going on!

I never passed params into the bFitModel.fit() function call.

It is now fully running with no errors.
Reply all
Reply to author
Forward
0 new messages