Cannot figure out how to fit a complicated custom equation.

6 views (last 30 days)
I am having trouble implementing this equation into the curve fitting toolbox, both in the command and by utilizing the curve fitting GUI.
A little background that may help explain this:
I am wanting to fit experimental data of T(K) vs K_ph (W/m K) which the thermal conductivity of a material, to a model from a journal paper. I have done an okay job in python with scipy.optimize but have been trying MATLAB for a more accurate method.
I have this equation I need to fit
where
A, B, b, C_1, C_2, D, Omega_res1, Omega_res2, and L (ignore L in the exmaple code) are all coefficients I want solved for.
Omega is the independent variable in the integral (omega is solved for) while T is the range 1 to 100 in 1K steps. Or T can simply be my experimental Temperature data as is in my code.
My problems (in the GUI) are in the ways to set the values for T and use an integral in the custom equation box. As in, I am not sure how to tyep the equation in the way MATLAB accepts in the GUI for the toolbox.
My problems for the code is in the integration and lsqcurve fit it seems. I have a lot of warnings/errors such as
%{
Warning: Derivative finite-differencing step was artificially reduced to be within bound constraints. This may
adversely affect convergence. Increasing distance between bound constraints, in dimension 6, to be at least 2e-20
may improve results.
Local minimum possible.
lsqcurvefit stopped because the size of the current step is less than
the value of the step size tolerance.
<stopping criteria details>
Fitted Parameters:
D = 1e-40
B = 1e-20
A = 1e-15
b = 100
C1 = 1e-40
C2 = 1e-40
%}
I am not sure how to fix these, I have gone through other posts on similar matters and have changed the bounds and manually changed the optimoptions values to very low, but reached a point where it was just iterating nonstop.
Any help is appreciated!
% Data from 0T.txt
data = readmatrix('0T.txt', 'HeaderLines', 1);
T_data = data(:, 1); % First col: Temperature (K)
k_ph_data = data(:, 2); % Second col: \kappa_{xx} (W/mK)
% Constants
k_B = 1.380649e-23; % Boltzmann constant in J/K
hbar = 1.0545718e-34; % Reduced Planck constant in J·s
v_s = 4.817e3; % Sound velocity in m/s
theta_D = 235; % Debye temperature in K
L = 1e-6; % Length in m
% Define the integrand function with omega_res1 and omega_res2
integrand = @(omega, T, D, B, A, b, C1, C2, omega_res1, omega_res2) ...
(omega.^4 .* exp(hbar*omega./(k_B*T)) ./ (exp(hbar*omega./(k_B*T)) - 1).^2) .* ...
(v_s / L + D*omega.^4 + B*omega + A*T*omega.^3 .* exp(-theta_D / (b*T)) + ...
C1 * omega.^4 ./ ((omega.^2 - omega_res1.^2).^2 + 1e-10) .* exp(-hbar*omega_res1 / (k_B * T)) ./ ...
(1 + exp(-hbar*omega_res1 / (k_B * T))) + ...
C2 * omega.^4 ./ ((omega.^2 - omega_res2.^2).^2 + 1e-10) .* exp(-hbar*omega_res2 / (k_B * T)) ./ ...
(1 + exp(-hbar*omega_res2 / (k_B * T))));
% Define the k_ph function
k_ph_func = @(params, T) (k_B / (2 * pi^2 * v_s)) * (k_B * T / hbar)^3 .* ...
integral(@(omega) integrand(omega, T, params(1), params(2), params(3), params(4), params(5), params(6), params(7), params(8)), 0, theta_D / T);
% Define the function to be minimized
fun = @(params, T) arrayfun(@(t) k_ph_func(params, t), T);
% Initial guess for parameters [D, B, A, b, C1, C2, omega_res1, omega_res2]
initial_guess = [1e-43, 1e-6, 1e-31, 1, 1e9, 1e10, 1e12, 4e12];
% Set bounds
lb = [1e-50, 1e-12, 1e-35, 1, 1e7, 1e8, 1e10, 3e12];
ub = [1e-40, 1e-3, 1e-28, 1000, 1e11, 1e12, 1e14, 5e12];
% Create opts structure
opts = optimoptions('lsqcurvefit', 'MaxFunctionEvaluations', 1e4, 'MaxIterations', 1e3);
% Use lsqcurvefit for the fitting
[fitted_params, resnorm, residual, exitflag, output] = lsqcurvefit(fun, initial_guess, T_data, k_ph_data, lb, ub, opts);
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Warning: Inf or NaN value encountered.
Error using lsqncommon (line 35)
Objective function is returning Inf or NaN values at initial point. lsqcurvefit cannot continue.

