Skip to content

Commit 73d0301

Browse files
committed
docs: add viscosity models tutorial with LBC and Friction Theory tuning
1 parent da7bb54 commit 73d0301

File tree

1 file changed

+393
-0
lines changed

1 file changed

+393
-0
lines changed

examples/viscosityModels.py

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Oil Viscosity Models and Tuning Tutorial
4+
==========================================
5+
6+
This example demonstrates advanced viscosity modeling for oil systems in NeqSim,
7+
including the LBC (Lohrenz-Bray-Clark) and Friction Theory models, and how to
8+
tune their parameters to match laboratory data.
9+
10+
Topics Covered:
11+
1. Available viscosity models
12+
2. LBC model and its parameters
13+
3. Tuning LBC dense-fluid parameters
14+
4. Friction Theory model
15+
5. Tuning Friction Theory with TBP correction factor
16+
6. Model comparison and selection guidelines
17+
18+
@author: NeqSim Team
19+
"""
20+
21+
from neqsim.thermo import fluid, TPflash
22+
import neqsim.jneqsim as jneqsim
23+
24+
print("=" * 70)
25+
print("OIL VISCOSITY MODELS AND TUNING TUTORIAL")
26+
print("=" * 70)
27+
28+
# =============================================================================
29+
# 1. AVAILABLE VISCOSITY MODELS
30+
# =============================================================================
31+
print("\n1. AVAILABLE VISCOSITY MODELS")
32+
print("-" * 40)
33+
print("""
34+
Model | Keyword | Best For
35+
-------------------|--------------------|---------------------------------
36+
LBC | "LBC" | General oil, reservoir fluids
37+
Friction Theory | "friction theory" | Wide range, EoS-consistent
38+
PFCT | "PFCT" | Petroleum fractions
39+
PFCT Heavy Oil | "PFCT-Heavy-Oil" | Heavy oils, bitumen
40+
41+
The LBC model is based on corresponding states principle using critical
42+
properties. Friction Theory links viscosity to EoS pressure terms,
43+
providing thermodynamic consistency.
44+
""")
45+
46+
# =============================================================================
47+
# 2. BASIC VISCOSITY CALCULATION
48+
# =============================================================================
49+
print("\n2. BASIC VISCOSITY CALCULATION")
50+
print("-" * 40)
51+
52+
# Create a medium oil
53+
oil = fluid("srk")
54+
oil.addComponent("methane", 10.0, "mol%")
55+
oil.addComponent("n-pentane", 15.0, "mol%")
56+
oil.addComponent("n-heptane", 25.0, "mol%")
57+
oil.addComponent("n-decane", 30.0, "mol%")
58+
oil.addComponent("n-C16", 20.0, "mol%")
59+
oil.setMixingRule("classic")
60+
oil.setMultiPhaseCheck(True)
61+
62+
# Set conditions
63+
oil.setTemperature(50.0, "C")
64+
oil.setPressure(100.0, "bara")
65+
TPflash(oil)
66+
67+
print(f"Oil composition: C1: 10%, C5: 15%, C7: 25%, C10: 30%, C16: 20%")
68+
print(f"Conditions: T = 50°C, P = 100 bara")
69+
70+
# Compare different viscosity models
71+
print("\nViscosity with different models:")
72+
print("\nModel | Viscosity [cP]")
73+
print("-------------------|----------------")
74+
75+
for model in ["LBC", "friction theory", "PFCT"]:
76+
try:
77+
if oil.hasPhaseType("oil"):
78+
oil.getPhase("oil").getPhysicalProperties().setViscosityModel(model)
79+
oil.initPhysicalProperties()
80+
visc = oil.getPhase("oil").getViscosity("cP")
81+
print(f"{model:18} | {visc:.4f}")
82+
except Exception as e:
83+
print(f"{model:18} | Error: {e}")
84+
85+
# =============================================================================
86+
# 3. LBC MODEL EXPLANATION
87+
# =============================================================================
88+
print("\n3. LBC MODEL (LOHRENZ-BRAY-CLARK)")
89+
print("-" * 40)
90+
print("""
91+
The LBC model calculates viscosity as:
92+
93+
η = η* + η_dense / ξ_m
94+
95+
Where:
96+
η* = Low-pressure gas viscosity contribution
97+
η_dense = Dense-fluid contribution (function of reduced density)
98+
ξ_m = Mixture viscosity parameter
99+
100+
Dense-fluid contribution uses a polynomial:
101+
102+
(η_dense * ξ_m + 10^-4)^0.25 = a0 + a1*ρr + a2*ρr² + a3*ρr³ + a4*ρr⁴
103+
104+
Default LBC parameters (a0 to a4):
105+
a0 = 0.10230
106+
a1 = 0.023364
107+
a2 = 0.058533
108+
a3 = -0.040758
109+
a4 = 0.0093324
110+
111+
These parameters can be tuned to match laboratory viscosity data.
112+
""")
113+
114+
# =============================================================================
115+
# 4. TUNING LBC MODEL PARAMETERS
116+
# =============================================================================
117+
print("\n4. TUNING LBC MODEL PARAMETERS")
118+
print("-" * 40)
119+
print("Adjusting dense-fluid polynomial coefficients to match lab data")
120+
121+
# Create oil system
122+
tuning_oil = fluid("srk")
123+
tuning_oil.addComponent("n-heptane", 30.0, "mol%")
124+
tuning_oil.addComponent("n-decane", 40.0, "mol%")
125+
tuning_oil.addTBPfraction("C16", 30.0, 0.22, 830.0)
126+
tuning_oil.setMixingRule("classic")
127+
128+
tuning_oil.setTemperature(50.0, "C")
129+
tuning_oil.setPressure(150.0, "bara")
130+
TPflash(tuning_oil)
131+
tuning_oil.initThermoProperties()
132+
133+
# Set LBC model and get default viscosity
134+
if tuning_oil.hasPhaseType("oil"):
135+
tuning_oil.getPhase("oil").getPhysicalProperties().setViscosityModel("LBC")
136+
tuning_oil.initPhysicalProperties()
137+
default_visc = tuning_oil.getPhase("oil").getViscosity("cP")
138+
139+
print(f"\nDefault LBC viscosity: {default_visc:.4f} cP")
140+
141+
# Suppose lab measurement is 2.5 cP - we need to tune
142+
lab_viscosity = 2.5
143+
print(f"Laboratory measurement: {lab_viscosity:.4f} cP")
144+
145+
# Method 1: Set all five parameters at once
146+
# Increasing coefficients generally increases viscosity
147+
# Default: [0.10230, 0.023364, 0.058533, -0.040758, 0.0093324]
148+
tuned_params = [0.15, 0.04, 0.08, -0.03, 0.015] # Increased values
149+
150+
tuning_oil.getPhase("oil").getPhysicalProperties().setLbcParameters(tuned_params)
151+
tuning_oil.initPhysicalProperties()
152+
tuned_visc_1 = tuning_oil.getPhase("oil").getViscosity("cP")
153+
154+
print(f"\nTuned viscosity (all params): {tuned_visc_1:.4f} cP")
155+
156+
# Method 2: Adjust individual parameter
157+
# Parameter indices: a0=0, a1=1, a2=2, a3=3, a4=4
158+
# a0 (index 0) has most influence at low density
159+
# a4 (index 4) has most influence at high density
160+
161+
tuning_oil.getPhase("oil").getPhysicalProperties().setLbcParameter(2, 0.10)
162+
tuning_oil.initPhysicalProperties()
163+
tuned_visc_2 = tuning_oil.getPhase("oil").getViscosity("cP")
164+
165+
print(f"Further adjusted (a2=0.10): {tuned_visc_2:.4f} cP")
166+
167+
print("""
168+
LBC Tuning Guidelines:
169+
----------------------
170+
• a0 (index 0): Baseline offset - increase for higher overall viscosity
171+
• a1 (index 1): Linear density term - affects moderate densities
172+
• a2 (index 2): Quadratic term - significant for liquid viscosity
173+
• a3 (index 3): Cubic term - fine-tuning at high density
174+
• a4 (index 4): Quartic term - extreme density behavior
175+
""")
176+
177+
# =============================================================================
178+
# 5. FRICTION THEORY MODEL
179+
# =============================================================================
180+
print("\n5. FRICTION THEORY MODEL")
181+
print("-" * 40)
182+
print("""
183+
Friction Theory (f-theory) links viscosity to EoS pressure terms:
184+
185+
η = η0 + ηf
186+
187+
Where:
188+
η0 = Dilute gas viscosity (Chung correlation)
189+
ηf = Friction contribution from EoS
190+
191+
The friction term is proportional to attractive and repulsive pressure
192+
terms from the equation of state, providing thermodynamic consistency.
193+
194+
Advantages:
195+
✓ Consistent with phase equilibrium calculations
196+
✓ Better extrapolation behavior
197+
✓ Works well for wide T/P ranges
198+
""")
199+
200+
# =============================================================================
201+
# 6. TUNING FRICTION THEORY - TBP CORRECTION FACTOR
202+
# =============================================================================
203+
print("\n6. TUNING FRICTION THEORY - TBP CORRECTION FACTOR")
204+
print("-" * 40)
205+
print("For TBP (True Boiling Point) fractions, a correction factor can be applied")
206+
207+
# Create oil with TBP fractions
208+
ft_oil = fluid("srk")
209+
ft_oil.addComponent("methane", 5.0, "mol%")
210+
ft_oil.addComponent("n-heptane", 20.0, "mol%")
211+
ft_oil.addTBPfraction("C12", 25.0, 0.17, 780.0)
212+
ft_oil.addTBPfraction("C18", 30.0, 0.25, 820.0)
213+
ft_oil.addTBPfraction("C25", 20.0, 0.35, 860.0)
214+
ft_oil.setMixingRule("classic")
215+
216+
ft_oil.setTemperature(60.0, "C")
217+
ft_oil.setPressure(100.0, "bara")
218+
TPflash(ft_oil)
219+
ft_oil.initThermoProperties()
220+
221+
if ft_oil.hasPhaseType("oil"):
222+
# Set friction theory model
223+
ft_oil.getPhase("oil").getPhysicalProperties().setViscosityModel("friction theory")
224+
ft_oil.initPhysicalProperties()
225+
226+
# Get default viscosity
227+
default_ft_visc = ft_oil.getPhase("oil").getViscosity("cP")
228+
print(f"\nDefault Friction Theory viscosity: {default_ft_visc:.4f} cP")
229+
230+
# Apply TBP viscosity correction factor
231+
# Factor > 1.0 increases viscosity
232+
# Factor < 1.0 decreases viscosity
233+
visc_model = ft_oil.getPhase("oil").getPhysicalProperties().getViscosityModel()
234+
235+
# Access the FrictionTheoryViscosityMethod directly
236+
print("\nApplying TBP correction factors:")
237+
print("\nCorrection Factor | Viscosity [cP]")
238+
print("------------------|----------------")
239+
240+
for correction in [0.8, 1.0, 1.2, 1.5, 2.0]:
241+
try:
242+
# Set the TBP correction factor
243+
visc_model.setTBPviscosityCorrection(correction)
244+
ft_oil.initPhysicalProperties()
245+
246+
corrected_visc = ft_oil.getPhase("oil").getViscosity("cP")
247+
print(f"{correction:17.1f} | {corrected_visc:.4f}")
248+
except Exception as e:
249+
print(f"{correction:17.1f} | Error: {e}")
250+
251+
# Reset to default
252+
visc_model.setTBPviscosityCorrection(1.0)
253+
254+
print("""
255+
Friction Theory Tuning Guidelines:
256+
----------------------------------
257+
• TBP Correction Factor:
258+
- Default = 1.0 (no correction)
259+
- > 1.0: Increases viscosity for heavy fractions
260+
- < 1.0: Decreases viscosity
261+
262+
• Use when TBP fractions give incorrect viscosity predictions
263+
• Tune to match laboratory viscosity at one T/P condition
264+
• Model will extrapolate to other conditions
265+
""")
266+
267+
# =============================================================================
268+
# 7. ADVANCED: TUNING WITH EXPERIMENTAL DATA
269+
# =============================================================================
270+
print("\n7. ADVANCED: TUNING WITH EXPERIMENTAL DATA")
271+
print("-" * 40)
272+
print("Workflow for matching lab measurements")
273+
274+
# Example experimental data
275+
exp_data = [
276+
{"T_C": 25, "P_bara": 1, "visc_cP": 3.5},
277+
{"T_C": 50, "P_bara": 50, "visc_cP": 1.8},
278+
{"T_C": 80, "P_bara": 100, "visc_cP": 0.9},
279+
]
280+
281+
print("\nExample experimental viscosity data:")
282+
print("T [°C] | P [bara] | Viscosity [cP]")
283+
print("-------|----------|---------------")
284+
for pt in exp_data:
285+
print(f"{pt['T_C']:6} | {pt['P_bara']:8} | {pt['visc_cP']:.2f}")
286+
287+
print("""
288+
Tuning Workflow:
289+
----------------
290+
1. Create fluid with accurate composition
291+
2. Select viscosity model (LBC or Friction Theory)
292+
3. Calculate viscosity at each experimental condition
293+
4. Compare with experimental data
294+
5. Adjust parameters:
295+
- LBC: Tune a0-a4 dense-fluid parameters
296+
- Friction Theory: Tune TBP correction factor
297+
6. Iterate until deviation is acceptable
298+
7. Validate at conditions not used for tuning
299+
300+
For automatic optimization, use NeqSim's parameter fitting capabilities
301+
with the ViscosityFunction class in PVT simulation.
302+
""")
303+
304+
# =============================================================================
305+
# 8. MODEL COMPARISON AT DIFFERENT CONDITIONS
306+
# =============================================================================
307+
print("\n8. MODEL COMPARISON AT DIFFERENT CONDITIONS")
308+
print("-" * 40)
309+
310+
comp_oil = fluid("srk")
311+
comp_oil.addComponent("n-heptane", 30.0, "mol%")
312+
comp_oil.addComponent("n-decane", 40.0, "mol%")
313+
comp_oil.addComponent("n-C16", 30.0, "mol%")
314+
comp_oil.setMixingRule("classic")
315+
comp_oil.setMultiPhaseCheck(True)
316+
317+
print("Viscosity comparison: LBC vs Friction Theory")
318+
print("Oil: C7 30%, C10 40%, C16 30%")
319+
print("\nT [°C] | P [bara] | LBC [cP] | F-Theory [cP] | Ratio")
320+
print("-------|----------|-----------|---------------|-------")
321+
322+
conditions = [
323+
(25, 1),
324+
(50, 50),
325+
(80, 100),
326+
(100, 200),
327+
(120, 300),
328+
]
329+
330+
for t_c, p_bara in conditions:
331+
comp_oil.setTemperature(t_c, "C")
332+
comp_oil.setPressure(p_bara, "bara")
333+
TPflash(comp_oil)
334+
comp_oil.initThermoProperties()
335+
336+
if comp_oil.hasPhaseType("oil"):
337+
# LBC
338+
comp_oil.getPhase("oil").getPhysicalProperties().setViscosityModel("LBC")
339+
comp_oil.initPhysicalProperties()
340+
lbc_visc = comp_oil.getPhase("oil").getViscosity("cP")
341+
342+
# Friction Theory
343+
comp_oil.getPhase("oil").getPhysicalProperties().setViscosityModel("friction theory")
344+
comp_oil.initPhysicalProperties()
345+
ft_visc = comp_oil.getPhase("oil").getViscosity("cP")
346+
347+
ratio = lbc_visc / ft_visc if ft_visc > 0 else 0
348+
print(f"{t_c:6} | {p_bara:8} | {lbc_visc:9.4f} | {ft_visc:13.4f} | {ratio:.3f}")
349+
350+
# =============================================================================
351+
# 9. HEAVY OIL CONSIDERATIONS
352+
# =============================================================================
353+
print("\n9. HEAVY OIL CONSIDERATIONS")
354+
print("-" * 40)
355+
print("""
356+
For heavy oils (API < 20°, viscosity > 100 cP), consider:
357+
358+
1. Use PFCT-Heavy-Oil model:
359+
oil.getPhase("oil").getPhysicalProperties().setViscosityModel("PFCT-Heavy-Oil")
360+
361+
2. LBC may underpredict - needs significant parameter tuning
362+
363+
3. Friction Theory typically needs TBP correction > 1.0 for heavy ends
364+
365+
4. Temperature sensitivity is critical - ensure accurate measurements
366+
367+
5. Consider using Pedersen corresponding states for very heavy systems
368+
""")
369+
370+
# =============================================================================
371+
# 10. SUMMARY
372+
# =============================================================================
373+
print("\n10. SUMMARY: MODEL SELECTION GUIDELINES")
374+
print("-" * 40)
375+
print("""
376+
┌────────────────────┬──────────────────────────────────────────┐
377+
│ Oil Type │ Recommended Model & Notes │
378+
├────────────────────┼──────────────────────────────────────────┤
379+
│ Light oil │ LBC or Friction Theory │
380+
│ (API > 35°) │ Default parameters often sufficient │
381+
├────────────────────┼──────────────────────────────────────────┤
382+
│ Medium oil │ LBC with tuned parameters │
383+
│ (20° < API < 35°) │ or Friction Theory with TBP correction │
384+
├────────────────────┼──────────────────────────────────────────┤
385+
│ Heavy oil │ PFCT-Heavy-Oil or Friction Theory │
386+
│ (10° < API < 20°) │ TBP correction factor 1.5-2.0 │
387+
├────────────────────┼──────────────────────────────────────────┤
388+
│ Extra-heavy │ Specialized correlations │
389+
│ (API < 10°) │ May require custom viscosity data │
390+
└────────────────────┴──────────────────────────────────────────┘
391+
""")
392+
393+
print("=" * 70)

0 commit comments

Comments
 (0)