Skip to content

Commit 732aca8

Browse files
committed
add claude entries
1 parent f5c5625 commit 732aca8

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

.claude/CLAUDE.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# PowerSystemsMaps.jl — Claude Guide
2+
3+
Platform-wide Sienna conventions (performance, type stability, formatter, environments, code style) live in `.claude/Sienna.md` — read it too. This file is repo-specific and does not restate them.
4+
5+
## Purpose & place in the stack
6+
7+
PowerSystemsMaps (PSM) is a small **leaf visualization package**. It consumes a PowerSystems.jl `System` and draws the network — optionally on top of a geographic basemap from a shapefile. It is the bottom of the dependency chain: nothing else in Sienna depends on it, and it is *not* a JuMP/optimization package.
8+
9+
Verified `[deps]` (Project.toml, `version = 0.2.2`): `PowerSystems` (compat `4`), `Plots` (`1`), `Graphs` (`1.11`), `MetaGraphsNext` (`0.7`), `NetworkLayout` (`0.4`), `Shapefile` (`0.11, 0.12, 0.13`), `GeometryBasics` (`0.4`), `Colors` (`0.12`). Julia `^1.6`.
10+
11+
## Architecture: System → graph → layout → plot
12+
13+
Only two source files:
14+
15+
- `src/PowerSystemsMaps.jl` — module file: `using`/`import` lines and the export list. Exports: `plot`, `plot!`, `plot_net`, `plot_net!`, `plot_components!`, `make_graph`, `plot_map`. (`plot`/`plot!` are re-exported from Plots.) `include`s the one implementation file.
16+
- `src/plot_network.jl` — all the logic.
17+
18+
Pipeline inside `make_graph`:
19+
1. Build a `MetaGraphsNext.MetaGraph` (`String` labels, `Dict{Symbol,Any}` vertex data) from the `System` — one vertex per `Bus`, edges from `Arc`s carrying the `Branch` components.
20+
2. Bus geo-coordinates come from `GeographicInfo` supplemental attributes (GeoJSON `Point`); buses without one fall back to `DEFAULT_LON`/`DEFAULT_LAT`.
21+
3. Color nodes (`color_nodes!`, dispatched on `color_by`: a `Symbol` field, an `AggregationTopology` subtype, or default `:area`) using `Colors.distinguishable_colors`.
22+
4. Compute a layout: if not every bus is geo-pinned, run `NetworkLayout.sfdp` on the adjacency matrix (kwargs `K`, `C`, `tol`, `iterations`, with pinned positions); otherwise use the pinned coordinates directly.
23+
5. Store `:x`/`:y`/`:name` back onto the graph via `set_prop!`.
24+
25+
Coordinates are projected to Web Mercator by `lonlat_to_webmercator` (multiple-dispatch methods for `Tuple`, `Shapefile.Point`, `Shapefile.Polygon`, and a `Vector{Union{Missing,Shapefile.Polygon}}`) before plotting, so shapefile polygons and network nodes share one projected coordinate system.
26+
27+
## Main public API / entry points
28+
29+
(Signatures verified against `src/plot_network.jl`.)
30+
31+
- `make_graph(sys::System; kwargs...) -> MetaGraph` — builds and lays out the graph. Key kwargs: `K` (SFDP spring constant), `color_by`, `name_accessor`, plus SFDP `C`/`tol`/`iterations`.
32+
- `plot_net(g; kwargs...)` / `plot_net!(p::Plots.Plot, g; kwargs...)` — draw the network from a graph. Key kwargs: `lines::Bool`, `linecolor`, `linewidth`, `linealpha`, `nodesize`, `nodecolor`, `nodealpha`, `nodehover`, `shownodelegend`, `buffer`, `size`, `xlim`/`ylim`, `legend_font_color`. The `!` form overlays onto an existing plot (e.g. a basemap).
33+
- `plot_map(sys::System, shapefile::AbstractString; kwargs...)` — one-shot convenience: `make_graph` + load shapefile + plot basemap + `plot_net!`. Map-styling kwargs are passed with a `map_` prefix (e.g. `map_linecolor`), which `plot_map` strips and forwards to the basemap `plot` call; un-prefixed kwargs go to the network layer.
34+
- `plot_components!(p, components, color, markersize, label)` — add scatter dots for components (dispatched for a generic component iterator and for a `FlattenIteratorWrapper{Bus}`).
35+
36+
Not exported but used in the README/tests: `lonlat_to_webmercator`, `make_test_sys` (test-only). Reach them via the `PSM.` prefix.
37+
38+
## Plots backend (PlotlyJS vs GR) & how to select it
39+
40+
PSM draws with Plots.jl and does **not** force a backend. The user picks one before plotting:
41+
42+
- Interactive (hover tooltips work — the API sets `hover=` on series): call `PSM.Plots.plotlyjs()`, as in the README. Requires `PlotlyJS` to be installed in the active env (it is a `test/Project.toml` dep, not a package dep).
43+
- Static / headless: `PSM.Plots.gr()`. The test suite runs on the **GR** backend — `test/test_maps.jl` asserts `typeof(p) == PSM.Plots.Plot{PSM.Plots.GRBackend}`.
44+
45+
## Conventions & gotchas
46+
47+
- **Backend is caller-chosen**: nothing in `src/` calls `gr()`/`plotlyjs()`. If you add a feature relying on `hover`, document that it needs the PlotlyJS backend.
48+
- **Headless CI**: tests use GR with no display and only build plot objects (no `display`/`savefig`), so they run headless. Keep new tests display-free.
49+
- **Geo fallback**: buses lacking `GeographicInfo` silently fall back to the San-Francisco default lon/lat and get a low alpha — don't mistake that for a bug when an ungeocoded system plots oddly.
50+
- **PlotlyJS is not a package dep** — only `Plots`. Code in `src/` must not assume the PlotlyJS backend is available.
51+
52+
## Cross-package coupling
53+
54+
- **PowerSystems.jl** is the only Sienna dependency — PSM reads `Bus`, `Arc`, `Branch`, `AggregationTopology`, and `GeographicInfo` via PSY accessors (`get_components`, `get_name`, `get_lonlat` helper, etc.). Track PSY major bumps (currently compat `4`); accessor/attribute renames break PSM.
55+
- **PowerGraphics.jl**: separate package for plotting *simulation results* (production cost, dispatch stacks). PSM is unrelated — it plots network *topology/geography*, not results. No code dependency either way.
56+
57+
## Running tests, docs, formatter (verified commands)
58+
59+
**Formatter — script exists** at `scripts/formatter/formatter_code.jl` (activates its own env, runs JuliaFormatter over `./src` and `./test`). Run it after any `.jl` change, before reporting done:
60+
61+
```sh
62+
julia --project=scripts/formatter -e 'include("scripts/formatter/formatter_code.jl")'
63+
```
64+
65+
(There is no `.JuliaFormatter.toml`; format options are hard-coded in that script. CI also runs `.github/workflows/format-check.yml`.)
66+
67+
**Tests** — classic runner using `TestSetExtensions` + an `@includetests` macro (not ReTest). It auto-discovers `test_*.jl` files (currently just `test_maps.jl`). Deps incl. `PlotlyJS`, `CSV`, `DataFrames` live in `test/Project.toml`:
68+
69+
```sh
70+
julia --project=test test/runtests.jl # full suite
71+
julia --project=test test/runtests.jl test_maps # a single test file (name without .jl)
72+
julia --project=test -e 'using Pkg; Pkg.instantiate()'
73+
```
74+
75+
**Docs** — a `docs/` environment exists (`docs/make.jl`, `docs/Project.toml`); pages are `index.md` + `api.md`:
76+
77+
```sh
78+
julia --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' # first time
79+
julia --project=docs docs/make.jl
80+
```

