FLAMEGPU / FLAMEGPU2

FLAME GPU 2 is a GPU accelerated agent based modelling framework for CUDA C++ and Python
https://flamegpu.com
MIT License
105 stars 20 forks source link

Improved CLI - User provided arguments #257

Open ptheywood opened 4 years ago

ptheywood commented 4 years ago

Current CLI could be improved/extended to support user-provided cli args. ~

I.e. if a users wishes to provide environmetn vars from the command line in place of an initial states file, or if they wish to provide a number of agents to generate or similar (some of these cases could be made default optional arguments)

Doing this in a similar way to python's argparse module would likely be a nice way to do this, either by exposing an existing cli library to the user, or masking it behind methods on the Simulator/Simulation object.

It might be useful to have an extra class for the cli as a member of the simulation/simulator, or just do this directly.

This should support:

The following alternative/possible methods are to add the following flags/args.

-h/--help would be generated by default.

There are more complicated cases of cli which I've not attempted to cover here.

Removal of default arguments might also be useful? I.e. if for some reason the user does not wish to support loading from disk (Which should also be made configurable once we have more than one format supported).

Flags with multiple arguments would also likely be useful - i.e. --seeds 1 2 3 or --seed-max-min 0 1000 or similar, but I've not considered that.

Option 1: methods on the simulation object

// Get the simulation object
simulation = CUDASimulation(); // CUDASimulator()

// -v/--verbose as a boolean flag. False by default, !default if passed.
simulation.add_cli_flag<bool>("-v", "--verbose", false, "Sets verbose output");
simulation.add_cli_argument<int>("-n", "--number", 0, "Number of agents to generate");
simulation.add_cli_positional<long>("seed", -1, "Seed for the simulation/simulator");

// Process the arguments (maybe just use current `initalise()`)
simulation.process_cl(argc, argv);

Option 2: Use a CLI object

// Get the simulation object
simulation = CUDASimulation(); // CUDASimulator()

cli = simualtion.cli();

cli.add_flag<bool>("-v", "--verbose", false, "Sets verbose output");
cli.add_argument<int>("-n", "--number", 0, "Number of agents to generate");
cli.add_positional<long>("seed", -1, "Seed for the simulation/simulator");

// Alternatively construct new CLI object and add it's properties to the simulation
auto cli = CLI();
// cli.add ....
simalation.registerCLI(cli);

// Process the arguments (maybe just use current `initalise()`)
simulation.process_cl(argc, argv);

Option 3: Object per CLI argument (with common base class)

// Get the simulation object
simulation = CUDASimulation(); // CUDASimulator()

auto cli = simualtion.cli();

auto flag = CLIFlag<bool>("-v", "--verbose", false, "Sets verbose output");
auto arg = CLIArg<int>("-n", "--number", 0, "Number of agents to generate");
auto positional - CLIPositional<long>("seed", -1, "Seed for the simulation/simulator");

cli.add(flag);
cli.add(arg);
cli.add(positional);

// Process the arguments (maybe just use current `initalise()`)
simulation.process_cl(argc, argv);

Option 4: Method chaining

The inner class methods return this so methods can be chained. Could also get the CLI_x class from the main cli class?

// Get the simulation object
simulation = CUDASimulation(); // CUDASimulator()

auto cli = simualtion.cli();

