Custom Model Development
The Illuminator supports and endorses the creation of custom models for your simulation needs. Templates for these models are provided in TODO LINK. Model creation can be done with basic prior programming knowledge and a basic understanding of inheritance and object oriented programming.
All new models must satisfy the below criteria, this is to ensure a smooth integration and contribution to the Illuminator. Any model created & submitted must fulfill the following conventions to be added to the Illuminator package.
Good Coding Practices
The points listed in this subsection are general good coding practices already utilised in the Illuminator. We encourage you to adopt these habits for this and any project you are a part of. Such practices directly improve the readability and maintainability of the project.
# Bad Example
def func(x, y):
return x + y
temp = func(10, 20)
print(temp)
# Good Example
def add_numbers(first_number, second_number):
return first_number + second_number
result = add_numbers(10, 20)
print(result)
Meaningful Function & Variable Names
Functions and variables should have clean and meaningful names that clearly indicate their purpose and functionality.
A descriptive name provides context, reduces ambiguity, and eliminates the need for excessive comments to explain its use. Adhering to consistent naming conventions also ensures uniformity across the project and enhances collaboration.
Unnecessary Computations
Avoid redundant computations, excessive loops, and duplicate code segments to enhance efficiency and reduce points of error.
Evaluate whether computations can be precomputed, reused, or consolidated to minimize resource consumption. By refactoring repetitive patterns into shared methods, you not only simplify maintenance but also prevent errors caused by inconsistent updates to duplicated logic.
If you come across any such improvement in the existing Illuminator code, we would love to hear them! Contact the main developers at TODO LINK.
Hard-Coded bits & Spaghetti Code
Hard-coded values and spaghetti code undermine the flexibility and scalability of a project and make debugging and future development exceedingly difficult. Prioritize clean, versatille design.
Libraries, Dependencies & Versions
You are welcome to use any library or package in your custom models, try however to not import unused modules or entire libraries when only specific functionalities are required.
# Bad Example:
import pandas # Entire library is imported but only DataFrame is used
df = pandas.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
print(df)
# Good Example:
from pandas import DataFrame # Only importing what is needed
df = DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
print(df)
Additionally, please ensure you update and specify exact version numbers in dependency manifests (requirements.txt) to ensure that builds are reproducible and unaffected by breaking changes in newer releases.
Project Documentation
Documentation and code comprehensibility are crucial for an open-source project like the Illuminator. Only through them can contributors and users understand, maintain, and improve the codebase effectively.
Docstrings
Docstrings are crucial to custom models because each model’s documentation is generated through them. Follow the current style for functions and classes.
The docstrings should have a clearly separated sections for other parts of the code (if any). These may include, but is not limited to: Parameters, Attributes, Returns, Raises.
Each separated section should start with the Title of the section, followed by a row of dashes such as in the following section:
def multiply(a, b):
"""
Computes the multiplication of two numbers and returns its value.
...
Parameters
----------
a : int
The first integer of the multiplication formula
b : int
The second integer of the multiplication formula
Returns
-------
int
The two values multiplied.
"""
return a * b
When appropriate, we should also ensure to include the name and/or type of variables for the any of the aforementioned sections.
Lastly, type hints are also a useful addition to any code. They can be used to “hint” to other developers what is expected as input and/or output when a function is used.
def sum(a:int, b:int) -> float:
As seen from the example above we can immediately conclude that for this function to work it will need an integer a
and b
, with the return value being of type float
Combined, the docstrings may look something like this:
def sum(a:int, b:int) -> float:
"""
Computes the sum of `a` and `b` and returns the outcome
...
Parameters
----------
a : int
The first integer of the sum formula
b : int
The second integer of the sum formula
Returns
-------
result : float
The sum of a + b
"""
result = a + b
return result
Docstrings are essential to the Illuminator since each model’s documentation is automatically generated through them. It is a model developers responsibility to ensure thorough documentation of their implemented model.
Consistency & Linting
Always adhere to the conventions and style used in the existing code, including naming patterns, indentation, spacing, and structure. For example, if camelCase is used for variable names, avoid switching to snake_case.
Tools like linters and formatters can help enforce these conventions, this project utilises pylint TODO LINK across its codebase. This package also helps maintain good coding practices mentioned in TODO LINK. Any submitted code must pass pylint’s format check.
Model Testing
This section lists the testing methods you must implement along with your model to verify it operates properly within the rest of the Illuminator framework.
Scenario Implementation
Creating a YAML scenario file for your custom model is essential for verifying that it integrates and runs properly within the simulation framework. This file essentially acts as a lightweight end-to-end test, providing an easy way to confirm that the model behaves as expected.
Unit Tests
Unit tests are a critical component of ensuring the internal functionality of your custom model. These tests validate individual methods and components to confirm that they produce the expected outputs for a variety of input cases, including edge scenarios. Further instructions can be found in TODO LINK.
Comments
Focus on adding comments where the code’s purpose or logic is not immediately obvious to the reader. Avoid redundant comments that merely restate the code or clutter the file.