- One-compartment IV bolus: half-life, volume, clearance
- Oral dose: Cmax, tmax and AUC by integration
- Dosing regimen at steady state
- Multiple oral dosing by convolution
- Dissolution profile similarity: f1 and f2 factors
- Carboplatin dose with the Calvert formula
- Shelf life from accelerated stability (Arrhenius)
- Content uniformity: acceptance value and z-test
- Population PK: renal and non-renal clearance
- Over-lubrication and disintegration time
One-compartment IV bolus: half-life, volume, clearance
After an IV bolus of 500 mg, eight plasma concentrations were measured over 24 h. The script fits C = C0.exp(-k.t) (log-linear regression) and derives the half-life, the volume of distribution V = D/C0, the clearance CL = k.V and AUC = C0/k.
#1. IV bolus of 500 mg: plasma concentrations in mg/L, times in h; -> "[t]" "[0.5, 1, 2, 4, 6, 8, 12, 24]"; -> "[c]" "[13.42, 12.13, 10.01, 7.25, 5.14, 3.69, 1.78, 0.22]"; #2. One-compartment model C = C0.exp of -k.t, log-linear fit; json load "rx_ch_pk1" (stat fit [t] [c] "exp"); -> "[c0]" (json select "rx_ch_pk1" /a); -> "[k]" (math calc (concat "-1*" (json select "rx_ch_pk1" /b))); #3. Half-life, volume, clearance, AUC 0-inf; -> "[v]" (math calc "500/[c0]"); -> "[auc]" (math calc "[c0]/[k]"); concat "k = " (math round [k] 4) " 1/h, t1/2 = " (math round (math calc "ln(2)/[k]") 2) " h, V = " (math round [v] 1) " L, CL = " (math round (math calc "[k]*[v]") 2) " L/h, AUC = " (math round [auc] 1) " mg.h/L"
k = 0.1744 1/h, t1/2 = 3.97 h, V = 34.4 L, CL = 6 L/h, AUC = 83.3 mg.h/L
- Compute the trapezoidal AUC 0-24 with
num interpolate_integral"linear" for a non-compartmental check. - Fit a two-compartment model with
stat fit_model.
Oral dose: Cmax, tmax and AUC by integration
A 400 mg oral dose (F = 0.8, ka = 1.2 1/h, ke = 0.15 1/h, V = 40 L) follows the Bateman function. The script finds the peak concentration and its time, integrates the curve from 0 to infinity and checks AUC = F.D/CL.
#1. Oral dose 400 mg, F = 0.8, ka = 1.2 1/h, ke = 0.15 1/h, V = 40 L: Bateman function; -> "[cp]" "0.8*400*1.2/(40*(1.2-0.15))*(exp(-0.15*t) - exp(-1.2*t))"; #2. Peak concentration and time of the peak; json load "rx_ch_pk2" (num maximize [cp] "t" 0 24); #3. AUC 0-inf by integration, checked against F.D / CL; -> "[auc]" (num integrate [cp] "t" 0 "inf"); concat "Cmax = " (math round (json select "rx_ch_pk2" /value) 2) " mg/L at tmax = " (math round (json select "rx_ch_pk2" /x) 2) " h, AUC = " (math round [auc] 2) " mg.h/L, F.D/CL = " (math round (math calc "0.8*400/(0.15*40)") 2)
Cmax = 5.94 mg/L at tmax = 1.98 h, AUC = 53.33 mg.h/L, F.D/CL = 53.33
- Find the time above the MIC with
num solveon C(t) - MIC. - Compare two formulations with different ka.
Dosing regimen at steady state
A drug with CL = 4.5 L/h and V = 50 L must reach an average steady-state concentration of 15 mg/L with an IV dose every 12 h. The script computes the dose rounded to 250 mg vials, the accumulation factor, the peak and trough at steady state, and checks the peak after the 10th dose by superposition.
#1. Target average steady state 15 mg/L, CL = 4.5 L/h, V = 50 L, IV every 12 h; -> "[d]" (math calc "15*4.5*12"); -> "[dose]" (math calc "250*round([d]/250)"); -> "[k]" (math calc "4.5/50"); #2. Accumulation factor, peak and trough at steady state; -> "[r]" (math calc "1/(1-exp(-[k]*12))"); -> "[cmax]" (math calc "[dose]/50*[r]"); -> "[cmin]" (math calc "[cmax]*exp(-[k]*12)"); #3. Check: peak after the 10th dose by superposition of the 10 doses; -> "[c10]" (num sum (concat [dose] "/50*exp(-" [k] "*12*j)") "j" 0 9); concat "Dose " [dose] " mg q12h, R = " (math round [r] 2) ", Cmax,ss = " (math round [cmax] 1) " mg/L, Cmin,ss = " (math round [cmin] 1) " mg/L, peak after dose 10 = " (math round [c10] 1) " mg/L"
Dose 750 mg q12h, R = 1.51, Cmax,ss = 22.7 mg/L, Cmin,ss = 7.7 mg/L, peak after dose 10 = 22.7 mg/L
- Add a loading dose = Cmax,ss.V.
- Adjust the interval to keep the trough above a target with
num solve.
Multiple oral dosing by convolution
One oral dose gives a Bateman curve. The script computes its exact AUC with the CAS, then the concentration for a dose every 8 h over 3 days by convolving the dose train with the single-dose curve (superposition principle), and draws it.
#1. Oral dose: C of t = 10 * exp -0.1 t - exp -1.2 t in mg/L, t in h; -> "[C]" "10*(exp(-0.1*t)-exp(-1.2*t))"; #2. Exact AUC from 0 to infinity with the CAS; -> "[auc]" (cas integrate [C] "t" 0 "Infinity"); #3. Single dose curve and a dose every 8 h for 3 days, sampled every hour; -> "[h]" (matrix col (num table [C] "t" 0 72 1) 2); -> "[doses]" (matrix col (num table "floor(t/8)-floor((t-1)/8)" "t" 0 71 1) 2); #4. Superposition principle: concentration = dose train convolved with the single dose curve; -> "[Ct]" (dsp convolve [doses] [h]); plot signal [Ct] 1
The chart is shown in the Plot tab of the editor.
Dissolution profile similarity: f1 and f2 factors
Compare the dissolution profile of a generic tablet with the reference product (FDA/EMA guidance): mean squared difference, similarity factor f2 (similar if >= 50) and difference factor f1 (similar if <= 15), with a paired t-test showing why significance is not the criterion.
#1. Dissolution of a generic tablet against the reference, % dissolved at 10, 15, 20, 30, 45 min, mean of 12 units; -> "[ref]" "[38, 55, 68, 84, 93]"; -> "[test]" "[33, 49, 63, 80, 91]"; #2. Squared differences between the profiles; -> "[d]" (vector sub [test] [ref]); -> "[msd]" (/ (vector dot [d] [d]) 5); #3. FDA similarity factor f2 = 50.log10 of 100 over sqrt 1 + MSD, and difference factor f1, the test is below the reference at every point; -> "[f2]" (math calc "50*log(100/sqrt(1+[msd]))"); -> "[f1]" (math calc (concat "100*" (math abs (stat sum [d])) "/" (stat sum [ref]))); #4. Paired test of the time points, only for information; -> "[p]" (json load select "rx_tu1_pt" (stat ttest_paired [test] [ref]) "/p_value"); concat "MSD = " [msd] ", f2 = " (math round [f2] 1) " (similar if >= 50), f1 = " (math round [f1] 1) " (similar if <= 15), mean difference " (stat mean [d]) " %, paired t-test p = " (math round_sig [p] 3)
MSD = 21.2, f2 = 66.3 (similar if >= 50), f1 = 6.5 (similar if <= 15), mean difference -4.4 %, paired t-test p = 0.00291
- Bootstrap the confidence interval of f2 when the CV of the units exceeds 20 %
- Fit a Weibull dissolution model with
stat fit_modeland compare the time to 63.2 % dissolved
Carboplatin dose with the Calvert formula
An oncology pharmacist validates a carboplatin AUC 5 prescription: Cockcroft-Gault clearance capped at 125 mL/min, Du Bois body surface area, Calvert dose and the dose actually prepared, rounded down to 10 mg.
#1. Patient for carboplatin AUC 5: woman, 68 years, 72 kg, 165 cm, serum creatinine 1.1 mg/dL; -> "[age]" 68; -> "[wt]" 72; -> "[ht]" 165; -> "[scr]" 1.1; -> "[auc]" 5; #2. Cockcroft-Gault creatinine clearance with the 0.85 female factor, capped at 125 mL/min; -> "[crcl]" (math calc "(140-[age])*[wt]/(72*[scr])*0.85"); -> "[gfr]" (math min [crcl] 125); #3. Du Bois body surface area 0.007184 W^0.425 H^0.725; -> "[bsa]" (* 0.007184 (* (math power [wt] 0.425) (math power [ht] 0.725))); #4. Calvert formula dose = AUC x GFR + 25, rounded down to 10 mg for the preparation; -> "[dose]" (* [auc] (+ [gfr] 25)); -> "[prep]" (* 10 (math trunc (/ [dose] 10))); concat "CrCl = " (math round [crcl] 1) " mL/min, BSA = " (math round [bsa] 2) " m2, Calvert dose = " (math round [dose] 1) " mg, prepared " [prep] " mg = " (math round (/ [prep] [bsa]) 0) " mg/m2"
CrCl = 55.6 mL/min, BSA = 1.79 m2, Calvert dose = 403.2 mg, prepared 400 mg = 223 mg/m2
- Compare with the CKD-EPI eGFR de-indexed by the BSA (
math power,math calc). - Loop over a list of patients with
forandatom getto check a whole day of prescriptions.
Shelf life from accelerated stability (Arrhenius)
Rate constants of a first-order degradation measured at 40, 50 and 60 C are fitted with the Arrhenius law to get the activation energy, the rate at 25 C, the t90 shelf life and the loss after 24 months.
#1. Accelerated stability: k of a first-order degradation at 40, 50 and 60 C in 1/day; -> "[t]" "[313.15, 323.15, 333.15]"; -> "[k]" "[0.00062, 0.00171, 0.00445]"; #2. Arrhenius ln k = ln A - Ea/RT: fit k = a.exp of b over T as an exp model in 1/T; -> "[invT]" (concat "[" (/ 1 313.15) ", " (/ 1 323.15) ", " (/ 1 333.15) "]"); -> "[fit]" (stat fit [invT] [k] "exp"); -> "[b]" (json load select "rx_p4d_arr" [fit] "/b"); -> "[a]" (json select "rx_p4d_arr" "/a"); #3. Activation energy Ea = -b.R, then k at 25 C; -> "[ea]" (math calc "-[b]*8.314462618/1000"); -> "[k25]" (* [a] (math exp (/ [b] 298.15))); #4. Shelf life t90 = -ln 0.9 / k, log1p keeps the precision of small losses; -> "[t90]" (/ (- 0 (math log1p -0.1)) [k25]); -> "[loss24]" (* -100 (math expm1 (* (- 0 [k25]) 730))); concat "Ea = " (math round [ea] 1) " kJ/mol (R = " (constant physics_r) "), k25 = " (math round_sig [k25] 3) " 1/day, t90 = " (math round (/ [t90] 30.44) 1) " months, loss after 24 months = " (math round [loss24] 2) " %"
Ea = 85.5 kJ/mol (R = 8.31446261815324 J/(mol·K)), k25 = 0.000119 1/day, t90 = 29.1 months, loss after 24 months = 8.31 %
- Add the 95 % confidence limit of k25 with
stat fit_modeland its parameter errors (ICH Q1E). - Use
num solveto find the storage temperature that gives 36 months.
Content uniformity: acceptance value and z-test
Ten tablets are assayed in % of the label claim. The script computes the USP <905> / Ph. Eur. 2.9.40 acceptance value, tests the batch mean against 100 % with the known method SD, and gives both variances.
#1. Assay of 10 tablets in % of label claim, validated method SD known 1.2 %; -> "[x]" "[98.1, 101.3, 97.6, 99.4, 102.0, 96.8, 100.2, 98.9, 97.3, 99.8]"; -> "[m]" (stat mean [x]); -> "[s]" (stat stddev [x]); #2. USP 905 acceptance value AV = abs of M - mean + k.s with k = 2.4 and M clamped to 98.5-101.5; -> "[mref]" (math max 98.5 (math min 101.5 [m])); -> "[av]" (+ (math abs (- [mref] [m])) (* 2.4 [s])); #3. Is the batch mean on target 100 percent, z-test with the known method SD; -> "[z]" (stat ztest [x] 100 1.2); #4. Spread: sample and population variances; concat "mean = " [m] " %, s = " (math round [s] 3) ", AV = " (math round [av] 2) " (L1 = 15: " (if (<= [av] 15) {"pass"} {"fail"}) "), pvariance = " (math round (stat pvariance [x]) 3) ", z-test " [z]
mean = 99.14 %, s = 1.727, AV = 4.14 (L1 = 15: pass), pvariance = 2.684, z-test {"z": -2.2662989897873373, "p_value": 0.023433083242250855}- Stage 2 with 30 units: k = 2.0 and L2 = 25 % for each unit (
stat min,stat max). - Check the normality of the assays with
stat shapiro.
Population PK: renal and non-renal clearance
Clearance of 8 patients is regressed on creatinine clearance and body weight with no intercept (CL = a.CrCl + b.WT), then used to predict the clearance and the infusion rate of a new patient for a target concentration of 15 mg/L.
#1. Population PK: clearance of 8 patients in L/h with creatinine clearance in mL/min and weight in kg; -> "[x]" "[[35, 58], [52, 64], [68, 70], [80, 77], [95, 82], [110, 69], [61, 90], [120, 85]]"; -> "[cl]" "[2.6, 4.1, 4.4, 5.6, 5.8, 6.1, 5.0, 7.4]"; #2. CL = a.CrCl + b.WT, renal and non-renal parts, no intercept; pa rm load_from_json "rx_p4d_pk" [x] [cl]; pa rm set_no_intercept "rx_p4d_pk" true; -> "[p]" (pa rm estimate_regression_parameters "rx_p4d_pk"); -> "[se]" (pa rm estimate_regression_parameters_standard_errors "rx_p4d_pk"); -> "[r2]" (pa rm calculate_r_squared "rx_p4d_pk"); -> "[rse]" (pa rm estimate_regression_standard_error "rx_p4d_pk"); #3. Predicted clearance of a new patient, CrCl 40 and 60 kg, then maintenance dose rate for Css 15 mg/L; -> "[clnew]" (pa rm predict "rx_p4d_pk" "[40, 60]"); pa rm close "rx_p4d_pk"; concat "coefficients [CrCl, WT] = " (string replace (string replace [p] (concat [_n_] " ") "") [_n_] "") ", standard errors = " (string replace (string replace [se] (concat [_n_] " ") "") [_n_] "") ", R2 = " (math round [r2] 4) ", residual SE = " (math round [rse] 3) " L/h, new patient CL = " (math round [clnew] 2) " L/h, dose rate = " (math round (* 15 [clnew]) 0) " mg/h"
coefficients [CrCl, WT] = [0.040651202947506966,0.026677905116331634], standard errors = [0.004480714900747793,0.004912012826719722], R2 = 0.9976, residual SE = 0.3 L/h, new patient CL = 3.23 L/h, dose rate = 48 mg/h
- Without intercept the R2 is uncentered: compare with the model with intercept (
pa rm set_no_interceptfalse). - Look at
pa rm estimate_residualsto find an outlier patient.
Over-lubrication and disintegration time
Formulation development: tablets with 0.5 % and 1.5 % magnesium stearate are compared on their disintegration times with a non-parametric test, as the samples are small and skewed.
#1. Disintegration times in seconds of tablets with 0.5 % and 1.5 % magnesium stearate; -> "[lo]" "[62, 58, 71, 66, 60, 64, 69]"; -> "[hi]" "[88, 79, 95, 84, 102, 91, 86]"; #2. Over-lubrication slows disintegration: non-parametric two-sample test; -> "[mw]" (stat mann_whitney [lo] [hi]); #3. Robust summary of each batch; concat "median 0.5 % = " (stat median [lo]) " s, median 1.5 % = " (stat median [hi]) " s, ratio = " (math round (/ (stat median [hi]) (stat median [lo])) 2) ", Mann-Whitney " [mw] ", both below the 15 min limit: " (< (stat max [hi]) 900)
median 0.5 % = 64 s, median 1.5 % = 88 s, ratio = 1.38, Mann-Whitney {"u": 0, "p_value": 5.827505827505828E-4, "method": "exact"}, both below the 15 min limit: 1- Use
stat frequencyon the disintegration classes of a larger lot. - Fit the disintegration time versus the lubricant level with
stat fitlinear.
