これは、技術的には Pyomo の問題ではなく、処方の問題です。
ソルバーが P_branch_ij と Q_branch_ij の値を 0 に駆動するときに、ASL (ソルバー実行可能ファイルの一部) によってエラーがスローされます (これは、非アクティブなラインまたは不適切な初期値が原因で発生している可能性があります)。ゼロでは、 の導関数sqrt(0)
は未定義です。この数値エラーにより、ソルバーは解を返さずに終了します。
考えられる回避策はいくつかあります。
編集で指摘したように、さまざまな初期変数値を試すことができます。ソルバーが別の開始点から開始する場合、ゼロまで駆動するパスを使用しない場合があります。このアプローチの欠点は、ソルバー パス スルーを持たない初期値を取得する前に、さまざまな初期値を試す必要があり、機能する初期値を見つけることが保証されないことです (特に、問題の解が実際に 0 である場合)。 !)。P_branch_ij
Q_branch_ij
sqrt(0)
枝の全パワー ( P_branch_ij**2 + Q_branch_ij**2
) が決してゼロにならないように、変数を制限します。単純な制約では実行できないため、これは少しトリッキーです。ほとんどのソルバーは、解決プロセス中に制約に違反することが許可されており、ソルバーがの導関数を評価しようとsqrt(0)
すると、致命的なエラーが発生します。幸いなことに、ほとんどのソルバーは常に可変境界を尊重します。したがって、ソルバーが評価しsqrt'(0)
ないようにするには、中間の Pyomo 変数 (Python 式だけでなく) を定義する必要があります。PQ2_branch_ij
、次に変数の下限を 0 より大きい値に設定します。このアプローチの欠点は、現在別の問題を解決していることであり、元の問題の解決策が実際には 0 であった場合、次善の解決策を強制される可能性があります。
model.PQ2_branch_ij = Var(branch_from_to, scenario_set, bounds=(1e-8, None))
def compute_PQ2_branch_ij(m, i, j, k):
P_branch_ij = (m.V_magn[i, k]**2) * np.float(real(Y_matrix[i, j])) - m.V_magn[i, k] * m.V_magn[j, k] * (np.float(real(Y_matrix[i, j])) * cos(m.V_angle[i, k]-m.V_angle[j, k]) + np.float(imag(Y_matrix[i,j])) * sin(m.V_angle[i, k]-m.V_angle[j, k]))
Q_branch_ij = (m.V_magn[i, k]**2) * np.float(imag(Y_matrix[i, j])) + m.V_magn[i, k] * m.V_magn[j, k] * (np.float((real(Y_matrix[i, j]))) * sin(m.V_angle[i, k]-m.V_angle[j, k]) - np.float(imag(Y_matrix[i,j])) * cos(m.V_angle[i, k]-m.V_angle[j, k]))
return m.PQ2_branch_ij[i,j,k] == P_branch_ij**2 + Q_branch_ij**2
def thermal_lim_ineq_con(m, i, j, k):
return sqrt(m.PQ2_branch_ij) <= limits_flows[i, j]
if line_loading_limit:
model.compute_PQ2_branch_ij = Constraint(branch_from_to, scenario_set, rule=compute_PQ2_branch_ij)
model.thermal_lim_ineq_con = Constraint(branch_from_to, scenario_set, rule=thermal_lim_ineq_con)`
sqrt()
を 2 乗して製剤から除去しlimits_flows[i,j]
ます。通常、これが最適なオプションです。問題は数学的に同等ですが、sqrt()
関数は含まれておらず、分岐フローが 0 になった場合でも問題は発生しません。このアプローチを試したときに観察された実行不可能性は、まったく別の問題である可能性があります。たとえば、非凸の問題 (ACOPF など) では、実行可能な位置に移動できず、「ローカルで実行不可能な点に収束する」ようにソルバーを初期化できます (詳細については、特定のソルバーのドキュメントを参照してください。例:IPOPT、Knitro)。
def thermal_lim_ineq_con(model, i, j, k):
if line_loading_limit == True:
P_branch_ij = (model.V_magn[i, k]**2) * np.float(real(Y_matrix[i, j])) - model.V_magn[i, k] * model.V_magn[j, k] * (np.float(real(Y_matrix[i, j])) * cos(model.V_angle[i, k]-model.V_angle[j, k]) + np.float(imag(Y_matrix[i,j])) * sin(model.V_angle[i, k]-model.V_angle[j, k]))
Q_branch_ij = (model.V_magn[i, k]**2) * np.float(imag(Y_matrix[i, j])) + model.V_magn[i, k] * model.V_magn[j, k] * (np.float((real(Y_matrix[i, j]))) * sin(model.V_angle[i, k]-model.V_angle[j, k]) - np.float(imag(Y_matrix[i,j])) * cos(model.V_angle[i, k]-model.V_angle[j, k]))
return P_branch_ij**2 + Q_branch_ij**2 <= limits_flows[i, j]**2
else:
return Constraint.Skip