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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ Speed vesselSpeed = Speed.FromKnots(8);

A nautical mile is exactly 1852 m, and a knot is one nautical mile per hour. Nautical helpers do not generate SI-prefixed variants.

Add `DimensionalQuantities.Extensions.CgsEmag` for practical CGS mechanical, electromagnetic (EMU), and magnetic conversions. Import its namespace to use helpers such as:

```csharp
using DimensionalQuantities.Extensions.CgsEmag;

MagneticFluxDensity field = MagneticFluxDensity.FromGauss(10_000);
MagneticFieldStrength strength = MagneticFieldStrength.FromOersteds(1);
Energy work = Energy.FromErgs(1_000_000);
```

It includes dynes, ergs, baryes, gals, the common `ab` electrical units, maxwells, gauss and oersteds. These are named conversions into coherent SI quantities; the package does not model a separate CGS electromagnetic dimension system or generate SI-prefixed variants. See [NIST's CGS unit definitions](https://www.nist.gov/pml/special-publication-811/nist-guide-si-chapter-5-units-outside-si) for the distinction between EMU, ESU and Gaussian systems.

```csharp
Voltage voltage = Voltage.FromVolts(12);
Current current = Current.FromAmps(3);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Reflection;
using DimensionalQuantities.Extensions.CgsEmag;
using Xunit;

namespace DimensionalQuantities.Extensions.CgsEmag.Tests;

public sealed class CgsEmagConversionsTests
{
[Fact]
public void MechanicalUnitsConvertToCoherentSi()
{
Assert.Multiple(
() => Assert.Equal(1e-5, Force.FromDynes(1).AsSiBaseUnit()),
() => Assert.Equal(1e-7, Energy.FromErgs(1).AsSiBaseUnit()),
() => Assert.Equal(0.1, Pressure.FromBaryes(1).AsSiBaseUnit()),
() => Assert.Equal(0.01, Acceleration.FromGals(1).AsSiBaseUnit()));
}

[Fact]
public void ElectromagneticUnitsConvertToCoherentSi()
{
Assert.Multiple(
() => Assert.Equal(10, Current.FromAbamperes(1).AsSiBaseUnit()),
() => Assert.Equal(10, Current.FromBiots(1).AsSiBaseUnit()),
() => Assert.Equal(10, ElectricCharge.FromAbcoulombs(1).AsSiBaseUnit()),
() => Assert.Equal(1e-8, Voltage.FromAbvolts(1).AsSiBaseUnit()),
() => Assert.Equal(1e-9, Resistance.FromAbohms(1).AsSiBaseUnit()),
() => Assert.Equal(1e-9, Inductance.FromAbhenries(1).AsSiBaseUnit()),
() => Assert.Equal(1e9, Capacitance.FromAbfarads(1).AsSiBaseUnit()),
() => Assert.Equal(1e-8, MagneticFlux.FromMaxwells(1).AsSiBaseUnit()),
() => Assert.Equal(1e-4, MagneticFluxDensity.FromGauss(1).AsSiBaseUnit()));

double oersted = MagneticFieldStrength.FromOersteds(1).AsSiBaseUnit();
Assert.InRange(oersted, 1000 / (4 * Math.PI) - 1e-12, 1000 / (4 * Math.PI) + 1e-12);
}

[Fact]
public void AccessorsReturnOriginalCgsMagnitude()
{
Assert.Multiple(
() => Assert.Equal(1, Force.FromSiBaseUnit(1e-5).AsDynes()),
() => Assert.Equal(1, Energy.FromSiBaseUnit(1e-7).AsErgs()),
() => Assert.Equal(1, Pressure.FromSiBaseUnit(0.1).AsBaryes()),
() => Assert.Equal(1, Acceleration.FromSiBaseUnit(0.01).AsGals()),
() => Assert.Equal(1, Current.FromSiBaseUnit(10).AsAbamperes()),
() => Assert.Equal(1, Current.FromSiBaseUnit(10).AsBiots()),
() => Assert.Equal(1, ElectricCharge.FromSiBaseUnit(10).AsAbcoulombs()),
() => Assert.Equal(1, Voltage.FromSiBaseUnit(1e-8).AsAbvolts()),
() => Assert.Equal(1, Resistance.FromSiBaseUnit(1e-9).AsAbohms()),
() => Assert.Equal(1, Inductance.FromSiBaseUnit(1e-9).AsAbhenries()),
() => Assert.Equal(1, Capacitance.FromSiBaseUnit(1e9).AsAbfarads()),
() => Assert.Equal(1, MagneticFlux.FromSiBaseUnit(1e-8).AsMaxwells()),
() => Assert.Equal(1, MagneticFluxDensity.FromSiBaseUnit(1e-4).AsGauss()));

double oersted = MagneticFieldStrength.FromSiBaseUnit(1000 / (4 * Math.PI)).AsOersteds();
Assert.InRange(oersted, 1 - 1e-14, 1 + 1e-14);
}

[Fact]
public void SharedDimensionAliasesUseTheConversions()
{
Assert.Multiple(
() => Assert.Equal(1e-7, Torque.FromErgs(1).AsSiBaseUnit()),
() => Assert.Equal(0.1, Stress.FromBaryes(1).AsSiBaseUnit()),
() => Assert.Equal(0.1, YoungsModulus.FromBaryes(1).AsSiBaseUnit()),
() => Assert.Equal(1e-8, FluxLinkage.FromMaxwells(1).AsSiBaseUnit()),
() => Assert.Equal(1e-4, RemanentFluxDensity.FromGauss(1).AsSiBaseUnit()));
}

[Fact]
public void ProviderDoesNotGeneratePrefixConversions()
{
string[] names = Assembly.Load("DimensionalQuantities.Extensions.CgsEmag").GetExportedTypes()
.Where(type => type.Namespace == "DimensionalQuantities.Extensions.CgsEmag")
.SelectMany(type => type.GetMethods()).Select(method => method.Name).ToArray();

Assert.Multiple(
() => Assert.DoesNotContain("FromPrefixedUnits", names),
() => Assert.DoesNotContain("AsPrefixedUnits", names),
() => Assert.DoesNotContain("FromKiloGauss", names),
() => Assert.DoesNotContain("AsKiloGauss", names));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net11.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" Version="4.0.2" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="2.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../DimensionalQuantities.Extensions.CgsEmag/DimensionalQuantities.Extensions.CgsEmag.csproj" />
<ProjectReference Include="../DimensionalQuantities.Roslyn/DimensionalQuantities.Roslyn.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<Analyzer Include="../DimensionalQuantities/bin/$(Configuration)/netstandard2.0/DimensionalQuantities.dll" />
</ItemGroup>
</Project>
35 changes: 35 additions & 0 deletions src/DimensionalQuantities.Extensions.CgsEmag/CgsEmagSymbols.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using DimensionalQuantities.Units.Declarations;

namespace DimensionalQuantities.Extensions.CgsEmag;

internal static class CgsEmagSymbols
{
[UnitSymbol("Dyne", "Dynes", "dyn", Scale = 1e-5)]
internal sealed class Dyne { }
[UnitSymbol("Erg", "Ergs", "erg", Scale = 1e-7)]
internal sealed class Erg { }
[UnitSymbol("Barye", "Baryes", "Ba", Scale = 0.1)]
internal sealed class Barye { }
[UnitSymbol("Gal", "Gals", "Gal", Scale = 0.01)]
internal sealed class Gal { }
[UnitSymbol("Abampere", "Abamperes", "abA", Scale = 10)]
internal sealed class Abampere { }
[UnitSymbol("Biot", "Biots", "Bi", Scale = 10)]
internal sealed class Biot { }
[UnitSymbol("Abcoulomb", "Abcoulombs", "abC", Scale = 10)]
internal sealed class Abcoulomb { }
[UnitSymbol("Abvolt", "Abvolts", "abV", Scale = 1e-8)]
internal sealed class Abvolt { }
[UnitSymbol("Abohm", "Abohms", "abΩ", Scale = 1e-9)]
internal sealed class Abohm { }
[UnitSymbol("Abhenry", "Abhenries", "abH", Scale = 1e-9)]
internal sealed class Abhenry { }
[UnitSymbol("Abfarad", "Abfarads", "abF", Scale = 1e9)]
internal sealed class Abfarad { }
[UnitSymbol("Maxwell", "Maxwells", "Mx", Scale = 1e-8)]
internal sealed class Maxwell { }
[UnitSymbol("Gauss", "Gauss", "G", Scale = 1e-4)]
internal sealed class Gauss { }
[UnitSymbol("Oersted", "Oersteds", "Oe", Scale = 79.57747154594767)]
internal sealed class Oersted { }
}
69 changes: 69 additions & 0 deletions src/DimensionalQuantities.Extensions.CgsEmag/CgsEmagUnits.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using DimensionalQuantities.Units.Declarations;

namespace DimensionalQuantities.Extensions.CgsEmag;

[UnitProvider]
internal static class CgsEmagUnits
{
[QuantityUnit(typeof(Force))]
[UnitFactor(typeof(CgsEmagSymbols.Dyne))]
private sealed class ForceUnit { }

[QuantityUnit(typeof(Energy))]
[QuantityUnit(typeof(Torque))]
[UnitFactor(typeof(CgsEmagSymbols.Erg))]
private sealed class EnergyUnit { }

[QuantityUnit(typeof(Pressure))]
[QuantityUnit(typeof(Stress))]
[QuantityUnit(typeof(YoungsModulus))]
[UnitFactor(typeof(CgsEmagSymbols.Barye))]
private sealed class PressureUnit { }

[QuantityUnit(typeof(Acceleration))]
[UnitFactor(typeof(CgsEmagSymbols.Gal))]
private sealed class AccelerationUnit { }

[QuantityUnit(typeof(Current))]
[UnitFactor(typeof(CgsEmagSymbols.Abampere))]
[AdditionalUnit(typeof(BiotUnit))]
private sealed class CurrentUnit { }

[UnitFactor(typeof(CgsEmagSymbols.Biot))]
private sealed class BiotUnit { }

[QuantityUnit(typeof(ElectricCharge))]
[UnitFactor(typeof(CgsEmagSymbols.Abcoulomb))]
private sealed class ChargeUnit { }

[QuantityUnit(typeof(Voltage))]
[UnitFactor(typeof(CgsEmagSymbols.Abvolt))]
private sealed class VoltageUnit { }

[QuantityUnit(typeof(Resistance))]
[UnitFactor(typeof(CgsEmagSymbols.Abohm))]
private sealed class ResistanceUnit { }

[QuantityUnit(typeof(Inductance))]
[UnitFactor(typeof(CgsEmagSymbols.Abhenry))]
private sealed class InductanceUnit { }

[QuantityUnit(typeof(Capacitance))]
[UnitFactor(typeof(CgsEmagSymbols.Abfarad))]
private sealed class CapacitanceUnit { }

[QuantityUnit(typeof(MagneticFlux))]
[QuantityUnit(typeof(FluxLinkage))]
[UnitFactor(typeof(CgsEmagSymbols.Maxwell))]
private sealed class MagneticFluxUnit { }

[QuantityUnit(typeof(MagneticFluxDensity))]
[QuantityUnit(typeof(RemanentFluxDensity))]
[UnitFactor(typeof(CgsEmagSymbols.Gauss))]
private sealed class MagneticFluxDensityUnit { }

[QuantityUnit(typeof(MagneticFieldStrength))]
[QuantityUnit(typeof(CoerciveFieldStrength))]
[UnitFactor(typeof(CgsEmagSymbols.Oersted))]
private sealed class MagneticFieldStrengthUnit { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Authors>GoSim</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/GoSimulate/DimensionalQuantities</PackageProjectUrl>
<Description>Named CGS electromagnetic and mechanical conversions for dimensional quantities.</Description>
<RepositoryType>git</RepositoryType>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/generated</CompilerGeneratedFilesOutputPath>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<Deterministic>true</Deterministic>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../DimensionalQuantities/DimensionalQuantities.csproj" PrivateAssets="none" />
<ProjectReference Include="../DimensionalQuantities.Roslyn/DimensionalQuantities.Roslyn.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
<Analyzer Include="../DimensionalQuantities/bin/$(Configuration)/netstandard2.0/DimensionalQuantities.dll" />
<None Include="../../LICENSE" Pack="true" PackagePath="" />
<None Include="../../README.md" Pack="true" PackagePath="" />
</ItemGroup>
<Target Name="PinCorePackageDependency" AfterTargets="_GetProjectReferenceVersions" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_ProjectReferencesWithVersions Update="@(_ProjectReferencesWithVersions)"
Condition="'%(_ProjectReferencesWithVersions.Filename)' == 'DimensionalQuantities'">
<ProjectVersion>[$(PackageVersion)]</ProjectVersion>
</_ProjectReferencesWithVersions>
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,33 @@ public static class Consumer
() => Assert.Equal(1852d / 3600d, InvokeDouble(type, "ConvertSpeed")));
}

[Fact]
public void CgsEmagPackageProvidesConversionsThroughCoreDependency()
{
using PackageRepository repository = PackageRepository.Create(_scratch, new Uri("https://api.nuget.org/v3/index.json"));
PackCore(repository);
Package cgsEmag = PackSourceProject(repository, "DimensionalQuantities.Extensions.CgsEmag");
ProjectCreator consumer = CreateProject("CgsEmagConsumer", """
using DimensionalQuantities.Extensions.CgsEmag;

public static class Consumer
{
public static double ConvertFluxDensity() => MagneticFluxDensity.FromGauss(10_000).AsSiBaseUnit();
public static double ConvertCurrent() => Current.FromAbamperes(1).AsSiBaseUnit();
public static double ConvertCharge() => ElectricCharge.FromAbcoulombs(1).AsSiBaseUnit();
}
""", cgsEmag);
Build(consumer);

using PackageAssemblyContext context = new(OutputDirectory("CgsEmagConsumer"));
Type type = context.LoadFromAssemblyPath(Path.Combine(OutputDirectory("CgsEmagConsumer"), "CgsEmagConsumer.dll"))
.GetType("Consumer", throwOnError: true)!;
Assert.Multiple(
() => Assert.Equal(1, InvokeDouble(type, "ConvertFluxDensity")),
() => Assert.Equal(10, InvokeDouble(type, "ConvertCurrent")),
() => Assert.Equal(10, InvokeDouble(type, "ConvertCharge")));
}

[Fact]
public void MetricNamedConversionsRequireNamespaceImport()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public void CoreSymbolPackageMatchesRuntimeAndAnalyzerAssemblies()
[InlineData("Metric")]
[InlineData("Imperial")]
[InlineData("Nautical")]
[InlineData("CgsEmag")]
public void ExtensionSymbolPackageMatchesAssemblyAndEmbedsGeneratedSource(string extension)
{
string projectName = "DimensionalQuantities.Extensions." + extension;
Expand Down
4 changes: 4 additions & 0 deletions src/DimensionalQuantities.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
<Project Path="DimensionalQuantities.Extensions.Nautical/DimensionalQuantities.Extensions.Nautical.csproj" />
<Project Path="DimensionalQuantities.Extensions.Nautical.Tests/DimensionalQuantities.Extensions.Nautical.Tests.csproj" />
</Folder>
<Folder Name="/CgsEmag/">
<Project Path="DimensionalQuantities.Extensions.CgsEmag/DimensionalQuantities.Extensions.CgsEmag.csproj" />
<Project Path="DimensionalQuantities.Extensions.CgsEmag.Tests/DimensionalQuantities.Extensions.CgsEmag.Tests.csproj" />
</Folder>
<Folder Name="/Roslyn/">
<Project Path="DimensionalQuantities.Roslyn.CodeFixes/DimensionalQuantities.Roslyn.CodeFixes.csproj" />
<Project Path="DimensionalQuantities.Roslyn.Tests/DimensionalQuantities.Roslyn.Tests.csproj" />
Expand Down
3 changes: 3 additions & 0 deletions src/DimensionalQuantities/Units/EngineeringQuantityAliases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal static class EngineeringQuantityAliases
{ new(Length: 2), ["Area"] },
{ new(Length: 3), ["Volume"] },
{ new(Length: 1, Time: -1), ["Speed"] },
{ new(Length: 1, Time: -2), ["Acceleration"] },
{ new(Time: -1), ["Frequency", "AngularVelocity"] },
{ new(Length: 1, Mass: 1, Time: -2), ["Force"] },
{ new(Length: -3, Mass: 1), ["Density"] },
Expand All @@ -18,7 +19,9 @@ internal static class EngineeringQuantityAliases
{ new(Length: 2, Time: -3), ["SpecificPower", "SpecificPowerLoss"] },
{ new(Temperature: -1), ["TemperatureCoefficient"] },
{ new(Length: -1, Mass: 1, Time: -3), ["PowerDensity", "VolumetricPowerLoss"] },
{ new(Time: 1, ElectricCurrent: 1), ["ElectricCharge"] },
{ new(Length: 2, Mass: 1, Time: -3, ElectricCurrent: -1), ["Voltage"] },
{ new(Length: -2, Mass: -1, Time: 4, ElectricCurrent: 2), ["Capacitance"] },
{ new(Length: 2, Mass: 1, Time: -3, ElectricCurrent: -2), ["Resistance"] },
{ new(Length: 2, Mass: 1, Time: -2, ElectricCurrent: -2), ["Inductance"] },
{ new(Length: 2, Mass: 1, Time: -2, ElectricCurrent: -1), ["MagneticFlux", "FluxLinkage"] },
Expand Down
Loading