0

After constructive comments from @M Newville, I have altered my original question in order to produce a minimal example.

I have performed experiments under different conditions. I have a lot more experimental data at Condition 1 than Condition 2:

import numpy as np
from lmfit import minimize, Parameters, fit_report    

# CONDITION 1.

x_data_1  = np.array([4.68, 4.70, 4.71, 4.72, 4.74])
y_data_1  = np.array([7.01, 7.03, 7.04, 7.04, 7.04]) 
z_data_1  = np.array([5.67, 5.67, 5.68, 5.69, 5.72])

n1_data_1 = np.array([0.374, 0.371, 0.369, 0.376, 0.375])
n2_data_1 = np.array([0.284, 0.284, 0.282, 0.282, 0.283])
n3_data_1 = np.array([0.284, 0.284, 0.282, 0.282, 0.283])

# CONDITION 2.

x_data_2  = np.array([10.72, 10.68, 10.77, 10.76, 10.79])

n1_data_2 = np.array([0.207, 0.205, 0.203, 0.224, 0.205])

However, I need Y>Z>X to be true for both conditions. X, Y, Z calculated by Function_X, Function_Y, and Function_Z depend on parameters A, B, C, D, and E. As do N1, N2, and N3 described by Function_N1, Function_N2, and Function_N3.

# FUNCTIONS.

def Function_X(A, B, C, E):
    return C-B**2/(A-E)

def Function_Y(A, B, C, E):
    return (4*E*((A-E)*C-B**2))/(A*C-B**2)

def Function_Z(A, B, C, D, E, X, Y):
    return 4*(1/X+1/Y+1/D-B/((A-E)*C-B**2))**(-1)

def Function_N1(A, B, E):
    return B/(2*(A-E))

def Function_N2(A, B, C, E):
    return 2*E*B/(A*C-B**2)

def Function_N3(A, B, C, E):
    return ((A-2*E)*C-B**2)/(A*C-B**2)

On the one hand, FitFunction1 is able to achieve the desired Y>Z>X (y_computed_1>z_computed_1>x_computed_1) without using any mathematical constraints due to the larger amount of data.

# FIT FUNCTION (CONDITION 1).

def FitFunction1(params1, x_data_1=None, y_data_1=None, z_data_1=None, n1_data_1=None, n2_data_1=None, n3_data_1=None):
    # MODEL.
    x_mod  = Function_X(params1['A'], params1['B'], params1['C'], params1['E'])
    y_mod  = Function_Y(params1['A'], params1['B'], params1['C'], params1['E'])
    z_mod  = Function_Z(params1['A'], params1['B'], params1['C'], params1['D'], params1['E'], x_mod, y_mod)
    n1_mod = Function_N1(params1['A'], params1['B'], params1['E'])
    n2_mod = Function_N2(params1['A'], params1['B'], params1['C'], params1['E'])
    n3_mod = Function_N3(params1['A'], params1['B'], params1['C'], params1['E'])
    # RESIDUALS.
    x_res  = x_data_1  - x_mod
    y_res  = y_data_1  - y_mod
    z_res  = z_data_1  - z_mod
    n1_res = n1_data_1 - n1_mod
    n2_res = n2_data_1 - n2_mod
    n3_res = n3_data_1 - n3_mod
    return np.concatenate((x_res.ravel(), y_res.ravel(), z_res.ravel(), n1_res.ravel(), n2_res.ravel(), n3_res.ravel()))

params1 = Parameters()
params1.add('fc',    value= 1000, min=10, max=100000)
params1.add('alpha', value=0.4, min=0.2, max=0.8)
params1.add('A', value=20, min=10, max=30)
params1.add('B', value=10, min=1, max=15)
params1.add('C', value=15, min=10, max=20)
params1.add('D', value=2.5, min=1, max=5)
params1.add('E', value=5, min=2.5, max=7.5)

res1 = minimize(FitFunction1, params1, kws={'x_data_1': x_data_1, 'y_data_1': y_data_1, 'z_data_1': z_data_1, 'n1_data_1': n1_data_1, 'n2_data_1': n2_data_1, 'n3_data_1': n3_data_1})

print(fit_report(res1))

for keys in res1.params:
    exec(f'jf_{keys}_1 = res1.params[keys].value')

x_computed_1 = Function_X(jf_A_1, jf_B_1, jf_C_1, jf_E_1)
y_computed_1 = Function_Y(jf_A_1, jf_B_1, jf_C_1, jf_E_1)
z_computed_1 = Function_Z(jf_A_1, jf_B_1, jf_C_1, jf_D_1, jf_E_1, Function_X(jf_A_1, jf_B_1, jf_C_1, jf_E_1), Function_Y(jf_A_1, jf_B_1, jf_C_1, jf_E_1))

On the other hand, FitFunction2 is unable to produce the same (Y>Z>X) left unconstrained (without mathematical constraints) due to the smaller amount of data.

# FIT FUNCTION (CONDITION 2).

def FitFunction2(params2, x_data_2=None, n1_data_2=None):
    # MODEL.
    x_mod  = Function_X(params2['A'], params2['B'], params2['C'], params2['E'])
    n1_mod = Function_N1(params2['A'], params2['B'], params2['E'])
    # RESIDUALS.
    x_res  = x_data_2 - x_mod
    n1_res = n1_data_2 - n1_mod
    return np.concatenate((x_res.ravel(), n1_res.ravel()))

