0

我有一个主要功能,用于将测量的热容量拟合到某个模型:

    HeatCapacity[a_, t_] := 
      If[t > 1, 
       t, (6*a^3/(\[Pi]^2*t)) NIntegrate[
         FermiDirac[a, \[Epsilon], 
           t]*(1 - FermiDirac[a, \[Epsilon], 
             t])*(Energy[\[Epsilon], t]^(2)/t - 
            0.5*d\[CapitalDelta]2[t]), {\[Epsilon], 0, \[Infinity]}, 
         AccuracyGoal -> 5]];

该函数隐含的是对另一个数值积分函数的重复调用:

    Delta[t_] := 
     Block[{a = 
        Subscript[k, B]
          Subscript[\[CapitalTheta], D]/Subscript[\[CapitalDelta], 0], 
       b = Subscript[\[Alpha], BCS]/2/t}, 
      Return[FindRoot[
          NIntegrate[(1/Sqrt[\[Epsilon]^2 + x^2]) Tanh[
              b*Sqrt[\[Epsilon]^2 + x^2]], {\[Epsilon], 0, a}, 
            AccuracyGoal -> 5] - Log[2 a], {x, 0.01, 0.1}] [[1, 2]]*1 ]]

现在,一旦 Delta[t] 被计算一次,它就不会改变,原则上每次调用它时都不需要重新计算——这就是我当前的方法正在做的事情。

我的问题是,我怎样才能最好地优化我的代码,使 Delta[t] 只计算一次?是否需要某种形式的查找表?如果是这样,这是否会改变我对执行非线性拟合例程的要求(即某种离散非线性模型拟合?)。

为了完整起见,我将包含我使用的所有功能的完整代码。我意识到数学下标等在这里看起来不太好,所以如果人们愿意,我可以重新格式化。

干杯

Energy[\[Epsilon]_, t_] := 
  Sqrt[\[Epsilon]^2 + 
    Delta[t]^2]; (* energy spectrum, \[Epsilon] measured wrt Fermi \
level *)

g[\[Epsilon]_, t_] := 
  Subscript[\[Alpha], BCS] Energy[\[Epsilon], t]/(2 t);

dtop[t_] := 
  NIntegrate[Sech[g[\[Epsilon], t]]^2, {\[Epsilon], 0, \[Infinity]}, 
   AccuracyGoal -> 5];

dbottom[t_] := 
  NIntegrate[
   t*Sech[g[\[Epsilon], t]]^2/(2 Energy[\[Epsilon], t]^2) - 
    t^2 Tanh[
       g[\[Epsilon], t]]/(Subscript[\[Alpha], BCS]
         Energy[\[Epsilon], t]^3), {\[Epsilon], 0, \[Infinity]}, 
   AccuracyGoal -> 5];

d\[CapitalDelta]2[t_] := dtop[t]/dbottom[t];

FermiDirac[\[Alpha]_, \[Epsilon]_, 
   t_] := (E^(\[Alpha] Energy[\[Epsilon], t]/t) + 1)^(-1);

HeatCapacity[a_, t_] := 
  If[t > 1, 
   t, (6*a^3/(\[Pi]^2*t)) NIntegrate[
     FermiDirac[a, \[Epsilon], 
       t]*(1 - FermiDirac[a, \[Epsilon], 
         t])*(Energy[\[Epsilon], t]^(2)/t - 
        0.5*d\[CapitalDelta]2[t]), {\[Epsilon], 0, \[Infinity]}, 
     AccuracyGoal -> 5]];

ScaledHC[\[Gamma]_, Tc_, a_, t_] := \[Gamma] Tc HeatCapacity[a, t/Tc];

result = NonlinearModelFit[datain, 
  ScaledHC[gamma, 4.7, alpha, 
   t], {{gamma, Subscript[\[Gamma], fit]}, {alpha, Subscript[\[Alpha],
     fit]}}, t, 
  Weights -> (1./err^2.), {StepMonitor :> 
    Print["Gamma = ", Evaluate[gamma], 
     " \!\(\*SubscriptBox[\(T\), \(C\)]\) = ", Evaluate[b], 
     " alpha = ", Evaluate[alpha]]}]
4

1 回答 1

0

您可能会阅读一些关于 = 和 := 之间的区别,有时称为 Set[] 和 SetDelayed[],不要与 == 混淆,甚至还有 ===,它们都是不同的。= 在使用所有变量具有的当前值评估单元格时评估右侧,并将结果保存在名称 Delta 下。当左侧被使用或将来重复使用时,它不应该再次评估 Delta 的主体,只要您不再次手动评估该单元格。:= 简单地存储右手边的形式,并在未来每次使用左手边时评估它,并使用该未来时间的值变量。如果您的变量不会改变,那么也许 = 对您来说就足够了。

如果您可以安排在评估之前初始化除 t 之外的所有变量

Delta[t_]=Block[...]

那么这应该只评估一次。您可以通过在 Delta 函数中包含诊断 Print[] 来验证这一点。

您还可以调查您是否真的需要 Return[] 。Return[] 过去一直是令人困惑的问题的根源,如果我正确理解您的代码,则可以消除。*1 也可能被丢弃,因为我看不出它对你有什么作用。

如果您不一定需要隐藏 a 和 b 的值,那么您甚至可以将其写为

Delta[t_]=(a=...;b=...;FindRoot[...][[1,2]]);

您将每个...替换为显而易见的地方。( 和 ) 将覆盖分号的优先级,并允许您在单个函数定义中使用复合语句。

你甚至可以对代码做进一步的修改,但现在也许这已经足够了。

我没有也没有足够的信息来这样做,在进行此类修改后仔细测试了您的所有代码,因此请仔细测试。

于 2013-11-07T22:43:38.430 回答