Skip to content

High: [Drying] Gas balance and Darcy velocity produce order-of-magnitude drying transient errors #81

Description

@sergey-gusev94

Maintainer triage (June 29, 2026)

  • Status: Verified bug against the current master source in this fork.
  • Severity: High.
  • Area labels: area:drying.
  • Tackle batch: P2 - shared thermo, phase, and basis correctness.

The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.


Original audit details

Severity: High · Part of #67 (round-2 audit batch)

All three defects live in PharmaPy/Drying_Model.py in the same drying subsystem and are exercised on the same code paths (material_balance RHS + solve_unit initialization). The gas-velocity (243-244) and gas-species-source (334) defects both corrupt the gas-phase balance and would be fixed and validated together in a single drying-correctness pass; the single-node init omission (472) is the same solve_unit setup that feeds that balance. Bundling avoids three overlapping PRs touching the same file and lets one regression test cover the coupled transient. The Wilke vapor-viscosity defect is intentionally kept separate (different file, general thermo property).

This issue bundles 3 defects that share one fix/PR.

1. (High) Darcy gas velocity discards relative permeability k_ra and divides by mean saturation (wrong gas flow at both saturation limits)

Location: PharmaPy/Drying_Model.py:243-244 (k_ra computed but unused at 239-241; correct form commented at 242)

Lines 239-241 compute the two-phase gas relative permeability k_ra = (1-sat_red)^2*(1-sat_red^1.4) but it is never used. The active line 243-244 computes vel_gas = self.dPg_dz/(alphavisc_gasrho_sol*(1-porosity))/np.mean(satur), i.e. single-phase Darcy velocity (= k_permdPg_dz/visc, since k_perm=1/alpha/rho_sol/(1-porosity) at line 520) divided by mean saturation. This (a) drops the k_ra throttle entirely and (b) substitutes a 1/mean(S) factor that runs backwards at the limits: at full saturation (S~1) gas cannot flow but the code returns full single-phase velocity, and as S decreases the velocity grows instead of approaching the finite k_ra->1 limit. The physically correct, intended form (k_permk_ra*dPg_dz/visc_gas) is the commented line 242.

2. (High) Gas-phase species evaporation source over-divided by an extra (1-satur) factor

Location: PharmaPy/Drying_Model.py:334

epsilon_gas (line 324) is already porosity*(1-satur), the gas volume fraction. The correct accumulation coefficient for a mass-fraction source is eps_grho_g, so the source should be N_i/(porosity(1-satur)rho_gas). But line 334 codes transfer_gas = dry_rate.T/epsilon_gas/dens_gas/(1-satur), dividing additionally by (1-satur), i.e. by porosity(1-satur)^2rho_gas. The companion total_mass_correction (line 336) already correctly carries the single 1/(1-satur) from d(eps_g)/dt, and the energy balance (line 362, denom_gas = cvg_mixepsilon_gas*rho_gas) uses exactly one (1-satur) for the same accumulation coefficient, directly contradicting line 334.

3. (High) Uniform/single-node initialization omits temp_cond from the initial state vector

Location: PharmaPy/Drying_Model.py:470-475 (else branch; cf. correct if branch at 463-468)

When x_liq_init.ndim==1 and len(satur_init)==1, line 472 builds states_tuple = (satur_init, y_gas_init, x_liq_init, temp_gas_init), omitting temp_cond_init, giving a per-node width of 2+num_comp+num_volatiles. The parallel branch (lines 463-468) correctly stacks all five state groups (S, y_gas, x_liq, Tg, Tcond). unit_model later does states.reshape(-1, 3 + num_comp + self.num_volatiles) (line 225), which expects the temp_cond column.

Related existing issues (referenced, not modified): #20, #21, #24, #28, #37, #42, #48 (existing drying balance/property issues in the same module; reference only). #21 specifically shares line 334 (mol-vs-mass) but is a distinct mechanism from the extra (1-satur) factor here.


Found by a multi-agent source audit (round 2); confirmed by re-reading the source and cross-checked against all 80 existing open issues. Each defect was verified by an independent code-truth skeptic and a novelty skeptic.

Metadata

Metadata

Assignees

Labels

area:dryingDrying model balances and transport termsbugSomething isn't workingcorrectnessModel/numerical correctness defectseverity:highConfirmed bug with major correctness impact or broken documented workflowstatus:verifiedSource-reviewed against the current codebase

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions