Skip to content

Contributing to Canopy-App

Welcome to the Canopy-App development community! This guide will help you contribute effectively to the project.

Getting Started

Development Environment Setup

Prerequisites

# Required tools
sudo apt-get install gfortran netcdf-bin libnetcdf-dev
sudo apt-get install git make cmake
sudo apt-get install python3 python3-pip

# Optional but recommended
sudo apt-get install valgrind gdb
pip3 install pre-commit black flake8

Fork and Clone

# Fork the repository on GitHub, then:
git clone https://github.com/YOUR_USERNAME/canopy-app.git
cd canopy-app

# Add upstream remote
git remote add upstream https://github.com/canopy-app/canopy-app.git

# Set up pre-commit hooks
pre-commit install

Development Workflow

1. Create Feature Branch

# Update your fork
git checkout main
git pull upstream main
git push origin main

# Create feature branch
git checkout -b feature/your-feature-name

2. Make Changes

# Make your changes
# Test thoroughly
# Update documentation

# Stage changes
git add .
git commit -m "feat: descriptive commit message"

3. Submit Pull Request

# Push to your fork
git push origin feature/your-feature-name

# Create PR on GitHub
# Fill out PR template completely

Code Organization

Directory Structure

canopy-app/
├── src/                    # Fortran source code
│   ├── canopy_app.F90     # Main program
│   ├── *_mod.F90          # Module files
│   └── Makefile           # Build system
├── input/                 # Example input files
├── output/                # Example outputs (gitignored)
├── docs/                  # Documentation source
├── python/                # Python utilities
├── tests/                 # Test suite (future)
└── .github/               # GitHub workflows

Module Organization

Core Modules

  • canopy_app.F90 - Main program entry point
  • canopy_init.F90 - Initialization routines
  • canopy_calcs.F90 - Main calculation driver

I/O Modules

  • canopy_files_mod.F90 - File management
  • canopy_ncf_io_mod.F90 - NetCDF operations
  • canopy_txt_io_mod.F90 - Text file operations

Physics Modules

  • canopy_canmet_mod.F90 - Meteorology
  • canopy_rad_mod.F90 - Radiation
  • canopy_bioemi_mod.F90 - Biogenic emissions
  • canopy_drydep_mod.F90 - Dry deposition

Support Modules

  • canopy_const_mod.F90 - Constants
  • canopy_utils_mod.F90 - Utilities
  • canopy_coord_mod.F90 - Coordinates

Coding Standards

Fortran Style Guide

Naming Conventions

! Module names: lowercase with underscores
module canopy_physics_mod

! Subroutine/function names: lowercase with underscores
subroutine calc_wind_profile()
real function interpolate_linear()

! Variable names: descriptive, lowercase with underscores
real :: temperature_k        ! Temperature in Kelvin
real :: wind_speed_ms       ! Wind speed in m/s
integer :: num_canopy_levels

! Constants: uppercase with underscores
real, parameter :: PI = 3.14159265359
real, parameter :: GRAV_ACCEL = 9.81

Code Formatting

! Indentation: 2 spaces (no tabs)
module example_mod
  implicit none

  ! Module variables
  real :: module_variable

  contains

  subroutine example_routine(input_var, output_var)
    ! Subroutine arguments
    real, intent(in) :: input_var
    real, intent(out) :: output_var

    ! Local variables
    integer :: i, j
    real :: temporary_value

    ! Main code block
    do i = 1, 10
      if (input_var > 0.0) then
        temporary_value = sqrt(input_var)
        output_var = temporary_value * 2.0
      else
        output_var = 0.0
      end if
    end do

  end subroutine example_routine

end module example_mod

Documentation Standards

!> \brief Calculate wind speed profile through canopy
!!
!! This subroutine computes the vertical wind speed profile
!! through the canopy using an exponential attenuation model.
!!
!! \param[in] height_levels Vertical coordinate array (m)
!! \param[in] reference_wind Reference wind speed (m/s)
!! \param[in] reference_height Reference height (m)
!! \param[in] canopy_height Canopy top height (m)
!! \param[in] attenuation_coeff Attenuation coefficient
!! \param[out] wind_profile Computed wind speeds (m/s)
!!
!! \author Your Name
!! \date 2024-01-01
!! \version 1.0
!!
!! \see Harman and Finnigan (2007) for theoretical background
!!
subroutine calc_wind_profile(height_levels, reference_wind, &
                             reference_height, canopy_height, &
                             attenuation_coeff, wind_profile)

Error Handling

Robust Error Checking

subroutine safe_file_operations()
  implicit none

  integer :: iostat_val
  character(len=256) :: error_msg

  ! Check file existence
  if (.not. file_exists(input_filename)) then
    write(error_msg, '("Input file not found: ", a)') trim(input_filename)
    call abort_with_message(error_msg)
  end if

  ! Safe file opening
  open(unit=10, file=input_filename, status='old', &
       action='read', iostat=iostat_val)
  if (iostat_val /= 0) then
    write(error_msg, '("Error opening file: ", a)') trim(input_filename)
    call abort_with_message(error_msg)
  end if

  ! Always close files
  close(10)

end subroutine safe_file_operations

Input Validation

subroutine validate_inputs()
  implicit none

  ! Check physical bounds
  if (canopy_height <= 0.0) then
    call abort_with_message("Canopy height must be positive")
  end if

  if (num_levels < 3) then
    call abort_with_message("Minimum 3 vertical levels required")
  end if

  ! Check array bounds
  if (size(temperature_array) /= num_levels) then
    call abort_with_message("Temperature array size mismatch")
  end if

  ! Warn about questionable values
  if (canopy_height > 100.0) then
    call warning_message("Canopy height > 100m is unusual")
  end if

end subroutine validate_inputs