Skip to content

Latest commit

 

History

History
160 lines (108 loc) · 7.98 KB

README.md

File metadata and controls

160 lines (108 loc) · 7.98 KB

DimensionalQuantities

CI CD NuGet NuGet Downloads License

A C# library for dimensional quantities, with generated type aliases, SI unit conversions, and compile-time dimensional arithmetic.

Warning

We developed this library for our own internal use and are sharing it because we believe it may be useful to the wider developer community. Issues and pull requests are welcome, but we make no support commitments or warranties, and we cannot guarantee that we will respond to issues or review or merge pull requests.

Usage

The runtime library targets .NET Standard 2.0. Consumers need a C# 14 compiler for the generated extension blocks. The DimensionalQuantities NuGet package includes both the runtime library and its source generator.

Voltage voltage = Voltage.FromVolts(12);
Current current = Current.FromAmps(3);

Resistance resistance = voltage / current;
Power power = voltage * current;

double ohms = resistance.AsOhms(); // 4
double watts = power.AsWatts();    // 36

SI prefixes and compound units

Named helpers handle conversion into and out of SI prefixes, including powers of prefixed units:

Length length = Length.FromMilliMetres(2500);
double metres = length.AsMetres(); // 2.5

Density density = Density.FromGramsPerCubicCentiMetre(1);
double kilogramsPerCubicMetre = density.AsSiBaseUnit(); // 1000

For more control, FromPrefixedUnits and AsPrefixedUnits accept decimal prefix exponents for each unit factor. Powers are taken into account automatically:

// 1 A/mm² = 1,000,000 A/m²
CurrentDensity density = CurrentDensity.FromPrefixedUnits(
    1, ampPrefixExponent: 0, metrePrefixExponent: -3);

double ampsPerSquareMillimetre = density.AsPrefixedUnits(
    ampPrefixExponent: 0, metrePrefixExponent: -3); // 1

Named compound units remain a single factor where appropriate: Voltage.FromPrefixedUnits(2, -3) means 2 millivolts, without requiring you to know the SI dimensions of a volt.

Arithmetic and generated intermediate quantities

The generator derives dimensions through arithmetic and generates the required operators and intermediate aliases. Quantities also support addition, subtraction and equality checks with quantities of the same dimension:

Current current = Current.FromAmps(3);
Resistance resistance = Resistance.FromOhms(4);

CurrentSquared squared = current * current;
Power heating = current * current * resistance; // 36 W
Current doubled = 2 * current;
Current halved = current / 2;
Current total = current + doubled;
double ratio = doubled / current; // 2: matching dimensions cancel
Frequency frequency = 1 / Time.FromSeconds(0.02); // 50 Hz

Known dimensions use names from the engineering catalogue, such as Power, Voltage, Permeability and MagneticFluxDensity. Other dimensions receive mechanical names such as CurrentSquared or TimePerCurrent. Discovered quantities have SI base-unit and generic prefix conversion helpers.

Aliases with the same dimensions share a type. For example, Energy and Torque are interchangeable: the library checks dimensions, not the physical meaning of a calculation. Magnitudes are stored as double in coherent SI base units.

Comparisons and numerical helpers

Quantities with matching dimensions support <, >, <= and >=, along with Abs, Min, Max and Clamp:

Current measured = Current.FromAmps(-3);
Current limit = Current.FromAmps(10);

Current magnitude = Current.Abs(measured); // 3 A
bool withinLimit = magnitude <= limit;
Current smaller = Current.Min(magnitude, limit);
Current larger = Current.Max(magnitude, limit);
Current bounded = Current.Clamp(measured, Current.FromAmps(0), limit); // 0 A

Comparisons follow ordinary double behaviour, including comparisons with NaN. The numerical helpers follow the corresponding Math behaviour.

Powers and roots

SI base and catalogue quantities have Squared(), Cubed(), Pow4() through Pow6(), and the corresponding SquareRoot(), CubeRoot(), Root4() through Root6() helpers. Helpers for intermediate quantities are generated when called.

For other integer or rational powers, use Power<TExponent>.Of(...). English exponent aliases such as NumberTwo, NumberHalf and NumberTwoOverThree are generated on demand:

using DimensionalQuantities.TypeSystem;

Length length = Length.FromMetres(3);
Area area = length.Squared();
Volume volume = length.Cubed();
Length recovered = Power<NumberHalf>.Of(area); // 3 m

Fractional dimensions are supported. Results whose dimensions cancel completely, including a zeroth power, are returned as double.

Nullable quantities

Arithmetic supports nullable quantity operands and nullable scalars. Missing values propagate as null; power and root helpers can be called through ?.:

Length? length = Length.FromMetres(3);
Current? current = null;

LengthCurrent? product = length * current; // null
Area? area = length?.Squared();            // 9 m²
Length? recovered = area?.SquareRoot();    // 3 m

Discovery through your code

Intermediate quantities can flow through:

  • var locals and explicitly typed locals.
  • Conditional (?:) and switch expressions whose value branches have matching dimensions.
  • Fields, properties and helper method returns, including declarations in other source files.
  • Parameters, arrays, generic collections, spans and indexers.
  • Generic interface members, constrained generic calls, out variables and ref returns.
  • Pattern variables and deconstruction results.
  • Awaited results, iterator elements and async iterator elements.

Canonical compound names can also be used directly in type declarations, without first writing an expression that produces them:

static LengthCurrent Combine(Length length, Current current) => length * current;

LengthCurrent combined = Combine(Length.FromMetres(2), Current.FromAmps(3));
var timed = combined * Time.FromSeconds(4);
double value = timed.AsSiBaseUnit(); // 24

The generator recognises canonical names such as LengthCurrent, LengthPerTime and SquareRootLength. Canonical-name discovery leaves existing bound types and explicit aliases alone. Incompatible dimensions remain compiler errors.

Sharing quantities between packages

Generated names are aliases for types in the shared runtime library. Independently compiled packages can therefore exchange the same quantity through method parameters, return values, collections and containing objects.

A consuming project with the generator can discover quantities from referenced values, generate local conversion helpers, and use those values in further arithmetic. Quantity aliases are generated separately in each compilation; they are not exported by a referenced assembly.

Current scope

Discovery uses the types and operations that the compiler can resolve as generated quantities become available. It supports async methods and iterators with quantity return or element types, but does not infer a new variable type from arbitrary reassignment chains. Dedicated analyser diagnostics and IDE fixes are still follow-up work.

The library is under active development; the API and supported expression patterns are still evolving.

Licence

MIT, copyright GoSim.