Author

Suparna Chaudhry and Andrew Heiss

Modified

February 2, 2023

Code
library(tidyverse)
library(targets)
library(brms)
library(glue)
library(kableExtra)
library(lubridate)
library(here)

tar_config_set(store = here::here('_targets'),
               script = here::here('_targets.R'))

# Treatment models
tar_load(c(m_oda_treatment_total, m_oda_treatment_advocacy, 
           m_oda_treatment_entry, m_oda_treatment_funding, 
           m_oda_treatment_ccsi, m_oda_treatment_repress))
tar_load(c(m_purpose_treatment_total, m_purpose_treatment_advocacy,
           m_purpose_treatment_entry, m_purpose_treatment_funding,
           m_purpose_treatment_ccsi, m_purpose_treatment_repress))
tar_load(c(m_recip_treatment_total_dom, m_recip_treatment_advocacy_dom,
           m_recip_treatment_entry_dom, m_recip_treatment_funding_dom,
           m_recip_treatment_ccsi_dom, m_recip_treatment_repress_dom))
tar_load(c(m_recip_treatment_total_foreign, m_recip_treatment_advocacy_foreign,
           m_recip_treatment_entry_foreign, m_recip_treatment_funding_foreign,
           m_recip_treatment_ccsi_foreign, m_recip_treatment_repress_foreign))

# Outcome models
tar_load(c(m_oda_outcome_total, m_oda_outcome_advocacy, 
           m_oda_outcome_entry, m_oda_outcome_funding,
           m_oda_outcome_ccsi, m_oda_outcome_repress))
tar_load(c(m_purpose_outcome_total, m_purpose_outcome_advocacy,
           m_purpose_outcome_entry, m_purpose_outcome_funding,
           m_purpose_outcome_ccsi, m_purpose_outcome_repress))
tar_load(c(m_recip_outcome_total_dom, m_recip_outcome_advocacy_dom,
           m_recip_outcome_entry_dom, m_recip_outcome_funding_dom,
           m_recip_outcome_ccsi_dom, m_recip_outcome_repress_dom))
tar_load(c(m_recip_outcome_total_foreign, m_recip_outcome_advocacy_foreign,
           m_recip_outcome_entry_foreign, m_recip_outcome_funding_foreign,
           m_recip_outcome_ccsi_foreign, m_recip_outcome_repress_foreign))

We ran these models on a 2021 M1 MacBook Pro with 32 GB of RAM, with 4 MCMC chains spread across 8 cores, with two CPU threads per chain, using Stan through brms through cmdstanr.

In total, it took 7 hours, 31 minutes, and 44 seconds to run everything.

Model run times

Models for H1 (total ODA)

Code
model_df_h1 <- tribble(
  ~model, ~slot, ~treatment_var, ~stage, ~details,
  "m_oda_treatment_total", "model_num", "Total barriers", "Treatment", "Numerator",
  "m_oda_treatment_total", "model_denom", "Total barriers", "Treatment", "Denominator",
  "m_oda_outcome_total", "model", "Total barriers", "Outcome", "",
  
  "m_oda_treatment_advocacy", "model_num", "Barriers to advocacy", "Treatment", "Numerator",
  "m_oda_treatment_advocacy", "model_denom", "Barriers to advocacy", "Treatment", "Denominator",
  "m_oda_outcome_advocacy", "model", "Barriers to advocacy", "Outcome", "",
  
  "m_oda_treatment_entry", "model_num", "Barriers to entry", "Treatment", "Numerator",
  "m_oda_treatment_entry", "model_denom", "Barriers to entry", "Treatment", "Denominator",
  "m_oda_outcome_entry", "model", "Barriers to entry", "Outcome", "",
  
  "m_oda_treatment_funding", "model_num", "Barriers to funding", "Treatment", "Numerator",
  "m_oda_treatment_funding", "model_denom", "Barriers to funding", "Treatment", "Denominator",
  "m_oda_outcome_funding", "model", "Barriers to funding", "Outcome", "",
  
  "m_oda_treatment_ccsi", "model_num", "Civil society index", "Treatment", "Numerator",
  "m_oda_treatment_ccsi", "model_denom", "Civil society index", "Treatment", "Denominator",
  "m_oda_outcome_ccsi", "model_50", "Civil society index", "Outcome", "IPTW truncated at 50",
  "m_oda_outcome_ccsi", "model_500", "Civil society index", "Outcome", "IPTW truncated at 500",
  
  "m_oda_treatment_repress", "model_num", "Civil society repression", "Treatment", "Numerator",
  "m_oda_treatment_repress", "model_denom", "Civil society repression", "Treatment", "Denominator",
  "m_oda_outcome_repress", "model_50", "Civil society repression", "Outcome", "IPTW truncated at 50"
) %>% 
  mutate(model_nice = glue("<code>{model}${slot}</code>"))

models_h1 <- model_df_h1 %>% 
  mutate(actual_model = map2(model, slot, ~eval(rlang::sym(.x))[[.y]])) %>% 
  mutate(across(c(treatment_var, stage, details), ~fct_inorder(., ordered = TRUE))) %>% 
  mutate(duration = map(actual_model, ~rstan::get_elapsed_time(.$fit)),
         duration = map(duration, ~rownames_to_column(as_tibble(.)))) %>% 
  select(-actual_model) %>% 
  unnest(duration) %>% 
  group_by(Model = model_nice, Treatment = treatment_var, 
           Stage = stage, Details = details) %>% 
  summarize(`Total time (i.e. longest chain)` = as.duration(max(warmup + sample))) %>%
  ungroup() %>% 
  arrange(Treatment, Stage, Details)

total_row_h1 <- tibble(Treatment = "Total", 
                       `Total time (i.e. longest chain)` =
                         as.duration(sum(models_h1$`Total time (i.e. longest chain)`)))

model_time_h1 <- models_h1 %>% 
  bind_rows(total_row_h1)

model_time_h1 %>% 
  select(-Treatment) %>% 
  rename(` ` = Model) %>% 
  kbl(escape = FALSE) %>% 
  pack_rows(index = table(fct_inorder(model_time_h1$Treatment))) %>% 
  kable_styling(htmltable_class = "table table-sm")
Stage Details Total time (i.e. longest chain)
Total barriers
m_oda_treatment_total$model_num Treatment Numerator 16.4s
m_oda_treatment_total$model_denom Treatment Denominator 33.415s
m_oda_outcome_total$model Outcome 374.079s (~6.23 minutes)
Barriers to advocacy
m_oda_treatment_advocacy$model_num Treatment Numerator 19.293s
m_oda_treatment_advocacy$model_denom Treatment Denominator 35.066s
m_oda_outcome_advocacy$model Outcome 178.668s (~2.98 minutes)
Barriers to entry
m_oda_treatment_entry$model_num Treatment Numerator 20.572s
m_oda_treatment_entry$model_denom Treatment Denominator 47.97s
m_oda_outcome_entry$model Outcome 190.837s (~3.18 minutes)
Barriers to funding
m_oda_treatment_funding$model_num Treatment Numerator 19.4s
m_oda_treatment_funding$model_denom Treatment Denominator 34.861s
m_oda_outcome_funding$model Outcome 187.082s (~3.12 minutes)
Civil society index
m_oda_treatment_ccsi$model_num Treatment Numerator 38.434s
m_oda_treatment_ccsi$model_denom Treatment Denominator 115.156s (~1.92 minutes)
m_oda_outcome_ccsi$model_50 Outcome IPTW truncated at 50 1001.767s (~16.7 minutes)
m_oda_outcome_ccsi$model_500 Outcome IPTW truncated at 500 3729.708s (~1.04 hours)
Civil society repression
m_oda_treatment_repress$model_num Treatment Numerator 35.689s
m_oda_treatment_repress$model_denom Treatment Denominator 124.632s (~2.08 minutes)
m_oda_outcome_repress$model_50 Outcome IPTW truncated at 50 1407.371s (~23.46 minutes)
Total
7610.4s (~2.11 hours)

Models for H2 (aid contentiousness)

Code
model_df_h2 <- tribble(
  ~model, ~slot, ~treatment_var, ~stage, ~details,
  "m_purpose_treatment_total", "model_num", "Total barriers", "Treatment", "Numerator",
  "m_purpose_treatment_total", "model_denom", "Total barriers", "Treatment", "Denominator",
  "m_purpose_outcome_total", "model", "Total barriers", "Outcome", "",
  
  "m_purpose_treatment_advocacy", "model_num", "Barriers to advocacy", "Treatment", "Numerator",
  "m_purpose_treatment_advocacy", "model_denom", "Barriers to advocacy", "Treatment", "Denominator",
  "m_purpose_outcome_advocacy", "model", "Barriers to advocacy", "Outcome", "",
  
  "m_purpose_treatment_entry", "model_num", "Barriers to entry", "Treatment", "Numerator",
  "m_purpose_treatment_entry", "model_denom", "Barriers to entry", "Treatment", "Denominator",
  "m_purpose_outcome_entry", "model", "Barriers to entry", "Outcome", "",
  
  "m_purpose_treatment_funding", "model_num", "Barriers to funding", "Treatment", "Numerator",
  "m_purpose_treatment_funding", "model_denom", "Barriers to funding", "Treatment", "Denominator",
  "m_purpose_outcome_funding", "model", "Barriers to funding", "Outcome", "",
  
  "m_purpose_treatment_ccsi", "model_num", "Civil society index", "Treatment", "Numerator",
  "m_purpose_treatment_ccsi", "model_denom", "Civil society index", "Treatment", "Denominator",
  "m_purpose_outcome_ccsi", "model_50", "Civil society index", "Outcome", "IPTW truncated at 50",
  
  "m_purpose_treatment_repress", "model_num", "Civil society repression", "Treatment", "Numerator",
  "m_purpose_treatment_repress", "model_denom", "Civil society repression", "Treatment", "Denominator",
  "m_purpose_outcome_repress", "model_50", "Civil society repression", "Outcome", "IPTW truncated at 50"
) %>% 
  mutate(model_nice = glue("<code>{model}${slot}</code>"))

