Repository navigation
Expand file tree
/
Copy pathcio_mrgsolve_model.R
More file actions
740 lines (664 loc) · 37 KB
/
Copy pathcio_mrgsolve_model.R
File metadata and controls
740 lines (664 loc) · 37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
## =============================================================================
## cio_mrgsolve_model.R
## Cisplatin-Induced Ototoxicity (CIO) — QSP model
## 시스플라틴 유발 이독성 정량적 시스템 약리학 모델
##
## 73 ODEs
## 25 systemic / cochlear-global states
## 48 = 8 tonotopic bands x 6 states
## (labile Pt, bound Pt, glutathione, OHC, IHC, spiral ganglion)
##
## The eight bands sit at their GREENWOOD positions for 0.25, 0.5, 1, 2, 4, 6,
## 8 and 12.5 kHz, so the audiogram is READ OFF a spatial gradient rather than
## fitted eight times over.
##
## ---------------------------------------------------------------------------
## THE FOUR STRUCTURAL CHOICES THAT DO THE WORK
## ---------------------------------------------------------------------------
## 1. Cochlear platinum is a STOCK, not a concentration, and it is split into
## a LABILE redox-active pool (t1/2 TLAB_D = 60 d) and a BOUND inert pool
## (t1/2 TRET_D = 2 y). Only the first does damage; the second is what a
## mass spectrometer still finds decades later. Changing TRET_D by 240-fold
## moves the audiogram by 0.00 dB — retained platinum is a MARKER.
##
## 2. The cochlea is reached through a CASCADE:
## free plasma Pt -> stria vascularis -> perilymph -> hair cell
## Free plasma platinum has a 22 min half-life; perilymph platinum peaks at
## 6.9 h. At 6 h, 0.0039% of the plasma exposure but 79% of the cochlear
## uptake is still ahead of you. The entire 6-hour sodium-thiosulfate rule
## is that one lag, and nothing else.
##
## 3. Glutathione is consumed at a SATURATING rate by the oxidant flux, so each
## band has a critical labile load
## PT*_j = KSYN*GMAX_j / (KCON*KROS)
## above which its reserve collapses. Ototoxicity is a threshold sweeping
## apex-ward as cumulative dose rises, not a curve fitted per frequency.
##
## 4. Tonotopic vulnerability is PT*_j / uptake_j, i.e. the PRODUCT of a
## reserve gradient (apex/base 2.63) and an uptake gradient (base/apex
## 1.98). Deleting the reserve gradient removes 96% of the audiogram
## slope; deleting the uptake gradient removes 57%.
##
## ---------------------------------------------------------------------------
## VERIFICATION
## ---------------------------------------------------------------------------
## Every equation below was first written and executed in an independent Python
## implementation (`cio_reference_model.py`), whose full run is saved as
## `cio_reference_output.txt`. That exercise found and fixed three real
## defects, each of which is documented at the point where it was fixed:
## (a) the integration driver carried the state at the last REQUESTED output
## time rather than at the interval end, silently truncating state
## between dose intervals;
## (b) intratympanic thiosulfate was applied to the well-mixed perilymph
## pool, which made a round-window bolus saturate the whole cochlea and
## destroyed the base-ward gradient that is the point of the route;
## (c) a single retained-platinum pool made post-treatment progression run
## to +46 dB over two years, because a pool with a 2-year half-life keeps
## the death hazard at its treatment-era value forever.
##
## Units: time h, platinum uM (free plasma) or normalised tissue units,
## thiosulfate uM, GFR mL/min, thresholds dB HL, EP mV.
##
## DOSING CONVENTION: compartments carrying a concentration (CISC, STSC, NACC)
## are dosed in CONCENTRATION units, i.e. amt = (umol dose)/(volume in L).
## The helper `cio_ev()` at the foot of this file does that conversion.
## =============================================================================
library(mrgsolve)
code <- '
$PROB
# Cisplatin-Induced Ototoxicity (CIO) — 73-ODE QSP model
# 8 tonotopic bands at Greenwood positions for 0.25-12.5 kHz
$PARAM @annotated
// ---- patient -------------------------------------------------------------
BSA : 1.73 : body surface area (m2)
GFR0 : 100 : baseline glomerular filtration rate (mL/min)
AGE : 8 : age (years), scales cochlear antioxidant reserve
AGEK : 4 : age at half-maximal maturation of that reserve (years)
AGEMIN : 0.62 : reserve floor in the neonate (fraction of adult)
// ---- cisplatin PK, free (ultrafilterable) platinum ------------------------
// Free platinum leaving plasma is excreted, protein-bound, or already
// covalently bound in tissue; none returns as reactive drug, so K21 = 0.
VC : 20 : central volume for free platinum (L)
KBIND : 1.30 : irreversible binding to plasma protein (1/h)
CLRSL : 0.054 : renal clearance per mL/min of GFR (L/h per mL/min)
K12 : 0.30 : free Pt to tissue (1/h)
K21 : 0.0 : tissue to free Pt (1/h) - irreversible sink
KELB : 0.0060 : elimination of protein-bound platinum (1/h)
// ---- kidney ---------------------------------------------------------------
KKID : 0.55 : OCT2-mediated cortical uptake (1/h, tracer: no plasma sink)
KKOUT : 0.030 : cortical platinum efflux (1/h)
KTUB : 0.0200 : proximal tubular injury formation (1/h)
KT50 : 9.0 : cortical platinum at half-maximal injury
KREPT : 0.0060 : tubular repair (1/h)
KLOSS : 0.0120 : reversible GFR loss per unit injury (1/h)
KREC : 0.0060 : recovery of reversible GFR loss (1/h)
KPERM : 0.00016 : permanent nephron loss per unit injury (1/h)
// ---- tumour ---------------------------------------------------------------
QT : 0.90 : perfusion-limited exchange at TUMPERF = 1 (1/h)
TUMPERF : 1.0 : 1.0 well-perfused localised, 0.15 disseminated
KPTUM : 1.0 : tumour:plasma partition
KADF : 0.55 : Pt-DNA adduct formation (1/h)
FADC : 1.0 : adduct potency multiplier (0.25 for carboplatin)
KREPAIR : 0.018 : nucleotide excision repair of adducts (1/h)
KKILL : 0.045 : log-kill per adduct-hour
// ---- cochlear route: plasma -> stria -> perilymph -------------------------
KINBL : 0.085 : free plasma Pt into stria vascularis (1/h)
KSTRO : 0.050 : strial platinum efflux (1/h)
KSTP : 0.150 : stria into perilymph (1/h)
KOUTPE : 0.120 : perilymph platinum clearance (1/h)
FURO : 0 : loop diuretic co-administration (0/1)
FUROF : 1.45 : fold increase in KINBL on furosemide
// ---- cochlear route: perilymph -> hair cell -------------------------------
KUPT : 0.025 : perilymph into organ of Corti (1/h)
BUPT : 0.95 : base-ward uptake gradient (log-slope over x)
TLAB_D : 60 : half-life of the labile redox-active pool (d)
FBND : 0.75 : fraction of labile platinum that becomes covalently bound
TRET_D : 730 : half-life of the bound inert pool (d)
// ---- redox ----------------------------------------------------------------
GSH0 : 1.00 : apical glutathione capacity (normalised)
BGSH : 1.35 : base-ward decline in reserve (log-slope over x)
KSYN : 0.045 : glutathione resynthesis (1/h)
KCON : 0.02720 : saturating glutathione consumption per unit oxidant flux
KMG : 0.050 : Michaelis constant of that consumption
KROS : 1.00 : oxidant flux per unit labile platinum
RBASE : 0.010 : constitutive oxidant flux
KSCV : 1.00 : scavenging strength of glutathione
KBOX : 0.030 : non-glutathione floor of antioxidant defence
NOISE : 0 : concurrent high-level noise exposure (0/1)
FNOISE : 0.16 : oxidant-flux multiplier from noise
AMGLY : 0 : concurrent aminoglycoside (0/1)
FAG : 0.26 : oxidant-flux multiplier from aminoglycoside
// ---- cell death -----------------------------------------------------------
KAP : 0.00220 : maximal hair-cell death rate (1/h)
OXC : 9.0 : oxidative stress at half-maximal death rate
HILL : 1.70 : steepness of the death function
FIHC : 0.30 : inner hair cells are more resistant than outer
FSGN : 0.10 : direct spiral-ganglion sensitivity
KDEAFF : 0.0016 : secondary ganglion loss after inner-hair-cell loss (1/h)
GINFL : 0.85 : inflammation multiplier on the death rate
// ---- stria vascularis and endocochlear potential --------------------------
KSV : 0.0060 : strial injury rate (1/h)
KSVREP : 0.00008 : strial repair (1/h)
OXCSV : 0.80 : strial stress at half-maximal injury
EP0 : 85 : normal endocochlear potential (mV)
KEP : 0.25 : EP equilibration with strial function (1/h)
GEP : 0.55 : exponent linking EP to cochlear amplifier gain
// ---- cochlear inflammation ------------------------------------------------
KINF : 0.010 : induction by the damage signal (1/h)
KINFOUT : 0.030 : resolution (1/h)
// ---- audiometry -----------------------------------------------------------
TSO : 48 : dB shift at complete loss of the cochlear amplifier
GTS : 2.20 : curvature of amplifier loss into dB
TSI : 42 : further dB shift from inner-hair-cell (dead-region) loss
TSMAX : 110 : audiometer ceiling (dB)
// ---- sodium thiosulfate ---------------------------------------------------
// Thiosulfate is a small hydrophilic anion and reaches perilymph directly,
// not through the transporter-mediated strial route platinum must use.
VCS : 20 : central volume (L)
KELS : 1.00 : elimination (1/h)
K12S : 0.55 : central to peripheral (1/h)
K21S : 0.40 : peripheral to central (1/h)
KINBLS : 0.010 : plasma into perilymph (1/h)
KOUTPES : 0.500 : perilymph clearance of thiosulfate (1/h)
K2STS : 0.006 : 2nd-order Pt + thiosulfate inactivation (1/(uM*h))
K2LOC : 0.002 : local block of hair-cell platinum uptake (1/uM)
BSTS : 0.45 : maximal fractional boost of glutathione capacity
KSTS : 60 : concentration at half-maximal boost (uM)
KITA : 0.55 : round-window absorption of an intratympanic dose (1/h)
FRW : 0.005 : fraction of a middle-ear dose crossing the round window
VPERI : 1.6e-4 : human perilymph volume (L)
KITOUT : 1.20 : clearance of intratympanically-derived thiosulfate (1/h)
BIT : 2.20 : base-ward gradient of intratympanic delivery
// ---- N-acetylcysteine -----------------------------------------------------
VCN : 30 : central volume (L)
KELN : 0.35 : elimination (1/h)
KINBLN : 0.030 : plasma into perilymph (1/h)
KOUTPEN : 0.30 : perilymph clearance (1/h)
BNAC : 0.40 : maximal fractional boost of glutathione capacity
KNAC : 40 : concentration at half-maximal boost (uM)
$PARAM @annotated
// ---- Greenwood positions of the eight audiometric bands -------------------
// f(Hz) = 165.4*(10^(2.1x) - 0.88), x = 0 apex .. 1 base
XP1 : 0.180318 : Greenwood position of the 0.25 kHz band (0 apex, 1 base)
XP2 : 0.281617 : Greenwood position of the 0.5 kHz band (0 apex, 1 base)
XP3 : 0.400228 : Greenwood position of the 1 kHz band (0 apex, 1 base)
XP4 : 0.530002 : Greenwood position of the 2 kHz band (0 apex, 1 base)
XP5 : 0.666213 : Greenwood position of the 4 kHz band (0 apex, 1 base)
XP6 : 0.747631 : Greenwood position of the 6 kHz band (0 apex, 1 base)
XP7 : 0.805898 : Greenwood position of the 8 kHz band (0 apex, 1 base)
XP8 : 0.896858 : Greenwood position of the 12.5 kHz band (0 apex, 1 base)
$CMT @annotated
CISC : free (ultrafilterable) platinum, plasma (uM)
CISB : platinum irreversibly bound to plasma protein (uM)
CISP : tissue-bound platinum, terminal sink (uM)
KIDPT : renal cortical platinum
TUBI : proximal tubular injury (0-1)
GFRL : reversible fractional GFR loss
GPERM : permanent fractional nephron loss
TUMPT : free platinum in tumour interstitium
TUMAD : tumour Pt-DNA adducts
TUMLK : cumulative tumour log-kill
STRPT : stria vascularis platinum depot
PERI : perilymph platinum (uM)
SVF : strial functional integrity (0-1)
EP : endocochlear potential (mV)
INFL : cochlear inflammation index
STSC : sodium thiosulfate, plasma (uM)
STSP : sodium thiosulfate, peripheral (uM)
STSPE : systemically-derived thiosulfate in perilymph (uM)
STSIT : intratympanically-derived thiosulfate in perilymph (uM)
STSTU : thiosulfate in tumour interstitium (uM)
ITD : intratympanic middle-ear depot (umol)
NACC : N-acetylcysteine, plasma (uM)
NACPE : N-acetylcysteine, perilymph (uM)
CUMD : cumulative cisplatin dose tracker (mg/m2)
PTAUC : cumulative mean labile cochlear platinum (AUC)
$CMT
PT1 PT2 PT3 PT4 PT5 PT6 PT7 PT8
PTB1 PTB2 PTB3 PTB4 PTB5 PTB6 PTB7 PTB8
GSH1 GSH2 GSH3 GSH4 GSH5 GSH6 GSH7 GSH8
OHC1 OHC2 OHC3 OHC4 OHC5 OHC6 OHC7 OHC8
IHC1 IHC2 IHC3 IHC4 IHC5 IHC6 IHC7 IHC8
SGN1 SGN2 SGN3 SGN4 SGN5 SGN6 SGN7 SGN8
$MAIN
// Antioxidant reserve matures with age; normalised so an adult scores 1.0.
double AGEF = (AGEMIN + (1.0-AGEMIN)*AGE/(AGEK+AGE)) /
(AGEMIN + (1.0-AGEMIN)*25.0/(AGEK+25.0));
SVF_0 = 1.0;
EP_0 = EP0;
double GMAX1 = GSH0*exp(-BGSH*XP1)*AGEF; GSH1_0 = GMAX1; OHC1_0 = 1.0; IHC1_0 = 1.0; SGN1_0 = 1.0;
double GMAX2 = GSH0*exp(-BGSH*XP2)*AGEF; GSH2_0 = GMAX2; OHC2_0 = 1.0; IHC2_0 = 1.0; SGN2_0 = 1.0;
double GMAX3 = GSH0*exp(-BGSH*XP3)*AGEF; GSH3_0 = GMAX3; OHC3_0 = 1.0; IHC3_0 = 1.0; SGN3_0 = 1.0;
double GMAX4 = GSH0*exp(-BGSH*XP4)*AGEF; GSH4_0 = GMAX4; OHC4_0 = 1.0; IHC4_0 = 1.0; SGN4_0 = 1.0;
double GMAX5 = GSH0*exp(-BGSH*XP5)*AGEF; GSH5_0 = GMAX5; OHC5_0 = 1.0; IHC5_0 = 1.0; SGN5_0 = 1.0;
double GMAX6 = GSH0*exp(-BGSH*XP6)*AGEF; GSH6_0 = GMAX6; OHC6_0 = 1.0; IHC6_0 = 1.0; SGN6_0 = 1.0;
double GMAX7 = GSH0*exp(-BGSH*XP7)*AGEF; GSH7_0 = GMAX7; OHC7_0 = 1.0; IHC7_0 = 1.0; SGN7_0 = 1.0;
double GMAX8 = GSH0*exp(-BGSH*XP8)*AGEF; GSH8_0 = GMAX8; OHC8_0 = 1.0; IHC8_0 = 1.0; SGN8_0 = 1.0;
$ODE
double CISCp = fmax(CISC ,0.0);
double CISPp = fmax(CISP ,0.0);
double KIDPTp = fmax(KIDPT,0.0);
double TUBIp = fmin(fmax(TUBI,0.0),1.0);
double TUMPTp = fmax(TUMPT,0.0);
double STRPTp = fmax(STRPT,0.0);
double PERIp = fmax(PERI ,0.0);
double SVFp = fmin(fmax(SVF,0.0),1.0);
double STSCp = fmax(STSC ,0.0);
double STSPEp = fmax(STSPE,0.0);
double STSITp = fmax(STSIT,0.0);
double STSTUp = fmax(STSTU,0.0);
double NACPEp = fmax(NACPE,0.0);
double AGEF = (AGEMIN + (1.0-AGEMIN)*AGE/(AGEK+AGE)) /
(AGEMIN + (1.0-AGEMIN)*25.0/(AGEK+25.0));
// ---- tonotopic gradients ------------------------------------------------
double upt1 = exp(BUPT*(XP1-0.5)); double itg1 = exp(BIT*(XP1-0.5)); double gmax1 = GSH0*exp(-BGSH*XP1)*AGEF;
double upt2 = exp(BUPT*(XP2-0.5)); double itg2 = exp(BIT*(XP2-0.5)); double gmax2 = GSH0*exp(-BGSH*XP2)*AGEF;
double upt3 = exp(BUPT*(XP3-0.5)); double itg3 = exp(BIT*(XP3-0.5)); double gmax3 = GSH0*exp(-BGSH*XP3)*AGEF;
double upt4 = exp(BUPT*(XP4-0.5)); double itg4 = exp(BIT*(XP4-0.5)); double gmax4 = GSH0*exp(-BGSH*XP4)*AGEF;
double upt5 = exp(BUPT*(XP5-0.5)); double itg5 = exp(BIT*(XP5-0.5)); double gmax5 = GSH0*exp(-BGSH*XP5)*AGEF;
double upt6 = exp(BUPT*(XP6-0.5)); double itg6 = exp(BIT*(XP6-0.5)); double gmax6 = GSH0*exp(-BGSH*XP6)*AGEF;
double upt7 = exp(BUPT*(XP7-0.5)); double itg7 = exp(BIT*(XP7-0.5)); double gmax7 = GSH0*exp(-BGSH*XP7)*AGEF;
double upt8 = exp(BUPT*(XP8-0.5)); double itg8 = exp(BIT*(XP8-0.5)); double gmax8 = GSH0*exp(-BGSH*XP8)*AGEF;
// ---- renal function -----------------------------------------------------
double floss = fmin(0.85, fmax(GFRL,0.0) + fmax(GPERM,0.0));
double GFRt = GFR0*(1.0 - floss);
// ---- cisplatin PK -------------------------------------------------------
dxdt_CISC = -KBIND*CISCp - (CLRSL*GFRt/VC)*CISCp - K12*CISCp + K21*CISPp
- K2STS*CISCp*STSCp;
dxdt_CISB = KBIND*CISCp - KELB*fmax(CISB,0.0);
dxdt_CISP = K12*CISCp - K21*CISPp;
// ---- kidney and nephrotoxicity -----------------------------------------
dxdt_KIDPT = KKID*CISCp - KKOUT*KIDPTp;
dxdt_TUBI = KTUB*KIDPTp/(KT50+KIDPTp)*(1.0-TUBIp) - KREPT*TUBIp;
dxdt_GFRL = KLOSS*TUBIp - KREC*fmax(GFRL,0.0);
dxdt_GPERM = KPERM*TUBIp;
// ---- tumour -------------------------------------------------------------
double qt = QT*TUMPERF;
dxdt_TUMPT = qt*(CISCp - TUMPTp/KPTUM) - KADF*TUMPTp - K2STS*TUMPTp*STSTUp;
dxdt_TUMAD = KADF*FADC*TUMPTp - KREPAIR*fmax(TUMAD,0.0);
dxdt_TUMLK = KKILL*fmax(TUMAD,0.0);
dxdt_STSTU = qt*(STSCp - STSTUp) - K2STS*TUMPTp*STSTUp;
// ---- cochlear route -----------------------------------------------------
// NB: thiosulfate reaches plasma and perilymph but NOT the intracellular
// strial depot, so the stria keeps refilling perilymph after the rescue has
// washed out. That is what caps the achievable protection at ~50%.
double kin_bl = KINBL*(1.0 + FURO*(FUROF-1.0));
double stsloc1 = STSPE + STSIT*itg1;
double up1 = KUPT*upt1*PERIp/(1.0 + K2LOC*stsloc1);
double stsloc2 = STSPE + STSIT*itg2;
double up2 = KUPT*upt2*PERIp/(1.0 + K2LOC*stsloc2);
double stsloc3 = STSPE + STSIT*itg3;
double up3 = KUPT*upt3*PERIp/(1.0 + K2LOC*stsloc3);
double stsloc4 = STSPE + STSIT*itg4;
double up4 = KUPT*upt4*PERIp/(1.0 + K2LOC*stsloc4);
double stsloc5 = STSPE + STSIT*itg5;
double up5 = KUPT*upt5*PERIp/(1.0 + K2LOC*stsloc5);
double stsloc6 = STSPE + STSIT*itg6;
double up6 = KUPT*upt6*PERIp/(1.0 + K2LOC*stsloc6);
double stsloc7 = STSPE + STSIT*itg7;
double up7 = KUPT*upt7*PERIp/(1.0 + K2LOC*stsloc7);
double stsloc8 = STSPE + STSIT*itg8;
double up8 = KUPT*upt8*PERIp/(1.0 + K2LOC*stsloc8);
double upsum = (up1+up2+up3+up4+up5+up6+up7+up8)/8.0;
dxdt_STRPT = kin_bl*CISCp - (KSTRO+KSTP)*STRPTp;
dxdt_PERI = KSTP*STRPTp - KOUTPE*PERIp - K2STS*PERIp*STSPEp - upsum;
double ktot = log(2.0)/(TLAB_D*24.0);
double kbnd = FBND*ktot;
double klab = (1.0-FBND)*ktot;
double koutc = log(2.0)/(TRET_D*24.0);
// ---- redox: saturating consumption gives a per-band threshold -----------
double env = 1.0 + FNOISE*NOISE + FAG*AMGLY;
double flux1 = (KROS*fmax(PT1,0.0) + RBASE)*env;
double boost1 = 1.0 + BSTS*stsloc1/(KSTS+stsloc1) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh1 = fmax(GSH1,0.0);
double OX1 = flux1/(KSCV*gsh1 + KBOX);
double hz1 = KAP*pow(OX1,HILL)/(pow(OXC,HILL)+pow(OX1,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux2 = (KROS*fmax(PT2,0.0) + RBASE)*env;
double boost2 = 1.0 + BSTS*stsloc2/(KSTS+stsloc2) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh2 = fmax(GSH2,0.0);
double OX2 = flux2/(KSCV*gsh2 + KBOX);
double hz2 = KAP*pow(OX2,HILL)/(pow(OXC,HILL)+pow(OX2,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux3 = (KROS*fmax(PT3,0.0) + RBASE)*env;
double boost3 = 1.0 + BSTS*stsloc3/(KSTS+stsloc3) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh3 = fmax(GSH3,0.0);
double OX3 = flux3/(KSCV*gsh3 + KBOX);
double hz3 = KAP*pow(OX3,HILL)/(pow(OXC,HILL)+pow(OX3,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux4 = (KROS*fmax(PT4,0.0) + RBASE)*env;
double boost4 = 1.0 + BSTS*stsloc4/(KSTS+stsloc4) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh4 = fmax(GSH4,0.0);
double OX4 = flux4/(KSCV*gsh4 + KBOX);
double hz4 = KAP*pow(OX4,HILL)/(pow(OXC,HILL)+pow(OX4,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux5 = (KROS*fmax(PT5,0.0) + RBASE)*env;
double boost5 = 1.0 + BSTS*stsloc5/(KSTS+stsloc5) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh5 = fmax(GSH5,0.0);
double OX5 = flux5/(KSCV*gsh5 + KBOX);
double hz5 = KAP*pow(OX5,HILL)/(pow(OXC,HILL)+pow(OX5,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux6 = (KROS*fmax(PT6,0.0) + RBASE)*env;
double boost6 = 1.0 + BSTS*stsloc6/(KSTS+stsloc6) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh6 = fmax(GSH6,0.0);
double OX6 = flux6/(KSCV*gsh6 + KBOX);
double hz6 = KAP*pow(OX6,HILL)/(pow(OXC,HILL)+pow(OX6,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux7 = (KROS*fmax(PT7,0.0) + RBASE)*env;
double boost7 = 1.0 + BSTS*stsloc7/(KSTS+stsloc7) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh7 = fmax(GSH7,0.0);
double OX7 = flux7/(KSCV*gsh7 + KBOX);
double hz7 = KAP*pow(OX7,HILL)/(pow(OXC,HILL)+pow(OX7,HILL))*(1.0+GINFL*fmax(INFL,0.0));
double flux8 = (KROS*fmax(PT8,0.0) + RBASE)*env;
double boost8 = 1.0 + BSTS*stsloc8/(KSTS+stsloc8) + BNAC*NACPEp/(KNAC+NACPEp);
double gsh8 = fmax(GSH8,0.0);
double OX8 = flux8/(KSCV*gsh8 + KBOX);
double hz8 = KAP*pow(OX8,HILL)/(pow(OXC,HILL)+pow(OX8,HILL))*(1.0+GINFL*fmax(INFL,0.0));
// ---- band states --------------------------------------------------------
dxdt_PT1 = up1 - (kbnd+klab)*fmax(PT1,0.0);
dxdt_PTB1 = kbnd*fmax(PT1,0.0) - koutc*fmax(PTB1,0.0);
dxdt_GSH1 = KSYN*(gmax1*boost1 - gsh1) - KCON*flux1*gsh1/(KMG+gsh1);
dxdt_OHC1 = -hz1*fmax(OHC1,0.0);
dxdt_IHC1 = -FIHC*hz1*fmax(IHC1,0.0);
dxdt_SGN1 = -FSGN*hz1*fmax(SGN1,0.0) - KDEAFF*(1.0-fmax(IHC1,0.0))*fmax(SGN1,0.0);
dxdt_PT2 = up2 - (kbnd+klab)*fmax(PT2,0.0);
dxdt_PTB2 = kbnd*fmax(PT2,0.0) - koutc*fmax(PTB2,0.0);
dxdt_GSH2 = KSYN*(gmax2*boost2 - gsh2) - KCON*flux2*gsh2/(KMG+gsh2);
dxdt_OHC2 = -hz2*fmax(OHC2,0.0);
dxdt_IHC2 = -FIHC*hz2*fmax(IHC2,0.0);
dxdt_SGN2 = -FSGN*hz2*fmax(SGN2,0.0) - KDEAFF*(1.0-fmax(IHC2,0.0))*fmax(SGN2,0.0);
dxdt_PT3 = up3 - (kbnd+klab)*fmax(PT3,0.0);
dxdt_PTB3 = kbnd*fmax(PT3,0.0) - koutc*fmax(PTB3,0.0);
dxdt_GSH3 = KSYN*(gmax3*boost3 - gsh3) - KCON*flux3*gsh3/(KMG+gsh3);
dxdt_OHC3 = -hz3*fmax(OHC3,0.0);
dxdt_IHC3 = -FIHC*hz3*fmax(IHC3,0.0);
dxdt_SGN3 = -FSGN*hz3*fmax(SGN3,0.0) - KDEAFF*(1.0-fmax(IHC3,0.0))*fmax(SGN3,0.0);
dxdt_PT4 = up4 - (kbnd+klab)*fmax(PT4,0.0);
dxdt_PTB4 = kbnd*fmax(PT4,0.0) - koutc*fmax(PTB4,0.0);
dxdt_GSH4 = KSYN*(gmax4*boost4 - gsh4) - KCON*flux4*gsh4/(KMG+gsh4);
dxdt_OHC4 = -hz4*fmax(OHC4,0.0);
dxdt_IHC4 = -FIHC*hz4*fmax(IHC4,0.0);
dxdt_SGN4 = -FSGN*hz4*fmax(SGN4,0.0) - KDEAFF*(1.0-fmax(IHC4,0.0))*fmax(SGN4,0.0);
dxdt_PT5 = up5 - (kbnd+klab)*fmax(PT5,0.0);
dxdt_PTB5 = kbnd*fmax(PT5,0.0) - koutc*fmax(PTB5,0.0);
dxdt_GSH5 = KSYN*(gmax5*boost5 - gsh5) - KCON*flux5*gsh5/(KMG+gsh5);
dxdt_OHC5 = -hz5*fmax(OHC5,0.0);
dxdt_IHC5 = -FIHC*hz5*fmax(IHC5,0.0);
dxdt_SGN5 = -FSGN*hz5*fmax(SGN5,0.0) - KDEAFF*(1.0-fmax(IHC5,0.0))*fmax(SGN5,0.0);
dxdt_PT6 = up6 - (kbnd+klab)*fmax(PT6,0.0);
dxdt_PTB6 = kbnd*fmax(PT6,0.0) - koutc*fmax(PTB6,0.0);
dxdt_GSH6 = KSYN*(gmax6*boost6 - gsh6) - KCON*flux6*gsh6/(KMG+gsh6);
dxdt_OHC6 = -hz6*fmax(OHC6,0.0);
dxdt_IHC6 = -FIHC*hz6*fmax(IHC6,0.0);
dxdt_SGN6 = -FSGN*hz6*fmax(SGN6,0.0) - KDEAFF*(1.0-fmax(IHC6,0.0))*fmax(SGN6,0.0);
dxdt_PT7 = up7 - (kbnd+klab)*fmax(PT7,0.0);
dxdt_PTB7 = kbnd*fmax(PT7,0.0) - koutc*fmax(PTB7,0.0);
dxdt_GSH7 = KSYN*(gmax7*boost7 - gsh7) - KCON*flux7*gsh7/(KMG+gsh7);
dxdt_OHC7 = -hz7*fmax(OHC7,0.0);
dxdt_IHC7 = -FIHC*hz7*fmax(IHC7,0.0);
dxdt_SGN7 = -FSGN*hz7*fmax(SGN7,0.0) - KDEAFF*(1.0-fmax(IHC7,0.0))*fmax(SGN7,0.0);
dxdt_PT8 = up8 - (kbnd+klab)*fmax(PT8,0.0);
dxdt_PTB8 = kbnd*fmax(PT8,0.0) - koutc*fmax(PTB8,0.0);
dxdt_GSH8 = KSYN*(gmax8*boost8 - gsh8) - KCON*flux8*gsh8/(KMG+gsh8);
dxdt_OHC8 = -hz8*fmax(OHC8,0.0);
dxdt_IHC8 = -FIHC*hz8*fmax(IHC8,0.0);
dxdt_SGN8 = -FSGN*hz8*fmax(SGN8,0.0) - KDEAFF*(1.0-fmax(IHC8,0.0))*fmax(SGN8,0.0);
// ---- stria vascularis and endocochlear potential ------------------------
double ox_sv = KROS*STRPTp*env/(KSCV*GSH0 + KBOX);
dxdt_SVF = -KSV*pow(ox_sv,HILL)/(pow(OXCSV,HILL)+pow(ox_sv,HILL))*SVFp
+ KSVREP*(1.0-SVFp);
dxdt_EP = KEP*(EP0*SVFp - fmax(EP,0.0));
// ---- cochlear inflammation ---------------------------------------------
double hzbar = (hz1+hz2+hz3+hz4+hz5+hz6+hz7+hz8)/8.0;
dxdt_INFL = KINF*(hzbar/KAP)*(1.0-fmax(INFL,0.0)) - KINFOUT*fmax(INFL,0.0);
// ---- sodium thiosulfate -------------------------------------------------
dxdt_STSC = -KELS*STSCp - K12S*STSCp + K21S*fmax(STSP,0.0) - K2STS*CISCp*STSCp;
dxdt_STSP = K12S*STSCp - K21S*fmax(STSP,0.0);
dxdt_STSPE = KINBLS*STSCp - KOUTPES*STSPEp - K2STS*PERIp*STSPEp;
dxdt_ITD = -KITA*fmax(ITD,0.0);
dxdt_STSIT = KITA*fmax(ITD,0.0)*FRW/VPERI - KITOUT*STSITp - K2STS*PERIp*STSITp;
// ---- N-acetylcysteine ---------------------------------------------------
dxdt_NACC = -KELN*fmax(NACC,0.0) - KINBLN*fmax(NACC,0.0);
dxdt_NACPE = KINBLN*fmax(NACC,0.0) - KOUTPEN*NACPEp;
// ---- trackers -----------------------------------------------------------
dxdt_CUMD = 0.0;
dxdt_PTAUC = (fmax(PT1,0.0)+fmax(PT2,0.0)+fmax(PT3,0.0)+fmax(PT4,0.0)+
fmax(PT5,0.0)+fmax(PT6,0.0)+fmax(PT7,0.0)+fmax(PT8,0.0))/8.0;
$TABLE
// ---- threshold shift per band ------------------------------------------
double amp1 = fmax(fmin(OHC1,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS1 = fmin(TSO*pow(1.0-amp1,GTS) + TSI*(1.0-fmax(fmin(IHC1,1.0),0.0)), TSMAX);
double amp2 = fmax(fmin(OHC2,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS2 = fmin(TSO*pow(1.0-amp2,GTS) + TSI*(1.0-fmax(fmin(IHC2,1.0),0.0)), TSMAX);
double amp3 = fmax(fmin(OHC3,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS3 = fmin(TSO*pow(1.0-amp3,GTS) + TSI*(1.0-fmax(fmin(IHC3,1.0),0.0)), TSMAX);
double amp4 = fmax(fmin(OHC4,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS4 = fmin(TSO*pow(1.0-amp4,GTS) + TSI*(1.0-fmax(fmin(IHC4,1.0),0.0)), TSMAX);
double amp5 = fmax(fmin(OHC5,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS5 = fmin(TSO*pow(1.0-amp5,GTS) + TSI*(1.0-fmax(fmin(IHC5,1.0),0.0)), TSMAX);
double amp6 = fmax(fmin(OHC6,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS6 = fmin(TSO*pow(1.0-amp6,GTS) + TSI*(1.0-fmax(fmin(IHC6,1.0),0.0)), TSMAX);
double amp7 = fmax(fmin(OHC7,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS7 = fmin(TSO*pow(1.0-amp7,GTS) + TSI*(1.0-fmax(fmin(IHC7,1.0),0.0)), TSMAX);
double amp8 = fmax(fmin(OHC8,1.0),0.0)*pow(fmax(EP,0.0)/EP0, GEP);
double TS8 = fmin(TSO*pow(1.0-amp8,GTS) + TSI*(1.0-fmax(fmin(IHC8,1.0),0.0)), TSMAX);
// ---- speech-frequency pure-tone average (0.5/1/2/4 kHz) -----------------
double PTA = (TS2 + TS3 + TS4 + TS5)/4.0;
// ---- Brock grade: 40 dB criterion at 8/4/2/1 kHz, marching apex-ward ----
int BROCK = 0;
if(TS7 >= 40.0) BROCK = 1;
if(TS5 >= 40.0) BROCK = 2;
if(TS4 >= 40.0) BROCK = 3;
if(TS3 >= 40.0) BROCK = 4;
// ---- SIOP Boston Ototoxicity Scale: 20 dB criterion ---------------------
int SIOP = 0;
if(TS6 > 20.0 || TS7 > 20.0 || TS8 > 20.0) SIOP = 1;
if(TS5 > 20.0) SIOP = 2;
if(TS4 > 20.0) SIOP = 3;
if(TS3 > 20.0) SIOP = 4;
// ---- ASHA: >=20 dB at one frequency, or >=10 dB at two adjacent ---------
int ASHA = 0;
if(TS1>=20||TS2>=20||TS3>=20||TS4>=20||TS5>=20||TS6>=20||TS7>=20||TS8>=20) ASHA = 1;
if((TS1>=10&&TS2>=10)||(TS2>=10&&TS3>=10)||(TS3>=10&&TS4>=10)||
(TS4>=10&&TS5>=10)||(TS5>=10&&TS6>=10)||(TS6>=10&&TS7>=10)||
(TS7>=10&&TS8>=10)) ASHA = 1;
// ---- CTCAE v5.0 adult hearing-loss grade -------------------------------
double hi = fmax(fmax(TS4,TS5),fmax(TS6,TS7));
int CTCAE = 0;
if(hi >= 15.0) CTCAE = 1;
if(hi >= 25.0) CTCAE = 2;
if(PTA >= 25.0) CTCAE = 3;
if(PTA >= 40.0) CTCAE = 4;
// ---- speech-in-noise penalty: the part a pure-tone audiogram cannot see -
double syn = 1.0 - (fmax(fmin(IHC2,1.0),0.0)*fmax(fmin(SGN2,1.0),0.0) +
fmax(fmin(IHC3,1.0),0.0)*fmax(fmin(SGN3,1.0),0.0) +
fmax(fmin(IHC4,1.0),0.0)*fmax(fmin(SGN4,1.0),0.0) +
fmax(fmin(IHC5,1.0),0.0)*fmax(fmin(SGN5,1.0),0.0))/4.0;
double SNRLOSS = 12.0*syn;
// ---- other read-outs ----------------------------------------------------
double TINN = 1.0/(1.0 + exp(-(-2.2 + 0.055*(TS5+TS6+TS7+TS8)/4.0)));
double GFROUT = GFR0*(1.0 - fmin(0.85, fmax(GFRL,0.0)+fmax(GPERM,0.0)));
// Closed-form critical labile load at 8 kHz, PT* = KSYN*GMAX/(KCON*KROS).
// Above it the glutathione reserve of that band collapses; see the verification
// table in cio_reference_output.txt, where the cycle predicted by PT > PT*
// and the cycle observed from GSH < G* agree to within 0.05 cycles.
double AGEFt = (AGEMIN + (1.0-AGEMIN)*AGE/(AGEK+AGE)) /
(AGEMIN + (1.0-AGEMIN)*25.0/(AGEK+25.0));
double PTSTAR8 = KSYN*(GSH0*exp(-BGSH*XP7)*AGEFt)/(KCON*KROS);
double DPOAE = 100.0*fmax(fmin(OHC7,1.0),0.0); // OHC-specific read-out
$CAPTURE @annotated
TS1 : threshold shift at 0.25 kHz (dB)
TS2 : threshold shift at 0.5 kHz (dB)
TS3 : threshold shift at 1 kHz (dB)
TS4 : threshold shift at 2 kHz (dB)
TS5 : threshold shift at 4 kHz (dB)
TS6 : threshold shift at 6 kHz (dB)
TS7 : threshold shift at 8 kHz (dB)
TS8 : threshold shift at 12.5 kHz (dB)
PTA : speech-frequency pure-tone average (dB)
BROCK : Brock grade (0-4)
SIOP : SIOP Boston grade (0-4)
ASHA : ASHA significant-shift criterion met (0/1)
CTCAE : CTCAE v5.0 hearing-loss grade (0-4)
SNRLOSS : speech-in-noise penalty (dB SNR)
TINN : modelled tinnitus probability
GFROUT : glomerular filtration rate (mL/min)
DPOAE : distortion-product emission surrogate (% of normal)
PTSTAR8 : closed-form critical labile platinum load at 8 kHz
'
mod <- mcode("cio", code)
## =============================================================================
## Dosing helpers
## =============================================================================
MW_CIS <- 300.05 # g/mol, cisplatin
MW_CARB <- 371.25 # g/mol, carboplatin
MW_STS <- 248.2 # g/mol, sodium thiosulfate pentahydrate
MW_NAC <- 163.2 # g/mol, N-acetylcysteine
#\' Build an event table for one CIO scenario.
#\'
#\' @param cycles number of cisplatin cycles
#\' @param dose_mgm2 cisplatin dose per administration (mg/m2)
#\' @param cycle_h cycle length in hours (default 21 d)
#\' @param ndays administrations per cycle on consecutive days
#\' @param tinf infusion duration (h)
#\' @param sts_cycles 0-based cycle indices at which systemic thiosulfate is given
#\' @param sts_gm2 thiosulfate dose (g/m2)
#\' @param sts_delay delay after the end of the cisplatin infusion (h)
#\' @param it_cycles 0-based cycle indices for an intratympanic dose
#\' @param it_umol intratympanic dose (umol); 0.5 mL of 8% = 161 umol
#\' @param nac_cycles 0-based cycle indices for IV N-acetylcysteine
#\' @param nac_mg N-acetylcysteine dose (mg)
#\' @param bsa body surface area (m2)
cio_ev <- function(cycles = 6, dose_mgm2 = 100, cycle_h = 21*24, ndays = 1,
tinf = 1, sts_cycles = NULL, sts_gm2 = 20, sts_delay = 6,
it_cycles = NULL, it_umol = 161, nac_cycles = NULL,
nac_mg = 0, bsa = 1.73, carbo = FALSE) {
mw <- if (carbo) MW_CARB else MW_CIS
dose_umol <- dose_mgm2*bsa/mw*1e3/ndays
sts_umol <- sts_gm2*bsa/MW_STS*1e6
ev_list <- list()
for (c in seq_len(cycles) - 1L) {
t0 <- c*cycle_h
for (d in seq_len(ndays) - 1L) {
ev_list[[length(ev_list)+1L]] <-
ev(time = t0 + d*24, amt = dose_umol/20, cmt = "CISC", rate = dose_umol/20/tinf)
}
anchor <- t0 + (ndays-1L)*24 + tinf
if (!is.null(sts_cycles) && c %in% sts_cycles)
ev_list[[length(ev_list)+1L]] <-
ev(time = anchor + sts_delay, amt = sts_umol/20, cmt = "STSC",
rate = sts_umol/20/0.25)
if (!is.null(it_cycles) && c %in% it_cycles)
ev_list[[length(ev_list)+1L]] <-
ev(time = anchor + sts_delay, amt = it_umol, cmt = "ITD")
if (!is.null(nac_cycles) && c %in% nac_cycles)
ev_list[[length(ev_list)+1L]] <-
ev(time = anchor + sts_delay, amt = nac_mg/MW_NAC*1e3/30, cmt = "NACC",
rate = nac_mg/MW_NAC*1e3/30/0.5)
}
Reduce(`+`, ev_list)
}
cio_run <- function(mod, ev_tab, cycles = 6, cycle_h = 21*24, follow_h = 0,
delta = 6, ...) {
mrgsim(mod, events = ev_tab, end = cycles*cycle_h + follow_h, delta = delta,
atol = 1e-10, rtol = 1e-8, ...)
}
## =============================================================================
## SCENARIO LIBRARY (20 scenarios)
##
## Every scenario below has been executed in the Python reference
## implementation; the end-of-treatment read-outs it produced are quoted in
## the comment so that an mrgsolve run can be checked against them directly.
## Format: 8 kHz dB / speech-frequency PTA dB / Brock / SIOP.
## =============================================================================
cio_scenarios <- function(mod) {
S <- list()
## S01 adult head-and-neck / testicular backbone, 600 mg/m2 cumulative
## -> 45.3 / 9.54 / Brock 1 / SIOP 2 ; EP 76.1 mV ; GFR 79.9
S$S01 <- list(param = list(), ev = cio_ev(6, 100))
## S02 paediatric backbone, 480 mg/m2 cumulative, 3-year-old
## -> 32.5 / 6.03 / Brock 0 / SIOP 1
S$S02 <- list(param = list(AGE = 3), ev = cio_ev(6, 80))
## S03 S02 + sodium thiosulfate 20 g/m2 at 6 h (SIOPEL-6 protocol)
## -> 15.4 / 2.64 / Brock 0 / SIOP 1 ; 53% relative reduction at 8 kHz
S$S03 <- list(param = list(AGE = 3), ev = cio_ev(6, 80, sts_cycles = 0:5))
## S04 S02 + thiosulfate at 0 h — near-total otoprotection, but the tumour
## log-kill falls from 64.3 to 23.0, i.e. 64% of the efficacy is gone
## -> 3.1 / 0.68 / Brock 0 / SIOP 0
S$S04 <- list(param = list(AGE = 3),
ev = cio_ev(6, 80, sts_cycles = 0:5, sts_delay = 0))
## S05 S02 + intratympanic thiosulfate, 0.5 mL of 8% per cycle
## -> 15.2 / 3.06 / Brock 0 / SIOP 1 ; protection 21% at 0.25 kHz
## rising to 53% at 8 kHz, with ZERO measurable tumour exposure
S$S05 <- list(param = list(AGE = 3), ev = cio_ev(6, 80, it_cycles = 0:5))
## S06 S02 + IV N-acetylcysteine 150 mg/kg — the model says it buys 0.1 dB,
## because its perilymph window is far shorter than the platinum influx
## -> 32.4 / 5.94 / Brock 0 / SIOP 1
S$S06 <- list(param = list(AGE = 3),
ev = cio_ev(6, 80, nac_cycles = 0:5, nac_mg = 2250))
## S07 same 600 mg/m2 given as 20 mg/m2 x 5 days — fractionation buys 0.50 dB
## -> 44.6 / 9.04 / Brock 1 / SIOP 2
S$S07 <- list(param = list(), ev = cio_ev(6, 100, ndays = 5))
## S08 carboplatin 560 mg/m2 x 6 -> 1.0 / 0.24 / Brock 0 / SIOP 0
S$S08 <- list(param = list(FADC = 0.25, KINBL = 0.085*0.060, KKID = 0.55*0.25),
ev = cio_ev(6, 560, carbo = TRUE))
## S08b myeloablative carboplatin 1500 mg/m2 x 3 -> 2.3 / 0.49
S$S08b <- list(param = list(FADC = 0.25, KINBL = 0.085*0.060, KKID = 0.55*0.25),
ev = cio_ev(3, 1500, carbo = TRUE))
## S09 S01 + concurrent aminoglycoside -> 62.5 / 19.46 / Brock 2 / SIOP 3
S$S09 <- list(param = list(AMGLY = 1), ev = cio_ev(6, 100))
## S10 S01 + concurrent noise 85 dBA -> 57.1 / 15.36 / Brock 1 / SIOP 2
S$S10 <- list(param = list(NOISE = 1), ev = cio_ev(6, 100))
## S11 S01 + furosemide (opens the blood-labyrinth barrier)
## -> 69.3 / 27.21 / Brock 2 / SIOP 3 [most exposed prediction in the model]
S$S11 <- list(param = list(FURO = 1), ev = cio_ev(6, 100))
## S12 S02 in a 1-year-old -> 39.1 / 8.11 / Brock 0 / SIOP 1
S$S12 <- list(param = list(AGE = 1), ev = cio_ev(6, 80))
## S13 S02 in a 16-year-old -> 23.2 / 3.81 / Brock 0 / SIOP 1
S$S13 <- list(param = list(AGE = 16), ev = cio_ev(6, 80))
## S14 S01 followed by 24 months off treatment — the audiogram keeps moving
## -> 58.0 / 13.33 (from 45.3 / 9.54 at end of treatment)
S$S14 <- list(param = list(), ev = cio_ev(6, 100), follow_h = 24*730)
## S15 S01 with GFR clamped: isolates the nephro-oto amplification loop
## -> 43.6 / 8.91 (vs 45.3 / 9.54 with the loop intact)
S$S15 <- list(param = list(KLOSS = 0, KPERM = 0), ev = cio_ev(6, 100))
## S16 S01 with a uniform reserve gradient: 96% of the audiogram slope is lost
## -> 2.5 / 1.16
S$S16 <- list(param = list(BGSH = 0), ev = cio_ev(6, 100))
## S17 S01 with a uniform uptake gradient: 57% of the slope is lost
## -> 23.1 / 7.85
S$S17 <- list(param = list(BUPT = 0), ev = cio_ev(6, 100))
## S18 S01 + thiosulfate at 6 h -> 24.3 / 4.14 / Brock 0 / SIOP 1
S$S18 <- list(param = list(), ev = cio_ev(6, 100, sts_cycles = 0:5))
## S19 S01 in pre-existing CKD (GFR 45) -> 51.3 / 12.08 / Brock 1 / SIOP 2
S$S19 <- list(param = list(GFR0 = 45), ev = cio_ev(6, 100))
## S20 low-dose weekly 40 mg/m2 x 9 -> 9.1 / 1.54 / Brock 0 / SIOP 0
## but GFR 60.7, LOWER than the 600 mg/m2 q3w arm, because the tubular
## repair half-life is longer than the 7-day interval. Flagged in the
## references file as a prediction needing separate validation.
S$S20 <- list(param = list(), ev = cio_ev(9, 40, cycle_h = 7*24))
S
}
#\' Run the whole scenario library and return end-of-treatment read-outs.
cio_table <- function(mod) {
S <- cio_scenarios(mod)
do.call(rbind, lapply(names(S), function(nm) {
s <- S[[nm]]
fu <- if (is.null(s$follow_h)) 0 else s$follow_h
m <- if (length(s$param)) param(mod, s$param) else mod
ncy <- if (nm == "S20") 9 else if (nm == "S08b") 3 else 6
ch <- if (nm == "S20") 7*24 else 21*24
out <- as.data.frame(cio_run(m, s$ev, cycles = ncy, cycle_h = ch, follow_h = fu))
e <- out[nrow(out), ]
data.frame(scenario = nm, TS_8k = e$TS7, TS_4k = e$TS5, PTA = e$PTA,
Brock = e$BROCK, SIOP = e$SIOP, CTCAE = e$CTCAE,
SNR = e$SNRLOSS, GFR = e$GFROUT)
}))
}
## -----------------------------------------------------------------------------
## Example
## -----------------------------------------------------------------------------
## mod <- mcode("cio", code)
## print(cio_table(mod))
##
## # the thiosulfate delay sweep of Part 3 — the ototoxicity/efficacy trade-off
## sapply(c(0, 1, 2, 4, 6, 8, 12, 24), function(d) {
## o <- as.data.frame(cio_run(param(mod, AGE = 3),
## cio_ev(6, 80, sts_cycles = 0:5, sts_delay = d)))
## c(delay = d, PTA = tail(o$PTA, 1), TS8k = tail(o$TS7, 1))
## })
## -----------------------------------------------------------------------------