*STATA code for producing results in paper "Post-covid medical complaints following infection with SARS-CoV-2 Omicron vs Delta variants", by Magnusson et al., 2022.
*Developed and tested in STATA MP v. 17.0. 
*No software or operating system dependencies
*No required non-standard hardware
*Instructions/guidance to interpretation included for every step beneath (starred)
*Typical time to run the entire code on a "normal" desktop computer: 4 days
*Data are not available due to privacy restrictions
*Contact: Karin Magnusson (corresponding author) karin.magnusson@fhi.no

*Step 1: Load data and tabulate variant 
clear all
use population, clear
tab variant

*Step 2: Find descriptive characteristics by variant (produce Table 1)
*Data on: age, sex, education (primary school, upper secondary school, college/university, comorbiditis, vaccination status (1, 2, or 3 doses), primary care visits, number of negative tests)
collapse (mean) age (sd) agesd = age (sum) sexF=sex (mean) sex (sum) antprimschool=primschool (mean) primschool (sum) antusschool=usschool (mean) usschool (sum) antcoluniv=coluniv (mean) coluniv (sum) antNorway = Norway (mean) Norway (sum) antComorb = comorb2  (mean) comorb2 (sum) nr1dose = dose1 (mean) dose1 (sum) nr2dose = dose2 (mean) dose2 (sum) nr3dose = dose3 (mean) dose3 (median) medianpcbehav=nrprevisits (p25) iqr25pcbehav=nrprevisits (p75) iqr75pcbehav=nrprevisits (median) mediantestbehav=pretestNegtests (p25) iqr25testbehav=pretestNegtests (p75) iqr75testbehav=pretestNegtests, by(variant)

*Step 3: Calculate proportions of positive screened tests with omicron or delta for each day (produce S-Figure 1)
use population, clear

recode variant 0=1 1/4=., gen(neg)
recode variant 3=1 1/2=. 0=. 4=., gen(delt)
recode variant 4=1 2/4=. 0=., gen(omic)
recode variant .=1 1/4=., gen(unt)

collapse (count) unt (count)  neg (count) omic (count) delt, by(Prøvedato)

gen omicrdelt=delt+omic

gen omicprop=omic/omicrdelt
gen deltprop=delt/omicrdelt
sc omicprop Prøvedato, connect(l) || sc  deltprop Prøvedato, connect(l)
graph save "../plott/propOmicDelt.gph", replace


*Step 4: Calculate person-time and number of events by outcome, estimate hazard ratios with and without censoring of observations from the date of positive test among non-infected in the comparison groups. Repeat with setting 1) test negative as reference category, 2) untested as reference category, and 3) test negative + untested as reference category. Together, all parts of this step produces estimates for inclusion in Figure 2, Figure 3, S-Tables 2-4 and S-Figure 2-3.
*Outcomes Any complaint, musculoskeletal pain (multpain) fatigue, cough, heart palpitations (heartp), shortness of breath (breath), anxiety and depression (anxdepr), brain fog/concentration problems/memory loss (brainfog) are included in a dataset with all cause-specific healthcarevisits and their dates (kontaktdato). 
*encrypted ID variable: persId_hash
use population, clear
foreach x of varlist anycomplaint multpain fatigue cough heartp breath anxdepr brainfog {
use population, clear
gen `x'date = kontaktdato if `x'==1
*select the first date per outcome
by persId_hash, sort: egen min`x'date=min(`x'date)
by persId_hash, sort: egen max`x'=max(`x')
*generate date variable containing all information, censor if individual dies or emigrates (indicated in fregdatotype and regdato)and if this date come prior to the date with outcome in question or the latest possible day of followup (sensurdatoCOX, April 13th 2022)
replace sensurdatoCOX = regdato if max`x'!=1 & fregdatotype!=1 & regdato<=sensurdatoCOX
replace `x'date = min`x'date if `x'==1 & min`x'date<=sensurdatoCOX 
replace `x'date =sensurdatoCOX if `x'!=1 & min`x'date>=sensurdatoCOX 
format `x'date %d

*The following three lines only apply in analyses including censoring of observations from the date of positive test (indicated in posafterneg and prøvedatoPosAdded) and onwards
format `x'date %d
recode max`x' .=0
replace max`x'=. if posafterneg==1 & prøvedatoPosAdded<=min`x'date

*by outcome, keep only one record per individual
recode max`x' .=0
bysort persId_hash: gen n1=_n
bysort persId_hash: gen N1=_N
keep if n1==N1

*generate day by day variable for estimation (Prøvedato = date of PCR testing for SARS-CoV-2)
gen Prøvedato14 = Prøvedato+14
gen `x'nrdays = `x'date-Prøvedato14
*all visits outside follow-up period are excluded
replace `x'nrdays = 126 if `x'nrdays<=0
replace `x'nrdays = 126 if `x'nrdays>=126

*declare the data in memory to be survival-time data prior to time to event estimation
stset `x'nrdays, failure(max`x'=1) id(persId_hash)

*calculate person-time by variant 
label define variant 0 "Delta" 1 "Omicron" 2 "Testing negative"
stptime if variant==0, at(0(126)126) by(variant) per(100000)

gen failneg=`r(failures)' 
gen ptimeneg =`r(ptime)' 
gen IRneg =`r(rate)'

stptime if variant==1, at(0(126)126) by(variant) per(100000)

gen faildelta=`r(failures)' 
gen ptimedelta = `r(ptime)'
gen IRdelta = `r(rate)'

stptime if variant==2, at(0(126)126) by(variant) per(100000)

gen failomicron=`r(failures)' 
gen ptimeomicron = `r(ptime)' 
gen IRomicron = `r(rate)' 
gen total=1

collapse (mean) ptime* fail* IR*
save "../DATA/`x'ptime_R2.dta", replace
*these data are later appended to each other, using append and order (not shown here)

*user written files eststo.ado and esttab.ado are installed and accessed 
ssc install estout, replace
sysdir set PERSONAL "G:\Helseregistre\BeredtC19\TeamHelsetjenester\KMAG\ado"

*estimate hazard ratios using COX regression: 1) crude, 2) adjusted for potential confounders, and 3) adjusted for potential confounders + vaccination status, stratified on calendar week of testing (pdweek)
eststo varSENS_`x': stcox i.variant, strata(pdweek)

eststo adjvarSENS_`x': stcox i.variant i.pcbehav i.comorb2 i.testbehav Norge alder sex i.educ, strata(pdweek)

eststo adjvarSENS_`x'vax: stcox i.variant i.pcbehav i.comorb2 i.testbehav i.AntDoserFørTest Norge alder sex i.educ, strata(pdweek)

*check proportional hazards assumptions by visual inspection of residuals
stphplot
stphplot, by(variant)

*add it all in one table
esttab varSENS_`x' adjvarSENS_`x' adjvarSENS_`x'vax  using "G:\Helseregistre\BeredtC19\TeamHelsetjenester\DOKRKMAG\PLOTTomikron_R2\coxvariant_strata_R2vax.xls", b(a2) ci(a2) wide keep(1.variant 2.variant) nomti ///
noobs nogaps nolines noeqli nostar nodep nonum nonotes tab eform mlabels([,"`val'"]) append

*Step 5. Calculate weekly shares visiting primary care with the different outcomes using logit model, after first having saved the data in a panel structure (outcome data taking values 0 or 1 for every week from the test week and until week 19 (day 126), with and without censoring from the week of positive test and onwards among the non-infected.
*This step is later repeated for the vaccinated and unvaccinated (vaccine status strata calculated by: egen lastdose = rowmax(dose1dato dose2dato dose3dato) /// format lastdose %d /// gen daysincevax=Prøvedato-lastdose /// gen vax =1 if daysincevax>=14 & daysincevax<=210 /// recode vax .=0 )

use panel_all, clear
foreach x of varlist anycomplaint multpain fatigue cough heartp shortbreath anxdepr brainfog 
use panel_all, clear
*make censordate variables, add 4 weeks to make calendar weeks and study weeks align
gen sensurdatoCOX=Prøvedato + 126
format %d sensurdatoCOX
gen sensurweek=week(sensurdatoCOX)
replace sensurweek =sensurweek+4
gen lastdate =mdy(4,13,2022)
format lastdate %d
gen apr13week = week(lastdate)
replace apr13week = apr13week+4
gen lastweek = apr13week-pdweek

*The following three lines only apply in analyses including censoring of observations from the date of positive test (indicated in posafterneg and prøvedatoPosAdded) and onwards
gen pos_testweek=week(prøvedatoPosAdded)
replace pos_testweek=pos_testweek+4
replace lastweek=pos_testweek if pos_testweek<lastweek

recode `x' .=0
replace `x'=. if week>lastweek
replace `x'=. if time==.

label define variant 1 "Tested negative" 2 "Untested" 3 "Delta" 4 "Omicron"

*run logit models, with robust standard errors clustered on patient
logit `x' i.time#i.variant i.pcbehav i.comorb2 i.testbehav i.AntDoserFørTest Norge alder i.pdweek i.educ, vce(cluster persId_hash)

*predict adjusted probabilities
quietly margins time, over(variant) predict(xb) post saving(m_`x', replace)
*take inverse logit and multiply by 10 000 for plotting (produces Figure 4 and S-Figure 4 and S-Figure 5 when run stratified on vaccination status)

*estimate period-wise group differences for Omicron vs Delta.
gen timerec=time*7
replace timerec = 0 if timerec<14
replace timerec = 1 if timerec>=14 & timerec<=29
replace timerec = 2 if timerec>=30 & timerec<=89
replace timerec = 3 if timerec>=90 & timerec<=126

logit `x' i.timerec##i.variant i.pcbehav i.comorb2 i.testbehav i.AntDoserFørTest Norge alder i.pdweek i.educ, vce(cluster persId_hash)
*take the difference and multiply by 10 000 to obtain results presented in Table 3 and S-Table 5. 
margins, dydx(variant) over(timerec) post saving (mdx_`x'unt, replace)