models_h2 <- model_df_h2 %>% 
  mutate(actual_model = map2(model, slot, ~eval(rlang::sym(.x))[[.y]])) %>% 
  mutate(across(c(treatment_var, stage, details), ~fct_inorder(., ordered = TRUE))) %>% 
  mutate(duration = map(actual_model, ~rstan::get_elapsed_time(.$fit)),
         duration = map(duration, ~rownames_to_column(as_tibble(.)))) %>% 
  select(-actual_model) %>% 
  unnest(duration) %>% 
  group_by(Model = model_nice, Treatment = treatment_var, 
           Stage = stage, Details = details) %>% 
  summarize(`Total time (i.e. longest chain)` = as.duration(max(warmup + sample))) %>%
  ungroup() %>% 
  arrange(Treatment, Stage, Details)

total_row_h2 <- tibble(Treatment = "Total", 
                       `Total time (i.e. longest chain)` =
                         as.duration(sum(models_h2$`Total time (i.e. longest chain)`)))

model_time_h2 <- models_h2 %>% 
  bind_rows(total_row_h2)

model_time_h2 %>% 
  select(-Treatment) %>% 
  rename(` ` = Model) %>% 
  kbl(escape = FALSE) %>% 
  pack_rows(index = table(fct_inorder(model_time_h2$Treatment))) %>% 
  kable_styling(htmltable_class = "table table-sm")
Stage Details Total time (i.e. longest chain)
Total barriers
m_purpose_treatment_total$model_num Treatment Numerator 19.225s
m_purpose_treatment_total$model_denom Treatment Denominator 52.748s
m_purpose_outcome_total$model Outcome 327.009s (~5.45 minutes)
Barriers to advocacy
m_purpose_treatment_advocacy$model_num Treatment Numerator 22.654s
m_purpose_treatment_advocacy$model_denom Treatment Denominator 37.543s
m_purpose_outcome_advocacy$model Outcome 249.26s (~4.15 minutes)
Barriers to entry
m_purpose_treatment_entry$model_num Treatment Numerator 20.675s
m_purpose_treatment_entry$model_denom Treatment Denominator 46.79s
m_purpose_outcome_entry$model Outcome 274.818s (~4.58 minutes)
Barriers to funding
m_purpose_treatment_funding$model_num Treatment Numerator 19.561s
m_purpose_treatment_funding$model_denom Treatment Denominator 51.126s
m_purpose_outcome_funding$model Outcome 316.45s (~5.27 minutes)
Civil society index
m_purpose_treatment_ccsi$model_num Treatment Numerator 47.483s
m_purpose_treatment_ccsi$model_denom Treatment Denominator 128.473s (~2.14 minutes)
m_purpose_outcome_ccsi$model_50 Outcome IPTW truncated at 50 4402.096s (~1.22 hours)
Civil society repression
m_purpose_treatment_repress$model_num Treatment Numerator 36.594s
m_purpose_treatment_repress$model_denom Treatment Denominator 71.595s (~1.19 minutes)
m_purpose_outcome_repress$model_50 Outcome IPTW truncated at 50 4841.638s (~1.34 hours)
Total
10965.738s (~3.05 hours)

Models for H3 (aid recipients)

Domestic NGOs

Foreign NGOs

