mirror of
https://github.com/acamarata/nrel-spa-dart.git
synced 2026-06-30 19:04:24 +00:00
chore: polish pubspec, fix unused import, add wiki docs
This commit is contained in:
parent
241c773a9f
commit
01a1c56cd0
8 changed files with 293 additions and 17 deletions
|
|
@ -1 +0,0 @@
|
|||
CLAUDE.md
|
||||
46
.github/wiki/CONTRIBUTING.md
vendored
Normal file
46
.github/wiki/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Contributing to nrel-spa-dart
|
||||
|
||||
Thanks for taking the time to contribute.
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Fork the repository and clone your fork.
|
||||
2. Install the Dart SDK (stable channel): [dart.dev/get-dart](https://dart.dev/get-dart)
|
||||
3. Install dependencies: `dart pub get`
|
||||
4. Run the tests: `dart test`
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Open a GitHub issue with:
|
||||
- A minimal reproducible example
|
||||
- The actual output and the expected output
|
||||
- Your Dart SDK version (`dart --version`)
|
||||
- Your operating system
|
||||
|
||||
## Suggesting enhancements
|
||||
|
||||
Open a GitHub issue before writing code. Describe the use case and the proposed API. Algorithm changes require a reference to the relevant paper or standard.
|
||||
|
||||
## Pull requests
|
||||
|
||||
1. Create a feature branch from `main`.
|
||||
2. Keep changes focused. One feature or bug fix per PR.
|
||||
3. Add or update tests for any changed behavior.
|
||||
4. Run `dart analyze` and confirm zero issues.
|
||||
5. Run `dart format lib/ test/` before committing.
|
||||
6. Update the CHANGELOG.md under `## [Unreleased]` with a brief description.
|
||||
7. Open the PR with a clear title and description.
|
||||
|
||||
## Code style
|
||||
|
||||
Follow standard Dart conventions. The project uses `dart format` with default settings. Lint rules are defined in `analysis_options.yaml` and inherit from the `lints` package.
|
||||
|
||||
Comments should explain *why*, not *what*. Algorithm steps should reference the equation number from Reda & Andreas (2004).
|
||||
|
||||
## Algorithm changes
|
||||
|
||||
This package implements the NREL Solar Position Algorithm exactly as specified in NREL/TP-560-34302. Proposed deviations from the paper require strong justification and a test against the validation dataset from the paper.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||
33
.github/wiki/Home.md
vendored
33
.github/wiki/Home.md
vendored
|
|
@ -1,29 +1,34 @@
|
|||
# nrel_spa
|
||||
|
||||
NREL Solar Position Algorithm for Dart and Flutter. Calculates solar zenith, azimuth, sunrise, sunset, and solar noon for any location and time. Pure Dart, zero dependencies.
|
||||
NREL Solar Position Algorithm for Dart and Flutter. Calculates solar zenith, azimuth, sunrise, sunset, and solar noon for any location and time. Pure Dart, zero dependencies, accurate to ±0.0003 degrees.
|
||||
|
||||
Accurate to +/- 0.0003 degrees. Based on Reda & Andreas (2004), NREL/TP-560-34302.
|
||||
Based on Reda & Andreas (2004), NREL/TP-560-34302.
|
||||
|
||||
## Quick Start
|
||||
## Install
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
nrel_spa: ^1.0.1
|
||||
```
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
final result = getSpa(
|
||||
DateTime.utc(2024, 3, 15, 17, 0, 0),
|
||||
40.7128, // latitude
|
||||
-74.0060, // longitude
|
||||
-5.0, // UTC offset (EST)
|
||||
40.7128, // latitude
|
||||
-74.0060, // longitude
|
||||
-5.0, // UTC offset (EST)
|
||||
);
|
||||
|
||||
print('Zenith: ${result.zenith.toStringAsFixed(4)}');
|
||||
print('Azimuth: ${result.azimuth.toStringAsFixed(4)}');
|
||||
print('Sunrise: ${result.sunrise.toStringAsFixed(4)} h');
|
||||
print('Solar Noon: ${result.solarNoon.toStringAsFixed(4)} h');
|
||||
print('Sunset: ${result.sunset.toStringAsFixed(4)} h');
|
||||
print('Zenith: ${result.zenith.toStringAsFixed(4)}°');
|
||||
print('Sunrise: ${result.sunrise.toStringAsFixed(4)} h');
|
||||
```
|
||||
|
||||
## Pages
|
||||
## Contents
|
||||
|
||||
- [API Reference](API-Reference): Full function and type reference
|
||||
- [Architecture](Architecture): Algorithm design and implementation notes
|
||||
- [Quickstart Guide](guides/quickstart) — install, first call, common patterns
|
||||
- [Advanced Usage](guides/advanced) — custom zenith angles, elevation, atmospheric correction
|
||||
- [API Reference](API-Reference) — full function and type reference
|
||||
- [Examples](examples/basic-usage) — real-world snippets
|
||||
- [Contributing](CONTRIBUTING)
|
||||
|
|
|
|||
74
.github/wiki/examples/basic-usage.md
vendored
Normal file
74
.github/wiki/examples/basic-usage.md
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# Basic Usage Examples
|
||||
|
||||
## Sunrise and Sunset for a City
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
void printSolarDay(String city, double lat, double lng, double utcOffset) {
|
||||
final now = DateTime.now().toUtc();
|
||||
final result = getSpa(now, lat, lng, utcOffset);
|
||||
|
||||
String fmt(double h) {
|
||||
if (h.isNaN) return 'n/a';
|
||||
final hh = h.truncate();
|
||||
final mm = ((h - hh) * 60).round();
|
||||
return '${hh.toString().padLeft(2, '0')}:${mm.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
print('$city');
|
||||
print(' Sunrise: ${fmt(result.sunrise)}');
|
||||
print(' Solar noon: ${fmt(result.solarNoon)}');
|
||||
print(' Sunset: ${fmt(result.sunset)}');
|
||||
print(' Zenith now: ${result.zenith.toStringAsFixed(2)}°');
|
||||
}
|
||||
|
||||
void main() {
|
||||
printSolarDay('New York', 40.7128, -74.0060, -5.0);
|
||||
printSolarDay('London', 51.5074, -0.1278, 0.0);
|
||||
printSolarDay('Makkah', 21.3891, 39.8579, 3.0);
|
||||
printSolarDay('Melbourne', -37.8136, 144.9631, 10.0);
|
||||
}
|
||||
```
|
||||
|
||||
## Annual Solar Noon Curve
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
void main() {
|
||||
const lat = 40.7128;
|
||||
const lng = -74.0060;
|
||||
const utcOffset = -5.0;
|
||||
|
||||
print('Day,SolarNoon');
|
||||
for (int day = 1; day <= 365; day++) {
|
||||
final date = DateTime.utc(2024, 1, 1).add(Duration(days: day - 1));
|
||||
final result = getSpa(date.add(const Duration(hours: 12)), lat, lng, utcOffset);
|
||||
print('$day,${result.solarNoon.toStringAsFixed(6)}');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Twilight Times for Prayer Calculation
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
void main() {
|
||||
final date = DateTime.utc(2024, 3, 15, 12, 0, 0);
|
||||
const lat = 33.8938; // Jerusalem
|
||||
const lng = 35.5018;
|
||||
const utcOffset = 2.0; // EET
|
||||
|
||||
final result = getSpa(
|
||||
date, lat, lng, utcOffset,
|
||||
customAngles: [108.0, 107.0], // Fajr 18°, Isha 17°
|
||||
);
|
||||
|
||||
print('Fajr (18°): ${result.angles[0].sunrise.toStringAsFixed(4)} h');
|
||||
print('Isha (17°): ${result.angles[1].sunset.toStringAsFixed(4)} h');
|
||||
print('Sunrise: ${result.sunrise.toStringAsFixed(4)} h');
|
||||
print('Sunset: ${result.sunset.toStringAsFixed(4)} h');
|
||||
}
|
||||
```
|
||||
83
.github/wiki/guides/advanced.md
vendored
Normal file
83
.github/wiki/guides/advanced.md
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Advanced Usage
|
||||
|
||||
## Custom Zenith Angles
|
||||
|
||||
Calculate rise/set times for any solar depression angle. Useful for computing civil, nautical, and astronomical twilight, or Islamic prayer times.
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
final result = getSpa(
|
||||
DateTime.utc(2024, 3, 15, 12, 0, 0),
|
||||
40.7128, -74.0060, -5.0,
|
||||
customAngles: [96.0, 102.0, 108.0], // civil, nautical, astronomical
|
||||
);
|
||||
|
||||
for (int i = 0; i < result.angles.length; i++) {
|
||||
final a = result.angles[i];
|
||||
print('Angle ${a.angle}°: rise=${a.sunrise.toStringAsFixed(4)} h, set=${a.sunset.toStringAsFixed(4)} h');
|
||||
}
|
||||
```
|
||||
|
||||
Standard zenith angles:
|
||||
|
||||
| Twilight type | Zenith angle |
|
||||
| --- | --- |
|
||||
| Civil | 96.0° |
|
||||
| Nautical | 102.0° |
|
||||
| Astronomical | 108.0° |
|
||||
| Fajr (18°) | 108.0° |
|
||||
| Isha (17°) | 107.0° |
|
||||
|
||||
## Elevation and Atmospheric Correction
|
||||
|
||||
For more accurate results at high elevation or in varying atmospheric conditions:
|
||||
|
||||
```dart
|
||||
final result = getSpa(
|
||||
DateTime.utc(2024, 3, 15, 12, 0, 0),
|
||||
39.7392, // Denver latitude
|
||||
-104.9903, // Denver longitude
|
||||
-7.0, // UTC offset (MST)
|
||||
elevation: 1609.0, // meters above sea level
|
||||
pressure: 835.0, // mbar (lower at altitude)
|
||||
temperature: 10.0, // Celsius
|
||||
);
|
||||
```
|
||||
|
||||
## deltaT Parameter
|
||||
|
||||
`deltaT` is the difference between Terrestrial Time (TT) and Universal Time (UT1), in seconds. The default is 67 seconds, which is accurate for recent dates. For historical calculations or projections, supply the correct value from [IERS tables](https://www.iers.org/IERS/EN/Science/EarthRotation/EarthRotation.html).
|
||||
|
||||
```dart
|
||||
// Historical calculation (1990)
|
||||
final result = getSpa(
|
||||
DateTime.utc(1990, 6, 21, 12, 0, 0),
|
||||
40.7128, -74.0060, -5.0,
|
||||
deltaT: 57.2,
|
||||
);
|
||||
```
|
||||
|
||||
## Batch Calculations
|
||||
|
||||
For high-volume calculations (annual ephemeris, solar energy modeling), call `getSpa` in a loop. The function is synchronous and pure — safe to call from any isolate.
|
||||
|
||||
```dart
|
||||
final times = List.generate(365, (i) {
|
||||
final date = DateTime.utc(2024, 1, 1).add(Duration(days: i));
|
||||
return getSpa(date, lat, lng, utcOffset);
|
||||
});
|
||||
```
|
||||
|
||||
For parallel batch work in Flutter, dispatch to an isolate:
|
||||
|
||||
```dart
|
||||
import 'dart:isolate';
|
||||
|
||||
final results = await Isolate.run(() {
|
||||
return List.generate(365, (i) {
|
||||
final date = DateTime.utc(2024, 1, 1).add(Duration(days: i));
|
||||
return getSpa(date, lat, lng, utcOffset);
|
||||
});
|
||||
});
|
||||
```
|
||||
69
.github/wiki/guides/quickstart.md
vendored
Normal file
69
.github/wiki/guides/quickstart.md
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Quickstart
|
||||
|
||||
## Install
|
||||
|
||||
Add to `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
nrel_spa: ^1.0.1
|
||||
```
|
||||
|
||||
Run `dart pub get`.
|
||||
|
||||
## First Call
|
||||
|
||||
```dart
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
|
||||
void main() {
|
||||
final result = getSpa(
|
||||
DateTime.utc(2024, 3, 15, 17, 0, 0),
|
||||
40.7128, // latitude (New York)
|
||||
-74.0060, // longitude
|
||||
-5.0, // UTC offset (EST)
|
||||
);
|
||||
|
||||
print('Solar zenith: ${result.zenith.toStringAsFixed(4)}°');
|
||||
print('Solar azimuth: ${result.azimuth.toStringAsFixed(4)}°');
|
||||
print('Sunrise: ${result.sunrise.toStringAsFixed(4)} h');
|
||||
print('Solar noon: ${result.solarNoon.toStringAsFixed(4)} h');
|
||||
print('Sunset: ${result.sunset.toStringAsFixed(4)} h');
|
||||
}
|
||||
```
|
||||
|
||||
## Reading Results
|
||||
|
||||
`getSpa` returns an `SpaResult`:
|
||||
|
||||
| Field | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `zenith` | `double` | Solar zenith angle (degrees) |
|
||||
| `azimuth` | `double` | Solar azimuth angle (degrees from north) |
|
||||
| `sunrise` | `double` | Sunrise time (decimal hours, UTC) |
|
||||
| `solarNoon` | `double` | Solar noon time (decimal hours, UTC) |
|
||||
| `sunset` | `double` | Sunset time (decimal hours, UTC) |
|
||||
| `angles` | `List<AngleResult>` | Rise/set times for custom zenith angles |
|
||||
|
||||
## DateTime Input
|
||||
|
||||
Always pass UTC `DateTime` values. The `timezone` parameter shifts the output times to local time.
|
||||
|
||||
```dart
|
||||
// Convert local DateTime to UTC before passing
|
||||
final local = DateTime(2024, 3, 15, 12, 0, 0);
|
||||
final utc = local.toUtc();
|
||||
final result = getSpa(utc, lat, lng, utcOffset);
|
||||
```
|
||||
|
||||
## Null Results for Sunrise/Sunset
|
||||
|
||||
At polar latitudes or in summer/winter extremes, sunrise or sunset may not occur. In those cases, `result.sunrise` and `result.sunset` return `double.nan`. Always check before displaying:
|
||||
|
||||
```dart
|
||||
if (!result.sunrise.isNaN) {
|
||||
print('Sunrise: ${result.sunrise}');
|
||||
} else {
|
||||
print('No sunrise today.');
|
||||
}
|
||||
```
|
||||
|
|
@ -4,8 +4,10 @@ description: >
|
|||
azimuth, sunrise, sunset, and solar noon for any location and time.
|
||||
Pure Dart, zero dependencies, ±0.0003° accuracy.
|
||||
version: 1.0.1
|
||||
homepage: https://github.com/acamarata/nrel-spa-dart
|
||||
repository: https://github.com/acamarata/nrel-spa-dart
|
||||
issue_tracker: https://github.com/acamarata/nrel-spa-dart/issues
|
||||
publisher: ariccamarata.com
|
||||
topics:
|
||||
- solar
|
||||
- astronomy
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:nrel_spa/nrel_spa.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue