Skip to content

ps.polymer

ps.polymer.Adsorption(*, rows) -> None

The polymer’s adsorption isotherm: what the rock holds against the polymer concentration.

ps.polymer.Adsorption(rows=[(0.0, 0.0), (1.0, 0.00002)]): the rock adsorbs 0.00002 of polymer where the water carries 1.

Each row is a polymer concentration in the model’s units and the polymer adsorbed there (polymer mass per rock mass), the concentrations strictly rising. It writes PLYADS (PROPS), one table, which ps.load reads back. ps.polymer.Package(adsorption=...) holds it, at physics/polymer/adsorption.

Rows: (concentration, adsorbed_concentration). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.Mixing(*, value: float) -> None

The Todd-Longstaff mixing parameter of one polymer mixing region.

ps.polymer.Mixing(value=0.7) is one mixing region’s Todd-Longstaff parameter, between no mixing (0) and full mixing (1).

It writes one record of PLMIXPAR (PROPS), which ps.load reads back. ps.polymer.Package(mixing_parameter=...) holds one per mixing region, at physics/polymer/mixing_parameter (physics/polymer/mixing_parameter/<n> in a list).

ps.polymer.MolecularWeightTable() -> None

Polymer molecular-weight injection lookup over throughput and velocity (PLYMWINJ).

ps.polymer.MolecularWeightTable(number=1, throughput=[0.0, 100.0], velocity=[0.0, 1.0], molecular_weight=[[20.0, 18.0], [20.0, 15.0]]) is table 1: the injected molecular weight falls with throughput and velocity.

A lookup grid, like a lift table: its two axes, throughput (strictly rising, one row of the body each) and velocity (strictly rising, one column each), and its body, molecular_weight, one row per throughput with a value per velocity; each is held as a read-only float array. The throughput is a length and the velocity a length per time, in the model’s units. An injector selects the table by its number (ps.wells.InjectedStream(well=..., molecular_weight_table=1), WPMITAB).

It writes one PLYMWINJ table (PROPS), which ps.load reads back, and makes the run a molecular-weight one (POLYMW), the only run Flow reads it in. ps.polymer.Package(molecular_weight_injection=...) holds it, at physics/polymer/molecular_weight_injection.

ps.polymer.Package() -> None

A polymer flood’s physics: the polymer’s viscosity, its adsorption and its rock tables.

ps.polymer.Package(viscosity=viscosity, adsorption=adsorption, rock=polymer_rock, maximum_concentration=1.0, mixing_parameter=ps.polymer.Mixing(value=0.7)) is a polymer flood’s package; ps.Model(physics=[...]) holds it, at physics/polymer.

It writes POLYMER (RUNSPEC), and POLYMW, the molecular-weight model, where molecular_weight is set or a molecular_weight_injection or an initial_molecular_weight is stated; each table it holds writes its own card (each class says which, and whether ps.load reads it back), and the initial concentration and molecular weight write SPOLY and SPOLYMW (SOLUTION), which ps.load refuses. It states one field at least. A well injects polymer with ps.wells.InjectedStream(well=..., polymer_concentration=...), the stream’s polymer card.

ps.polymer.Rock(*, inaccessible_pore_volume: float, residual_resistance_factor: float, rock_density: ScalarPropertyInput, adsorption_index: int, maximum_adsorption: ScalarPropertyInput) -> None

How the rock of one saturation region meets the polymer: pore access and adsorption.

ps.polymer.Rock(inaccessible_pore_volume=0.1, residual_resistance_factor=2.0, rock_density=2650.0, adsorption_index=2, maximum_adsorption=0.00002) keeps the polymer out of a tenth of the pores and holds what it adsorbs. Flow divides the water’s mobility by 1 + (2.0 - 1) x adsorbed / maximum adsorption, so the water’s mobility halves where the adsorbed polymer reaches the maximum adsorption, and falls by less below it.

The inaccessible pore volume is a fraction, the residual resistance factor a positive number, the rock density a density in the model’s units, and the maximum adsorption the polymer mass per rock mass. ps.polymer.Package(rock=...) holds it, at physics/polymer/rock; one rock writes one record of PLYROCK (PROPS), which ps.load reads back. Flow reads one record per saturation region, but several rocks in a list (physics/polymer/rock/<n>) are written as one merged record, only the last rock ending with the record’s slash, which ps.load refuses (deck.record.malformed) and Flow refuses as too many items.