Error in lsqcurvefit (line 322)
lsqncommon(funfcn,xCurrent,lb,ub,options,defaultopt,optimgetFlag,caller,...
% Generate fitted curve (using log spacing)
T_fit = logspace(log10(min(T_data)), log10(max(T_data)), 100);
k_ph_fit = fun(fitted_params, T_fit);
  13 Comments
Torsten
Torsten on 24 Aug 2024
Please give us the solution for the parameters from your Python code for comparison that produced the figures you included.
Johnathan
Johnathan on 31 Aug 2024
I just saw this comment now, sorry about that. Here is the python code for my closest fitting.
The figure created is attached as well.
import numpy as np
import scipy.integrate as integrate
import matplotlib.pyplot as plt
import pandas as pd
# Constants
k_B = 1.380649e-23 # Boltzmann constant (J/K)
hbar = 1.0545718e-34 # Reduced Planck constant (J·s)
# Parameters for FeCl2
theta_D = 235 # Debye temperature (K) fecl2, constant
v_s = 4.817e3 # Sound velocity (m/s) fecl2, solved for
# Parameters
L = 3.38e-4 # (m)
A = 7.03e-31 # (K^-1 s^2)
b = 3.2 # unitless
C1 = 3.029e+09 # s^-1 adjusts height/slope of second peak
C2 = 1.548e+10 # s^-1 adjusts height/slope of overall conductivity
omega_res1_0T = 3.5043973583e+12 # res1 for 0T fecl2 paper, constant
omega_res2_0T = 2.9114816436e+12 # res2 for 0T fecl2 paper, constant
D = 0.8e-43 # adjusts the higher-temperature peak
B = -5.298e-06 # adjusts the lowee_temperature peak
# Given omega values for 0T (in Hz)
omega_res1_0T = 3.5043973583e+12 # res1 for 0T fecl2 paper
omega_res2_0T = 2.9114816436e+12 # res2 for 0T fecl2 paper
# Modify tau_tot_inv to use the given omega values for 0T
def tau_tot_inv(omega, T, H):
tau_boundary_inv = v_s / L
tau_defect_inv = D * omega**4
tau_dislocation_inv = B * omega
tau_umklapp_inv = A * T * omega**3 * np.exp(-theta_D / (b * T))
tau_mag1_inv = C1 * (omega**4 / (omega**2 - omega_res1_0T**2)**2) * \
(np.exp(-hbar * omega_res1_0T / (k_B * T)) /
(1 + np.exp(-hbar * omega_res1_0T / (k_B * T))))
tau_mag2_inv = C2 * (omega**4 / (omega**2 - omega_res2_0T**2)**2) * \
(np.exp(-hbar * omega_res2_0T / (k_B * T)) /
(1 + np.exp(-hbar * omega_res2_0T / (k_B * T))))
return tau_boundary_inv + tau_defect_inv + tau_dislocation_inv + \
tau_umklapp_inv + tau_mag1_inv + tau_mag2_inv
def integrand(x, T, H):
omega = (x * k_B * T) / hbar
F = (x**4 * np.exp(x)) / (np.exp(x) - 1)**2
return F * (1 / tau_tot_inv(omega, T, H))
def k_ph(T, H):
prefactor = (k_B / (2 * np.pi**2 * v_s)) * ((k_B * T / hbar)**3)
integral, _ = integrate.quad(integrand, 0, theta_D / T, args=(T, H))
return prefactor * integral
# Temperature range for calculation
temperatures = np.logspace(np.log10(1), np.log10(100), num=100)
# Calculate k_ph for each temperature (assuming H = 0 for now)
H = 0 # Magnetic field (T)
k_ph_values = [k_ph(T, H) for T in temperatures]
# Load data from the 0T.txt file, skipping the first row
data = np.loadtxt('0T.txt', skiprows=1)
# Extract temperature and thermal conductivity
temperature = data[:, 0] # First column: Temperature (K)
thermal_conductivity = data[:, 1] # Second column: \kappa_{xx} (W/m K)
# Plot both calculated and experimental data
plt.figure(figsize=(10, 6))
plt.plot(temperatures, k_ph_values, marker='', linestyle='-', color='b', label='Calculated')
plt.plot(temperature, thermal_conductivity, marker='o', linestyle='-', color='r', label='Raw')
plt.xscale('log')
# plt.yscale('log')
plt.xlabel('T(K)')
plt.ylabel('$\kappa_{xx}$ (W/K m)')
plt.title('Data: Calculated vs Experimental')
plt.legend()
plt.grid(True)
plt.show()

Sign in to comment.

Answers (1)

Matt J
Matt J on 24 Aug 2024
Edited: Matt J on 24 Aug 2024
I recommend using fminspleas, downloadable from,
for this problem instead of lsqcurvefit.
This is more suitable for your problem in several ways. First, the model function depends nonlinearly on only 3 of your unknowns b, and , which fminspleas can exploit (once you make the change of variables C_3=1/L). Also, your function might not be continuous and differentiable in and , violating the assumptions of lsqcurvefit. In particular, your integrand has poles at and and it is not clear that the interval of integration avoids these poles.
Additionally, it will probably help with the numerical behavior of the exponential expressions to implement the objective function in terms of the transformed variables , and rather than in terms of b, and directly.
Obviously, you will then also need to transform the lb, ub bounds accordingly. I doubt you would ever want to allow any of the unknowns to go outside of [-15,+15]. The exp() outputs reach crazy values there.
  21 Comments
Torsten
Torsten on 1 Sep 2024
Edited: Torsten on 1 Sep 2024
Usually, all the T's in your integrand should be replaced by h*omega/(k_B*x), shouldn't they ? But the upper limit of the integrand (Theta_D/T) also depends on T (which varies with x). Strange ...
Matt J
Matt J on 1 Sep 2024
No, x is the variable of integration and T is constant with respect to the integration. It is omega that needs to be replaced with k_B*T*x/h.

Sign in to comment.

Products


Release

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!