Files
vigilcare-clinical/docs/simulator-guide.md
T

13 KiB

VigilCare Clinical Simulator -- User Guide

Welcome! The VigilCare Simulator lets you replay realistic hospital patient scenarios against the VigilCare Clinical API. You can watch a patient's vitals change over time, see alerts fire (NEWS2, SIRS/qSOFA, sepsis bundles), and observe how the system detects clinical deterioration -- all without real patients.

Think of it as a flight simulator, but for clinical decision support.


Table of Contents

  1. Prerequisites
  2. Quick Start
  3. Available Commands
  4. Understanding Scenarios
  5. Available Scenarios
  6. Controlling Replay Speed
  7. Reading the Output
  8. Creating Your Own Scenarios
  9. Troubleshooting

1. Prerequisites

You need two things installed:

  • .NET 8 SDK -- Download from dotnet.microsoft.com
  • The VigilCare API running locally -- The simulator sends data to the API, so it must be up first

Starting the API

From the project root directory, run:

docker compose up -d
dotnet run --project VigilCare.Api

The API starts on http://localhost:5270 by default.

See docker-compose-usage-and-troubleshooting.md if you have trouble with Docker.


2. Quick Start

Open a terminal in the project root and run:

dotnet run --project VigilCare.Simulator -- replay \
  VigilCare.Simulator/Scenarios/List/uti-sepsis-elderly-01.json \
  --speed 60 --poll

This replays a 4-hour UTI-to-sepsis progression in about 4 seconds, showing alerts as they fire.

That's it! Read on for more detail.


3. Available Commands

The simulator has four commands. All are run with dotnet run --project VigilCare.Simulator -- <command>.

replay -- Run a scenario against the API

dotnet run --project VigilCare.Simulator -- replay <scenario-file> [options]

Options:

Option Default Description
--speed <number> 60 How fast to run (see Speed)
--base-url <url> http://localhost:5270 API address (change if your API runs elsewhere)
--poll off Show alerts and scores after each set of vitals
--poll-interval <seconds> 5 How often to check for alerts when polling

Example -- run the stable baseline scenario in real-time with polling:

dotnet run --project VigilCare.Simulator -- replay \
  VigilCare.Simulator/Scenarios/List/stable-baseline-01.json \
  --speed 1 --poll

replay-all -- Run every scenario in a folder

dotnet run --project VigilCare.Simulator -- replay-all <directory> [options]

Runs all .json scenario files in the given directory, one after another. Accepts --speed and --base-url.

Example:

dotnet run --project VigilCare.Simulator -- replay-all \
  VigilCare.Simulator/Scenarios/List --speed 60

validate -- Check a scenario file for errors

dotnet run --project VigilCare.Simulator -- validate <scenario-file>

Checks that the JSON is well-formed and all fields are valid. Does not contact the API.

Example:

dotnet run --project VigilCare.Simulator -- validate \
  VigilCare.Simulator/Scenarios/List/stable-baseline-01.json

dry-run -- Preview the timeline without touching the API

dotnet run --project VigilCare.Simulator -- dry-run <scenario-file>

Prints exactly what would happen (every vital sign, medication, and order) without sending anything.

Example:

dotnet run --project VigilCare.Simulator -- dry-run \
  VigilCare.Simulator/Scenarios/List/cardiac-arrest-post-mi-01.json

4. Understanding Scenarios

Each scenario is a JSON file that tells a clinical story. It contains:

  • Patient -- Name, date of birth, gender
  • Encounter -- Department, encounter type, attending physician, room/bed
  • Events -- A timeline of observations (vitals, labs), medications, and orders

Here is what a simplified scenario looks like:

{
  "scenario": {
    "id": "stable-baseline-01",
    "name": "Stable Baseline -- Routine Inpatient Monitoring",
    "description": "52-year-old female admitted for elective cholecystectomy...",
    "durationMinutes": 480,
    "tags": ["stable", "baseline", "control", "surgery"]
  },
  "patient": {
    "firstName": "Linda",
    "lastName": "Weston",
    "dateOfBirth": "1974-02-18",
    "gender": "Female"
  },
  "encounter": {
    "department": "Surgery",
    "encounterType": "Inpatient",
    "attendingPhysician": "Dr. James Nakamura",
    "roomBed": "SURG-204B",
    "admissionReason": "Elective laparoscopic cholecystectomy"
  },
  "events": [
    {
      "offsetMinutes": 0,
      "type": "observation",
      "data": {
        "code": "HEART_RATE",
        "value": 72,
        "unit": "bpm"
      },
      "note": "Post-op arrival, patient alert and comfortable"
    },
    {
      "offsetMinutes": 60,
      "type": "medication",
      "data": {
        "drugName": "acetaminophen",
        "dose": 1000,
        "doseUnit": "mg",
        "route": "PO",
        "administeredBy": "RN Davis"
      }
    }
  ]
}

The key concept is offsetMinutes -- each event happens at a certain number of minutes after the scenario starts. The simulator waits the appropriate amount of time (adjusted by your speed setting) before sending each event.

Event Types

Type What It Represents Example
observation A vital sign or lab result Heart rate 110 bpm, Temperature 39.2 C
medication A drug being administered Ceftriaxone 1g IV
order A clinical order being placed "Blood cultures", "Chest X-ray"
order_result Result of a prior order "Positive for E. coli"

Vital Sign Codes

These are the observation codes used in scenarios:

Code What It Measures Unit Normal Range
HEART_RATE Heart rate bpm 51--90
RESP_RATE Respiratory rate /min 12--20
SYSTOLIC_BP Systolic blood pressure mmHg 111--219
DIASTOLIC_BP Diastolic blood pressure mmHg 60--90
TEMP_C Temperature C 36.1--38.0
SPO2 Oxygen saturation % 96--100
AVPU Consciousness level score 0 = Alert
SUPPLEMENTAL_O2 On supplemental oxygen? flag 0 = No
WBC_K_UL White blood cell count x10^3/uL 4.5--11.0
LACTATE_MMOL_L Serum lactate mmol/L 0.5--1.5
POTASSIUM_MEQ_L Potassium mEq/L 3.5--5.0
GLUCOSE_MG_DL Blood glucose mg/dL 70--140

5. Available Scenarios

The simulator ships with 8 scenarios covering different clinical situations:

Scenario Clinical Story Duration
stable-baseline-01 Post-op cholecystectomy, all vitals normal. Control case -- no alerts should fire. 8 hours
uti-sepsis-elderly-01 78-year-old with UTI progressing to sepsis. SIRS criteria met, sepsis bundle triggered. 4 hours
cardiac-arrest-post-mi-01 Post-MI patient deteriorating into cardiogenic shock. Rapid HR/BP changes. Varies
post-op-hemorrhage-01 Surgical patient with internal bleeding. Rising HR, falling BP and SpO2. Varies
respiratory-failure-asthma-01 Asthma exacerbation progressing to respiratory failure. Falling SpO2, rising RR. Varies
dka-electrolyte-01 Diabetic ketoacidosis with potassium and glucose derangement. Varies
hypothermia-elderly-01 Elderly patient with severe hypothermia. Slow HR, dropping temperature. Varies
medication-false-alarm-01 Beta-blocker causing bradycardia. Tests whether the system correctly handles medication-induced vital changes. 3 hours

All scenario files are in: VigilCare.Simulator/Scenarios/List/


6. Controlling Replay Speed

The --speed option controls how fast simulated time passes:

Speed Meaning A 4-hour scenario takes...
0 Instant -- no waiting, all events fire immediately < 1 second
1 Real-time -- 1 simulated minute = 1 real minute 4 hours
10 10x -- 1 simulated minute = 6 real seconds 24 minutes
60 60x (default) -- 1 simulated minute = 1 real second 4 minutes
120 120x -- 1 simulated minute = 0.5 real seconds 2 minutes

Recommendations:

  • For demos / presentations: Use --speed 10 with --poll so people can follow along
  • For quick testing: Use --speed 60 or --speed 0
  • For the most realistic experience: Use --speed 1 (real-time, a 4-hour scenario takes 4 hours)

7. Reading the Output

When you run a replay, the simulator prints a colored timeline. Here's what to look for:

────────────────── Stable Baseline -- Routine Inpatient Monitoring ──────────────────
52-year-old female admitted for elective cholecystectomy...

Patient registered: 3fa85f64-... (MRN-12345)
Encounter opened: 7c9e6679-... (active)

  [00:00] HEART_RATE 72 bpm
  [00:00] RESP_RATE 14 /min
  [00:00] SYSTOLIC_BP 124 mmHg
  [00:00] SPO2 98 %

  ... waiting 60m simulated (1.0s real) ...

  [01:00] HEART_RATE 74 bpm
  [01:00] medication: acetaminophen 1000 mg PO

With --poll enabled, you also see clinical scoring:

  [01:30] NEWS2 = 5 (Medium)
  [01:30] ALERT SEPSIS_WARNING (Critical)
  [01:30] SEPSIS BUNDLE InProgress (2/4 completed)

At the end, a summary table appears:

Metric                    Value
-----------------------------------
Scenario                  uti-sepsis-elderly-01
Observations sent         42
Medications sent          2
Orders placed             3
Wall-clock time           12.3s

What the Alerts Mean

Alert Meaning
NEWS2_LOW NEWS2 score 1--4: Low risk, routine monitoring
NEWS2_MEDIUM NEWS2 score 5--6 or single parameter score of 3: Urgent review needed
NEWS2_HIGH NEWS2 score 7+: Emergency response needed
SEPSIS_WARNING SIRS criteria met (2+ of: temp, HR, RR, WBC abnormal)
QSOFA_WARNING qSOFA criteria met (2+ of: altered mentation, RR >= 22, SBP <= 100)
RAPID_DETERIORATION Sudden significant change in vital signs

8. Creating Your Own Scenarios

You can create new clinical scenarios by writing a JSON file. There are two ways:

Option A: Write it manually

  1. Copy an existing scenario from VigilCare.Simulator/Scenarios/List/ as a template
  2. Modify the patient, encounter, and events to match your clinical story
  3. Make sure offsetMinutes values are in ascending order
  4. Validate it:
dotnet run --project VigilCare.Simulator -- validate ./my-scenario.json

Option B: Use AI to generate it

There is a generation prompt file at VigilCare.Simulator/Scenarios/GENERATE_PROMPT.md. You can paste its contents into ChatGPT, Claude, or another AI assistant, describe the clinical case you want, and it will generate a valid scenario JSON file for you.

Validation Rules

The simulator enforces these rules on scenario files:

  • scenario.id and scenario.name are required
  • encounter.department must be one of: Icu, GeneralMedicine, Emergency, Cardiology, Surgery, Pediatrics
  • encounter.encounterType must be one of: Inpatient, Outpatient, Emergency
  • events must be non-empty, with offsetMinutes in ascending order
  • observation codes must match one of the 12 valid codes listed above
  • Maximum 10 observations per time point (API batch limit)
  • order_result events must reference a matching prior order (or a sepsis bundle auto-order)

Sepsis Bundle Auto-Orders

When the system detects sepsis (SIRS or qSOFA criteria met), it automatically creates four orders:

  • SEP-1: Blood cultures
  • SEP-1: Serum lactate
  • SEP-1: Broad-spectrum antibiotics
  • SEP-1: IV fluid bolus

You do not need to create order events for these. Just add order_result events referencing them to simulate bundle completion.


9. Troubleshooting

"Connection refused" error

The API is not running. Start it first:

docker compose up -d
dotnet run --project VigilCare.Api

"scenario.json has N error(s)"

Run validate to see what's wrong:

dotnet run --project VigilCare.Simulator -- validate ./your-scenario.json

Common issues:

  • Invalid department name (must match exact casing: Icu, not ICU)
  • offsetMinutes out of order
  • Missing required fields (scenario.id, scenario.name, encounter.attendingPhysician)

Medications show "skipped"

The medication tracking endpoint may not be available. This is non-fatal -- the scenario continues.

"dotnet" command not found

Install .NET 8 SDK from dotnet.microsoft.com.

I want to point the simulator at a different API

Use --base-url:

dotnet run --project VigilCare.Simulator -- replay scenario.json \
  --base-url http://192.168.1.50:5270