ps.polymer.SaltSensitivity(*, rows) -> None

The polymer’s viscosity multiplier against salinity and polymer concentration.

rows hold a salinity node, a polymer concentration and its viscosity multiplier, the card’s flat shape with its node column first: each salinity’s rows together and the salinities rising, the concentrations rising within one salinity. Each number is in the model’s units.

It writes PLYVISCS in the SCHEDULE section. OPM Flow lists PLYVISCS as unsupported and stops the run on it, and ps.load refuses a deck that states it; ps.compile writes it all the same. ps.polymer.Package(salt_viscosity=...) holds it, at physics/polymer/salt_viscosity. The model refuses it without a ps.brine.Package (polymer.viscosity.salt_requires_brine).

Rows: (salinity, concentration, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.SaltTemperatureSensitivity(*, rows) -> None

The polymer’s viscosity multiplier over a grid of salinity and temperature nodes.

rows hold a salinity, a temperature, a polymer concentration and its viscosity multiplier, node columns first (each node has its own concentration rows, so it is a family table): each node’s rows together, the nodes rising by salinity and then temperature, the concentrations rising within one node, and every salinity stated at every temperature. The two node lists follow from the rows. Each number is in the model’s units.

It writes PLYVSCST in the SCHEDULE section. OPM Flow lists PLYVSCST as unsupported and stops the run on it, and ps.load refuses a deck that states it; ps.compile writes it all the same. ps.polymer.Package(salt_temperature_viscosity=...) holds it, at physics/polymer/salt_temperature_viscosity. The model refuses it without both a ps.brine.Package and a ps.thermal.Package (polymer.viscosity.joint_requires_brine_and_thermal), and beside the one-variable tables, salt_viscosity or temperature_viscosity (polymer.viscosity.sensitivity_conflict).

Rows: (salinity, temperature, concentration, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.Shear(*, rows) -> None

The polymer’s shear response: the viscosity factor against the flow velocity.

rows hold a flow velocity (in the model’s units) and the viscosity factor there, the velocities strictly rising from the first row (0.0, 1.0).

It writes PLYSHEAR in the SCHEDULE section. OPM Flow lists PLYSHEAR as unsupported and stops the run on it, and ps.load refuses a deck that states it; ps.compile writes it all the same. ps.polymer.Package(shear_response=...) holds it, at physics/polymer/shear_response. The model refuses it beside a ps.polymer.ShearLog that states a log_shear_rate (polymer.shear.style_conflict).

Rows: (velocity, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.ShearLog(*, reference_polymer_concentration: ScalarPropertyInput, rows, log_shear_rate: float | None = None) -> None

The polymer’s shear thinning: a viscosity multiplier against water velocity or shear rate.

ps.polymer.ShearLog(reference_polymer_concentration=1.0, rows=[(1.0e-7, 1.0), (1.0, 0.8)]) thins the polymer by a fifth at a velocity of 1, measured at a concentration of 1.

rows are the table’s first-column value and multiplier pairs, the first column strictly rising, at the reference_polymer_concentration the table is measured at. With log_shear_rate None (no SHRATE written) the first column is the water velocity, a length per time in the model’s units. With it stated (SHRATE, Flow’s default 4.8) the first column is a shear rate, a reciprocal time in the model’s time unit (per day, per hour on a LAB model): Flow turns the water velocity into a shear rate, multiplying it by log_shear_rate and by the square root of porosity times water saturation over the water relative permeability times the permeability, and reads the table at that rate. Flow takes the logarithm of each first-column value, so the first is a small positive number such as 1.0e-7, never 0; the class takes a 0, which Flow cannot take the logarithm of.

It writes PLYSHLOG (PROPS), which ps.load reads back, and SHRATE, which ps.load refuses; a molecular-weight run (POLYMW) ignores both. ps.polymer.Package(shear_log=...) holds it, at physics/polymer/shear_log. With a log_shear_rate stated, the model refuses it beside a ps.polymer.Shear (shear_response; polymer.shear.style_conflict).

Rows: (velocity, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.SkinPressure() -> None

An injector’s skin pressure: the pressure drop against throughput and velocity.

ps.polymer.SkinPressure(number=1, throughput=[0.0, 100.0], velocity=[0.0, 1.0], pressure_drop=[[0.0, 0.0], [0.0, 5.0]]) is water table 1: a skin pressure of 5 after a throughput of 100 at a velocity of 1.

A water table (SKPRWAT) states no reference_polymer_concentration; a polymer table (SKPRPOLY) states it. ps.polymer.Package holds the water tables in water_skin_pressure and the polymer tables in polymer_skin_pressure.

A lookup grid, like a lift table: its two axes, throughput (strictly rising, one row of the body each) and velocity (strictly rising, one column each), and its body, pressure_drop, one row per throughput with a value per velocity; each is held as a read-only float array. The throughput is a length, the velocity a length per time and the pressure drop a pressure, in the model’s units. An injector selects a water table and a polymer table by their number, the two stated together: ps.wells.InjectedStream(well="I1", water_skin_pressure_table=1, polymer_skin_pressure_table=2).

It writes one SKPRWAT or SKPRPOLY table (PROPS), which ps.load reads back, at physics/polymer/water_skin_pressure or physics/polymer/polymer_skin_pressure. Flow reads the two cards only in a molecular-weight run (POLYMW), which a skin-pressure table alone does not switch on.

ps.polymer.TemperatureSensitivity(*, rows) -> None

The polymer’s viscosity multiplier against temperature and polymer concentration.

rows hold a temperature node, a polymer concentration and its viscosity multiplier, node column first: each temperature’s rows together and the temperatures rising, the concentrations rising within one temperature. Each number is in the model’s units.

It writes PLYVISCT in the SCHEDULE section. OPM Flow lists PLYVISCT as unsupported and stops the run on it, and ps.load refuses a deck that states it; ps.compile writes it all the same. ps.polymer.Package(temperature_viscosity=...) holds it, at physics/polymer/temperature_viscosity. The model refuses it without a ps.thermal.Package (polymer.viscosity.temperature_requires_thermal).

Rows: (temperature, concentration, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.ThermalDegradation(*, rows) -> None

The polymer’s half-life against temperature: how fast heat degrades it.

ps.polymer.ThermalDegradation(rows=[(50.0, 400.0), (90.0, 40.0)]) halves the polymer in 400 days at 50 degrees and in 40 at 90, on a METRIC model.

Each row is a temperature and the half-life there, a time in the model’s time unit (days; hours on a LAB model), two rows at least, the temperatures strictly rising. It writes PLYDHFLF in the SCHEDULE section. OPM Flow lists PLYDHFLF as unsupported and stops the run on it, and ps.load refuses a deck that states it; ps.compile writes it all the same. ps.polymer.Package(thermal_degradation=...) holds it, at physics/polymer/thermal_degradation. The model refuses it without a ps.thermal.Package (polymer.degradation.requires_thermal).

Rows: (temperature, half_life). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.Viscosity(*, rows) -> None

The water’s viscosity multiplier against the polymer concentration.

ps.polymer.Viscosity(rows=[(0.0, 1.0), (1.0, 20.0)]) thickens the water 20 times at a polymer concentration of 1.

Each row is a polymer concentration in the model’s units and the positive multiplier there, the concentrations strictly rising. It writes PLYVISC (PROPS), one table, which ps.load reads back; a molecular-weight run (POLYMW) ignores it and reads viscosity_mixing instead. ps.polymer.Package(viscosity=...) holds it, at physics/polymer/viscosity.

Rows: (concentration, multiplier). State each row as a sequence in this order, or as a mapping by column name.

ps.polymer.ViscosityMixing(*, mixing_parameter: float, shear_factor: float, inaccessible_pore_volume: float, permeability_reduction: float) -> None

The four parameters of Flow’s molecular-weight viscosity model (PLYVMH).

ps.polymer.ViscosityMixing(mixing_parameter=1.0, shear_factor=1.0, inaccessible_pore_volume=0.1, permeability_reduction=2.0) states the four parameters.

Flow reads PLYVMH’s items as the Mark-Houwink and Huggins constants of its molecular-weight model, whatever the field names say: mixing_parameter is K_MH and shear_factor A_MH (the intrinsic viscosity is K_MH times (1000 times the molecular weight) raised to A_MH), and inaccessible_pore_volume is GAMMA and permeability_reduction KAPPA (the water viscosity grows by 1 + GAMMA (x + KAPPA x squared), x the concentration times the intrinsic viscosity). Each is a non-negative number. It writes one record of PLYVMH (PROPS), which ps.load reads back; Flow reads it only in a molecular-weight run (POLYMW), where it needs it. ps.polymer.Package(viscosity_mixing=...) holds it, at physics/polymer/viscosity_mixing.

PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt