matrix(): Honour chain rule of differentiation.

The original implementation of change-set 90d8dd8c8040 contained a
crucial misprint leading to incorrect results for all compressible
fluids.
This commit is contained in:
Bård Skaflestad 2012-05-11 14:26:48 +02:00
parent 0677f58026
commit 29cb30ed58

View File

@ -147,19 +147,40 @@ namespace Opm
} }
// Derivative of A matrix. // Derivative of A matrix.
// A = R*inv(B) whence
//
// dA/dp = (dR/dp*inv(B) + R*d(inv(B))/dp)
// = (dR/dp*inv(B) - R*inv(B)*(dB/dp)*inv(B))
// = (dR/dp - A*(dB/dp)) * inv(B)
//
// The B matrix is diagonal and that fact is exploited in the
// following implementation.
if (dAdp) { if (dAdp) {
// #pragma omp parallel for // #pragma omp parallel for
std::copy(A, A + n*np*np, dAdp);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
double* m = dAdp + i*np*np; double* m = dAdp + i*np*np;
std::fill(m, m + np*np, 0.0);
// Diagonal entries. const double* dB = & dB_[i * np];
for (int phase = 0; phase < np; ++phase) { for (int i2 = 0; i2 < np; ++i2) {
m[phase + phase*np] = -dB_[i*np + phase]/B_[i*np + phase]*B_[i*np + phase]; for (int i1 = 0; i1 < np; ++i1) {
m[i2*np + i1] *= - dB[ i1 ]; // Note sign.
}
} }
// Off-diagonal entries.
if (oil_and_gas) { if (oil_and_gas) {
m[o + g*np] = m[g + g*np]*R_[i*np + g] + dR_[i*np + g]/B_[i*np + g]; const double* dR = & dR_[i * np];
m[g + o*np] = m[o + o*np]*R_[i*np + o] + dR_[i*np + o]/B_[i*np + o];
m[o*np + g] += dR[ o ];
m[g*np + o] += dR[ g ];
}
const double* B = & B_[i * np];
for (int i2 = 0; i2 < np; ++i2) {
for (int i1 = 0; i1 < np; ++i1) {
m[i2*np + i1] /= B[ i1 ];
}
} }
} }
} }