Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand docs and set up site #329

Merged
merged 9 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/site.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Deploy site
on:
push:
branches:
- scratch/deploy-site
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Hugo
shell: bash
run: |
tdir=$(mktemp -d)
tgz=$tdir/hugo.tar.gz
bin=$HOME/bin
mkdir -p "$bin"

url=https://github.com/gohugoio/hugo/releases/download
curl -fSsL --retry 3 \
"$url/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \
>"$tgz"
printf '%s %s\n' "$HUGO_SHA" "$tgz" | sha256sum --check >/dev/null

tar --to-stdout --extract -zf "$tgz" hugo >"$bin"/hugo
chmod +x "$bin/hugo"
"$bin"/hugo version
echo "$bin" >>"$GITHUB_PATH"
env:
HUGO_VERSION: '0.133.0'
HUGO_SHA: '372530e2de9ae74087a987ca841429390a055123b8a4dec665cc601f10dc8e6e'
- uses: actions/configure-pages@v5
id: pages
- name: Check URL match
shell: bash
run: |
url=$(grep '^baseURL:' docs/site/hugo.yaml)
test "${{ steps.pages.outputs.base_url }}/" = "${url#baseURL: }"
- name: Build site
shell: bash
run: make -C docs/site build
env:
HUGO_ENVIRONMENT: production
HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
TZ: America/New_York
- name: Upload site
uses: actions/upload-pages-artifact@v3
with:
path: ./docs/site/public
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

# bbi

Documentation for `bbi` is available at
<https://metrumresearchgroup.github.io/bbi/docs/>.

bbi is (will be) a complete solution for managing projects involving modeling and simulation with a number
of software solutions used in pharmaceutical sciences.

Expand Down Expand Up @@ -316,15 +319,21 @@ No Heuristic Problems Detected

### Development

Test-driven development encouraged, facilitated by goconvey to monitor coverage
and re-run tests on change(s)
To run the test suite, you can invoke [scripts/run-unit-tests][ru] and
[scripts/run-integration-tests][ri] directly or via `make vt-test`.

During development, while installing new versions for testing, running "make install" will auto-append a timestamp to the build version.
After updating a subcommand, regenerate the Markdown documentation at
[docs/commands][dc] by running `make vt-gen-docs`. See `make vt-help` and
[internal/valtools/README.md][vr] for more details on the validation tooling.

```
$ go get github.com/smartystreets/goconvey
goconvey
```
The setup for building the documentation site is described in
[docs/site/README.md][dr].

a web UI will be started at localhost:8080 with file watchers to rerun tests on
file change(s)
<!-- Note: Use GitHub URLs rather than relative paths (e.g., "/docs/commands") so -->
<!-- that these work on https://metrumresearchgroup.github.io/bbi/ without further -->
<!-- processing. -->
[dc]: https://github.com/metrumresearchgroup/bbi/blob/main/docs/commands
[dr]: https://github.com/metrumresearchgroup/bbi/blob/main/docs/site/README.md
[ri]: https://github.com/metrumresearchgroup/bbi/blob/main/scripts/run-integration-tests
[ru]: https://github.com/metrumresearchgroup/bbi/blob/main/scripts/run-unit-tests
[vr]: https://github.com/metrumresearchgroup/bbi/blob/main/internal/valtools/README.md
54 changes: 24 additions & 30 deletions cmd/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,36 +152,30 @@ func getMatches(s []string, expr string, regex bool) ([]string, error) {

func NewCleanCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "clean",
Short: "clean files and folders",
Long: `
glob examples:
bbi clean *.mod // anything with extension .mod
bbi clean *.mod --noFolders // anything with extension .mod
bbi clean run* // anything starting with run
regular expression examples:

bbi clean ^run --regex // anything beginning with the letters run
bbi clean ^run -v --regex // print out files and folders that will be deleted
bbi clean ^run --filesOnly --regex // only remove matching files
bbi clean _est_ --dirsOnly --regex // only remove matching folders
bbi clean _est_ --dirsOnly --preview --regex // show what output would be if clean occured but don't actually clean
bbi clean "run009.[^mod]" --regex // all matching run009.<ext> but not .mod files
bbi clean "run009.(mod|lst)$" --regex // match run009.lst and run009.mod

can also clean via the opposite of a match with inverse

bbi clean ".modt{0,1}$" --filesOnly --inverse --regex // clean all files not matching .mod or .modt

clean copied files via

bbi clean --copiedRuns="run001"
bbi clean --copiedRuns="run[001:010]"

can be a comma separated list as well

bbi clean --copiedRuns="run[001:010],run100"
`,
Use: "clean [flags] <pattern> [<pattern>...]",
Short: "Clean files and folders",
Long: `Clean the files and directories that match the specified patterns.
Whether the pattern is interpreted as a glob or regex is controlled by the
--regex flag.

If files were copied to the parent directory automatically after model
execution (via the copy_lvl configuration), the original files in the run
directory can be cleaned up by selecting the run with the --copiedRuns
option.`,
Example: ` # Remove items in the current directory that end with ".mod"
bbi nonmem clean *.mod
# The same as above but ensure only files are removed
bbi nonmem clean --filesOnly *.mod

# Remove files in the current directory that start with "run" and end with
# ".mod" or ".lst"
bbi nonmem clean --filesOnly --regex "run.*\.(mod|lst)$"
# Report what the above would remove but don't actually do it
bbi nonmem clean --preview --filesOnly --regex "run.*\.(mod|lst)$"

# Remove copied files (recorded in '{run}_copied.json' by 'bbi run') for
# run001, run002, run003, and run100
bbi nonmem clean --copiedRuns='run[001:003],run100'`,
RunE: clean,
}