.claude/Sienna.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Sienna Programming Practices
2+
3+
General programming practices and conventions that apply across all Sienna packages (PowerSystems.jl, PowerSimulations.jl, PowerFlows.jl, PowerNetworkMatrices.jl, InfrastructureSystems.jl, etc.). This file is intended to be **identical across every Sienna repository** — package-specific guidance belongs in that package's `CLAUDE.md`, not here.
4+
5+
## Performance Requirements
6+
7+
**Priority:** Critical. See the [Julia Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/). Apply with judgment — focus optimization on hot paths and frequently called code, not every function.
8+
9+
### Anti-Patterns to Avoid
10+
11+
- **Type instability** — functions must return consistent concrete types. Check with `@code_warntype`. Bad: `f(x) = x > 0 ? 1 : 1.0`; good: `f(x) = x > 0 ? 1.0 : 1.0`.
12+
- **Abstract field types** — struct fields must be concrete or parameterized. Bad: `struct Foo; data::AbstractVector; end`; good: `struct Foo{T<:AbstractVector}; data::T; end`.
13+
- **Untyped containers** — use `Vector{Float64}()`, not `Vector{Any}()` / `Vector{Real}()`.
14+
- **Non-const globals** — use `const THRESHOLD = 0.5`. (No type annotation needed on a `const`; the compiler already infers it — annotating gives no precompilation benefit.)
15+
- **Unnecessary allocations** — use views (`@view`/`@views`), pre-allocate instead of `push!` in loops, use in-place (`!`) operations.
16+
- **Captured variables** — avoid closures that box captured variables; pass them as arguments instead.
17+
- **Splatting penalty** — avoid `...` in performance-critical code.
18+
- **Abstract return types** — avoid returning `Union`s or abstract types.
19+
20+
#### Runtime type checking (`isa` and `<:`) — the canonical rule
21+
22+
**ABSOLUTELY FORBIDDEN unless the user explicitly asks for it.** Never use `isa` or `<:` (subtype) checks to branch on types in a function body — use multiple dispatch instead. Using `<:` to branch is just `isa` with extra steps.
23+
24+
- Bad: `if x isa Float64 ... elseif x isa Int ... end`
25+
- Bad: `if typeof(x) <: AbstractVector ... end`
26+
- Bad: `if T <: SomeAbstractType ... else ... end` (branching on a type parameter)
27+
- Good: `f(x::AbstractVector) = sum(x); f(x::Number) = x`
28+
29+
**Why:** runtime type checks force the compiler to handle multiple paths at runtime, lose type information, prevent specialization, and trigger runtime compilation — defeating Julia's performance model. The only acceptable use of `isa` is filtering inside a `catch` block, where dispatch is unavailable.
30+
31+
### Best Practices
32+
33+
- Use `@inbounds` when bounds are verified; use broadcasting for element-wise ops.
34+
- Avoid `try-catch` in hot paths; use function barriers to isolate type instability.
35+
36+
## Code Conventions
37+
38+
Style guide: <https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/>
39+
40+
**Always run the formatter after completing each task — before reporting it done. This is not optional.** Run the package's formatter script (the script self-activates its own environment):
41+
42+
```sh
43+
julia --project=scripts/formatter -e 'include("scripts/formatter/formatter_code.jl")'
44+
```
45+
46+
This applies after any change to `.jl` files. Treat the formatter's output as authoritative; do not manually revert its changes.
47+
48+
Key rules:
49+
50+
- Constructors: use `function Foo()`, not `Foo() = ...`
51+
- Asserts: prefer `InfrastructureSystems.@assert_op` over `@assert`
52+
- Globals: `UPPER_CASE` for constants; exports: all in the main module file
53+
- Comments: complete sentences; describe why, not how
54+
- Nothing checks: use `isnothing(x)` / `!isnothing(x)`, not `x === nothing` / `x !== nothing`
55+
- Type checks: use multiple dispatch, never `isa`/`<:` branching — see the runtime type-checking rule above
56+
- Conditionals: prefer `if/else` over the ternary `? :`, especially in multi-line expressions
57+
- Cache lookups: use the lazy closure form `get!(dict, key) do ... end` (only evaluates on a miss). Never use 3-arg `get!(dict, key, default)` when `default` is expensive — Julia evaluates arguments eagerly, so `default` runs on every call and silently defeats the cache.
58+
59+
## Documentation Practices and Requirements
60+
61+
Framework: [Diataxis](https://diataxis.fr/). Sienna guides:
62+
63+
- Explanation / best practices: <https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/explanation/>
64+
- Tutorials: <https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/how-to/write_a_tutorial/> (script format via Literate.jl: <https://fredrikekre.github.io/Literate.jl/v2/>)
65+
- How-to's: <https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/how-to/write_a_how-to/>
66+
- API docstrings: <https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/how-to/write_docstrings_org_api/>
67+
68+
Docstrings: cover all public-interface elements (IS is selective about exports); include signatures + argument lists; automate with `DocStringExtensions.TYPEDSIGNATURES` (`TYPEDFIELDS` sparingly); add "see also" links for same-named (multiple-dispatch) functions. API docs: public in `docs/src/api/public.md` via `@autodocs` (`Public=true, Private=false`); internals in `docs/src/api/internals.md`.
69+
70+
**The documentation must build to succeed.** Before considering any documentation-affecting task complete, confirm the docs build cleanly — a broken docs build is a task failure, not a warning. Documenter treats missing docstring references, broken `@ref` links, and failing doctests as errors:
71+
72+
```sh
73+
julia --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' # first time
74+
julia --project=docs docs/make.jl # must finish without errors
75+
```
76+
77+
Where the package provides a docstring-coverage checker, also run it so every exported symbol is documented (this is enforced in CI):
78+
79+
```sh
80+
julia --project=test scripts/check_docstrings.jl <PackageName>
81+
```
82+
83+
## Design Principles
84+
85+
- Elegance and concision in both interface and implementation
86+
- Fail fast with actionable error messages rather than hiding problems
87+
- Validate invariants explicitly in subtle cases
88+
- Avoid over-adherence to backwards compatibility for internal helpers
89+
90+
## Contribution Workflow
91+
92+
**The default branch for all Sienna packages is `main`, not `master`.** Branch naming: `feature/description` or `fix/description`. Workflow: create a feature branch → follow the style guide and run the formatter → ensure tests pass → submit a pull request.
93+
94+
## Testing Guidelines
95+
96+
**Test custom logic, not language guarantees.** Do not write tests that only verify Julia's built-in behavior.
97+
98+
Avoid: `@test obj isa SomeType` when the type hierarchy makes it tautological; testing that a plain data-holder struct stores the value it was constructed with; testing `==`/`isequal`/`hash` inherited from a parent with no added logic; duplicating a test with trivially different inputs that exercise no new code path.
99+
100+
Instead test: custom dispatch logic and predicates you defined; type-mapping tables and accessors (where typos hide); serialization round-trips; custom `show`/display formatting; validation logic, error paths, and edge cases.
101+
102+
## Julia Environment Best Practices
103+
104+
**CRITICAL: always run Julia with `julia --project=<env>`** — never bare `julia` or `julia --project` without specifying the environment, or required packages won't be available. Each package defines its environments under `test/`, `docs/`, and `scripts/formatter/`.
105+
106+
```sh
107+
julia --project=test test/runtests.jl # full test suite
108+
julia --project=test test/runtests.jl test_file_name # a single test file
109+
julia --project=test -e 'using Pkg; Pkg.instantiate()' # instantiate test env
110+
julia --project=docs docs/make.jl # build docs
111+
```
112+
113+
(See each repo's `CLAUDE.md` for its exact, verified commands and test-runner style.)
114+
115+
## AI Agent Guidance
116+
117+
**Priorities:** read existing patterns first; maintain consistency; use concrete types in hot paths; add docstrings to public API; consider downstream-package impact; ensure tests pass. **Then run the formatter and never edit auto-generated files.** The two rules most often violated:
118+
119+
- **Never use `isa`/`<:` for runtime type branching** — use multiple dispatch (see the canonical rule above).
120+
- **Always run the formatter** (`julia --project=scripts/formatter -e 'include("scripts/formatter/formatter_code.jl")'`) before reporting a task done.
121+
122+
## Troubleshooting
123+
124+
- **Tests fail unexpectedly / packages missing:** re-instantiate — `julia --project=test -e 'using Pkg; Pkg.instantiate()'`.
125+
- **Poor performance, many allocations:** run `@code_warntype` on the suspect function (see the performance anti-patterns above).

0 commit comments

Comments
 (0)