Embody


Major features in 𝒏 minutes

Vector arithmetic

open Embody.LinearAlgebra
open FSharp.Data.UnitSystems.SI.UnitSymbols

let position = vector3 5.0<m> 4.0<m> 3.0<m>
let velocity = vector3 10.0<m/s> 0.0<m/s> 0.0<m/s>
let deltaT = 0.1<s>

let newPosition = position + velocity * deltaT

printfn "%A" newPosition

Celestial system definition

open Embody.Domain
open Embody.LinearAlgebra

(* Instead of relying on SI unit system, one can choose their own units.
It can be useful when comparing with external data that use particular units.
The downside is that some parameters (e.g. gravitational constant)
depend on a choice of units and will have to be recalculated. *)
[<Measure>] type km
[<Measure>] type s
[<Measure>] type earthMass

let earthOrbitRadius = 150e6<km>
let averageEarthSpeed = 29.78<km/s>

let system : CelestialSystem<km, s, earthMass> = {
    Bodies = [|
        {
            Name = "Sol"
            Mass = 332950.0<earthMass>
            R = Vector3.zero()
            V = Vector3.zero()
        }
        {
            Name = "Earth"
            Mass = 1.0<earthMass>
            R = vector3 earthOrbitRadius 0.0<_> 0.0<_>
            V = vector3 0.0<_> averageEarthSpeed 0.0<_>
        }
    |]
}

Simulation

Assuming we'd like to simulate the motion of the above system:

open Embody.Integration
open Embody.Simulation

(*
    The simulation preset expects a gravitational constant G expressed in
    'kilometers', 'seconds' and 'earth masses'.
    One can convert a common value of G to desired units. When units of measure
    are explicitly specified, the compiler will verify the unit of a calculation result.

    `kg` and `m` are used for conversion purposes. They are not used in the simulation.
*)
[<Measure>] type kg
[<Measure>] type m

let gravitationalConstant: float<km^3/earthMass/s^2> =
    let G = 6.674e-11<m^3/kg/s^2>                    // commonly known value of G

    // No time conversion needed: seconds are used in both cases.
    let m2km = 1.0<km>/1000.0<m>                     // distance conversion
    let kg2EarthMass = 1.0<earthMass>/5.9722e24<kg>  // mass conversion
    G * m2km * m2km * m2km / kg2EarthMass


(* Integrator settings.
    - The number of steps depends on `DeltaT`, `TStart` and `TEnd` parameters.
    - Accelerator: a function that computes body accelerations.
 *)
let settings: IntegratorSettings<km, s, earthMass> = {
    DeltaT = 3600.0<s>
    TStart = 0.0<s>
    TEnd = 3600.0<s> * 24.0 * 365.25
    GravitationalConstant = gravitationalConstant
    Accelerator = Accelerators.allBodiesConnected
}


(* Preset is a wrapper on all the things needed to kick off a simulation.
    - Celestial system
    - Integrator settings
    - Integrator: a function that implements a numerical method.
 *)
let preset: SimulationPreset<km, s, earthMass> = {
    System = system
    Settings = settings
    Integrator = Integrators.integrateVelocityVerlet
}

let result = preset |> Execution.simulate

printfn "Generated %d steps (~%f hours in a year)." result.Steps.Length (24.0*365.25)

let lastStep = result.Steps |> Array.last
let earthPosition = lastStep.R.[1] - lastStep.R.[0]
printfn "Final Earth's position (relative to Sun): %A" earthPosition
Multiple items
namespace Microsoft.FSharp

--------------------
namespace FSharp
namespace Microsoft.FSharp.Data
namespace Microsoft.FSharp.Data.UnitSystems
namespace Microsoft.FSharp.Data.UnitSystems.SI
namespace Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols
val position: float<s>
[<Measure>] type m = Data.UnitSystems.SI.UnitNames.metre
<summary> A synonym for Metre, the SI unit of length </summary>
val velocity: float
[<Measure>] type s = Data.UnitSystems.SI.UnitNames.second
<summary> A synonym for second, the SI unit of time </summary>
val deltaT: float<s>
val newPosition: float<s>
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
<summary>Print to <c>stdout</c> using the given format, and add a newline.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.printfn</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatLine``1" />) for examples.</example>
Multiple items
type MeasureAttribute = inherit Attribute new: unit -> MeasureAttribute
<summary>Adding this attribute to a type causes it to be interpreted as a unit of measure. This may only be used under very limited conditions.</summary>
<category>Attributes</category>


--------------------
new: unit -> MeasureAttribute
[<Measure>] type km
[<Measure>] type s
[<Measure>] type earthMass
val earthOrbitRadius: float<km>
val averageEarthSpeed: float<km/s>
val system: obj
[<Measure>] type V = Data.UnitSystems.SI.UnitNames.volt
<summary> A synonym for volt, the SI unit of electric potential difference, electromotive force </summary>
[<Measure>] type kg
[<Measure>] type m
val gravitationalConstant: float<km ^ 3/(earthMass s ^ 2)>
Multiple items
val float: value: 'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>
<example id="float-example"><code lang="fsharp"></code></example>


--------------------
[<Struct>] type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>


--------------------
type float<'Measure> = float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
val G: float<m ^ 3/(kg s ^ 2)>
val m2km: float<km/m>
val kg2EarthMass: float<earthMass/kg>
val settings: obj
val preset: obj
namespace System
val result: obj
val lastStep: obj
module Array from Microsoft.FSharp.Collections
<summary>Contains operations for working with arrays.</summary>
<remarks> See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/arrays">F# Language Guide - Arrays</a>. </remarks>
val last: array: 'T[] -> 'T
<summary>Returns the last element of the array.</summary>
<param name="array">The input array.</param>
<returns>The last element of the array.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
<exception cref="T:System.ArgumentException">Thrown when the input does not have any elements.</exception>
<example id="last-1"><code lang="fsharp"> [| "pear"; "banana" |] |&gt; Array.last </code> Evaluates to <c>banana</c></example>
<example id="last-2"><code lang="fsharp"> [| |] |&gt; Array.last </code> Throws <c>ArgumentException</c></example>
val earthPosition: obj