To help statisticians explore wider ranges of possibilities for clinical trials, the write_facts() function generates multiple versions of existing FACTS files with different features. This vignette walks through the process
FACTS files have a special XML format to define clinical trial simulations. Most of the internal configuration settings are defined in <property> tags inside <parameterSet>...</parameterSet> and <parameterSets>...</parameterSets>.
<?xml version="1.0" encoding="utf-8"?>
<facts version="6.2.5.22668" name="contin" host="host">
  <parameterSets type="NucleusParameterSet">
    <parameterSet name="nucleus">
      <property name="type">1</property>
      ...
      <property name="max_subjects">300</property>
      <property name="cohort_size">5</property>
      <property name="num_cohorts">50</property>
      <property name="cohort_time">0</property>
      ...
    </parameterSet>
  </parameterSets>
  ...
  <parameterSets type="EfficacyParameterSet">
     <parameterSet name="resp2" EndpointType="1">
      <property name="true_endpoint_response">
        <items>
          <item>0</item>
          <item>10</item>
        </items>
      </property>
      ...
    </parameterSet>
    ...
  </parameterSets>
</facst>write_facts() works on the <property> tags located above. Any <property> within a <facts><parameterSets><parameterSet> block can be modified programmatically. To demonstrate, we will create two new FACTS files with modified virtual subject response scenarios and different numbers of patients. We start with a known FACTS file we create from the Windows GUI (or a built-in example from this package).
library(dplyr)
library(rfacts)
library(tibble)
tmp <- file.copy(get_facts_file_example("contin.facts"), getwd())
facts_file <- "contin.facts"Next, we declare the XML fields we want to replace. We define one field to control the maximum number of subjects,
field_subjects <- tibble(
  field = "my_subjects",        # custom name the user can make up
  type = "NucleusParameterSet", # "type" attribute of the <parameterSets> tag
  set = "nucleus",              # "name" attribute of the <parameterSet> tag
  property = "max_subjects"     # "name" attribute of the <property> tag
)and another field to modify the "resp2" virtual subject response scenario.
field_vsr <- tibble(
  field = "my_vsr",                 
  type = "EfficacyParameterSet",      
  set = "resp2",                      
  property = "true_endpoint_response" 
)We put the fields together in a single data frame.
fields <- bind_rows(field_subjects, field_vsr)
fields
#> # A tibble: 2 × 4
#>   field       type                 set     property              
#>   <chr>       <chr>                <chr>   <chr>                 
#> 1 my_subjects NucleusParameterSet  nucleus max_subjects          
#> 2 my_vsr      EfficacyParameterSet resp2   true_endpoint_responseNext, we define a grid of values to iterate over when we modify these fields. The grid should have one row per FACTS file and one column for every value of fields$field you want to modify in the XML. The values data frame must also contain a facts_file column to identify the source file. You can optionally include an output column to control the output path of each generated FACTS file, but this is not required.
values <- tibble(
  facts_file = facts_file,
  my_subjects = c(1000, 2000),
  my_vsr = list(c(15, 50), c(25, 75))
)
values
#> # A tibble: 2 × 3
#>   facts_file   my_subjects my_vsr   
#>   <chr>              <dbl> <list>   
#> 1 contin.facts        1000 <dbl [2]>
#> 2 contin.facts        2000 <dbl [2]>Above, my_subjects is a vector of max sample sizes, and my_vsr is a list of VSR response means (one for each treatment group). Each value of my_vsr will be inserted as an <item> list in each output FACTS file, and the length of each list element must equal the length of the original <item> list.
To generate the FACTS files, simply call write_facts().
write_facts(fields = fields, values = values)
#> [1] "_facts/38b2cfd4.facts" "_facts/00e8e729.facts"
list.files("_facts")
#> [1] "00e8e729.facts" "38b2cfd4.facts"To control the output paths, add an output column to the values data frame.
unlink("_facts", recursive = TRUE)
values$output <- c("small.facts", "large.facts")
write_facts(fields = fields, values = values)
#> [1] "small.facts" "large.facts"To verify that the generated FACTS files are correct, you can open them in a text or XML editor. Above, small.facts should have 1000 max subjects and resp2 VSR parameters equal to 15 and 50.
<?xml version="1.0" encoding="utf-8"?>
<facts version="6.2.5.22668" name="contin" host="host">
  <parameterSets type="NucleusParameterSet">
    <parameterSet name="nucleus">
      <property name="max_subjects">1000</property>
      ...
    </parameterSet>
  </parameterSets>
  ...
  <parameterSets type="EfficacyParameterSet">
     <parameterSet name="resp2" EndpointType="1">
      <property name="true_endpoint_response">
        <items>
          <item>15</item>
          <item>50</item>
        </items>
      </property>
      ...
    </parameterSet>
    ...
  </parameterSets>
</facst>Likewise, large.facts should have 2000 max subjects and resp2 VSR parameters equal to 25 and 75.
<?xml version="1.0" encoding="utf-8"?>
<facts version="6.2.5.22668" name="contin" host="host">
  <parameterSets type="NucleusParameterSet">
    <parameterSet name="nucleus">
      <property name="max_subjects">2000</property>
      ...
    </parameterSet>
  </parameterSets>
  ...
  <parameterSets type="EfficacyParameterSet">
     <parameterSet name="resp2" EndpointType="1">
      <property name="true_endpoint_response">
        <items>
          <item>25</item>
          <item>75</item>
        </items>
      </property>
      ...
    </parameterSet>
    ...
  </parameterSets>
</facst>Other ways to check your work include the following.
run_facts() and check that the output is consistent with the input settings you specified.read_facts() to inspect the settings that should be modified.read_facts(facts_file = facts_file, fields = fields)
#> # A tibble: 1 × 3
#>   facts_file   my_subjects my_vsr   
#>   <chr>        <chr>       <list>   
#> 1 contin.facts 300         <chr [2]>
read_facts(facts_file = "small.facts", fields = fields)
#> # A tibble: 1 × 3
#>   facts_file  my_subjects my_vsr   
#>   <chr>       <chr>       <list>   
#> 1 small.facts 1000        <chr [2]>
read_facts(facts_file = "large.facts", fields = fields)
#> # A tibble: 1 × 3
#>   facts_file  my_subjects my_vsr   
#>   <chr>       <chr>       <list>   
#> 1 large.facts 2000        <chr [2]>