Expand Down
20 changes: 12 additions & 8 deletions cmd/covcor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import (
"github.com/spf13/viper"
)

const covcorLongDescription string = `load .cov and .cor output from model(s), for example:
bbi nonmem covcor run001/run001
bbi nonmem covcor run001/run001.cov
`
const covcorExamples string = ` # Display .cov/cor values from run001/run001.{cov,cor}
bbi nonmem covcor run001/run001
# Display the same values by specifying a full output file
bbi nonmem covcor run001/run001.cov`

func covcor(cmd *cobra.Command, args []string) {
if debug {
Expand All @@ -47,9 +47,13 @@ func covcor(cmd *cobra.Command, args []string) {

func NewCovcorCmd() *cobra.Command {
return &cobra.Command{
Use: "covcor",
Short: "load .cov and .cor output from a model run",
Long: covcorLongDescription,
Run: covcor,
Use: "covcor [flags] <run file>",
Short: "Display .cov and .cor output for a model",
Long: `Read the .cov and .cor files from a model's output directory and
display the values as a JSON object. The argument is typically a shared prefix
for the run output files, but it can be any path from which the run name can be
derived.`,
Example: covcorExamples,
Run: covcor,
}
}
11 changes: 8 additions & 3 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,18 @@ func NewInitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Create configuration file with defaults",
Long: `Run bbi init to create a bbi.yaml configuration file in the current directory.
`,
Long: `Write a bbi.yaml configuration file in the current directory
to initialize it for running bbi.

If the --dir=DIR option is specified, DIR should point to a directory that
contains one or more NONMEM installations directories. Any subdirectory in
DIR is taken as an installation if it has the expected layout (e.g., a "run"
directory with an nmfe executable)`,
RunE: initializer,
}

const directory string = "dir"
cmd.Flags().StringSlice(directory, []string{}, "A directory in which to look for NonMem Installations")
cmd.Flags().StringSlice(directory, []string{}, "directory in which to look for NONMEM installations")

return cmd
}
Expand Down
12 changes: 6 additions & 6 deletions cmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,15 @@ func (l LocalModel) Cleanup(channels *turnstile.ChannelMap) {

func NewLocalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "local",
Short: "local specifies to run a (set of) models locally",
Long: runLongDescription,
Run: local,
Use: "local [flags] <model> [<model>...]",
Short: "Run models locally",
Example: fmt.Sprintf(runExamples, "local"),
Run: local,
}

childDirIdentifier := "create_child_dirs"
cmd.PersistentFlags().Bool(childDirIdentifier, true, "Indicates whether or not local branch execution"+
"should create a new subdirectory with the output_dir variable as its name and execute in that directory")
cmd.PersistentFlags().Bool(childDirIdentifier, true,
"create a new subdirectory, named based on the output_dir option, for execution")
errpanic(viper.BindPFlag("local."+childDirIdentifier, cmd.PersistentFlags().Lookup(childDirIdentifier)))

return cmd
Expand Down
43 changes: 23 additions & 20 deletions cmd/nonmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,79 +164,82 @@ type NonMemModel struct {
Error error `json:"error"`
}

var nonmemLongDescription string = fmt.Sprintf("\n%s\n\n%s\n\n%s\n", runLongDescription, summaryLongDescription, covcorLongDescription)
var nonmemExamples string = fmt.Sprintf("%s\n\n%s\n\n%s\n",
fmt.Sprintf(runExamples, "(local|sge)"),
summaryExamples,
covcorExamples)

func nonmem(_ *cobra.Command, _ []string) {
println(nonmemLongDescription)
println(nonmemExamples)
}

func NewNonmemCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "nonmem",
Short: "nonmem a (set of) models locally or on the grid",
Long: nonmemLongDescription,
Run: nonmem,
Use: "nonmem",
Short: "Entry point for NONMEM-related subcommands",
Example: nonmemExamples,
Run: nonmem,
}

