Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,25 @@ These are now baked into the generator and enforced by tests. **Do not reopen wi
1. **`V0 - V0` returns the same `V0` of `T.Abs(a - b)`.** Magnitude subtraction stays non-negative; signed subtraction must use the V1 form explicitly.
2. **Dimensionless and angular quantities have both `Ratio` (V0) and `SignedRatio` (V1) bases.** Ratios that semantically must be non-negative (e.g. `RefractiveIndex`, `MachNumber`, `SpecificGravity`) are V0 overloads of `Ratio`.
3. **Semantic overloads widen implicitly to their base, narrow explicitly from it.** A `Weight` is implicitly a `ForceMagnitude`; the reverse requires `Weight.From(forceMagnitude)` or an explicit cast.
4. **Physical constraints come from per-dimension metadata.** Floors like absolute zero or non-negative frequency are declared in `dimensions.json` and the generator emits `ArgumentException`-throwing guards inside the `Create`/`From*` factories.
4. **Physical constraints are enforced structurally via the V0 (magnitude) form.** `Vector0` factories run `Vector0Guards.EnsureNonNegative` and throw `ArgumentException` on a negative value. That covers absolute zero (Temperature is V0, so Kelvin must be ≥ 0), non-negative frequency, non-negative absolute pressure, etc. Strict-positive or upper-bound constraints are not yet declared in metadata (tracked separately).

### Physical constants

`PhysicalConstants` is **generated** from `dimensions.json` (and a constants fixture). Public surface:
`PhysicalConstants` is **generated** from `domains.json`. Public surface:

```csharp
// Domain-grouped PreciseNumber values:
PhysicalConstants.Fundamental.SpeedOfLight
PhysicalConstants.Fundamental.PlanckConstant
PhysicalConstants.AngularMechanics.DegreesPerRadian

// Generic accessors that materialise into any T : INumber<T>:
PhysicalConstants.Generic.SpeedOfLight<T>()
PhysicalConstants.Generic.PlanckConstant<T>()
PhysicalConstants.Conversion.FeetToMeters<T>()
PhysicalConstants.Generic.DegreesPerRadian<T>()
```

Use these accessors instead of hard-coded numerics. Backing values are stored as `PreciseNumber` and converted with `T.CreateChecked` per call.
Backing values are stored as `PreciseNumber` and converted with `T.CreateChecked` per call.

### Operators and physics relationships

Expand Down Expand Up @@ -139,6 +145,9 @@ var converted = sourceString.As<SourceType, TargetType>();
- Edit `Semantics.SourceGenerators/Metadata/dimensions.json` to add a dimension, vector form, semantic overload, or relationship.
- Rebuild `Semantics.SourceGenerators` and the consuming `Semantics.Quantities` project; emitted files appear in `Semantics.Quantities/Generated/Semantics.SourceGenerators/<GeneratorName>/`.
- Treat generator output as committed source. Diff it before commit so accidental regressions are visible.
- Generator diagnostics:
- **SEM001** — a relationship in `dimensions.json` references a dimension that does not exist (typo or rename). The operator is silently dropped.
- **SEM002** — schema-level validation issue (missing `name`/`symbol`, empty `availableUnits`, duplicate type names, no vector forms declared).
- See `docs/physics-generator.md` for the full schema and an end-to-end "add a dimension" walk-through.

This file is the entry point. For deeper material:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public record AbsorbedDose<T> : PhysicalQuantity<AbsorbedDose<T>, T>, IVector0<A
/// </summary>
/// <param name="value">The value in Gray.</param>
/// <returns>A new <see cref="AbsorbedDose{T}"/> instance.</returns>
public static AbsorbedDose<T> FromGray(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AbsorbedDose<T> FromGray(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AbsorbedDose values, returning the absolute difference as a non-negative AbsorbedDose.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AbsorbedDose<T> operator -(AbsorbedDose<T> left, AbsorbedDose<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ public record AccelerationMagnitude<T> : PhysicalQuantity<AccelerationMagnitude<
/// </summary>
/// <param name="value">The value in MetersPerSecondSquared.</param>
/// <returns>A new <see cref="AccelerationMagnitude{T}"/> instance.</returns>
public static AccelerationMagnitude<T> FromMetersPerSecondSquared(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AccelerationMagnitude<T> FromMetersPerSecondSquared(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AccelerationMagnitude values, returning a signed Acceleration1D result.
/// Subtracts two AccelerationMagnitude values, returning the absolute difference as a non-negative AccelerationMagnitude.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Acceleration1D<T> operator -(AccelerationMagnitude<T> left, AccelerationMagnitude<T> right) => Acceleration1D<T>.Create(left.Quantity - right.Quantity);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AccelerationMagnitude<T> operator -(AccelerationMagnitude<T> left, AccelerationMagnitude<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
/// <summary>
/// Multiplies AccelerationMagnitude by Mass to produce ForceMagnitude.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public record AcousticImpedance<T> : PhysicalQuantity<AcousticImpedance<T>, T>,
/// </summary>
/// <param name="value">The value in PascalSecondPerMeter.</param>
/// <returns>A new <see cref="AcousticImpedance{T}"/> instance.</returns>
public static AcousticImpedance<T> FromPascalSecondPerMeter(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AcousticImpedance<T> FromPascalSecondPerMeter(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AcousticImpedance values, returning the absolute difference as a non-negative AcousticImpedance.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AcousticImpedance<T> operator -(AcousticImpedance<T> left, AcousticImpedance<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ public record ActivationEnergy<T> : PhysicalQuantity<ActivationEnergy<T>, T>, IV
public static ActivationEnergy<T> Zero => Create(T.Zero);

/// <summary>Creates a new ActivationEnergy from a value in JoulePerMole.</summary>
public static ActivationEnergy<T> FromJoulePerMole(T value) => Create(value);
public static ActivationEnergy<T> FromJoulePerMole(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>Implicit conversion to MolarEnergy.</summary>
public static implicit operator MolarEnergy<T>(ActivationEnergy<T> value) => MolarEnergy<T>.Create(value.Value);
/// <summary>Explicit conversion from MolarEnergy.</summary>
public static explicit operator ActivationEnergy<T>(MolarEnergy<T> value) => Create(value.Value);
/// <summary>Creates a ActivationEnergy from a MolarEnergy value.</summary>
public static ActivationEnergy<T> From(MolarEnergy<T> value) => Create(value.Value);
/// <summary>Subtracts two ActivationEnergy values, returning the absolute difference as a non-negative ActivationEnergy.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static ActivationEnergy<T> operator -(ActivationEnergy<T> left, ActivationEnergy<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ public record Admittance<T> : PhysicalQuantity<Admittance<T>, T>, IVector0<Admit
public static Admittance<T> Zero => Create(T.Zero);

/// <summary>Creates a new Admittance from a value in Siemens.</summary>
public static Admittance<T> FromSiemens(T value) => Create(value);
public static Admittance<T> FromSiemens(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>Implicit conversion to Conductance.</summary>
public static implicit operator Conductance<T>(Admittance<T> value) => Conductance<T>.Create(value.Value);
/// <summary>Explicit conversion from Conductance.</summary>
public static explicit operator Admittance<T>(Conductance<T> value) => Create(value.Value);
/// <summary>Creates a Admittance from a Conductance value.</summary>
public static Admittance<T> From(Conductance<T> value) => Create(value.Value);
/// <summary>Subtracts two Admittance values, returning the absolute difference as a non-negative Admittance.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Admittance<T> operator -(Admittance<T> left, Admittance<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ public record Airspeed<T> : PhysicalQuantity<Airspeed<T>, T>, IVector0<Airspeed<
public static Airspeed<T> Zero => Create(T.Zero);

/// <summary>Creates a new Airspeed from a value in MetersPerSecond.</summary>
public static Airspeed<T> FromMetersPerSecond(T value) => Create(value);
public static Airspeed<T> FromMetersPerSecond(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>Implicit conversion to Speed.</summary>
public static implicit operator Speed<T>(Airspeed<T> value) => Speed<T>.Create(value.Value);
/// <summary>Explicit conversion from Speed.</summary>
public static explicit operator Airspeed<T>(Speed<T> value) => Create(value.Value);
/// <summary>Creates a Airspeed from a Speed value.</summary>
public static Airspeed<T> From(Speed<T> value) => Create(value.Value);
/// <summary>Subtracts two Airspeed values, returning a signed Velocity1D result.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Velocity1D<T> operator -(Airspeed<T> left, Airspeed<T> right) => Velocity1D<T>.Create(left.Quantity - right.Quantity);
/// <summary>Subtracts two Airspeed values, returning the absolute difference as a non-negative Airspeed.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Airspeed<T> operator -(Airspeed<T> left, Airspeed<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ public record Altitude<T> : PhysicalQuantity<Altitude<T>, T>, IVector0<Altitude<
public static Altitude<T> Zero => Create(T.Zero);

/// <summary>Creates a new Altitude from a value in Meter.</summary>
public static Altitude<T> FromMeter(T value) => Create(value);
public static Altitude<T> FromMeter(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>Implicit conversion to Length.</summary>
public static implicit operator Length<T>(Altitude<T> value) => Length<T>.Create(value.Value);
/// <summary>Explicit conversion from Length.</summary>
public static explicit operator Altitude<T>(Length<T> value) => Create(value.Value);
/// <summary>Creates a Altitude from a Length value.</summary>
public static Altitude<T> From(Length<T> value) => Create(value.Value);
/// <summary>Subtracts two Altitude values, returning a signed Displacement1D result.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Displacement1D<T> operator -(Altitude<T> left, Altitude<T> right) => Displacement1D<T>.Create(left.Quantity - right.Quantity);
/// <summary>Subtracts two Altitude values, returning the absolute difference as a non-negative Altitude.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Altitude<T> operator -(Altitude<T> left, Altitude<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
};

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ public record AmountOfSubstance<T> : PhysicalQuantity<AmountOfSubstance<T>, T>,
/// </summary>
/// <param name="value">The value in Mole.</param>
/// <returns>A new <see cref="AmountOfSubstance{T}"/> instance.</returns>
public static AmountOfSubstance<T> FromMole(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AmountOfSubstance<T> FromMole(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AmountOfSubstance values, returning the absolute difference as a non-negative AmountOfSubstance.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AmountOfSubstance<T> operator -(AmountOfSubstance<T> left, AmountOfSubstance<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
/// <summary>
/// Divides AmountOfSubstance by Volume to produce Concentration.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ public record Angle<T> : PhysicalQuantity<Angle<T>, T>, IVector0<Angle<T>, T>
/// </summary>
/// <param name="value">The value in Radian.</param>
/// <returns>A new <see cref="Angle{T}"/> instance.</returns>
public static Angle<T> FromRadian(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static Angle<T> FromRadian(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two Angle values, returning a signed SignedAngle result.
/// Subtracts two Angle values, returning the absolute difference as a non-negative Angle.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static SignedAngle<T> operator -(Angle<T> left, Angle<T> right) => SignedAngle<T>.Create(left.Quantity - right.Quantity);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static Angle<T> operator -(Angle<T> left, Angle<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
/// <summary>
/// Divides Angle by Duration to produce AngularSpeed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ public record AngularAccelerationMagnitude<T> : PhysicalQuantity<AngularAccelera
/// </summary>
/// <param name="value">The value in RadiansPerSecondSquared.</param>
/// <returns>A new <see cref="AngularAccelerationMagnitude{T}"/> instance.</returns>
public static AngularAccelerationMagnitude<T> FromRadiansPerSecondSquared(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AngularAccelerationMagnitude<T> FromRadiansPerSecondSquared(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AngularAccelerationMagnitude values, returning a signed AngularAcceleration1D result.
/// Subtracts two AngularAccelerationMagnitude values, returning the absolute difference as a non-negative AngularAccelerationMagnitude.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AngularAcceleration1D<T> operator -(AngularAccelerationMagnitude<T> left, AngularAccelerationMagnitude<T> right) => AngularAcceleration1D<T>.Create(left.Quantity - right.Quantity);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AngularAccelerationMagnitude<T> operator -(AngularAccelerationMagnitude<T> left, AngularAccelerationMagnitude<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
/// <summary>
/// Multiplies AngularAccelerationMagnitude by Duration to produce AngularSpeed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ public record AngularJerkMagnitude<T> : PhysicalQuantity<AngularJerkMagnitude<T>
/// </summary>
/// <param name="value">The value in RadiansPerSecondCubed.</param>
/// <returns>A new <see cref="AngularJerkMagnitude{T}"/> instance.</returns>
public static AngularJerkMagnitude<T> FromRadiansPerSecondCubed(T value) => Create(value);
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
public static AngularJerkMagnitude<T> FromRadiansPerSecondCubed(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
/// <summary>
/// Subtracts two AngularJerkMagnitude values, returning a signed AngularJerk1D result.
/// Subtracts two AngularJerkMagnitude values, returning the absolute difference as a non-negative AngularJerkMagnitude.
/// Magnitude subtraction stays a magnitude (per the unified-vector model).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AngularJerk1D<T> operator -(AngularJerkMagnitude<T> left, AngularJerkMagnitude<T> right) => AngularJerk1D<T>.Create(left.Quantity - right.Quantity);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Physics quantity operator")] public static AngularJerkMagnitude<T> operator -(AngularJerkMagnitude<T> left, AngularJerkMagnitude<T> right) => Create(T.Abs(left.Quantity - right.Quantity));
/// <summary>
/// Multiplies AngularJerkMagnitude by Duration to produce AngularAccelerationMagnitude.
/// </summary>
Expand Down
Loading
Loading