params2 = Parameters()
params2.add('fc',    value= 1000, min=10, max=100000)
params2.add('alpha', value=0.4, min=0.2, max=0.8)
params2.add('A', value=20, min=10, max=30)
params2.add('B', value=10, min=1, max=15)
params2.add('C', value=15, min=10, max=20)
params2.add('D', value=2.5, min=1, max=5)
params2.add('E', value=5, min=2.5, max=7.5)
params2.add('X', value=np.mean(x_data_2), min=0, expr='C-B**2/(A-E)')
params2.add('Z_minus_X', value=1, vary=True, min=0)
params2.add('Y_minus_Z', value=1, vary=True, min=0)
params2.add('Z', value=10, expr='X + Z_minus_X', min=0)#, expr='(4*E*((A-E)*C-B**2))/(A*C-B**2)')
params2.add('Y', value=10, expr='Z + Y_minus_Z', min=0)#, expr='4*(1/X+1/Y+1/D-B/((A-E)*C-B**2))**(-1)')

res2 = minimize(FitFunction2, params2, kws={'x_data_2': x_data_2, 'n1_data_2': n1_data_2})

print(fit_report(res2))

Note that parameter D is not present in FitFunction2. I tried to introduce additional five constraints to enforce Y>Z>X based on another question but it does not work. I know that the result of FitFunction2 does not depend on parameters X, Y, and Z in the current configuration. I wonder however if there is a way to make the result of FitFunction2 somehow depend on them with another configuration.

  • Is it possible to arrange parameters A, B, C, D, E in FitFunction2 so that Y>Z>X using mathematical constraints (or any other method)?
naughty_waves
  • 265
  • 1
  • 13
  • You say 'Y > Z > X is a fundamental constraint to my model', but it is not clear whether these are arrays, functions, or parameters. lmfit allows you to put constraints on Parameters, which are scalar values. It seems like you may want an array `Y` to be greater than array `Z`: is that point by point or must all values of `Y` be greater than all values of `Z`? But, then (and very weirdly) you define functions for `X`, `Y`, and `Z`. What does `f1>f2` mean? I think you need to clarify your question and what you mean by each of the 5 symbols (not counting spaces) in `Y > Z > X`. – M Newville Sep 30 '20 at 14:37
  • Thank you, @M Newville. I apologize for the confusing nature of my wording. I edited my question with additional comments at the end that I hope answers your questions. `f_1`, `f_2`, and `f_3` are just different frequencies probed by different techniques. – naughty_waves Sep 30 '20 at 15:52
  • I don't understand what you want to do. You have defined variable parameters `X_min`, `Z_min_minus_X_min`, but appear to not be using them (unless I am missing something in your code that is way too long for a "minimal example"). You compute a value `x_min` from your (confusingly named) function `X` and a bunch of the *other* parameters. I can't tell if you are being deliberately confusing or not, but I think you may have confused yourself. Of course, your python variable `x_min`, your function `X` and the parameter named `X_min` have no magical connection. – M Newville Oct 01 '20 at 12:01
  • Thank you again, @M Newville. I find myself in a constant state of confusion, so I can only imagine how confusing my question may appear to others. I do however really appreciate your time and willingness to help. I edited my question (and added an alternative "minimal question" at the end). – naughty_waves Oct 03 '20 at 12:52
  • I am sorry for the confusing use of variable names. I tried to be consistent so it would be obvious which parameters and functions are related. `x_min` is simply part of my model `x_mod` which could have been directly written as `x_mod = CC1(f_1, X(params['A_min'], params['B_min'], params['C_min'], params['E_min']), X(params['A_max'], params['B_max'], params['C_max'], params['E_max']), params['fc'], params['alpha'])` to avoid confusion. – naughty_waves Oct 03 '20 at 12:55
  • Your question is too long. Try to reduce the amount of information to the necessary stuff. Explain what your inout is and what you want as output. – MachineLearner Oct 03 '20 at 13:54
  • Um, I still don't understand what you're doing. Again, the result of your fit function does not depend on your parameters `X` or `Y`. It seems sort of obvious to me that those won't be varied in the fit. Were you expecting something different? And what is with "the fit function **could be** something like this? If you have a question, post a minimal and complete example that demonstrates the problem and show the result. Get rid of any extraneous noise or previous versions of your question. Until you do that, no one will understand what you are doing. – M Newville Oct 05 '20 at 12:15
  • I am terribly sorry for being unable to explain what I am doing, @M Newville. I overhauled the entire question in order for it to be clearer. If it is still confusing, I will stop wasting your time. I know that my fit function does not depend on parameters `X`, `Y`, and `Z`. I was hoping there was a way to make them depend on the result of my fit function by some clever manipulation using mathematical constraints. I have no idea if it is possible or not though. Thank you again for showing interest. – naughty_waves Oct 14 '20 at 14:43
  • @M Newville, I wonder if you had a chance to look at the overhauled question? I hope I managed to better explain what I want to do. If it is still confusing I will honor my word by not wasting your time anymore. I thank you for your time (or rather apologize for wasting it). – naughty_waves Dec 02 '20 at 13:24
  • @naughty_waves Nope, I do not understand what you are trying to do. I strongly suggest that you make a (much, really, much) smaller and complete example illustrating what you are trying to do. – M Newville Dec 02 '20 at 18:57

0 Answers0