A tutorial is needed for creating a profile for generating code in a user-defined manner
If we could have a tutorial which shows us how to modify a profile to change the way code is generated, it would be very beneficial. I think a tutorial for generating Python code that includes user-defined functions for external variables would be the best first tutorial. A more advanced one in C or C++ would also be helpful eventually.
Useful topics in the tutorial:
- How to change a variable into an external variable
- How to define how external variables are dealt with
- How to generate the code within a class
- How to specify a function to be used with an external variable
- How to change the way variables are accessed to make things more readable: i.e. instead of:
rates[0] = consts[0] * states[0]
could we change it to:
{const_name}_idx # defined in init of class or globally at top of file
{state_name}_idx # defined in init of class or globally at top of file
d_{state_name}_dt = consts[{const_name}_idx] * states[{state_name}_idx]
rates[{state_name}_idx] = d_{state_name}_dt
where the idxs are defined globally or within a class. Then we could read the equations without checking what index is what variable. Maybe there is a better way to use a named variable as an alias? Not sure. This is just to make things user-readable.
The alias part is better explained here https://github.com/cellml/libcellml/issues/1171
Not tutorials (yet), but:
- How to change a variable into an external variable
Have a look here. It will show you how to specify external variables and how to specify dependencies that an external variable might have. It's in C++, but it should be easily to convert it to Python.
- How to define how external variables are dealt with
- How to specify a function to be used with an external variable
You might want to check here and here. It's from a Python template that I use to test the different types of code that libCellML can generate and that includes some Python code with some external variables. The first link shows you how to "compute" such an external variable (here, it's done using a lookup table and linear interpolation) while the second link shows you how that external_variable() method is passed to the compute_rates() method. See here to find out more about my testing repo.
- How to change the way variables are accessed to make things more readable:
Yes, to name index values could be one option. Right, libCellML generates something like (sorry, I am using the version of libCellML that uses different arrays for constants, computed constants, and algebraic variables; see issue https://github.com/cellml/libcellml/issues/1243):
rates[0] = -(-algebraic[0]+algebraic[3]+algebraic[2]+algebraic[1])/constants[0];
but we could indeed easily generate something like:
rates[MEMBRANE_V] = -(-algebraic[MEMBRANE_I_STIM]+algebraic[SODIUM_CHANNEL_I_NA]+algebraic[POTASSIUM_CHANNEL_I_K]+algebraic[LEAKAGE_CURRENT_I_L])/constants[MEMBRANE_CM];
We could even remove the component information (and only include if two variables have the same name):
rates[V] = -(-algebraic[I_STIM]+algebraic[I_NA]+algebraic[I_K]+algebraic[I_L])/constants[CM];
We could also mimic what our legacy CellML API does (when requested to do it), i.e. something like:
#define dV_dtime rates[0]
#define Cm constants[0]
#define i_Stim algebraic[0]
#define i_L algebraic[1]
#define i_K algebraic[2]
#define i_Na algebraic[3]
dV_dtime = -(-i_Stim+i_Na+i_K+i_L)/Cm;