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

Rework CLI for a simpler syntax when using default file names #29

Merged
merged 3 commits into from
May 20, 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
14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ jobs:
go get ./...
- name: Run examples 1
run: |
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/base -x params.Termination.MaxTicks=365
go run . -r 5 -d _examples/base -e experiment.json -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/patches -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/weather_file -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/weather_builtin -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/systems --systems systems.json -x params.Termination.MaxTicks=730
go run . -d _examples/systems --systems systems.json -e experiment.json -r 10
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/base -x params.Termination.MaxTicks=365
go run . -r 5 -d _examples/base -e -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/patches -o -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/weather_file -o -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/weather_builtin -o -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/systems -o -s -x params.Termination.MaxTicks=730
go run . -d _examples/systems -o -s -e -r 10
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Adds support for seasonal and "scripted" patch dynamics (#23)
- Adds support for weather/foraging period files (#24)
- Adds support for adding custom resources/parameters as well as systems (#25)
- Rework of the command line interface for a simpler syntax when using default file names (#29)

### Other

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ Get CLI help like this:
beecs-cli -h
```

A single, slowed down run of the base example, with live plots:
A single simulation with live plots, at 30 ticks per second:

```
beecs-cli -s 30 -d _examples/base
beecs-cli -d _examples/base --observers --tps 30
```

Run the full base example with parameter variation and 10 runs per parameter set:

```
beecs-cli -r 10 -d _examples/base -e experiment.json
beecs-cli -d _examples/base --experiment -r 10
```

Print all default parameters in the tool's input format:
Expand Down Expand Up @@ -76,7 +76,7 @@ The default is file `parameters.json` in the working directory. Here is an examp

For any kind of output, an **observers file** is required.
It specifies which observers for visualizations or file output should be used.
The default is file `parameters.json` in the working directory. Here is an example:
Here is an example:

```json
{
Expand All @@ -90,6 +90,8 @@ The default is file `parameters.json` in the working directory. Here is an examp
}
```

Observers must be enabled using the `-o` flag. The default is file `observers.json` in the working directory.

These files are sufficient for single simulations with visual of file output.

With a further **experiment file**, parameters can be systematically varied in various ways.
Expand All @@ -114,6 +116,8 @@ Here is an example:
]
```

Experiments must be enabled using the `-e` flag. The default is file `experiments.json` in the working directory.

> Note: The prefix `params.` is required to unambiguously identify the type of the parameter group to modify.

See also the [examples](https://github.com/mlange-42/beecs-cli/tree/main/_examples) for the format of the required JSON files.
59 changes: 43 additions & 16 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import (
"github.com/mlange-42/beecs/experiment"
baseparams "github.com/mlange-42/beecs/params"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/exp/rand"
)

const (
_PARAMETERS = "parameters.json"
_OBSERVERS = "observers.json"
_EXPERIMENT = "experiment.json"
_SYSTEMS = "systems.json"
)

func Run() {
Expand All @@ -40,16 +42,17 @@ func rootCommand() *cobra.Command {
var dir string
var outDir string
var paramFiles []string
var expFile string
var obsFile string
var sysFile string
var expFile []string
var obsFile []string
var sysFile []string
var speed float64
var threads int
var runs int
var overwrite []string
var seed int

root := &cobra.Command{
var root cobra.Command
root = cobra.Command{
Use: "beecs-cli",
Short: "beecs-cli provides a command line interface for the beecs model.",
Long: `beecs-cli provides a command line interface for the beecs model.`,
Expand All @@ -64,6 +67,11 @@ func rootCommand() *cobra.Command {
os.Exit(0)
}

flagUsed := map[string]bool{}
root.Flags().Visit(func(f *pflag.Flag) {
flagUsed[f.Name] = true
})

rand.Seed(uint64(time.Now().UTC().Nanosecond()))

if outDir == "" {
Expand All @@ -90,8 +98,11 @@ func rootCommand() *cobra.Command {

var exp experiment.Experiment
var err error
if expFile != "" {
exp, err = util.ExperimentFromFile(path.Join(dir, expFile))
if flagUsed["experiment"] {
if len(expFile) > 1 {
return fmt.Errorf("only one (optional) experiment file can be used")
}
exp, err = util.ExperimentFromFile(path.Join(dir, expFile[0]))
if err != nil {
return err
}
Expand All @@ -103,15 +114,21 @@ func rootCommand() *cobra.Command {
}

var observers util.ObserversDef
if obsFile != "" {
observers, err = util.ObserversDefFromFile(path.Join(dir, obsFile))
if flagUsed["observers"] {
if len(obsFile) > 1 {
return fmt.Errorf("only one (optional) observers file can be used")
}
observers, err = util.ObserversDefFromFile(path.Join(dir, obsFile[0]))
if err != nil {
return err
}
}
var systems []model.System
if sysFile != "" {
systems, err = util.SystemsFromFile(path.Join(dir, sysFile))
if flagUsed["systems"] {
if len(sysFile) > 1 {
return fmt.Errorf("only one (optional) systems file can be used")
}
systems, err = util.SystemsFromFile(path.Join(dir, sysFile[0]))
if err != nil {
return err
}
Expand Down Expand Up @@ -147,11 +164,21 @@ func rootCommand() *cobra.Command {

root.Flags().StringVarP(&dir, "directory", "d", ".", "Working directory")
root.Flags().StringVarP(&outDir, "output", "", "", "Output directory if different from working directory")
root.Flags().StringSliceVarP(&paramFiles, "parameters", "p", []string{_PARAMETERS}, "Parameter files, processed in the given order")
root.Flags().StringVarP(&expFile, "experiment", "e", "", "Experiment file for parameter variation")
root.Flags().StringVarP(&obsFile, "observers", "o", _OBSERVERS, "Observers file for adding observers")
root.Flags().StringVarP(&sysFile, "systems", "", "", "Systems file for using custom systems or changing the scheduling")
root.Flags().Float64VarP(&speed, "speed", "s", 0, "Speed limit in ticks per second. Default: 0 (unlimited)")
root.Flags().StringSliceVarP(&paramFiles, "parameters", "p", []string{_PARAMETERS}, "Parameter files, processed in the given order\n")

root.Flags().StringSliceVarP(&expFile, "experiment", "e", []string{_EXPERIMENT},
"Run experiment. Optionally one experiment file for parameter variation\n")
root.Flag("experiment").NoOptDefVal = _EXPERIMENT

root.Flags().StringSliceVarP(&obsFile, "observers", "o", []string{_OBSERVERS},
"Run with observers. Optionally one observers file for adding observers\n")
root.Flag("observers").NoOptDefVal = _OBSERVERS

root.Flags().StringSliceVarP(&sysFile, "systems", "s", []string{_SYSTEMS},
"Run with custom systems. Optionally one systems file for using custom systems or changing the scheduling\n")
root.Flag("systems").NoOptDefVal = _SYSTEMS

root.Flags().Float64VarP(&speed, "tps", "", 0, "Speed limit in ticks per second. Default: 0 (unlimited)")
root.Flags().IntVarP(&threads, "threads", "t", runtime.NumCPU(), "Number of threads")
root.Flags().IntVarP(&runs, "runs", "r", 1, "Runs per parameter set")
root.Flags().IntVarP(&seed, "seed", "", 0, "Super random seed for seed generation. Default: 0 (unseeded)")
Expand All @@ -160,7 +187,7 @@ func rootCommand() *cobra.Command {
root.AddCommand(initCommand())
root.AddCommand(parametersCommand())

return root
return &root
}

func parametersCommand() *cobra.Command {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/mlange-42/arche-pixel v0.9.0
github.com/mlange-42/beecs v0.1.1-0.20240520193329-cfbd62899b75
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
)

Expand All @@ -31,7 +32,6 @@ require (
github.com/mazznoer/csscolorparser v0.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
Expand Down
Loading