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 pointcanopy_init.F90
- Initialization routinescanopy_calcs.F90
- Main calculation driver
I/O Modules
canopy_files_mod.F90
- File managementcanopy_ncf_io_mod.F90
- NetCDF operationscanopy_txt_io_mod.F90
- Text file operations
Physics Modules
canopy_canmet_mod.F90
- Meteorologycanopy_rad_mod.F90
- Radiationcanopy_bioemi_mod.F90
- Biogenic emissionscanopy_drydep_mod.F90
- Dry deposition
Support Modules
canopy_const_mod.F90
- Constantscanopy_utils_mod.F90
- Utilitiescanopy_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
- Architecture Overview - System design details
- API Reference - Code documentation