Master Dag
Bioloupe Forecasting Master DAG
Section titled “Bioloupe Forecasting Master DAG”Scope: Calculation dependency graph. For technical architecture (Jotai state, React Query, component patterns), see ARCHITECTURE.md.
Complete system in a single diagram - verified against source code.
flowchart TB
subgraph INPUTS["📥 INPUT VARIABLES"]
direction TB
subgraph INC_INPUTS["Incidence Inputs"]
BASE_INC[Base Incidence]
POP_DATA[Population Data<br/>by geo/year]
REG_FACTOR[Regional Factor<br/>EU5/Japan adjustments]
GEO[Geography<br/>USA/EU5/Japan/China]
INDICATION[Indication<br/>Disease name]
INC_EVO[Incidence Evolution<br/>growth rates array]
end
subgraph STAGE_INPUTS["Stage Mix Inputs"]
EARLY_PCT[Early Stage %]
MET_PCT[Metastatic %]
E2E_RELAPSE[Early→Early Relapse %]
E2M_RELAPSE[Early→Met Relapse %]
HC_ACCESS[Healthcare Access %]
end
subgraph PATIENT_INPUTS["Patient Flow Inputs"]
TREAT_RATE[Treatment Rate %]
TRANS_RATE[Transition Rate %]
RETREAT[Retreatment Factor]
CUSTOM_VARS[Custom Variables<br/>with growth rates]
end
subgraph PEAK_INPUTS["Peak Share Inputs"]
LAUNCH_ORD[Launch Order<br/>1-10]
BEST_CLASS[Best in Class<br/>true/false]
DELAY_COMP[Delay vs Competition<br/>quarters]
NUM_COMP[Num Competitors<br/>1-10]
CLASS_SHARE[Class Share %<br/>default 100]
end
subgraph MARKET_INPUTS["Market Inputs"]
LAUNCH_DT[Launch Date<br/>YYYY-MM-DD]
SPEED_PEAK[Speed to Peak<br/>e.g. 3 Year Medium]
LOE_DATE[LoE Date]
MOL_TYPE[Molecule Type<br/>Biologic/Small Mol]
EVENTS[Market Events<br/>impactPercent + startDate]
end
subgraph PRICE_INPUTS["Pricing Inputs"]
YEAR_FIRST_LAUNCH[Year of First Launch]
LAUNCH_PRICE[Launch Price<br/>$/month]
ANN_PRICE_CHG[Annual Price Change %]
NET_PRICE_EVO[Net Price Change<br/>custom array]
MKT_EXCL_YRS[Market Exclusivity Years]
end
subgraph SALES_INPUTS["Sales Inputs"]
MONTHS_THER[Months of Therapy<br/>can exceed 12]
COMPLIANCE[Compliance %]
end
subgraph MC_INPUTS["Monte Carlo Inputs"]
MC_VARS[Variable Ranges<br/>min/mode/max]
MC_DIST[Distribution Type<br/>triangular/normal/uniform]
MC_ITERS[Iterations<br/>default 1000]
end
end
subgraph REFERENCE["📚 REFERENCE DATA"]
LAUNCH_MATRIX[LAUNCH_ORDERS<br/>10x10 Matrix]
BIC_ARRAY[BEST_IN_CLASS<br/>Array by competitors]
UPTAKE_CURVES[UPTAKE_CURVE<br/>30+ curves]
MOL_EROSION[MOLECULE_SHARE_EROSION<br/>Small molecule rates]
BIO_EROSION[BIOLOGICS_SHARE_EROSION<br/>Biologic rates]
COHORT_YRS[COHORT_YEARS = 5<br/>Multi-year aggregation]
end
subgraph CALC_INC["🧮 INCIDENCE CALCULATION"]
POP_RATIO[Population Ratio<br/>Pop Year / Pop Base]
YEAR_INC[Year Incidence<br/>= Base × PopRatio × RegFactor]
INC_GROWTH[Apply Growth Rate<br/>from evolution array]
end
BASE_INC --> YEAR_INC
POP_DATA --> POP_RATIO
POP_RATIO --> YEAR_INC
REG_FACTOR --> YEAR_INC
GEO --> POP_RATIO
INC_EVO --> INC_GROWTH
YEAR_INC --> INC_GROWTH
subgraph CALC_ADDR["🧮 ADDRESSABLE POPULATION"]
direction TB
subgraph EARLY_CALC["Early Stage Path"]
EARLY_BASE[Incidence × Early%]
EARLY_REL[× 1+E2E%]
EARLY_HC[× HC%]
EARLY_ADDR[Early Addressable]
end
subgraph MET_CALC["Metastatic Path"]
MET_DENOVO[Incidence × Met%]
MET_REL[+ Incidence × Early% × E2M%]
MET_SUM[Sum]
MET_HC[× HC%]
MET_ADDR[Met Addressable]
end
subgraph THER_CALC["Therapy Path - Hematology"]
THER_ADDR[Therapy Addressable<br/>= Incidence × HC%]
end
subgraph CUSTOM_CALC["Custom Variables"]
CUSTOM_MULT[Custom Multiplier<br/>product of all custom vars]
FINAL_ADDR[Final Addressable<br/>× customMultiplier]
end
end
INC_GROWTH --> EARLY_BASE
EARLY_PCT --> EARLY_BASE
EARLY_BASE --> EARLY_REL
E2E_RELAPSE --> EARLY_REL
EARLY_REL --> EARLY_HC
HC_ACCESS --> EARLY_HC
EARLY_HC --> EARLY_ADDR
INC_GROWTH --> MET_DENOVO
MET_PCT --> MET_DENOVO
INC_GROWTH --> MET_REL
EARLY_PCT --> MET_REL
E2M_RELAPSE --> MET_REL
MET_DENOVO --> MET_SUM
MET_REL --> MET_SUM
MET_SUM --> MET_HC
HC_ACCESS --> MET_HC
MET_HC --> MET_ADDR
INC_GROWTH --> THER_ADDR
HC_ACCESS --> THER_ADDR
CUSTOM_VARS --> CUSTOM_MULT
EARLY_ADDR --> FINAL_ADDR
MET_ADDR --> FINAL_ADDR
THER_ADDR --> FINAL_ADDR
CUSTOM_MULT --> FINAL_ADDR
subgraph CALC_PEAK["🧮 PEAK SHARE CALCULATION"]
BASE_SHARE[Base Share<br/>from LAUNCH_ORDERS matrix]
BIC_BONUS[BIC Bonus<br/>from BEST_IN_CLASS array]
DELAY_PEN[Delay Penalty<br/>= delay > 3 ? delay × 0.5 : 0]
PEAK_SHARE[Peak Share %<br/>= clamp 0-100: Base + BIC - Delay]
EFF_PEAK[Effective Peak Share<br/>= Peak × ClassShare / 100]
end
LAUNCH_ORD --> BASE_SHARE
NUM_COMP --> BASE_SHARE
LAUNCH_MATRIX --> BASE_SHARE
BEST_CLASS --> BIC_BONUS
NUM_COMP --> BIC_BONUS
BIC_ARRAY --> BIC_BONUS
DELAY_COMP --> DELAY_PEN
BASE_SHARE --> PEAK_SHARE
BIC_BONUS --> PEAK_SHARE
DELAY_PEN --> PEAK_SHARE
PEAK_SHARE --> EFF_PEAK
CLASS_SHARE --> EFF_PEAK
subgraph CALC_MKS["🧮 MARKET SHARE OVER TIME"]
YEAR_OFFSET[Year Offset<br/>= Year - LaunchYear]
UPTAKE_VAL[Uptake Value<br/>from UPTAKE_CURVE by speed and offset]
PREV_UPTAKE[Previous Uptake<br/>from UPTAKE_CURVE by speed and offset]
WEIGHTED_SHARE[Weighted Share<br/>month-adjusted blend]
EVENT_IMPACT[Event Impact<br/>Σ event.impactPercent × uptake]
BASE_MKS[Base Market Share<br/>= Weighted × Peak%]
EROSION_LOOKUP[Erosion Rate Lookup<br/>by molecule type]
LOE_IMPACT[LoE Impact<br/>month-weighted erosion]
MKT_SHARE[Final Market Share %<br/>= Base + Events × LoE]
end
LAUNCH_DT --> YEAR_OFFSET
YEAR_OFFSET --> UPTAKE_VAL
SPEED_PEAK --> UPTAKE_VAL
UPTAKE_CURVES --> UPTAKE_VAL
UPTAKE_VAL --> WEIGHTED_SHARE
YEAR_OFFSET --> PREV_UPTAKE
PREV_UPTAKE --> WEIGHTED_SHARE
LAUNCH_DT --> WEIGHTED_SHARE
WEIGHTED_SHARE --> BASE_MKS
EFF_PEAK --> BASE_MKS
EVENTS --> EVENT_IMPACT
UPTAKE_VAL --> EVENT_IMPACT
LOE_DATE --> EROSION_LOOKUP
MOL_TYPE --> EROSION_LOOKUP
MOL_EROSION --> EROSION_LOOKUP
BIO_EROSION --> EROSION_LOOKUP
EROSION_LOOKUP --> LOE_IMPACT
LOE_DATE --> LOE_IMPACT
BASE_MKS --> MKT_SHARE
EVENT_IMPACT --> MKT_SHARE
LOE_IMPACT --> MKT_SHARE
subgraph CALC_PAT["🧮 PATIENT FLOW BY LINE"]
direction TB
subgraph LINE_1["1L First Line"]
L1_ELIG[1L Eligible<br/>= Addressable × TreatRate%]
L1_NEW[1L New Patients<br/>= Eligible × MktShare%]
end
subgraph LINE_2["2L Second Line"]
L2_POOL[2L Pool<br/>= 1L_Elig - 1L_New × Retreat]
L2_TRANS[× Transition%]
L2_ELIG[2L Eligible<br/>× TreatRate%]
L2_NEW[2L New Patients<br/>= Eligible × MktShare%]
end
subgraph LINE_3["3L+ Third Line+"]
L3_POOL[3L Pool<br/>= 2L_Elig - 2L_New × Retreat]
L3_ELIG[3L+ Eligible<br/>= Pool × Transition%<br/>NO TreatRate]
L3_NEW[3L+ New Patients<br/>= Eligible × MktShare%]
end
end
FINAL_ADDR --> L1_ELIG
TREAT_RATE --> L1_ELIG
L1_ELIG --> L1_NEW
MKT_SHARE --> L1_NEW
L1_ELIG --> L2_POOL
L1_NEW --> L2_POOL
RETREAT --> L2_POOL
L2_POOL --> L2_TRANS
TRANS_RATE --> L2_TRANS
L2_TRANS --> L2_ELIG
TREAT_RATE --> L2_ELIG
L2_ELIG --> L2_NEW
MKT_SHARE --> L2_NEW
L2_ELIG --> L3_POOL
L2_NEW --> L3_POOL
RETREAT --> L3_POOL
L3_POOL --> L3_ELIG
TRANS_RATE --> L3_ELIG
L3_ELIG --> L3_NEW
MKT_SHARE --> L3_NEW
subgraph CALC_PRICE["🧮 NET PRICE CALCULATION"]
YEARS_FROM_LAUNCH[Years from Launch<br/>= Year - YearOfFirstLaunch]
HAS_CUSTOM{Has Custom<br/>Evolution?}
DURATION_CALC[Duration Calculation<br/>capped near LoE by<br/>marketExclusivityYears]
COMPOUND_PRICE[Compound Price<br/>= Launch × 1+APC% ^ duration]
CUSTOM_PRICE[Custom Price<br/>cumulative year changes]
NET_PRICE[Net Price $/month]
end
YEAR_FIRST_LAUNCH --> YEARS_FROM_LAUNCH
NET_PRICE_EVO --> HAS_CUSTOM
HAS_CUSTOM -->|No| COMPOUND_PRICE
HAS_CUSTOM -->|Yes| CUSTOM_PRICE
LAUNCH_PRICE --> COMPOUND_PRICE
ANN_PRICE_CHG --> COMPOUND_PRICE
YEARS_FROM_LAUNCH --> DURATION_CALC
LOE_DATE --> DURATION_CALC
MKT_EXCL_YRS --> DURATION_CALC
DURATION_CALC --> COMPOUND_PRICE
LAUNCH_PRICE --> CUSTOM_PRICE
NET_PRICE_EVO --> CUSTOM_PRICE
COMPOUND_PRICE --> NET_PRICE
CUSTOM_PRICE --> NET_PRICE
subgraph CALC_SALES["🧮 LINE SALES CALCULATION"]
direction TB
subgraph COHORT_AGG["Multi-Year Cohort Aggregation"]
COHORT_LOOP[For each of 5 cohort years]
COHORT_PATIENTS[Get patients from<br/>year - offset]
COHORT_MONTHS[Calculate months<br/>for this cohort]
end
subgraph SALES_1["1L Sales"]
S1_MULT[NewPatients × NetPrice]
S1_COMP[× Compliance%]
S1_MOT[× months for cohort]
S1_DIV[÷ 1,000,000]
L1_SALES[1L Sales $M<br/>sum of all cohorts]
end
subgraph SALES_2["2L Sales"]
L2_SALES[2L Sales $M]
end
subgraph SALES_3["3L+ Sales"]
L3_SALES[3L+ Sales $M]
end
end
COHORT_YRS --> COHORT_LOOP
COHORT_LOOP --> COHORT_PATIENTS
COHORT_PATIENTS --> COHORT_MONTHS
MONTHS_THER --> COHORT_MONTHS
L1_NEW --> S1_MULT
NET_PRICE --> S1_MULT
S1_MULT --> S1_COMP
COMPLIANCE --> S1_COMP
S1_COMP --> S1_MOT
COHORT_MONTHS --> S1_MOT
S1_MOT --> S1_DIV
S1_DIV --> L1_SALES
L2_NEW --> L2_SALES
NET_PRICE --> L2_SALES
COMPLIANCE --> L2_SALES
COHORT_MONTHS --> L2_SALES
L3_NEW --> L3_SALES
NET_PRICE --> L3_SALES
COMPLIANCE --> L3_SALES
COHORT_MONTHS --> L3_SALES
subgraph CALC_TOTAL["🧮 TOTAL SALES"]
SALES_SUM[Sum All Lines]
TOTAL_SALES[Total Sales $M]
end
L1_SALES --> SALES_SUM
L2_SALES --> SALES_SUM
L3_SALES --> SALES_SUM
SALES_SUM --> TOTAL_SALES
subgraph CALC_MC["🎲 MONTE CARLO SIMULATION"]
direction TB
subgraph MC_SAMPLE["Sampling - per iteration"]
SAMPLE_HC[Sample HC%]
SAMPLE_TR[Sample TreatRate%]
SAMPLE_STAGE[Sample Stage Mix<br/>Early/Met/E2E/E2M]
SAMPLE_PS[Sample PeakShare]
SAMPLE_MOT[Sample MOT]
SAMPLE_LP[Sample LaunchPrice]
SAMPLE_CUSTOM[Sample Custom Vars]
end
subgraph MC_ITER["Iteration Loop - 1000x"]
CLONE_STATE[Clone Base State<br/>shallow copy]
APPLY_SAMPLES[Apply Sampled Values<br/>to cloned state]
RUN_CALC[Run Full Calculation<br/>using computations.ts]
COLLECT_RESULT[Collect Year Sales]
end
subgraph MC_ANALYZE["Statistical Analysis"]
ALL_RESULTS[All Results<br/>1000 × numYears]
CALC_P10[P10 - quantile 0.1]
CALC_P50[P50 - quantile 0.5]
CALC_P90[P90 - quantile 0.9]
CALC_MEAN[Mean]
end
subgraph MC_TORNADO["Tornado Analysis"]
HOLD_BASE[Hold all at mostLikely]
VAR_MIN[Run with var at min]
VAR_MAX[Run with var at max]
IMPACT[Impact = abs max - min]
RANK[Sort by total impact<br/>ascending]
end
end
MC_VARS --> SAMPLE_HC
MC_VARS --> SAMPLE_TR
MC_VARS --> SAMPLE_STAGE
MC_VARS --> SAMPLE_PS
MC_VARS --> SAMPLE_MOT
MC_VARS --> SAMPLE_LP
MC_VARS --> SAMPLE_CUSTOM
MC_DIST --> SAMPLE_HC
SAMPLE_HC --> APPLY_SAMPLES
SAMPLE_TR --> APPLY_SAMPLES
SAMPLE_STAGE --> APPLY_SAMPLES
SAMPLE_PS --> APPLY_SAMPLES
SAMPLE_MOT --> APPLY_SAMPLES
SAMPLE_LP --> APPLY_SAMPLES
SAMPLE_CUSTOM --> APPLY_SAMPLES
CLONE_STATE --> APPLY_SAMPLES
APPLY_SAMPLES --> RUN_CALC
RUN_CALC --> COLLECT_RESULT
COLLECT_RESULT --> ALL_RESULTS
ALL_RESULTS --> CALC_P10
ALL_RESULTS --> CALC_P50
ALL_RESULTS --> CALC_P90
ALL_RESULTS --> CALC_MEAN
MC_VARS --> HOLD_BASE
HOLD_BASE --> VAR_MIN
HOLD_BASE --> VAR_MAX
VAR_MIN --> IMPACT
VAR_MAX --> IMPACT
IMPACT --> RANK
subgraph OUTPUTS["📤 OUTPUTS"]
direction TB
subgraph MODEL_OUT["Model Outputs"]
OUT_PAT_LINE[Patients by Line/Year]
OUT_MKS_LINE[Market Share by Line/Year]
OUT_SALES_LINE[Sales by Line/Year]
OUT_TOTAL[Total Sales by Year]
end
subgraph CHART_OUT["Chart Outputs"]
SALES_CHART[Stacked Bar Chart<br/>Sales by Line]
end
subgraph MC_OUT["Monte Carlo Outputs"]
P10_FORECAST[P10 Forecast<br/>Pessimistic]
P50_FORECAST[P50 Forecast<br/>Median]
P90_FORECAST[P90 Forecast<br/>Optimistic]
TORNADO_CHART[Tornado Chart<br/>Sensitivity ranked]
end
end
L1_NEW --> OUT_PAT_LINE
L2_NEW --> OUT_PAT_LINE
L3_NEW --> OUT_PAT_LINE
MKT_SHARE --> OUT_MKS_LINE
L1_SALES --> OUT_SALES_LINE
L2_SALES --> OUT_SALES_LINE
L3_SALES --> OUT_SALES_LINE
TOTAL_SALES --> OUT_TOTAL
OUT_SALES_LINE --> SALES_CHART
CALC_P10 --> P10_FORECAST
CALC_P50 --> P50_FORECAST
CALC_P90 --> P90_FORECAST
RANK --> TORNADO_CHART
%% Container Styling per Legend - Dark colors for contrast
style INPUTS fill:#1565c0,stroke:#0d47a1,color:#fff
style REFERENCE fill:#e65100,stroke:#bf360c,color:#fff
style CALC_INC fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_ADDR fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_PEAK fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_MKS fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_PAT fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_PRICE fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_SALES fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_TOTAL fill:#2e7d32,stroke:#1b5e20,color:#fff
style CALC_MC fill:#ad1457,stroke:#880e4f,color:#fff
style OUTPUTS fill:#6a1b9a,stroke:#4a148c,color:#fff
Legend
Section titled “Legend”| Container | Color | Hex | Meaning |
|---|---|---|---|
| INPUTS | Blue | #1565c0 | Input Variables |
| REFERENCE | Orange | #e65100 | Reference Data / Lookup Tables |
| CALC_* | Green | #2e7d32 | Calculated Values |
| CALC_MC | Magenta | #ad1457 | Monte Carlo Simulation |
| OUTPUTS | Purple | #6a1b9a | Output Values |
Verified Formula Reference
Section titled “Verified Formula Reference”Incidence Calculation
Section titled “Incidence Calculation”Source: computations.ts (incidence computed via buildIncidenceEvolution in IncidenceEvolution/computations.ts)
YearIncidence = BaseIncidence × (Pop[Year] / Pop[BaseYear]) × RegionalFactorAddressable Population (Solid Tumors)
Section titled “Addressable Population (Solid Tumors)”Source: computations.ts (calculateLineFunnelForDisplay)
EarlyAddressable = Incidence × (EarlyStage% / 100) × (1 + EarlyToEarlyRelapse% / 100) × (HC% / 100)MetAddressable = (Incidence × MetStage% / 100 + Incidence × EarlyStage% / 100 × EarlyToMetRelapse% / 100) × (HC% / 100)Addressable Population (Hematology)
Section titled “Addressable Population (Hematology)”Source: computations.ts (hematology path in calculateLineFunnelForDisplay)
TherapyAddressable = Incidence × (HC% / 100)Custom Variables Multiplier
Section titled “Custom Variables Multiplier”Source: computations.ts (getCustomMultiplier)
customMultiplier = Π(customVar.value / 100) for all custom variablesFinalAddressable = Addressable × customMultiplierPeak Share
Section titled “Peak Share”Source: computations.ts (calculatePeakShare)
order = clamp(launchOrder, 1, 10)competitors = clamp(numCompetitors, 1, 10)baseShare = LAUNCH_ORDERS[order - 1][competitors - 1]bicBonus = bestInClass ? BEST_IN_CLASS[competitors - 1] : 0delayPenalty = delayVsCompetition > 3 ? delayVsCompetition × 0.5 : 0
PeakShare (within class) = clamp(0, 100, baseShare + bicBonus - delayPenalty)EffectivePeakShare = PeakShare × (classShare / 100)The EffectivePeakShare is used in market share calculations.
Market Share (Basic)
Section titled “Market Share (Basic)”Source: computations.ts (calculateMarketShare)
yearOffset = year - launchYearuptake = UPTAKE_CURVE[speedToPeak][yearOffset + 1]prevUptake = yearOffset > 0 ? UPTAKE_CURVE[speedToPeak][yearOffset] : 0launchMonth = launch.getMonth() + 1
weightedShare = (uptake × (13 - launchMonth) + prevUptake × (launchMonth - 1)) / 12
erosionOffset = year - loeYearloeMonth = loeDate.getUTCMonth() + 1preRate = (erosionRates[erosionOffset] / 100) × (13 - loeMonth) / 12postRate = (erosionRates[erosionOffset + 1] / 100) × (loeMonth - 1) / 12erosion = year >= loeYear ? 1 - (preRate + postRate) : 1
MarketShare = clamp(0, 100, weightedShare × (peakShare / 100) × erosion)Market Share (with Events) - Monte Carlo
Section titled “Market Share (with Events) - Monte Carlo”Source: MonteCarlo/computations.ts (event impact applied during simulation)
marketShare = calculateMarketShare(line, year, lines)eventImpact = Σ(event.impactPercent × monthWeightedUptake)loeImpact = calculateLoEImpact(year, erosionData, assumptions)
MarketShareA = clamp(0, 100, (marketShare + eventImpact) × loeImpact)LoE Impact (Month-Weighted)
Section titled “LoE Impact (Month-Weighted)”Source: MonteCarlo/computations.ts (LoE erosion applied during simulation)
if year < loeYear: return 1
offset = year - loeYearpreErosion = (erosionData[offset] / 100) × (13 - loeMonth) / 12postErosion = (erosionData[offset + 1] / 100) × (loeMonth - 1) / 12
LoEImpact = 1 - (preErosion + postErosion)Patient Flow - 1L
Section titled “Patient Flow - 1L”Source: computations.ts (calculateLinePatients)
1L_Eligible = Addressable × (TreatmentRate / 100)1L_NewPatients = 1L_Eligible × (MarketShare / 100)Patient Flow - 2L
Section titled “Patient Flow - 2L”Source: computations.ts (calculateLinePatients, 2L case)
2L_Pool = 1L_Eligible - (1L_NewPatients × Retreatment)2L_Eligible = (2L_Pool × TransitionRate / 100) × (TreatmentRate / 100)2L_NewPatients = 2L_Eligible × (MarketShare / 100)Patient Flow - 3L+
Section titled “Patient Flow - 3L+”Source: computations.ts (calculateLinePatients, 3L+ case)
3L_Pool = 2L_Eligible - (2L_NewPatients × Retreatment)3L_Eligible = 3L_Pool × (TransitionRate / 100) // NO TreatmentRate3L_NewPatients = 3L_Eligible × (MarketShare / 100)Net Price (Compound)
Section titled “Net Price (Compound)”Source: computations.ts (calculateNetPriceFromAssumptions)
if year <= launchYear: return launchPrice
yearsFromLaunch = year - launchYearNetPrice = launchPrice × (1 + annualPriceChange / 100) ^ yearsFromLaunchNet Price (with Duration Cap near LoE)
Section titled “Net Price (with Duration Cap near LoE)”Source: computations.ts (calculateNetPriceFromAssumptions, duration cap logic)
loeYear = parseInt(loeDate.split("-")[0])duration = year >= loeYear - 1 ? marketExclusivityYears - 1 : year - yearOfFirstLaunch
NetPrice = launchPrice × (1 + priceChange / 100) ^ durationLine Sales (Cohort-Based Distribution)
Section titled “Line Sales (Cohort-Based Distribution)”Both the Model/SalesChart path (calculateLineSales) and Monte Carlo/Tornado path (calculateLineSalesTotal) use cohort-based distribution. MonthsOfTherapy is spread across calendar years, each contributing up to 12 months.
Source: computations.ts (calculateLineSales, calculateLineSalesTotal)
COHORT_YEARS = 5
For yearOffset in 0..4: treatmentMonthThreshold = yearOffset × 12
if treatmentMonths <= treatmentMonthThreshold: break
months = yearOffset == 0 ? min(treatmentMonths, 12) : treatmentMonths > (threshold + 12) ? 12 : treatmentMonths - threshold
patients = getCohortPatients(line, year - yearOffset, ...) sale = (patients × netPrice × compliance × months) / 1,000,000
LineSales = Σ(sale for all cohort years)When MonthsOfTherapy ≤ 12, only yearOffset=0 iterates and the formula reduces to the simple form.
Total Sales
Section titled “Total Sales”TotalSales = Σ(LineSales[i]) for all therapy linesDistribution Functions
Section titled “Distribution Functions”Source: computations.ts (triangularDistribution, normalDistribution, uniformDistribution)
Triangular:
c = (mostLikely - min) / (max - min)u = random()
if u <= c: value = min + sqrt(u × (max - min) × (mostLikely - min))else: value = max - sqrt((1 - u) × (max - min) × (max - mostLikely))Normal (Box-Muller):
mean = (min + max) / 2stdDev = (max - min) / 6 // NORMAL_DISTRIBUTION_SIGMAS = 6
z = sqrt(-2 × ln(u1)) × cos(2π × u2)value = z × stdDev + meanUniform:
value = min + random() × (max - min)Variables NOT Simulated in Monte Carlo
Section titled “Variables NOT Simulated in Monte Carlo”Per FORECASTING_MODEL.md and code analysis:
- Transition Rate
- Compliance
- Annual Price Change
These are held constant during Monte Carlo simulation.
Incidence Evolution in Monte Carlo/Tornado
Section titled “Incidence Evolution in Monte Carlo/Tornado”Monte Carlo and Tornado analyses use getYearIncidence(year) for each simulated year, which applies the growth rates from the Incidence Evolution table (Custom Inputs). This ensures simulations properly reflect year-over-year incidence changes rather than using a static base incidence value.
Code File Reference
Section titled “Code File Reference”| Calculation | File | Function |
|---|---|---|
| Custom Multiplier | computations.ts | getCustomMultiplier |
| Line Funnel Display | computations.ts | calculateLineFunnelForDisplay |
| Market Share | computations.ts | calculateMarketShare |
| Net Price | computations.ts | calculateNetPriceFromAssumptions |
| Line Patients | computations.ts | calculateLinePatients |
| Line Sales | computations.ts | calculateLineSales |
| Changeable Values | computations.ts | applyChangeableValue |
| Treatment Eligible (MC) | computations.ts | calculateTreatmentEligiblePatients |
| Line Sales Total (MC) | computations.ts | calculateLineSalesTotal |
| Peak Share | computations.ts | calculatePeakShare |
| Growth Rates | IncidenceEvolution/computations.ts | computeGrowthRates |
| Incidence Evolution | IncidenceEvolution/computations.ts | buildIncidenceEvolution |
| Growth Rate Change | IncidenceEvolution/computations.ts | applyGrowthRateChange |
| Monte Carlo Engine | MonteCarlo/computations.ts | runMonteCarloSimulation |
| Tornado Analysis | Tornado/computations.ts | runTornadoAnalysis |