Generate a BioCro module header file.
module_write.Rd
To facilitate the creation of new BioCro modules, module_write
generates a BioCro module header file. Given a set of input and output
variables, module_write
will create a C++ header file ('.h' file) by
filling in a template with the input and output variables, ensuring the
correct C++ syntax for a BioCro module.
Usage
module_write(
module_name,
module_library,
module_type,
inputs,
outputs,
output_equations = NULL,
input_units = NULL,
output_units = NULL
)
Arguments
- module_name
A string for the module's name.
- module_library
A string for the module's library namespace. E.g.,
'biocro'
.- module_type
A string setting the module type:
'direct'
or'differential'
.- inputs
A character vector of the module's input variables.
- outputs
A character vector of the module's output variables.
- output_equations
A character vector. The module's output variables will be updated with these variables. If
NULL
, a zero is inserted instead.- input_units
A character vector of the inputs' units. If
NULL
, no units are embedded.- output_units
A character vector of the outputs' units. If
NULL
, no units are embedded.
Details
type
should be either 'direct'
or 'differential'
;
however, module_write
does not enforce this in case new module types
are created in the future.
Note
This function returns a string and has no file I/O. Use
writeLines
to print the output to console, or to save the
output. See examples below. Note that it is customary to name the header
file with the same name as the module.
module_write
checks for duplicate input or output variables, and if
detected, it will raise an error. In theory, this check should ensure that
the generated module will compile correctly. However, it is still possible
to define an module that is circular and will not pass the checks in
validate_dynamical_system_inputs
. See Example 4
.
Examples
# Example 1
# Inputs as character vector
xs = c('x1','x2','x3')
# Units
xs_units <- c('Mg / ha', 'Mg / ha / hr', 'dimensionless')
# Outputs
ys = c('y1','y2')
out <- module_write('testmod', 'testlib', 'direct',
inputs=xs, input_units= xs_units, outputs=ys)
# Use writeLines to print to console
writeLines(out)
#> #ifndef TESTLIB_TESTMOD_H
#> #define TESTLIB_TESTMOD_H
#>
#> #include "../framework/module.h"
#> #include "../framework/state_map.h"
#>
#> namespace testlib
#> {
#> /**
#> * @class testmod
#> *
#> * @brief Put documentation here.
#> *
#> */
#> class testmod : public direct_module
#> {
#> public:
#> testmod(
#> state_map const& input_quantities,
#> state_map* output_quantities)
#> : direct_module{},
#>
#> // Get references to input quantities
#> x1{get_input(input_quantities, "x1")},
#> x2{get_input(input_quantities, "x2")},
#> x3{get_input(input_quantities, "x3")},
#>
#> // Get pointers to output quantities
#> y1_op{get_op(output_quantities, "y1")},
#> y2_op{get_op(output_quantities, "y2")}
#> {
#> }
#> static string_vector get_inputs();
#> static string_vector get_outputs();
#> static std::string get_name() { return "testmod"; }
#>
#> private:
#> // References to input quantities
#> double const& x1;
#> double const& x2;
#> double const& x3;
#>
#> // Pointers to output quantities
#> double* y1_op;
#> double* y2_op;
#>
#> // Main operation
#> void do_operation() const;
#> };
#>
#> string_vector testmod::get_inputs()
#> {
#> return {
#> "x1", // Mg / ha
#> "x2", // Mg / ha / hr
#> "x3" // dimensionless
#> };
#> }
#>
#> string_vector testmod::get_outputs()
#> {
#> return {
#> "y1", // Put y1 units here
#> "y2" // Put y2 units here
#> };
#> }
#>
#> void testmod::do_operation() const
#> {
#> // Make calculations here
#>
#> // Use `update` to set outputs
#> update(y1_op, 0);
#> update(y2_op, 0);
#> }
#>
#> } // namespace testlib
#> #endif
#>
if (FALSE) { # \dontrun{
# Use writeLines to save as a `.h` file
writeLines(out, "./testmod.h")
} # }
# Example 2: A differential module
xs <- c('var_1','var_2')
out <- module_write('testmod', 'testlib', 'differential', xs, xs)
writeLines(out)
#> #ifndef TESTLIB_TESTMOD_H
#> #define TESTLIB_TESTMOD_H
#>
#> #include "../framework/module.h"
#> #include "../framework/state_map.h"
#>
#> namespace testlib
#> {
#> /**
#> * @class testmod
#> *
#> * @brief Put documentation here.
#> *
#> */
#> class testmod : public differential_module
#> {
#> public:
#> testmod(
#> state_map const& input_quantities,
#> state_map* output_quantities)
#> : differential_module{},
#>
#> // Get references to input quantities
#> var_1{get_input(input_quantities, "var_1")},
#> var_2{get_input(input_quantities, "var_2")},
#>
#> // Get pointers to output quantities
#> var_1_op{get_op(output_quantities, "var_1")},
#> var_2_op{get_op(output_quantities, "var_2")}
#> {
#> }
#> static string_vector get_inputs();
#> static string_vector get_outputs();
#> static std::string get_name() { return "testmod"; }
#>
#> private:
#> // References to input quantities
#> double const& var_1;
#> double const& var_2;
#>
#> // Pointers to output quantities
#> double* var_1_op;
#> double* var_2_op;
#>
#> // Main operation
#> void do_operation() const;
#> };
#>
#> string_vector testmod::get_inputs()
#> {
#> return {
#> "var_1", // Put var_1 units here
#> "var_2" // Put var_2 units here
#> };
#> }
#>
#> string_vector testmod::get_outputs()
#> {
#> return {
#> "var_1", // Put var_1 units here
#> "var_2" // Put var_2 units here
#> };
#> }
#>
#> void testmod::do_operation() const
#> {
#> // Make calculations here
#>
#> // Use `update` to set outputs
#> update(var_1_op, 0);
#> update(var_2_op, 0);
#> }
#>
#> } // namespace testlib
#> #endif
#>
# Example 3: A module with pairwise names
# Here we use an outer product to generate pairwise combinations of
# tissues and pool types
tissues <- c('leaf', 'stem', 'root')
pools <- c('carbon', 'nitrogen')
xs <- as.vector(outer(tissues, pools, paste, sep = '_'))
out <- module_write('testmod', 'testlib', 'differential', xs, xs)
writeLines(out)
#> #ifndef TESTLIB_TESTMOD_H
#> #define TESTLIB_TESTMOD_H
#>
#> #include "../framework/module.h"
#> #include "../framework/state_map.h"
#>
#> namespace testlib
#> {
#> /**
#> * @class testmod
#> *
#> * @brief Put documentation here.
#> *
#> */
#> class testmod : public differential_module
#> {
#> public:
#> testmod(
#> state_map const& input_quantities,
#> state_map* output_quantities)
#> : differential_module{},
#>
#> // Get references to input quantities
#> leaf_carbon{get_input(input_quantities, "leaf_carbon")},
#> stem_carbon{get_input(input_quantities, "stem_carbon")},
#> root_carbon{get_input(input_quantities, "root_carbon")},
#> leaf_nitrogen{get_input(input_quantities, "leaf_nitrogen")},
#> stem_nitrogen{get_input(input_quantities, "stem_nitrogen")},
#> root_nitrogen{get_input(input_quantities, "root_nitrogen")},
#>
#> // Get pointers to output quantities
#> leaf_carbon_op{get_op(output_quantities, "leaf_carbon")},
#> stem_carbon_op{get_op(output_quantities, "stem_carbon")},
#> root_carbon_op{get_op(output_quantities, "root_carbon")},
#> leaf_nitrogen_op{get_op(output_quantities, "leaf_nitrogen")},
#> stem_nitrogen_op{get_op(output_quantities, "stem_nitrogen")},
#> root_nitrogen_op{get_op(output_quantities, "root_nitrogen")}
#> {
#> }
#> static string_vector get_inputs();
#> static string_vector get_outputs();
#> static std::string get_name() { return "testmod"; }
#>
#> private:
#> // References to input quantities
#> double const& leaf_carbon;
#> double const& stem_carbon;
#> double const& root_carbon;
#> double const& leaf_nitrogen;
#> double const& stem_nitrogen;
#> double const& root_nitrogen;
#>
#> // Pointers to output quantities
#> double* leaf_carbon_op;
#> double* stem_carbon_op;
#> double* root_carbon_op;
#> double* leaf_nitrogen_op;
#> double* stem_nitrogen_op;
#> double* root_nitrogen_op;
#>
#> // Main operation
#> void do_operation() const;
#> };
#>
#> string_vector testmod::get_inputs()
#> {
#> return {
#> "leaf_carbon", // Put leaf_carbon units here
#> "stem_carbon", // Put stem_carbon units here
#> "root_carbon", // Put root_carbon units here
#> "leaf_nitrogen", // Put leaf_nitrogen units here
#> "stem_nitrogen", // Put stem_nitrogen units here
#> "root_nitrogen" // Put root_nitrogen units here
#> };
#> }
#>
#> string_vector testmod::get_outputs()
#> {
#> return {
#> "leaf_carbon", // Put leaf_carbon units here
#> "stem_carbon", // Put stem_carbon units here
#> "root_carbon", // Put root_carbon units here
#> "leaf_nitrogen", // Put leaf_nitrogen units here
#> "stem_nitrogen", // Put stem_nitrogen units here
#> "root_nitrogen" // Put root_nitrogen units here
#> };
#> }
#>
#> void testmod::do_operation() const
#> {
#> // Make calculations here
#>
#> // Use `update` to set outputs
#> update(leaf_carbon_op, 0);
#> update(stem_carbon_op, 0);
#> update(root_carbon_op, 0);
#> update(leaf_nitrogen_op, 0);
#> update(stem_nitrogen_op, 0);
#> update(root_nitrogen_op, 0);
#> }
#>
#> } // namespace testlib
#> #endif
#>
# Example 4: Circular modules
if (FALSE) { # \dontrun{
out <- module_write(inputs = c('x' ,'x'))
# Will compile, but will cause a "circular quantities" error if it is used
# in a BioCro simulation:
out <- module_write('inconsistent', 'examplelib', type='direct',
inputs = 'x', outputs = 'x')
} # }