-- ------------------------------------------------------------------
-- All-time arterial blood-gas pivot (PaO2 / FiO2 ratio at every gas).
--
-- This script is a fusion of the upstream MIMIC-III concepts_postgres
-- files
--   firstday/blood_gas_first_day.sql
--   firstday/blood_gas_first_day_arterial.sql
-- with their day-1 time predicate removed, so we get one row per
-- (icustay_id, charttime) for the entire ICU stay.
--
-- Output table:  blood_gas_arterial
-- Output cols :  subject_id, hadm_id, icustay_id, charttime,
--                specimen, specimen_pred, specimen_prob,
--                so2, spo2, po2, pco2, fio2_chartevents, fio2,
--                aado2, aado2_calc, pao2fio2, ph, baseexcess,
--                bicarbonate, totalco2, hematocrit, hemoglobin,
--                carboxyhemoglobin, methemoglobin, chloride, calcium,
--                temperature, potassium, sodium, lactate, glucose,
--                intubated, tidalvolume, ventilationrate, ventilator,
--                peep, o2flow, requiredo2
--
-- Restricted to *arterial* samples (specimen = 'ART' or
-- specimen_prob > 0.75).
-- ------------------------------------------------------------------

DROP TABLE IF EXISTS blood_gas_arterial;
CREATE TABLE blood_gas_arterial AS

