Skip to content

Tutorial: Dissolution Similarity

This tutorial walks through dissolution f1/f2 analysis, bootstrap confidence intervals, and dissolution model fitting using OpenPKFlow.


1. Quick f1 and f2

from openpkflow.dissolution import f1, f2

reference = [20.0, 40.0, 60.0, 80.0, 90.0]
test      = [21.0, 39.0, 61.0, 79.0, 88.0]

print(f"f1 = {f1(reference, test):.2f}")   # 1.33
print(f"f2 = {f2(reference, test):.2f}")   # 72.80
# f2 >= 50 → profiles are similar (FDA 1997 guidance)

FDA threshold: f2 >= 50 indicates similarity. f1 < 15 is sometimes cited as a complementary criterion.


2. From a CSV file

Create a CSV file with columns: formulation, batch, time, percent_released.

formulation,batch,time,percent_released
reference,R1,15,22.1
reference,R1,30,45.3
reference,R1,45,64.7
reference,R1,60,79.5
reference,R2,15,21.8
reference,R2,30,44.9
reference,R2,45,65.1
reference,R2,60,80.2
test,T1,15,21.5
test,T1,30,43.8
test,T1,45,62.9
test,T1,60,78.1
from openpkflow.dissolution import DissolutionStudy

study = DissolutionStudy.from_csv("dissolution_data.csv")
result = study.compare(reference="reference", test="test")

result.summary()   # prints f1, f2, time points, means
result.report("dissolution_report.html")   # generates HTML report

3. Bootstrap f2

Bootstrap f2 gives a confidence interval that accounts for between-batch variability.

result = study.bootstrap_compare(
    reference="reference",
    test="test",
    n_bootstrap=1000,
    seed=42,
)

print(f"Bootstrap f2: {result.f2_mean:.1f} [{result.f2_lower:.1f}, {result.f2_upper:.1f}]")

4. Dissolution model fitting

Fit five standard release kinetics models and rank by AICc:

from openpkflow.dissolution import fit_dissolution_models

time_points = [15, 30, 45, 60, 90]
observed    = [21.5, 43.8, 62.9, 78.1, 91.4]

results = fit_dissolution_models(time_points, observed, "test_formulation")

print(f"Best model: {results.best.name} (AICc={results.best.AICc:.1f})")
results.report("model_fit_report.html")

Models fitted: Weibull, Korsmeyer-Peppas (power law), Higuchi, first-order, zero-order.


5. PDF and Word export

result.report("dissolution_report.pdf")    # requires pip install openpkflow[reports]
result.report("dissolution_report.docx")

Regulatory notes

  • f2 requires a minimum of 3 matched time points.
  • At most one time point where both profiles exceed 85% may be included (FDA 1997 guidance). Use f2(method="regulatory") to automatically apply this rule.
  • The Korsmeyer-Peppas model is only mechanistically valid when release < 60%.