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 XML format

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 files

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_response

Next, 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"

Check your work

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.

  1. Open the generated FACTS files in the Windows GUI and inspect the various tabs.
  2. Run the generated FACTS files from the Windows GUI (using a small number of iterations if sufficient to detect the changed settings).
  3. Run the FACTS file with run_facts() and check that the output is consistent with the input settings you specified.
  4. Use 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]>