Code
model_df_h3_foreign <- tribble(
  ~model, ~slot, ~treatment_var, ~stage, ~details,
  "m_recip_treatment_total_foreign", "model_num", "Total barriers", "Treatment", "Numerator",
  "m_recip_treatment_total_foreign", "model_denom", "Total barriers", "Treatment", "Denominator",
  "m_recip_outcome_total_foreign", "model", "Total barriers", "Outcome", "",
  
  "m_recip_treatment_advocacy_foreign", "model_num", "Barriers to advocacy", "Treatment", "Numerator",
  "m_recip_treatment_advocacy_foreign", "model_denom", "Barriers to advocacy", "Treatment", "Denominator",
  "m_recip_outcome_advocacy_foreign", "model", "Barriers to advocacy", "Outcome", "",
  
  "m_recip_treatment_entry_foreign", "model_num", "Barriers to entry", "Treatment", "Numerator",
  "m_recip_treatment_entry_foreign", "model_denom", "Barriers to entry", "Treatment", "Denominator",
  "m_recip_outcome_entry_foreign", "model", "Barriers to entry", "Outcome", "",
  
  "m_recip_treatment_funding_foreign", "model_num", "Barriers to funding", "Treatment", "Numerator",
  "m_recip_treatment_funding_foreign", "model_denom", "Barriers to funding", "Treatment", "Denominator",
  "m_recip_outcome_funding_foreign", "model", "Barriers to funding", "Outcome", "",
  
  "m_recip_treatment_ccsi_foreign", "model_num", "Civil society index", "Treatment", "Numerator",
  "m_recip_treatment_ccsi_foreign", "model_denom", "Civil society index", "Treatment", "Denominator",
  "m_recip_outcome_ccsi_foreign", "model_50", "Civil society index", "Outcome", "IPTW truncated at 50",
  
  "m_recip_treatment_repress_foreign", "model_num", "Civil society repression", "Treatment", "Numerator",
  "m_recip_treatment_repress_foreign", "model_denom", "Civil society repression", "Treatment", "Denominator",
  "m_recip_outcome_repress_foreign", "model_50", "Civil society repression", "Outcome", "IPTW truncated at 50"
) %>% 
  mutate(model_nice = glue("<code>{model}${slot}</code>"))

models_h3_foreign <- model_df_h3_foreign %>% 
  mutate(actual_model = map2(model, slot, ~eval(rlang::sym(.x))[[.y]])) %>% 
  mutate(across(c(treatment_var, stage, details), ~fct_inorder(., ordered = TRUE))) %>% 
  mutate(duration = map(actual_model, ~rstan::get_elapsed_time(.$fit)),
         duration = map(duration, ~rownames_to_column(as_tibble(.)))) %>% 
  select(-actual_model) %>% 
  unnest(duration) %>% 
  group_by(Model = model_nice, Treatment = treatment_var, 
           Stage = stage, Details = details) %>% 
  summarize(`Total time (i.e. longest chain)` = as.duration(max(warmup + sample))) %>%
  ungroup() %>% 
  arrange(Treatment, Stage, Details)

total_row_h3_foreign <- tibble(Treatment = "Total", 
                               `Total time (i.e. longest chain)` =
                                 as.duration(sum(models_h3_foreign$`Total time (i.e. longest chain)`)))

model_time_h3_foreign <- models_h3_foreign %>% 
  bind_rows(total_row_h3_foreign)

model_time_h3_foreign %>% 
  select(-Treatment) %>% 
  rename(` ` = Model) %>% 
  kbl(escape = FALSE) %>% 
  pack_rows(index = table(fct_inorder(model_time_h3_foreign$Treatment))) %>% 
  kable_styling(htmltable_class = "table table-sm")
Stage Details Total time (i.e. longest chain)
Total barriers
m_recip_treatment_total_foreign$model_num Treatment Numerator 17.044s
m_recip_treatment_total_foreign$model_denom Treatment Denominator 26.729s
m_recip_outcome_total_foreign$model Outcome 195.911s (~3.27 minutes)
Barriers to advocacy
m_recip_treatment_advocacy_foreign$model_num Treatment Numerator 18.193s
m_recip_treatment_advocacy_foreign$model_denom Treatment Denominator 51.664s
m_recip_outcome_advocacy_foreign$model Outcome 269.6s (~4.49 minutes)
Barriers to entry
m_recip_treatment_entry_foreign$model_num Treatment Numerator 20.009s
m_recip_treatment_entry_foreign$model_denom Treatment Denominator 41.128s
m_recip_outcome_entry_foreign$model Outcome 211.453s (~3.52 minutes)
Barriers to funding
m_recip_treatment_funding_foreign$model_num Treatment Numerator 14.917s
m_recip_treatment_funding_foreign$model_denom Treatment Denominator 42.38s
m_recip_outcome_funding_foreign$model Outcome 221.329s (~3.69 minutes)
Civil society index
m_recip_treatment_ccsi_foreign$model_num Treatment Numerator 26.768s
m_recip_treatment_ccsi_foreign$model_denom Treatment Denominator 132.467s (~2.21 minutes)
m_recip_outcome_ccsi_foreign$model_50 Outcome IPTW truncated at 50 1253.969s (~20.9 minutes)
Civil society repression
m_recip_treatment_repress_foreign$model_num Treatment Numerator 29.38s
m_recip_treatment_repress_foreign$model_denom Treatment Denominator 103.338s (~1.72 minutes)
m_recip_outcome_repress_foreign$model_50 Outcome IPTW truncated at 50 2283.222s (~38.05 minutes)
Total
4959.501s (~1.38 hours)