Last active
August 29, 2015 14:11
-
-
Save jwosty/0e70ac6ec409e182901a to your computer and use it in GitHub Desktop.
Useful chemistry things
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames | |
open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols | |
open System | |
open System.Text.RegularExpressions | |
[<Measure>] type g | |
let (|Integer|_|) str = | |
let mutable result = 0 | |
if Int32.TryParse (str, &result) then Some(result) else None | |
let (|Regex|_|) regex input = | |
let m = Regex.Match (input, regex) | |
if m.Success then | |
let groups = [ for g in m.Groups -> g.Value ] | |
Some((if m.Groups.Count = 1 then groups else List.tail groups), input.Substring m.Length) | |
else None | |
let gPerKg = 1000.<g/mol> | |
/// Attempts to parse an integer from the beginning of the string. On success, yields the integer and the rest | |
/// of the string; if no integer is found, yields defaultValue and the rest | |
let parseInt defaultValue input = | |
let m = Regex.Match (input, "^\d+") | |
if m.Success then int m.Value, input.Substring m.Length else defaultValue, input | |
type Element = | |
{ name: string; abbreviation: string; atomicNumber: int; mass: float<g/mol> } | |
static member PeriodicTable = | |
[|"Hydrogen", "H", 1, 1.00794<g/mol>; "Helium", "He", 2, 4.002602<g/mol>; "Lithium", "Li", 3, 6.941<g/mol>; "Beryllium", "Be", 4, 9.012182<g/mol>; "Boron", "B", 5, 10.811<g/mol>; "Carbon", "C", 6, 12.0107<g/mol>; | |
"Nitrogen", "N", 7, 14.0067<g/mol>; "Oxygen", "O", 8, 15.9994<g/mol>; "Fluorine", "F", 9, 18.9984032<g/mol>; "Neon", "N", 10, 20.1797<g/mol>; | |
"Sodium", "Na", 11, 22.98976928<g/mol>; "Magnesium", "Mg", 12, 24.3050<g/mol>; "Aluminum", "Al", 13, 26.9815386<g/mol>; "Silicon", "Si", 14, 28.0855<g/mol>; | |
"Phosphorus", "P", 15, 30.973762<g/mol>; "Sulfer", "S", 16, 32.065<g/mol>; "Chlorine", "Cl", 17, 35.065<g/mol>; "Argon", "Ar", 18, 39.948<g/mol>; | |
"Potassium", "K", 19, 39.0983<g/mol>; "Calcium", "Ca", 20, 40.078<g/mol>; "Gallium", "Ga", 31, 69.723<g/mol>; "Garmanium", "Ge", 32, 72.64<g/mol>; | |
"Arsenic", "As", 33, 74.9216<g/mol>; "Selenium", "Se", 34, 78.96<g/mol>; "Bromine", "Br", 35, 79.904<g/mol>; "Krypton", "Kr", 36, 83.798<g/mol>|] | |
|> Array.map (fun (name, abr, num, mass) -> { name = name; abbreviation = abr; atomicNumber = num; mass = mass }) | |
/// Looks up an element by name or abbreviation (e.g. Gold/Au). Returns None if the name is not recognized. | |
static member TryFind name = Array.tryFind (fun element -> name = element.name || name = element.abbreviation) Element.PeriodicTable | |
/// Looks up an element by name or abbreviation (e.g. Gold/Au). Throws an error if the name is not recognized. | |
static member Find name = match Element.TryFind name with | Some(e) -> e | None -> failwith (name + " is not a recognized element name or abbreviation.") | |
type ChemicalFormula = | |
{ elements: (int*Element) list } | |
member this.molecularMass = this.elements |> List.fold (fun formulaMass (quantity, element) -> formulaMass + (element.mass * float quantity)) 0.<g/mol> | |
static member Parse formulaString = | |
let (|ElementRegex|_|) = (|Regex|_|) "^([A-Z][a-z]*)(\d*)" | |
match formulaString with | |
| "" -> [] | |
| ElementRegex ([name; ""], rest) -> (1, Element.Find name) :: ChemicalFormula.Parse rest | |
| ElementRegex ([name; Integer quantity], rest) -> (quantity, Element.Find name) :: ChemicalFormula.Parse rest | |
let findElement = Element.Find | |
let parseFormula = ChemicalFormula.Parse |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment