Skip to content

Code Contribution Guidelines

DINO is a high-performance scientific simulation code written primarily in Fortran90 and designed to run efficiently on massively parallel HPC systems. Contributions should therefore maintain high standards of readability, maintainability, numerical robustness, and parallel scalability. All contributors are expected to follow the guidelines below.


General Principles

Contributed code must satisfy the following principles:

  • Correctness first: numerical algorithms must be verified and validated where applicable.
  • Performance awareness: the code runs on large HPC systems; avoid unnecessary memory allocations, synchronization points, or communication overhead.
  • Readability and maintainability: code should be understandable by other developers.
  • Consistency: follow the coding style already used in DINO.
  • Reproducibility: numerical results should remain reproducible across platforms whenever possible.

Modular Code Structure

DINO follows a modular software design to improve readability, maintainability, and extensibility. New contributions should preserve this philosophy by implementing functionality in small, well-defined modules rather than adding code to existing routines whenever possible.

Design Principles

Each module should have a single, clearly defined responsibility. A developer should be able to understand the purpose of a module from its name and a brief description.

Examples of well-defined responsibilities include

  • grid generation,
  • boundary conditions,
  • chemistry integration,
  • time integration,
  • I/O routines,
  • turbulence statistics.

Avoid combining unrelated functionality into a single module.

Keep Interfaces Small

Expose only the procedures that are intended to be used by other parts of the code.

Declare helper procedures and internal variables as private whenever possible, and explicitly list the public interface.

module chemistry_solver

    implicit none

    private

    public :: initialize_chemistry
    public :: advance_chemistry

contains

    ...

end module chemistry_solver

A small public interface makes modules easier to understand and reduces unintended dependencies between different parts of the code.

One Task per Procedure

Each subroutine or function should perform a single logical task.

For example, a routine responsible for computing diffusive fluxes should not also

  • read input files,
  • allocate memory,
  • write output,
  • or modify unrelated variables.

If a procedure grows to several hundred lines or contains multiple distinct tasks, consider splitting it into smaller routines with descriptive names.

Minimize Dependencies

Modules should depend only on the functionality they actually require.

Avoid importing an entire module if only one or two procedures are needed.

use dino_constants, only : mytype, pi

instead of

use dino_constants

Reducing dependencies improves compilation times, limits namespace pollution, and makes the code easier to understand.

Reuse Existing Functionality

Before implementing a new routine, search the existing code base for similar functionality.

Duplicating algorithms often leads to inconsistent implementations and increases long-term maintenance effort. If existing functionality is sufficiently general, extend it rather than creating a second implementation.

Separate Physics from Infrastructure

Whenever possible, keep numerical algorithms and physical models independent of infrastructure code such as

  • file I/O,
  • MPI communication,
  • logging,
  • timers,
  • and user input.

This separation makes the scientific implementation easier to understand, test, and reuse.

Write for Future Developers

A module should be understandable without requiring knowledge of the entire code base. Developers should be able to identify

  • the purpose of the module,
  • its inputs and outputs,
  • and its interactions with other components

by reading only the module itself and its documentation.

Well-designed modules are easier to test, review, and extend, and they significantly reduce the effort required to maintain DINO over many years.


Code Formatting

Consistent code formatting is essential for maintaining readability and reducing the effort required for code reviews and future developments. The goal is not to enforce a specific visual style for its own sake, but to ensure that every developer can quickly understand and modify the code.

All contributions to DINO should follow the formatting conventions described below.

General Formatting Rules

Code should be written in a clear and structured way.

Avoid overly compact code that reduces readability. In scientific software, clarity is more important than minimizing the number of lines.

Prefer:

if (is_periodic) then
    call apply_periodic_boundary()
endif

over:

if (is_periodic) call apply_periodic_boundary()

Shorter code is not necessarily better code if it becomes harder to read.

Indentation

Use consistent indentation throughout the code.

Nested structures should be visually distinguishable by increasing the indentation level.

Example:

do k = k_start, k_end

    do j = j_start, j_end

        do i = i_start, i_end

            field(i,j,k) = 0.0_mytype

        enddo

    enddo

enddo

Avoid inconsistent indentation, as it makes the logical structure of the code difficult to follow.

Line Length

Avoid excessively long lines.

Lines should generally not exceed approximately 100–120 characters. Long expressions should be split into multiple lines using the Fortran continuation character.

Prefer:

rhs = convection_term &
    + diffusion_term &
    + chemical_source_term

over:

rhs = convection_term + diffusion_term + chemical_source_term

when expressions become difficult to read.

Spacing

Use whitespace to improve readability.

Operators should be surrounded by spaces:

temperature = energy / heat_capacity

Avoid:

temperature=energy/heat_capacity

Use blank lines to separate logical sections of a routine.

For example:

! Compute velocity gradients

call compute_gradients(velocity, gradients)


! Compute viscous stresses

call compute_stress(gradients, stress)

Naming and Alignment

Use descriptive and consistent naming, following the table below:

Element Convention Example
Modules dino_<name> dino_transport_mod
Subroutines verb-based dino_compute_flux
Functions descriptive enthalpy_from_temperature
Variables lowercase with _ cell_volume
Constants uppercase GAMMA_AIR
logical variables lowercase with _ 'is_periodic'

Avoid single-letter variables except for loop indices (i, j, k).

unless the abbreviation is a well-established term in the code or scientific field.

Align related declarations when it improves readability.

Example:

integer         :: i, j, k
real(mytype)    :: pressure
real(mytype)    :: temperature
logical         :: is_restart

Comments

Comments should explain why something is done, not simply repeat the code.

Avoid:

! Add density
density = density + correction

Prefer:

! Apply density correction to enforce mass conservation after the projection step.
density = density + correction

Important numerical methods, physical assumptions, approximations, or non-obvious implementation choices should always be documented.

Temporary and Debug Code

Temporary debugging statements should not be committed.

Remove

  • commented-out code,
  • unused variables,
  • debugging print statements,
  • obsolete routines,

before creating a merge request.

If code is intentionally disabled but may be required later, explain the reason in a comment or track it using the issue management system.

Fortran-Specific Guidelines

All Fortran source files should follow these rules:

  • Always use implicit none.
  • Always specify intent(in), intent(out), or intent(inout) for procedure arguments.
  • Use explicit interfaces through modules.
  • Avoid deprecated language features.
  • Avoid unnecessary global variables.
  • Use named constants instead of hard-coded numerical values.

Example:

Avoid:

dt = dt * 0.85

Prefer:

real(mytype), parameter :: CFL_SAFETY_FACTOR = 0.85_mytype

dt = dt * CFL_SAFETY_FACTOR

Formatting Before Submission

Before submitting a contribution:

  • ensure that the code follows the formatting conventions,
  • remove unnecessary whitespace changes,
  • verify that only relevant files are modified,
  • compile the code successfully.

Clean formatting makes code reviews easier and prevents unnecessary merge conflicts between developers.

A consistent style allows developers to focus on the scientific content of a contribution rather than spending time interpreting formatting differences.