Skip to content

Commit

Permalink
Update contributing docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven-Roberts committed Mar 31, 2024
1 parent bcfe045 commit 2570cfc
Showing 1 changed file with 64 additions and 99 deletions.
163 changes: 64 additions & 99 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,171 +1,142 @@
# Contributing Guide

This guide provides instructions for submitting and formatting new code in `OTP`.
This guide provides instructions for submitting and formatting new code in OTP.

## Submitting Changes

Changes to `OTP` should be proposed as a pull request and undergo a review process before being merged. New code must be free of warnings and errors and adhere to the style guidelines (see also [The style guidelines](## Style guidelines)).
Changes to OTP should be proposed as a pull request and undergo a review process before being merged. New code must be free of warnings and errors and adhere to the [style guidelines](#style-guidelines).

## Creating a Problem

Each problem defines a package under `+otp` that contains all files used by the problem. To add a new test problem follow these steps:
Each problem defines a package under `+otp` that contains all files used by the problem. When creating a new problem we recommend duplicating an existing problem package, e.g., [Lorenz63](https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/blob/master/toolbox/+otp/+lorenz63) or [Brusselator](https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/blob/master/toolbox/+otp/+brusselator), then renaming and editing the contents as needed.

1. Check out the latest version of `OTP`:
To add a new test problem from scratch follow these steps:

1. Check out the latest version of OTP:

```bash
git clone https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems.git
cd ODE-Test-Problems/
```

2. Create a new folder in the `src/+opt/` directory. Follow the same naming conventions as the existing problems. Start the name with `+` to maintain the structure of the Matlab/Octave package. Also create a subfolder named `+presets` in the new problem folder:
2. Create a new folder in the `toolbox/+opt/` directory with a name that starts with `+` to indicate it is a package. Also create a subfolder named `+presets` in the new problem folder:

```bash
mkdir src/+opt/+newtest
mkdir src/+opt/+newtest/+presets
cd src/+opt/+newtest/
mkdir toolbox/+opt/+example
cd toolbox/+opt/+example
mkdir +presets
```

3. The minimal set of files needed inside the problem folder to set up a new test problem are:
* The right-hand-side function named as `f.m`
* The problem class to initialize problem objects and its methods and properties
* The parameters class defines the parameters of the new problem
* A `Canonical.m` preset inside the `+presets` subfolder to set the initial condition and parameters in your case

```bash
touch f.m
touch NewTestProblem.m
touch NewTestParameters.m
touch +presets/Canonical.m
```
3. The minimal set of files needed inside the problem folder to set up a new example problem are:
* The right-hand side (RHS) function named as `f.m`
* The problem class to specify properties, override plotting and solver options, and convert parameters into arguments for RHS functions
* The parameters class
* A `Canonical.m` preset inside the `+presets` subfolder to set standard initial condition and parameters.

## The Right-hand-side Structure
```bash
touch f.m ExampleProblem.m ExampleParameters.m +presets/Canonical.m
```

The right-hand-side structure provides various derivatives of the problem. They are implemented in separate function files. The right-hand-side function `f.m`, which is the time-derivative of the state `y` is defined as a function with at least two arguments `f(t,y)`. If the right-hand-side function needs other parameters they can also be passed to this function:
### The RHS Function

```Matlab
The RHS function `f.m`, which is the time-derivative of the state `y`, is defined as a function with at least two arguments. If parameters are needed, they can be added as arguments.

function dy = f(t, y, Param1, ...)
dy = ...
```matlab
function dy = f(t, y, param1, ...)
dy = ...
end
```

For more information about this formulation please refer to our [paper](https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/blob/master/paper/paper.md).

## The Problem Class
Other functions associated with an `otp.RHS` like the Jacobian and mass matrix should be implemented in separate `.m` files with the same function signature as `f.m`.

A problem package must contain a class named `<Name>Problem.m` that is a subclass of `otp.Problem`. There are two
methods that must be implemented: the constructor and `onSettingsChanged`. Optionally, one can override functions such as `internalPlot` and `internalSolve` to provide problem-specific defaults. Partitioned problems can add custom right-hand-side functions
as class properties with private write access. The property name should start with `RHS`, e.g., `RHSStiff`.
### The Problem Class

The template for a new class of problems called `NewTest` looks like:
A problem package must contain a class named `<Name>Problem.m` that is a subclass of `otp.Problem`. There are two methods that must be implemented: the constructor and `onSettingsChanged`. Optionally, one can override functions such as `internalPlot` and `internalSolve` to provide problem-specific defaults. Partitioned problems can add custom RHS functions as class properties with private write access. The property name should start with `RHS`, e.g., `RHSStiff`.

```Matlab
classdef NewTestProblem < otp.Problem
A basic template for a new class of problems called `Example` looks like

```matlab
classdef ExampleProblem < otp.Problem
methods
function obj = NewTestProblem(timeSpan, y0, parameters)
[email protected]('New Test', [], timeSpan, y0, parameters);
function obj = ExampleProblem(timeSpan, y0, parameters)
[email protected]('Example', [], timeSpan, y0, parameters);
% The second argument specifies the number of variables in the problem is arbitrary
end
end
methods (Access=protected)
function onSettingsChanged(obj)
% Parameters are stored in the obj.Parameters structure. We can assign them to individual variables to be
% used in function calls
param1 = obj.Parameters.Param1;
% parameters are stored in the obj.Parameters structure
% We can assign them to individual variables
% to be used in function calls
Param1 = obj.Parameters.Param1; % ...
% set up the right-hand-side function wrapper
obj.RHS = otp.RHS(@(t, y) otp.newtest.f(t, y, Param1), 1:obj.NumVars);
% set up the RHS function wrapper
obj.RHS = otp.RHS(@(t, y) otp.example.f(t, y, param1));
end
% set up internal plot function
function fig = internalPlot(obj, t, y, varargin)
fig = [email protected](obj, t, y, ...
'xscale', 'log', 'yscale', 'log', varargin{:});
fig = [email protected](obj, t, y, 'xscale', 'log', 'yscale', 'log', varargin{:});
end
% set up internal movie function
function mov = internalMovie(obj, t, y, varargin)
mov = [email protected](obj, t, y, ...
'xscale', 'log', 'yscale', 'log', varargin{:});
mov = [email protected](obj, t, y,, 'xscale', 'log', 'yscale', 'log', varargin{:});
end
% set up internal solver
function sol = internalSolve(obj, varargin)
% Set tolerances due to the very small scales
sol = [email protected](obj, ...
'AbsTol', 1e-50, varargin{:});
sol = [email protected](obj, 'AbsTol', 1e-50, varargin{:});
end
end
end
```

## The Parameters Class

A problem package must also contain a class named `<Name>Parameters.m`. It only needs to provide public properties for each of the problem parameters; no constructor or methods are needed. Note that property validation is currently not supported in Octave. Therefore, we use a custom comment syntax that is parsed by the installer to optionally include validation. The following is an example of a parameter class with property validation:
### The Parameters Class

A problem package must also contain a class named `<Name>Parameters.m` that is a subclass of `otp.Parameters`. It needs to provide public properties for each of the problem parameters and a constructor which forwards arguments to the superclass constructor; no methods are needed. Note that property validation is currently not supported in Octave. Therefore, we use a custom comment syntax that is parsed by the installer to optionally include validation. The following is an example of a parameter class with property validation:

```Matlab
classdef NewTestParameters
%NewTestParameters
```matlab
classdef ExampleParameters
properties
Param1 %MATLAB ONLY: (1,1) {mustBeNumeric, mustBeReal, mustBeNonnegative}
Param1 %MATLAB ONLY: (1,1) {mustBeReal, mustBeNonnegative}
end
end
methods
function obj = ExampleParameters(varargin)
obj = [email protected](varargin{:});
end
end
end
```

## Adding presets

Within a problem package, there should be a subpackage named `+presets`. This contains subclasses of `<Name>Problem`
that specify the timespan, initial conditions, and parameters. Typically, only the constructor needs to be implemented
in a preset class.
### Adding presets

In our example, we add the `Canonical.m` preset inside the `+presets` subfolder containing:
Within a problem package, there should be a subpackage named `+presets`. This contains subclasses of `<Name>Problem` that specify the time span, initial conditions, and parameters. Typically, only the constructor needs to be implemented in a preset class.

```Matlab
In our example, we add a `Canonical.m` preset inside the `+presets` subfolder.

classdef Canonical < otp.newtest.NewTestProblem
```matlab
classdef Canonical < otp.example.ExampleProblem
methods
function obj = Canonical
params = otp.newtest.NewTestParameters;
params.Param1 = ...
function obj = Canonical(varargin)
y0 = ...
tspan = ...
obj = [email protected](tspan, y0, params);
% Specify a default value for Param1 which can be overridden by a name-value pair passed to this constructor
params = otp.example.ExampleParameters('Param1', pi, varargin{:});
obj = [email protected](tspan, y0, params);
end
end
end
```
## Copying the Problem Template

When creating a new problem, we
recommend duplicating an existing problem package, then renaming and editing the contents as needed.

[This is a minimal example of](https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/tree/81cf4e473c34fe04d70280d0a78222a4c75fd775/src/%2Botp/%2Bnewtest) the completed test problem started in this tutorial. It implements the trivial ODE $y'(t) = 1, y(0) = 1$ and can be used as a template to implement simple test problems.


An example of a more sophisticated problem with implemented Jacobians is the [Lorenz63 problem](https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/blob/master/src/+otp/+lorenz63). For an example of split right-hand-side PDE, see [the Brusselator problem]( https://github.com/ComputationalScienceLaboratory/ODE-Test-Problems/blob/master/src/+otp/+brusselator).


## Style Guidelines

In order for this project to maintain a consistent coding style, the following conventions should be used. These
standards match those most commonly used in MATLAB's code and documentation.
In order for this project to maintain a consistent coding style, the following conventions should be used. These standards largely match those most commonly used in MATLAB's code and documentation.

### Line Formatting

Expand Down Expand Up @@ -205,8 +176,7 @@ car = struct('make', 'Ford', 'modelYear', 2020);

### Packages

Package names should be completely lowercase and start with a plus symbol. No capitalization or special character is
used to distinguish between words.
Package names should be completely lowercase and start with a plus symbol. No capitalization or special character is used to distinguish between words.

```matlab
% Example
Expand All @@ -216,8 +186,7 @@ help otp.utils.PhysicalConstants

### Classes

Class names and properties should be written in Pascal case. When the name contains an acronym, all letters should be
capitalized. Methods should be written in camel case.
Class names and properties should be written in Pascal case. When the name contains an acronym, all letters should be capitalized. Methods should be written in camel case.

```matlab
% Examples
Expand All @@ -239,7 +208,3 @@ classdef ODETestProblems
...
end
```


## Creating Documentation

0 comments on commit 2570cfc

Please sign in to comment.