// NM Selector
const nmVersionIdentifier string = "nm_version"
cmd.PersistentFlags().String(nmVersionIdentifier, "", "Version of nonmem from the configuration list to use")
cmd.PersistentFlags().String(nmVersionIdentifier, "", "version of NONMEM from the configuration list to use")
errpanic(viper.BindPFlag(nmVersionIdentifier, cmd.PersistentFlags().Lookup(nmVersionIdentifier)))

// Parallelization Components
const parallelIdentifier string = "parallel"
cmd.PersistentFlags().Bool(parallelIdentifier, false, "Whether or not to run nonmem in parallel mode")
cmd.PersistentFlags().Bool(parallelIdentifier, false, "whether to run NONMEM in parallel mode")
errpanic(viper.BindPFlag(parallelIdentifier, cmd.PersistentFlags().Lookup(parallelIdentifier)))

const parallelCompletionTimeoutIdentifier string = "parallel_timeout"
cmd.PersistentFlags().Int(parallelCompletionTimeoutIdentifier, 2147483647, "The amount of time to wait for parallel operations in nonmem before timing out")
cmd.PersistentFlags().Int(parallelCompletionTimeoutIdentifier, 2147483647, "amount of time to wait for parallel operations in NONMEM before timing out")
errpanic(viper.BindPFlag(parallelCompletionTimeoutIdentifier, cmd.PersistentFlags().Lookup(parallelCompletionTimeoutIdentifier)))

const mpiExecPathIdentifier string = "mpi_exec_path"
cmd.PersistentFlags().String(mpiExecPathIdentifier, "/usr/local/mpich3/bin/mpiexec", "The fully qualified path to mpiexec. Used for nonmem parallel operations")
cmd.PersistentFlags().String(mpiExecPathIdentifier, "/usr/local/mpich3/bin/mpiexec", "fully qualified path to mpiexec to use for NONMEM parallel operations")
errpanic(viper.BindPFlag(mpiExecPathIdentifier, cmd.PersistentFlags().Lookup(mpiExecPathIdentifier)))

const parafileIdentifier string = "parafile"
cmd.PersistentFlags().String(parafileIdentifier, "", "Location of a user-provided parafile to use for parallel execution")
cmd.PersistentFlags().String(parafileIdentifier, "", "location of a user-provided parafile to use for parallel execution")
errpanic(viper.BindPFlag(parafileIdentifier, cmd.PersistentFlags().Lookup(parafileIdentifier)))

const nmQualIdentifier string = "nmqual"
cmd.PersistentFlags().Bool(nmQualIdentifier, false, "Whether or not to execute with nmqual (autolog.pl)")
cmd.PersistentFlags().Bool(nmQualIdentifier, false, "whether to execute with nmqual (autolog.pl)")
errpanic(viper.BindPFlag(nmQualIdentifier, cmd.PersistentFlags().Lookup(nmQualIdentifier)))

// NMFE Options
const nmfeGroup string = "nmfe_options"
const licFileIdentifier string = "licfile"
cmd.PersistentFlags().String(licFileIdentifier, "", "RAW NMFE OPTION - Specify a license file to use with NMFE (Nonmem)")
cmd.PersistentFlags().String(licFileIdentifier, "", "RAW NMFE OPTION - NONMEM license file to use")
errpanic(viper.BindPFlag(nmfeGroup+"."+licFileIdentifier, cmd.PersistentFlags().Lookup(licFileIdentifier)))

const prSameIdentifier string = "prsame"
cmd.PersistentFlags().Bool(prSameIdentifier, false, "RAW NMFE OPTION - Indicates to nonmem that the PREDPP compilation step should be skipped")
cmd.PersistentFlags().Bool(prSameIdentifier, false, "RAW NMFE OPTION - tell NONMEM to skip the PREDPP compilation step")
errpanic(viper.BindPFlag(nmfeGroup+"."+prSameIdentifier, cmd.PersistentFlags().Lookup(prSameIdentifier)))

