diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 205b0fe..81170e8 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -54,4 +54,3 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://docs.claude.com/en/docs/claude-code/cli-reference for available options claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' - diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 412cef9..d2d6008 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -47,4 +47,3 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://docs.claude.com/en/docs/claude-code/cli-reference for available options # claude_args: '--allowed-tools Bash(gh pr:*)' - diff --git a/.gitignore b/.gitignore index 13c446f..e83b5b2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ pathlength # Output data -*.csv \ No newline at end of file +*.csv diff --git a/.go-version b/.go-version index 2f4320f..26a9e99 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.24.4 +1.25.4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..93d6783 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,36 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-executables-have-shebangs + - id: check-json + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-toml + - id: check-xml + - id: check-yaml + args: [--allow-multiple-documents] + - id: detect-private-key + - id: end-of-file-fixer + - id: no-commit-to-branch + - id: pretty-format-json + - id: trailing-whitespace + +# Go-specific hooks +- repo: https://github.com/tekwizely/pre-commit-golang + rev: v1.0.0-rc.3 + hooks: + # Format Go code + - id: go-fmt + args: [-w] + + # Run go vet for static analysis + - id: go-vet-repo-mod + + # Run tests before committing + - id: go-test-repo-mod + args: [-v] + + # Ensure go.mod and go.sum are tidy + - id: go-mod-tidy-repo diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7ddbc86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,183 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +PathLength is a ray tracing model that calculates the resolution and sensitivity of reflective superposition compound eyes (found in crustaceans like Nephrops norvegicus). It's a Go rewrite of an original QBASIC program from 1995, ported from a Python version. + +## Development Commands + +### Build +```bash +go build +``` +This creates an executable named `pathlength` in the current directory. + +### Run from source +```bash +go run . +``` +Note: The program requires a `-f` flag with a CSV parameter file path. + +### Run with parameter file +```bash +go run . -f example_data/nephrops_parameters.txt +# or with built binary: +./pathlength -f example_data/nephrops_parameters.txt +``` + +### Test +```bash +# Run all tests +go test -v + +# Run a specific test +go test -v -run TestParseInputParameters +go test -v -run TestCalculateRessens +``` + +### Display help +```bash +./pathlength -h +``` + +## Development Workflow + +**IMPORTANT: Always run tests before committing changes.** + +This project uses pre-commit hooks to automatically enforce code quality. The hooks will: +- Format Go code with `go fmt` +- Run static analysis with `go vet` +- Run all tests with `go test` +- Ensure `go.mod` and `go.sum` are tidy +- Check for common issues (merge conflicts, large files, etc.) + +### Setup pre-commit (first time only) + +```bash +# Install pre-commit (if not already installed) +pip install pre-commit +# or: brew install pre-commit + +# Install the git hooks +pre-commit install +``` + +### Manual test run + +You can manually run tests before committing: + +```bash +go test -v +``` + +If tests fail, fix the issues before committing. This ensures the codebase remains stable and the scientific calculations remain accurate. + +### Commit Message Format + +Use conventional commit format for all commit messages: + +``` +(): + +[optional body] + +[optional footer] +``` + +**Types:** +- `feat`: New feature +- `fix`: Bug fix +- `refactor`: Code refactoring (no functional changes) +- `test`: Adding or updating tests +- `docs`: Documentation changes +- `chore`: Maintenance tasks (dependencies, build config, etc.) +- `perf`: Performance improvements + +**Examples:** +``` +feat(model): add support for pointy-ended rhabdoms +fix(csv): handle malformed records gracefully +test(parser): add edge case tests for parameter validation +docs: update README with installation instructions +refactor(model): simplify ray tracing calculation logic +``` + +## Code Architecture + +### Core Components + +The codebase is organized into 4 main Go files in a single package: + +1. **pathlength.go** - Entry point with CLI argument parsing + - Handles flags: `-f` (file), `-h` (help), `-v` (version), `-c` (citation), `-l` (license) + - Parses parameter file and orchestrates simulation runs + - Main loop iterates over each parameter set from CSV input + +2. **model.go** - Simulation engine and data structures + - `Parameters` struct: Holds 10 eye-specific configuration values from CSV + - `Model` struct: Contains calculated parameters and simulation state + - `NewModel()`: Initializes model from parameters + - `initialCalculations()`: Computes derived values (eye radius, critical angle, facet counts, etc.) + - `runModel()`: Main simulation loop implementing ray tracing logic + - Iterates over pigment combinations (tapetal and shielding) + - For each combination, iterates over facets in the eyeshine patch + - Calculates light paths through rhabdoms based on angle of incidence + - Four main cases: perpendicular ray, no reflection, edge reflection, base bounce + - Outputs pathlengths to CSV file + +3. **csv.go** - File I/O and data processing + - `parseInputParameters()`: Reads CSV parameter file, returns slice of Parameters + - `calculateRessens()`: Post-processes pathlengths to calculate resolution and sensitivity + - Reads `{species}_pathlengths.csv` + - Calculates absorbance, accumulates values across rhabdoms + - Outputs `{species}_summary_res.csv` and `{species}_summary_sen.csv` + +4. **csv_test.go** - Test suite + - `TestParseInputParameters`: Tests CSV parsing with valid, nonexistent, and malformed files + - `TestCalculateRessens`: Tests resolution/sensitivity calculation + +### Data Flow + +1. CSV parameter file → `parseInputParameters()` → slice of `Parameters` +2. For each Parameters → `NewModel()` → `Model` with calculated values +3. `Model.runModel()` → writes `{species}_pathlengths.csv` and `{species}_debug.csv` +4. `Model.calculateRessens()` → reads pathlengths → writes summary CSV files + +### Input File Format + +CSV files in `example_data/` directory with 10 comma-separated fields per row: +``` +species_name, rhabdom_length, rhabdom_width, eye_diameter, facet_width, +aperture_diameter, cytoplasm_refractive_index, rhabdom_refractive_index, +blur_circle_extent, proximal_rhabdom_angle +``` + +Each row represents a separate simulation run. Multiple rows can be processed in one execution. + +### Output Files + +For each parameter set with species name "X", generates: +- `X_debug.csv` - Debug information from simulation +- `X_pathlengths.csv` - Raw pathlength data for each facet/pigment combination +- `X_summary_res.csv` - Calculated resolution values +- `X_summary_sen.csv` - Calculated sensitivity values + +## Key Implementation Notes + +- The ray tracing simulation handles refraction at the cornea using empirical regression equations for different angle ranges +- The critical angle for total internal reflection is calculated using Snell's law +- Pigment migration is simulated by incrementing tapetal and shielding pigment values through the rhabdom length +- The blur circle feature adds additional facets to account for optical aberrations +- The Python version this was ported from had complex nested loops and state management; the Go version attempts to preserve this logic while using more idiomatic Go + +## Dependencies + +- Go 1.25.4 (specified in go.mod) +- No external dependencies required + +## Citation + +When using this program, cite: +Gaten, E., Moss, S., Johnson, M. 2013. The Reniform Reflecting Superposition Compound Eyes of Nephrops Norvegicus: Optics, Susceptibility to Light-Induced Damage, Electrophysiology and a Ray Tracing Model. In: M. L. Johnson and M. P. Johnson, ed(s). Advances in Marine Biology: The Ecology and Biology of Nephrops norvegicus. Oxford: Academic Press, 107:148. diff --git a/LICENSE.md b/LICENSE.md index aae2f33..281d399 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -616,4 +616,4 @@ above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. \ No newline at end of file +copy of the Program in return for a fee. diff --git a/README.md b/README.md index ec065cf..86acce2 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,17 @@ Email: gawbul@gmail.com /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" # Install Golang -brew install go@1.24 +brew install go@1.25 ``` ### Linux (Debian/Ubuntu) ```bash # Download tarball -wget -P /tmp https://dl.google.com/go/go1.24.4.linux-amd64.tar.gz +wget -P /tmp https://dl.google.com/go/go1.25.4.linux-amd64.tar.gz # Extract tarball -sudo tar -zxvf /tmp/go1.24.4.linux-amd64.tar.gz -C /usr/local +sudo tar -zxvf /tmp/go1.25.4.linux-amd64.tar.gz -C /usr/local # Setup environment echo "export GOROOT=/usr/local/go" >> ~/.profile diff --git a/example_data/acanthephyra_parameters.txt b/example_data/acanthephyra_parameters.txt index 349acb9..7656a96 100644 --- a/example_data/acanthephyra_parameters.txt +++ b/example_data/acanthephyra_parameters.txt @@ -1,3 +1,3 @@ acanthephyra,127,15.8,2480,22.5,870,1.34,1.37,1,0 acanthephyra_bce3,127,15.8,2480,22.5,870,1.34,1.37,3,0 -acanthephyra_bce6,127,15.8,2480,22.5,870,1.34,1.37,6,0 \ No newline at end of file +acanthephyra_bce6,127,15.8,2480,22.5,870,1.34,1.37,6,0 diff --git a/example_data/astacodes_parameters.txt b/example_data/astacodes_parameters.txt index 15c99df..e288999 100644 --- a/example_data/astacodes_parameters.txt +++ b/example_data/astacodes_parameters.txt @@ -1 +1 @@ -astacodes,84,16,890,32,445,1.34,1.37,18,0 \ No newline at end of file +astacodes,84,16,890,32,445,1.34,1.37,18,0 diff --git a/example_data/nephrops_parameters.txt b/example_data/nephrops_parameters.txt index 766e6e5..a644be6 100644 --- a/example_data/nephrops_parameters.txt +++ b/example_data/nephrops_parameters.txt @@ -1,4 +1,4 @@ nephropsfl,180,25,7800,50,3200,1.34,1.37,18,0 nephropspl,180,25,7800,50,3200,1.34,1.37,18,12.5 nephropsfa,180,25,6760,50,3060,1.34,1.37,10,0 -nephropspa,180,25,6760,50,3060,1.34,1.37,10,12.5 \ No newline at end of file +nephropspa,180,25,6760,50,3060,1.34,1.37,10,12.5 diff --git a/go.mod b/go.mod index 3f4cf25..6640e41 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ module pathlength -go 1.24.4 - -require github.com/stretchr/testify v1.10.0 // indirect +go 1.25.4 diff --git a/go.sum b/go.sum index 7bfdabe..e69de29 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +0,0 @@ -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=