WITH bg_pvt AS
(
  SELECT ie.subject_id, ie.hadm_id, ie.icustay_id
       , CASE
           WHEN itemid = 50800 THEN 'SPECIMEN'
           WHEN itemid = 50801 THEN 'AADO2'
           WHEN itemid = 50802 THEN 'BASEEXCESS'
           WHEN itemid = 50803 THEN 'BICARBONATE'
           WHEN itemid = 50804 THEN 'TOTALCO2'
           WHEN itemid = 50805 THEN 'CARBOXYHEMOGLOBIN'
           WHEN itemid = 50806 THEN 'CHLORIDE'
           WHEN itemid = 50808 THEN 'CALCIUM'
           WHEN itemid = 50809 THEN 'GLUCOSE'
           WHEN itemid = 50810 THEN 'HEMATOCRIT'
           WHEN itemid = 50811 THEN 'HEMOGLOBIN'
           WHEN itemid = 50812 THEN 'INTUBATED'
           WHEN itemid = 50813 THEN 'LACTATE'
           WHEN itemid = 50814 THEN 'METHEMOGLOBIN'
           WHEN itemid = 50815 THEN 'O2FLOW'
           WHEN itemid = 50816 THEN 'FIO2'
           WHEN itemid = 50817 THEN 'SO2'
           WHEN itemid = 50818 THEN 'PCO2'
           WHEN itemid = 50819 THEN 'PEEP'
           WHEN itemid = 50820 THEN 'PH'
           WHEN itemid = 50821 THEN 'PO2'
           WHEN itemid = 50822 THEN 'POTASSIUM'
           WHEN itemid = 50823 THEN 'REQUIREDO2'
           WHEN itemid = 50824 THEN 'SODIUM'
           WHEN itemid = 50825 THEN 'TEMPERATURE'
           WHEN itemid = 50826 THEN 'TIDALVOLUME'
           WHEN itemid = 50827 THEN 'VENTILATIONRATE'
           WHEN itemid = 50828 THEN 'VENTILATOR'
           ELSE NULL
         END AS label
       , le.charttime
       , le.value
       , CASE
           WHEN valuenum <= 0 AND itemid != 50802 THEN NULL
           WHEN itemid = 50810 AND valuenum > 100 THEN NULL
           WHEN itemid = 50816 AND valuenum < 20  THEN NULL
           WHEN itemid = 50816 AND valuenum > 100 THEN NULL
           WHEN itemid = 50817 AND valuenum > 100 THEN NULL
           WHEN itemid = 50815 AND valuenum >  70 THEN NULL
           WHEN itemid = 50821 AND valuenum > 800 THEN NULL
           ELSE valuenum
         END AS valuenum
  FROM   icustays ie
  INNER  JOIN labevents le
         ON  le.subject_id = ie.subject_id
         AND le.hadm_id    = ie.hadm_id
         AND le.charttime BETWEEN ie.intime AND ie.outtime
         AND le.itemid IN (
              50800,50801,50802,50803,50804,50805,50806,50807,50808,50809
            , 50810,50811,50812,50813,50814,50815,50816,50817,50818,50819
            , 50820,50821,50822,50823,50824,50825,50826,50827,50828
            , 51545
         )
)
, bg AS
(
  SELECT subject_id, hadm_id, icustay_id, charttime
       , MAX(CASE WHEN label = 'SPECIMEN'          THEN value    END) AS specimen
       , MAX(CASE WHEN label = 'AADO2'             THEN valuenum END) AS aado2
       , MAX(CASE WHEN label = 'BASEEXCESS'        THEN valuenum END) AS baseexcess
       , MAX(CASE WHEN label = 'BICARBONATE'       THEN valuenum END) AS bicarbonate
       , MAX(CASE WHEN label = 'TOTALCO2'          THEN valuenum END) AS totalco2
       , MAX(CASE WHEN label = 'CARBOXYHEMOGLOBIN' THEN valuenum END) AS carboxyhemoglobin
       , MAX(CASE WHEN label = 'CHLORIDE'          THEN valuenum END) AS chloride
       , MAX(CASE WHEN label = 'CALCIUM'           THEN valuenum END) AS calcium
       , MAX(CASE WHEN label = 'GLUCOSE'           THEN valuenum END) AS glucose
       , MAX(CASE WHEN label = 'HEMATOCRIT'        THEN valuenum END) AS hematocrit
       , MAX(CASE WHEN label = 'HEMOGLOBIN'        THEN valuenum END) AS hemoglobin
       , MAX(CASE WHEN label = 'INTUBATED'         THEN valuenum END) AS intubated
       , MAX(CASE WHEN label = 'LACTATE'           THEN valuenum END) AS lactate
       , MAX(CASE WHEN label = 'METHEMOGLOBIN'     THEN valuenum END) AS methemoglobin
       , MAX(CASE WHEN label = 'O2FLOW'            THEN valuenum END) AS o2flow
       , MAX(CASE WHEN label = 'FIO2'              THEN valuenum END) AS fio2
       , MAX(CASE WHEN label = 'SO2'               THEN valuenum END) AS so2
       , MAX(CASE WHEN label = 'PCO2'              THEN valuenum END) AS pco2
       , MAX(CASE WHEN label = 'PEEP'              THEN valuenum END) AS peep
       , MAX(CASE WHEN label = 'PH'                THEN valuenum END) AS ph
       , MAX(CASE WHEN label = 'PO2'               THEN valuenum END) AS po2
       , MAX(CASE WHEN label = 'POTASSIUM'         THEN valuenum END) AS potassium
       , MAX(CASE WHEN label = 'REQUIREDO2'        THEN valuenum END) AS requiredo2
       , MAX(CASE WHEN label = 'SODIUM'            THEN valuenum END) AS sodium
       , MAX(CASE WHEN label = 'TEMPERATURE'       THEN valuenum END) AS temperature
       , MAX(CASE WHEN label = 'TIDALVOLUME'       THEN valuenum END) AS tidalvolume
       , MAX(CASE WHEN label = 'VENTILATIONRATE'   THEN valuenum END) AS ventilationrate
       , MAX(CASE WHEN label = 'VENTILATOR'        THEN valuenum END) AS ventilator
  FROM   bg_pvt
  GROUP  BY subject_id, hadm_id, icustay_id, charttime
)
, stg_spo2 AS
(
  SELECT subject_id, hadm_id, icustay_id, charttime
       , MAX(CASE WHEN valuenum <= 0 OR valuenum > 100 THEN NULL ELSE valuenum END) AS spo2
  FROM   chartevents
  WHERE  itemid IN (646, 220277)
  GROUP  BY subject_id, hadm_id, icustay_id, charttime
)
, stg_fio2 AS
(
  SELECT subject_id, hadm_id, icustay_id, charttime
       , MAX(
           CASE
             WHEN itemid = 223835 THEN
               CASE
                 WHEN valuenum > 0  AND valuenum <= 1   THEN valuenum * 100
                 WHEN valuenum > 1  AND valuenum < 21   THEN NULL
                 WHEN valuenum >= 21 AND valuenum <= 100 THEN valuenum
                 ELSE NULL
               END
             WHEN itemid IN (3420, 3422)              THEN valuenum
             WHEN itemid = 190 AND valuenum > 0.20 AND valuenum < 1
                                                      THEN valuenum * 100
             ELSE NULL
           END
         ) AS fio2_chartevents
  FROM   chartevents
  WHERE  itemid IN (3420, 190, 223835, 3422)
    AND  COALESCE(error, 0) = 0
  GROUP  BY subject_id, hadm_id, icustay_id, charttime
)
, stg2 AS
(
  SELECT bg.*
       , ROW_NUMBER() OVER (
           PARTITION BY bg.icustay_id, bg.charttime
           ORDER BY     s1.charttime DESC
         ) AS lastrowspo2
       , s1.spo2
  FROM   bg
  LEFT   JOIN stg_spo2 s1
         ON  bg.icustay_id = s1.icustay_id
         AND s1.charttime >= DATETIME_SUB(bg.charttime, INTERVAL '2' HOUR)
         AND s1.charttime <= bg.charttime
  WHERE  bg.po2 IS NOT NULL
)
, stg3 AS
(
  SELECT stg2.*
       , ROW_NUMBER() OVER (
           PARTITION BY stg2.icustay_id, stg2.charttime
           ORDER BY     s2.charttime DESC
         ) AS lastrowfio2
       , s2.fio2_chartevents
       , 1 / (1 + EXP(-(-0.02544
            +  0.04598 * po2
            + COALESCE(-0.15356 * spo2             , -0.15356 *   97.49420 +    0.13429)
            + COALESCE( 0.00621 * s2.fio2_chartevents,  0.00621 *   51.49550 +   -0.24958)
            + COALESCE( 0.10559 * hemoglobin       ,  0.10559 *   10.32307 +    0.05954)
            + COALESCE( 0.13251 * so2              ,  0.13251 *   93.66539 +   -0.23172)
            + COALESCE(-0.01511 * pco2             , -0.01511 *   42.08866 +   -0.01630)
            + COALESCE( 0.01480 * fio2             ,  0.01480 *   63.97836 +   -0.31142)
            + COALESCE(-0.00200 * aado2            , -0.00200 *  442.21186 +   -0.01328)
            + COALESCE(-0.03220 * bicarbonate      , -0.03220 *   22.96894 +   -0.06535)
            + COALESCE( 0.05384 * totalco2         ,  0.05384 *   24.72632 +   -0.01405)
            + COALESCE( 0.08202 * lactate          ,  0.08202 *    3.06436 +    0.06038)
            + COALESCE( 0.10956 * ph               ,  0.10956 *    7.36233 +   -0.00617)
            + COALESCE( 0.00848 * o2flow           ,  0.00848 *    7.59362 +   -0.35803)
         ))) AS specimen_prob
  FROM   stg2
  LEFT   JOIN stg_fio2 s2
         ON  stg2.icustay_id = s2.icustay_id
         AND s2.charttime BETWEEN DATETIME_SUB(stg2.charttime, INTERVAL '4' HOUR)
                              AND stg2.charttime
  WHERE  stg2.lastrowspo2 = 1
)
SELECT subject_id, hadm_id, icustay_id, charttime
     , specimen
     , CASE
         WHEN specimen IS NOT NULL    THEN specimen
         WHEN specimen_prob > 0.75    THEN 'ART'
         ELSE NULL
       END AS specimen_pred
     , specimen_prob
     , so2, spo2, po2, pco2
     , fio2_chartevents, fio2
     , aado2
     , CASE
         WHEN po2 IS NOT NULL
          AND pco2 IS NOT NULL
          AND COALESCE(fio2, fio2_chartevents) IS NOT NULL
         THEN (COALESCE(fio2, fio2_chartevents) / 100) * (760 - 47) - (pco2 / 0.8) - po2
         ELSE NULL
       END AS aado2_calc
     , CASE
         WHEN po2 IS NOT NULL AND COALESCE(fio2, fio2_chartevents) IS NOT NULL
         THEN 100 * po2 / COALESCE(fio2, fio2_chartevents)
         ELSE NULL
       END AS pao2fio2
     , ph, baseexcess, bicarbonate, totalco2
     , hematocrit, hemoglobin, carboxyhemoglobin, methemoglobin
     , chloride, calcium, temperature, potassium, sodium, lactate, glucose
     , intubated, tidalvolume, ventilationrate, ventilator
     , peep, o2flow, requiredo2
FROM   stg3
WHERE  lastrowfio2 = 1
  AND  (specimen = 'ART' OR specimen_prob > 0.75);

CREATE INDEX IF NOT EXISTS blood_gas_arterial_idx
  ON blood_gas_arterial (icustay_id, charttime);