cli.add(CLIFlag<bool>("--verbose").short("-v").defualt(false).help("Sets verbose output));

cli.addArgument<int>("--number").short("-n").default(0).help("Number of agents to generate);

auto positional = cli.newPositionalArgument<int>("seed");
positional.default(-1).help("Seed for the simulation/simulator");

// Process the arguments (maybe just use current `initalise()`)
simulation.process_cl(argc, argv);

Libraries

We could make use of a CXX CLI library, to avoid having to work with argc/argv ourselves when someone else has already done the hard work, either exposing the library to the user, or masking it behind our own methods.

Some popular looking options to consider are:

This is not extensive, but some decent (and less decent) options after a quick search. We could still roll our own.

Closely related to #245

Robadob commented 4 years ago

Combination of options 2 and 4, (backed by an argparse library?). Probably depends on the library, whether we want to expose it to the user i'd assume not (e.g. we don't want to allow the user to actually perform the arg parsing themself?, maybe just expose ability to check args within host functions.)

On Fri, 8 May 2020 at 14:41, Peter Heywood notifications@github.com wrote:

Current CLI could be improved/extended to support user-provided cli args. ~

I.e. if a users wishes to provide environmetn vars from the command line in place of an initial states file, or if they wish to provide a number of agents to generate or similar (some of these cases could be made default optional arguments)

Doing this in a similar way to python's argparse module would likely be a nice way to do this, either by exposing an existing cli library to the user, or masking it behind methods on the Simulator/Simulation object.

It might be useful to have an extra class for the cli as a member of the simulation/simulator, or just do this directly.

This should support:

  • Positional arguments? i.e. simulation.exe path/to/file
  • Optional arguments i.e. simulation.exe --file path/to/file
  • Flags i.e. simulation.exe --verbose
  • Short forms as well as long forms -v/--verbose
  • Multiple short arguments with a common - - i.e. -am maps to --add --message

The following alternative/possible methods are to add the following flags/args.

  • -v/--verbose - A bool which is set to true if passed, otherwise false .
  • -n/--number - An integer number of something such as agents. defaults to 0.
  • seed - A positional , defaults to -1 to imply un-set.

-h/--help would be generated by default.

There are more complicated cases of cli which I've not attempted to cover here.

Removal of default arguments might also be useful? I.e. if for some reason the user does not wish to support loading from disk (Which should also be made configurable once we have more than one format supported).

Flags with multiple arguments would also likely be useful - i.e. --seeds 1 2 3 or --seed-max-min 0 1000 or similar, but I've not considered that. Option 1: methods on the simulation object

// Get the simulation object simulation = CUDASimulation(); // CUDASimulator()

// -v/--verbose as a boolean flag. False by default, !default if passed. simulation.add_cli_flag("-v", "--verbose", false, "Sets verbose output"); simulation.add_cli_argument("-n", "--number", 0, "Number of agents to generate"); simulation.add_cli_positional("seed", -1, "Seed for the simulation/simulator");

// Process the arguments (maybe just use current initalise()) simulation.process_cl(argc, argv);

Option 2: Use a CLI object

// Get the simulation object simulation = CUDASimulation(); // CUDASimulator()

cli = simualtion.cli();

cli.add_flag("-v", "--verbose", false, "Sets verbose output"); cli.add_argument("-n", "--number", 0, "Number of agents to generate"); cli.add_positional("seed", -1, "Seed for the simulation/simulator");

// Alternatively construct new CLI object and add it's properties to the simulation auto cli = CLI(); // cli.add .... simalation.registerCLI(cli);

// Process the arguments (maybe just use current initalise()) simulation.process_cl(argc, argv);

Option 3: Object per CLI argument (with common base class)

// Get the simulation object simulation = CUDASimulation(); // CUDASimulator()

auto cli = simualtion.cli();

auto flag = CLIFlag("-v", "--verbose", false, "Sets verbose output"); auto arg = CLIArg("-n", "--number", 0, "Number of agents to generate"); auto positional - CLIPositional("seed", -1, "Seed for the simulation/simulator");

cli.add(flag); cli.add(arg); cli.add(positional);

// Process the arguments (maybe just use current initalise()) simulation.process_cl(argc, argv);

Option 4: Method chaining

The inner class methods return this so methods can be chained. Could also get the CLI_x class from the main cli class?

// Get the simulation object simulation = CUDASimulation(); // CUDASimulator()

auto cli = simualtion.cli();

cli.add(CLIFlag("--verbose").short("-v").defualt(false).help("Sets verbose output));

cli.addArgument("--number").short("-n").default(0).help("Number of agents to generate);

auto positional = cli.newPositionalArgument("seed"); positional.default(-1).help("Seed for the simulation/simulator");

// Process the arguments (maybe just use current initalise()) simulation.process_cl(argc, argv);

Libraries

We could make use of a CXX CLI library, to avoid having to work with argc/argv ourselves when someone else has already done the hard work, either exposing the library to the user, or masking it behind our own methods.

Some popular looking options to consider are:

This is not extensive, but some decent (and less decent) options after a quick search. We could still roll our own.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/FLAMEGPU/FLAMEGPU2_dev/issues/257, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFVGCV74V7YG2L3OPPSEO3RQQDYTANCNFSM4M4FXPNQ .

Robadob commented 4 years ago

This probably also links in with improving the interface of Simulation, e.g. should we expose things like resetting the simulation (whatever that means), exporting population to file (with config of what to actually export), reseeding the simulation and other things. I think currently it's a mixed bag of what's actually exposed.

ptheywood commented 3 years ago

Ratesetter requries custom arg parsing (for custom input / output files). As argc/argv are accessible in main, this can be worked around, but having a nice programatic way to deal with this would be good.

The workaround is to extract the values required, then remove them from argv so that the CudaSimulation arg parsing doesn't error on invalid cli.

This might need to be available before the CUDASimulator() is constructed, although that will make providing accurate -h/--help difficult...

Possibly have a way to define additional CLI args which are passed to the Simulator constructor? Or manual invocation of cli parsing? Needs more thought / discussion.

ptheywood commented 3 years ago

Current output flags are also not standard convetion, Should short options should only be a single letter, long options use hyphens not underscores.

-os, --out_step <file.xml/file.json> Step log file (XML or JSON)
-oe, --out_exit <file.xml/file.json> Exit log file (XML or JSON)
-ol, --out_log <file.xml/file.json> Common log file (XML or JSON)

Edit:

This has been split out to #932 to be fixed in isolation of re-doing the cli entirely. Actually fixed in #609, i just didn't check before opening #932