const backgroundIdentifier string = "background"
cmd.PersistentFlags().Bool(backgroundIdentifier, false, "RAW NMFE OPTION - Tells nonmem not to scan StdIn for control characters")
cmd.PersistentFlags().Bool(backgroundIdentifier, false, "RAW NMFE OPTION - tell NONMEM not to scan stdin for control characters")
errpanic(viper.BindPFlag(nmfeGroup+"."+backgroundIdentifier, cmd.PersistentFlags().Lookup(backgroundIdentifier)))

const prCompileIdentifier string = "prcompile"
cmd.PersistentFlags().Bool(prCompileIdentifier, false, "RAW NMFE OPTION - Forces PREDPP compilation")
cmd.PersistentFlags().Bool(prCompileIdentifier, false, "RAW NMFE OPTION - forces PREDPP compilation")
errpanic(viper.BindPFlag(nmfeGroup+"."+prCompileIdentifier, cmd.PersistentFlags().Lookup(prCompileIdentifier)))

const prDefaultIdentifier string = "prdefault"
cmd.PersistentFlags().Bool(prDefaultIdentifier, false, "RAW NMFE OPTION - Do not recompile any routines other than FSUBS")
cmd.PersistentFlags().Bool(prDefaultIdentifier, false, "RAW NMFE OPTION - do not recompile any routines other than FSUBS")
errpanic(viper.BindPFlag(nmfeGroup+"."+prDefaultIdentifier, cmd.PersistentFlags().Lookup(prDefaultIdentifier)))

const tprDefaultIdentifier string = "tprdefault"
cmd.PersistentFlags().Bool(tprDefaultIdentifier, false, "RAW NMFE OPTION - Test if is okay to do -prdefault")
cmd.PersistentFlags().Bool(tprDefaultIdentifier, false, "RAW NMFE OPTION - test if is okay to do -prdefault")
errpanic(viper.BindPFlag(nmfeGroup+"."+tprDefaultIdentifier, cmd.PersistentFlags().Lookup(tprDefaultIdentifier)))

const noBuildIdentifier string = "nobuild"
cmd.PersistentFlags().Bool(noBuildIdentifier, false, "RAW NMFE OPTION - Skips recompiling and rebuilding on nonmem executable")
cmd.PersistentFlags().Bool(noBuildIdentifier, false, "RAW NMFE OPTION - do not build a new NONMEM executable")
errpanic(viper.BindPFlag(nmfeGroup+"."+noBuildIdentifier, cmd.PersistentFlags().Lookup(noBuildIdentifier)))

const maxLimIdentifier string = "maxlim"
cmd.PersistentFlags().Int(maxLimIdentifier, 2,
"RAW NMFE OPTION - Set the maximum values for the buffers used by Nonmem (if 0, don't pass -maxlim to nmfe)")
"RAW NMFE OPTION - set the maximum values for the buffers used by NONMEM (if 0, don't pass -maxlim to nmfe)")
errpanic(viper.BindPFlag(nmfeGroup+"."+maxLimIdentifier, cmd.PersistentFlags().Lookup(maxLimIdentifier)))

cmd.AddCommand(NewCleanCmd())
Expand Down
23 changes: 14 additions & 9 deletions cmd/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ import (
"github.com/spf13/viper"
)

const paramsLongDescription string = `summarize model(s), for example:
bbi nonmem params run001
bbi nonmem params run001
bbi nonmem params run001
`
const paramsExamples string = ` # Display table of parameters for run001
bbi nonmem params run001
# Display table of parameters for all model runs the current directory
bbi nonmem params --dir=.
# Print JSON output instead of a table
bbi nonmem params --json --dir=.`

var (
noParamNames bool
Expand Down Expand Up @@ -434,10 +435,14 @@ func params(cmd *cobra.Command, args []string) {

func NewParamsCmd() *cobra.Command {
var cmd = &cobra.Command{
Use: "params",
Short: "get the parameters of model(s)",
Long: paramsLongDescription,
Run: params,
Use: "params [flags] [<run dir>]",
Short: "Extract the parameter estimates of models",
Long: `Display the parameter values from completed models. If a directory is
specified via --dir, get the parameters of all model runs found in that
directory. Otherwise the positional argument should specify a run directory
to extract parameters from.`,
Example: paramsExamples,
Run: params,
}

//Used for Summary
Expand Down
Loading