module Isotope.Base (
Operators(..)
, IntegerMass
, MonoisotopicMass(..)
, NominalMass(..)
, AverageMass(..)
, IsotopicMass(..)
, ElementName
, IsotopicAbundance(..)
, AtomicNumber
, ProtonNumber
, NeutronNumber
, Nucleons
, MassNumber
, Isotope(..)
, Element(..)
, ElementSymbol(..)
, elementSymbolList
, elementMostAbundantIsotope
, elementIsotopicMasses
, elementIntegerMasses
, elementIsotopicAbundances
, elementMonoisotopicMass
, elementNominalMass
, elementAverageMass
, massNumber
, elements
, findElement
, elementName
, atomicNumber
, isotopes
, mostAbundantIsotope
, selectIsotope
, isotopicMasses
, integerMasses
, isotopicAbundances
, Formula(..)
, ElementalComposition(..)
, ToElementalComposition(..)
, mkElementalComposition
, MolecularFormula(..)
, ToMolecularFormula(..)
, mkMolecularFormula
, CondensedFormula(..)
, ToCondensedFormula(..)
, EmpiricalFormula(..)
, ToEmpiricalFormula(..)
, mkEmpiricalFormula
) where
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Foldable
import Data.Ord
import Data.List
import Data.Monoid
class Operators a where
(|+|) :: a -> a -> a
(|-|) :: a -> a -> a
(|*|) :: a -> Int -> a
infixl 6 |+|
infixl 7 |*|
infixl 6 |-|
type IntegerMass = MassNumber
newtype MonoisotopicMass = MonoisotopicMass { getMonoisotopicMass :: Double }
deriving (Show, Eq, Ord)
instance Monoid MonoisotopicMass where
mempty = MonoisotopicMass 0
mappend = (|+|)
instance Operators MonoisotopicMass where
MonoisotopicMass x |+| MonoisotopicMass y = MonoisotopicMass $ x + y
MonoisotopicMass x |-| MonoisotopicMass y = MonoisotopicMass $ x y
MonoisotopicMass x |*| y = MonoisotopicMass $ x * fromIntegral y
newtype NominalMass = NominalMass { getNominalMass :: Int }
deriving (Show, Eq, Ord)
instance Monoid NominalMass where
mempty = NominalMass 0
mappend = (|+|)
instance Operators NominalMass where
NominalMass x |+| NominalMass y = NominalMass $ x + y
NominalMass x |-| NominalMass y = NominalMass $ x y
NominalMass x |*| y = NominalMass $ x * y
newtype AverageMass = AverageMass { getAverageMass :: Double }
deriving (Show, Eq, Ord)
instance Monoid AverageMass where
mempty = AverageMass 0
mappend = (|+|)
instance Operators AverageMass where
AverageMass x |+| AverageMass y = AverageMass $ x + y
AverageMass x |-| AverageMass y = AverageMass $ x y
AverageMass x |*| y = AverageMass $ x * fromIntegral y
newtype IsotopicMass = IsotopicMass { getIsotopicMass :: Double }
deriving (Show, Eq, Ord)
instance Monoid IsotopicMass where
mempty = IsotopicMass 0
mappend = (|+|)
instance Operators IsotopicMass where
IsotopicMass x |+| IsotopicMass y = IsotopicMass $ x + y
IsotopicMass x |-| IsotopicMass y = IsotopicMass $ x y
IsotopicMass x |*| y = IsotopicMass $ x * fromIntegral y
type ElementName = String
newtype IsotopicAbundance = IsotopicAbundance { getIsotopicAbundance :: Double }
deriving (Show, Eq, Ord)
type AtomicNumber = Int
type ProtonNumber = AtomicNumber
type NeutronNumber = Int
type Nucleons = (ProtonNumber, NeutronNumber)
type MassNumber = Int
type Charge = Int
data Isotope = Isotope { nucleons :: Nucleons
, isotopicMass :: IsotopicMass
, isotopicAbundance :: IsotopicAbundance
} deriving (Show, Eq, Ord)
data Element = Element { atomicNumber' :: AtomicNumber
, elementName' :: ElementName
, isotopes' :: [Isotope]
} deriving (Show, Eq, Ord)
data ElementSymbol = H | He | Li | Be | B | C | N | O | F | Ne | Na | Mg |
Al | Si | P | S | Cl | Ar | K | Ca | Sc | Ti | V | Cr |
Mn | Fe | Co | Ni | Cu | Zn | Ga | Ge | As | Se | Br | Kr |
Rb | Sr | Y | Zr | Nb | Mo | Ru | Rh | Pd | Ag | Cd | In |
Sn | Sb | Te | I | Xe | Cs | Ba | La | Ce | Pr | Nd | Sm |
Eu | Gd | Tb | Dy | Ho | Er | Tm | Yb | Lu | Hf | Ta | W |
Re | Os | Ir | Pt | Au | Hg | Tl | Pb | Bi | Th | Pa | U
deriving (Show, Read, Eq, Ord, Enum, Bounded)
elementSymbolList :: [ElementSymbol]
elementSymbolList = [H .. U]
elementMostAbundantIsotope :: Element -> Isotope
elementMostAbundantIsotope e =
maximumBy (comparing isotopicAbundance) $ isotopes' e
elementIsotopicMasses :: Element -> [IsotopicMass]
elementIsotopicMasses e = isotopicMass <$> isotopes' e
elementIntegerMasses :: Element -> [IntegerMass]
elementIntegerMasses e = massNumber . nucleons <$> isotopes' e
elementIsotopicAbundances :: Element -> [IsotopicAbundance]
elementIsotopicAbundances e = isotopicAbundance <$> isotopes' e
elementMonoisotopicMass :: Element -> MonoisotopicMass
elementMonoisotopicMass =
MonoisotopicMass . getIsotopicMass . isotopicMass . elementMostAbundantIsotope
elementNominalMass :: Element -> NominalMass
elementNominalMass =
NominalMass . massNumber . nucleons . elementMostAbundantIsotope
elementAverageMass :: Element -> AverageMass
elementAverageMass e =
foldMap (\x -> AverageMass $
getIsotopicMass (isotopicMass x) *
getIsotopicAbundance (isotopicAbundance x))
(isotopes' e)
massNumber :: Nucleons -> MassNumber
massNumber (protonNum, neutronNum) = protonNum + neutronNum
tupleToIsotope :: (Nucleons, Double, Double) -> Isotope
tupleToIsotope (nucl, mass, abun) =
Isotope nucl (IsotopicMass mass) (IsotopicAbundance abun)
tupleToElement
:: (AtomicNumber, ElementName, [(Nucleons, Double, Double)]) -> Element
tupleToElement (atomNum, name, isotopes) =
Element atomNum name (tupleToIsotope <$> isotopes)
elements :: Map ElementSymbol Element
elements = tupleToElement <$> Map.fromList
[ (H, (1, "hydrogen", [ ((1, 0), 1.00782503223, 0.999885)
, ((1, 1), 2.01410177812, 0.000115) ]))
, (He, (2, "helium", [ ((2, 1), 3.0160293201, 0.00000134)
, ((2, 2), 4.00260325413, 0.99999866) ]))
, (Li, (3, "lithium", [ ((3, 3), 6.0151228874, 0.0759)
, ((3, 4), 7.0160034366, 0.9241) ]))
, (Be, (4, "beryllium", [ ((4, 5), 9.012183065, 1.0) ]))
, (B, (5, "boron", [ ((5, 5), 10.01293695, 0.199)
, ((5, 6), 11.00930536, 0.801) ]))
, (C, (6, "carbon", [ ((6, 6), 12.0000000, 0.9893)
, ((6, 7), 13.00335483507, 0.0107) ]))
, (N, (7, "nitrogen", [ ((7, 7), 14.00307400443, 0.99636)
, ((7, 8), 15.00010889888, 0.00364) ]))
, (O, (8, "oxygen", [ ((8, 8), 15.99491461957, 0.99757)
, ((8, 9), 16.99913175650, 0.00038)
, ((8, 10), 17.99915961286, 0.00205) ]))
, (F, (9, "fluorine", [ ((9, 10), 18.99840316273, 1.0) ]))
, (Ne, (10, "neon", [ ((10, 10), 19.9924401762, 0.9048)
, ((10, 11), 20.993846685, 0.0027)
, ((10, 12), 21.991385114, 0.0925) ]))
, (Na, (11, "sodium", [ ((11, 12), 22.9897692820, 1.0) ]))
, (Mg, (12, "magnesium", [ ((12, 12), 23.985041697, 0.7899)
, ((12, 13), 24.985836976, 0.1000)
, ((12, 14), 25.982592968, 0.1101) ]))
, (Al, (13, "aluminium", [ ((13, 14), 26.98153853, 1.0) ]))
, (Si, (14, "silicon", [ ((14, 14), 27.97692653465, 0.92223)
, ((14, 15), 28.97649466490, 0.04685)
, ((14, 16), 29.973770136, 0.03092) ]))
, (P, (15, "phosphorous", [ ((15, 16), 30.97376199842, 1.0) ]))
, (S, (16, "sulfur", [ ((16, 16), 31.9720711744, 0.9499)
, ((16, 17), 32.9714589098, 0.0075)
, ((16, 18), 33.967867004, 0.0425)
, ((16, 20), 35.96708071, 0.0001) ]))
, (Cl, (17, "chlorine", [ ((17, 18), 34.968852682, 0.7576)
, ((17, 20), 36.965902602, 0.2424) ]))
, (Ar, (18, "argon", [ ((18, 18), 35.967545105, 0.003336)
, ((18, 20), 37.96273211, 0.000629)
, ((18, 22), 39.9623831237, 0.996035) ]))
, (K, (19, "potassium", [ ((19, 20), 38.9637064864, 0.932581)
, ((19, 21), 39.963998166, 0.000117)
, ((19, 22), 40.9618252579, 0.067302) ]))
, (Ca, (20, "calcium", [ ((20, 20), 39.962590863, 0.96941)
, ((20, 22), 41.95861783, 0.00647)
, ((20, 23), 42.95876644, 0.00135)
, ((20, 24), 43.95548156, 0.02086)
, ((20, 26), 45.9536890, 0.00004)
, ((20, 28), 47.95252276, 0.00187) ]))
, (Sc, (21, "scandium", [ ((21, 24), 44.95590828, 1.0) ]))
, (Ti, (22, "titanium", [ ((22, 24), 45.95262772, 0.0825)
, ((22, 25), 46.95175879, 0.0744)
, ((22, 26), 47.94794198, 0.7372)
, ((22, 27), 48.94786568, 0.0541)
, ((22, 28), 49.94478689, 0.0518) ]))
, (V, (23, "vanadium", [ ((23, 27), 49.94715601, 0.00250)
, ((23, 28), 50.94395704, 0.99750) ]))
, (Cr, (24, "chromium", [ ((24, 26), 49.94604183, 0.04345)
, ((24, 28), 51.94050623, 0.83789)
, ((24, 29), 52.94064815, 0.09501)
, ((24, 30), 53.93887916, 0.02365) ]))
, (Mn, (25, "manganese", [ ((25, 30), 54.93804391, 1.0) ]))
, (Fe, (26, "iron", [ ((26, 28), 53.93960899, 0.05845)
, ((26, 30), 55.93493633, 0.91754)
, ((26, 31), 56.93539284, 0.02119)
, ((26, 32), 57.93327443, 0.00282) ]))
, (Co, (27, "cobalt", [ ((27, 32), 58.93319429, 1.0) ]))
, (Ni, (28, "nickel", [ ((28, 30), 57.93534241, 0.68077)
, ((28, 32), 59.93078588, 0.26223)
, ((28, 33), 60.93105557, 0.011399)
, ((28, 34), 61.92834537, 0.036346)
, ((28, 36), 63.92796682, 0.009255) ]))
, (Cu, (29, "copper", [ ((29, 34), 62.92959772, 0.6915)
, ((29, 36), 64.92778970, 0.3085) ]))
, (Zn, (30, "zinc", [ ((30, 34), 63.92914201, 0.4917)
, ((30, 36), 65.92603381, 0.2773)
, ((30, 37), 66.92712775, 0.0404)
, ((30, 38), 67.92484455, 0.1845)
, ((30, 40), 69.9253192, 0.0061) ]))
, (Ga, (31, "gallium", [ ((31, 38), 68.9255735, 0.60108)
, ((31, 40), 70.92470258, 0.39892) ]))
, (Ge, (32, "germanium", [ ((32, 38), 69.92424875, 0.2057)
, ((32, 40), 71.922075826, 0.2745)
, ((32, 41), 72.923458956, 0.0775)
, ((32, 42), 73.921177761, 0.3650)
, ((32, 44), 75.921402726, 0.0773) ]))
, (As, (33, "arsenic", [ ((33, 42), 74.92159457, 1.0) ]))
, (Se, (34, "selenium", [ ((34, 40), 73.922475934, 0.0089)
, ((34, 42), 75.919213704, 0.0937)
, ((34, 43), 76.919914154, 0.0763)
, ((34, 44), 77.91730928, 0.2377)
, ((34, 46), 79.9165218, 0.4961)
, ((34, 48), 81.9166995, 0.0873) ]))
, (Br, (35, "bromine", [ ((35, 44), 78.9183376, 0.5069)
, ((35, 46), 80.9162897, 0.4931) ]))
, (Kr, (36, "krypton", [ ((36, 42), 77.92036494, 0.00355)
, ((36, 44), 79.91637808, 0.02286)
, ((36, 46), 81.91348273, 0.11593)
, ((36, 47), 82.91412716, 0.11500)
, ((36, 48), 83.9114977282, 0.56987)
, ((36, 50), 85.9106106269, 0.17279) ]))
, (Rb, (37, "rubidium", [ ((37, 48), 84.9117897379, 0.7217)
, ((37, 50), 86.9091805310, 0.2783) ]))
, (Sr, (38, "strontium", [ ((38, 46), 83.9134191, 0.0056)
, ((38, 48), 85.9092606, 0.0986)
, ((38, 49), 86.9088775, 0.0700)
, ((38, 50), 87.9056125, 0.8258) ]))
, (Y, (39, "yttrium", [ ((39, 50), 88.9058403, 1.0) ]))
, (Zr, (40, "zirconium", [ ((40, 50), 89.9046977, 0.5145)
, ((40, 51), 90.9056396, 0.1122)
, ((40, 52), 91.9050347, 0.1715)
, ((40, 54), 93.9063108, 0.1738)
, ((40, 56), 95.9082714, 0.0280) ]))
, (Nb, (41, "niobium", [ ((41, 52), 92.9063730, 1.0) ]))
, (Mo, (42, "molybdenum", [ ((42, 50), 91.90680796, 0.1453)
, ((42, 52), 93.90508490, 0.0915)
, ((42, 53), 94.90583877, 0.1584)
, ((42, 54), 95.90467612, 0.1667)
, ((42, 55), 96.90601812, 0.0960)
, ((42, 56), 97.90540482, 0.2439)
, ((42, 58), 99.9074718, 0.0982) ]))
, (Ru, (44, "ruthenium", [ ((44, 52), 95.90759025, 0.0554)
, ((44, 54), 97.9052868, 0.0187)
, ((44, 55), 98.9059341, 0.1276)
, ((44, 56), 99.9042143, 0.1260)
, ((44, 57), 100.9055769, 0.1706)
, ((44, 58), 101.9043441, 0.3155)
, ((44, 59), 103.9054275, 0.1862) ]))
, (Rh, (45, "rhodium", [ ((45, 58), 102.9054980, 1.0) ]))
, (Pd, (46, "palladium", [ ((46, 56), 101.9056022, 0.0102)
, ((46, 58), 103.9040305, 0.1114)
, ((46, 59), 104.9050796, 0.2233)
, ((46, 60), 105.9034804, 0.2733)
, ((46, 62), 107.9038916, 0.2646)
, ((46, 64), 109.90517220, 0.1172) ]))
, (Ag, (47, "silver", [ ((47, 60), 106.9050916, 0.51839)
, ((47, 62), 108.9047553, 0.48161) ]))
, (Cd, (48, "cadmium", [ ((48, 58), 105.9064599, 0.0125)
, ((48, 60), 107.9041834, 0.0089)
, ((48, 62), 109.90300661, 0.1249)
, ((48, 63), 110.90418287, 0.1280)
, ((48, 64), 111.90276287, 0.2413)
, ((48, 65), 112.90440813, 0.1222)
, ((48, 66), 113.90336509, 0.2873)
, ((48, 68), 115.90476315, 0.0749) ]))
, (In, (49, "indium", [ ((49, 64), 112.90406184, 0.0429)
, ((49, 66), 114.903878776, 0.9571) ]))
, (Sn, (50, "tin", [ ((50, 62), 111.90482387, 0.0097)
, ((50, 64), 113.9027827, 0.0066)
, ((50, 65), 114.903344699, 0.0034)
, ((50, 66), 115.90174280, 0.1454)
, ((50, 67), 116.90295398, 0.0768)
, ((50, 68), 117.90160657, 0.2422)
, ((50, 69), 118.90331117, 0.0859)
, ((50, 70), 119.90220163, 0.3258)
, ((50, 72), 121.9034438, 0.0463)
, ((50, 74), 123.9052766, 0.0579) ]))
, (Sb, (51, "antimony", [ ((51, 70), 120.9038120, 0.5721)
, ((51, 72), 122.9042132, 0.4279) ]))
, (Te, (52, "tellurium", [ ((52, 68), 119.9040593, 0.0009)
, ((52, 70), 121.9030435, 0.0255)
, ((52, 71), 122.9042698, 0.0089)
, ((52, 72), 123.9028171, 0.0474)
, ((52, 73), 124.9044299, 0.0707)
, ((52, 74), 125.9033109, 0.1884)
, ((52, 76), 127.90446128, 0.3174)
, ((52, 78), 129.906222748, 0.3408) ]))
, (I, (53, "iodine", [ ((53, 74), 126.9044719, 1.0) ]))
, (Xe, (54, "xenon", [ ((54, 70), 123.9058920, 0.000952)
, ((54, 72), 125.9042983, 0.000890)
, ((54, 74), 127.9035310, 0.019102)
, ((54, 75), 128.9047808611, 0.264006)
, ((54, 76), 129.903509349, 0.040710)
, ((54, 77), 130.90508406, 0.212324)
, ((54, 78), 131.9041550856, 0.269086)
, ((54, 80), 133.90539466, 0.104357)
, ((54, 82), 135.907214484, 0.088573) ]))
, (Cs, (55, "caesium", [ ((55, 78), 132.9054519610, 1.0) ]))
, (Ba, (56, "barium", [ ((56, 74), 129.9063207, 0.00106)
, ((56, 76), 131.9050611, 0.00101)
, ((56, 78), 133.90450818, 0.02417)
, ((56, 79), 134.90568838, 0.06592)
, ((56, 80), 135.90457573, 0.07854)
, ((56, 81), 136.90582714, 0.11232)
, ((56, 82), 137.90524700, 0.71698) ]))
, (La, (57, "lanthanum", [ ((57, 81), 137.9071149, 0.0008881)
, ((57, 83), 138.9063563, 0.9991119) ]))
, (Ce, (58, "cerium", [ ((58, 78), 135.90712921, 0.00185)
, ((58, 80), 137.905991, 0.00251)
, ((58, 82), 139.9054431, 0.88450)
, ((58, 84), 141.9092504, 0.11114) ]))
, (Pr, (59, "praseodymium", [ ((59, 82), 140.9076576, 1.0) ]))
, (Nd, (60, "neodymium", [ ((60, 82), 141.9077290, 0.27152)
, ((60, 83), 142.9098200, 0.12174)
, ((60, 84), 143.9100930, 0.23798)
, ((60, 85), 144.9125793, 0.08293)
, ((60, 86), 145.9131226, 0.17189)
, ((60, 88), 147.9168993, 0.05756)
, ((60, 90), 149.9209022, 0.05638) ]))
, (Sm, (62, "samarium", [ ((62, 82), 143.9120065, 0.0307)
, ((62, 83), 146.9149044, 0.1499)
, ((62, 84), 147.9148292, 0.1124)
, ((62, 85), 148.9171921, 0.1382)
, ((62, 86), 149.9172829, 0.0738)
, ((62, 88), 151.9197397, 0.2675)
, ((62, 90), 153.9222169, 0.2275) ]))
, (Eu, (63, "europium", [ ((63, 88), 150.9198578, 0.4781)
, ((63, 90), 152.9212380, 0.5219) ]))
, (Gd, (64, "gadolinium", [ ((64, 88), 151.9197995, 0.0020)
, ((64, 90), 153.9208741, 0.0218)
, ((64, 91), 154.9226305, 0.1480)
, ((64, 92), 155.9221312, 0.2047)
, ((64, 93), 156.9239686, 0.1565)
, ((64, 94), 157.9241123, 0.2484)
, ((64, 96), 159.9270624, 0.2186) ]))
, (Tb, (65, "terbium", [ ((65, 94), 158.9253547, 1.0) ]))
, (Dy, (66, "dysprosium", [ ((66, 90), 155.9242847, 0.00056)
, ((66, 92), 157.9244159, 0.00095)
, ((66, 94), 159.9252046, 0.02329)
, ((66, 95), 160.9269405, 0.18889)
, ((66, 96), 161.9268056, 0.25475)
, ((66, 97), 162.9287383, 0.24896)
, ((66, 98), 163.9291819, 0.28260) ]))
, (Ho, (67, "holmium", [ ((67, 98), 164.9303288, 1.0) ]))
, (Er, (68, "erbium", [ ((68, 94), 161.9287884, 0.00139)
, ((68, 96), 163.9292088, 0.01601)
, ((68, 98), 165.9302995, 0.33503)
, ((68, 99), 166.9320546, 0.22869)
, ((68, 100), 167.9323767, 0.26978)
, ((68, 102), 169.9354702, 0.14910) ]))
, (Tm, (69, "thulium", [ ((69, 100), 168.9342179, 1.0) ]))
, (Yb, (70, "ytterbium", [ ((70, 98), 167.9338896, 0.00123)
, ((70, 100), 169.9347664, 0.02982)
, ((70, 101), 170.9363302, 0.1409)
, ((70, 102), 171.9363859, 0.2168)
, ((70, 103), 172.9382151, 0.16103)
, ((70, 104), 173.9388664, 0.32026)
, ((70, 106), 175.9425764, 0.12996) ]))
, (Lu, (71, "lutetium", [ ((71, 104), 174.9407752, 0.97401)
, ((71, 105), 175.9426897, 0.02599) ]))
, (Hf, (72, "hafnium", [ ((72, 102), 173.9400461, 0.0016)
, ((72, 104), 175.9414076, 0.0526)
, ((72, 105), 176.9432277, 0.1860)
, ((72, 106), 177.9437058, 0.2728)
, ((72, 107), 178.9458232, 0.1362)
, ((72, 108), 179.9465570, 0.3508) ]))
, (Ta, (73, "tantalum", [ ((73, 107), 179.9474648, 0.0001201)
, ((73, 108), 180.9479958, 0.9998799) ]))
, (W, (74, "tungsten", [ ((74, 106), 179.9467108, 0.0012)
, ((74, 108), 181.94820394, 0.2650)
, ((74, 109), 182.95022275, 0.1431)
, ((74, 110), 183.95093092, 0.3064)
, ((74, 112), 185.9543628, 0.2843) ]))
, (Re, (75, "rhenium", [ ((75, 110), 184.9529545, 0.3740)
, ((75, 112), 186.9557501, 0.6260) ]))
, (Os, (76, "osmium", [ ((76, 108), 183.9524885, 0.0002)
, ((76, 110), 185.9538350, 0.0159)
, ((76, 111), 186.9557474, 0.0196)
, ((76, 112), 187.9558352, 0.1324)
, ((76, 113), 188.9581442, 0.1615)
, ((76, 114), 189.9584437, 0.2626)
, ((76, 116), 191.9614770, 0.4078) ]))
, (Ir, (77, "iridium", [ ((77, 114), 190.9605893, 0.373)
, ((77, 116), 192.9629216, 0.627) ]))
, (Pt, (78, "platinum", [ ((78, 112), 189.9599297, 0.00012)
, ((78, 114), 191.9610387, 0.00782)
, ((78, 116), 193.9626809, 0.3286)
, ((78, 117), 194.9647917, 0.3378)
, ((78, 118), 195.96495209, 0.2521)
, ((78, 120), 197.9678949, 0.07356) ]))
, (Au, (79, "gold", [ ((79, 118), 196.96656879, 1.0) ]))
, (Hg, (80, "mercury", [ ((80, 116), 195.9658326, 0.0015)
, ((80, 118), 197.96676860, 0.0997)
, ((80, 119), 198.96828064, 0.1687)
, ((80, 120), 199.96832659, 0.2310)
, ((80, 121), 200.97030284, 0.1318)
, ((80, 122), 201.97064340, 0.2986)
, ((80, 124), 203.97349398, 0.0687) ]))
, (Tl, (81, "thallium", [ ((81, 122), 202.9723446, 0.2952)
, ((81, 124), 204.9744278, 0.7048) ]))
, (Pb, (82, "lead", [ ((82, 122), 203.9730440, 0.014)
, ((82, 124), 205.9744657, 0.241)
, ((82, 125), 206.9758973, 0.221)
, ((82, 126), 207.9766525, 0.524) ]))
, (Bi, (83, "bismuth", [ ((83, 126), 208.9803991, 1.0) ]))
, (Th, (90, "thorium", [ ((90, 142), 232.0380558, 1.0) ]))
, (Pa, (91, "protactinium", [ ((91, 140), 231.0358842, 1.0) ]))
, (U, (92, "uranium", [ ((92, 142), 234.0409523, 0.000054)
, ((92, 143), 235.0439301, 0.007204)
, ((92, 146), 238.0507884, 0.992742) ]))
]
findElement :: ElementSymbol -> Element
findElement = (Map.!) elements
elementName :: ElementSymbol -> ElementName
elementName = elementName' . findElement
atomicNumber :: ElementSymbol -> AtomicNumber
atomicNumber = atomicNumber' . findElement
isotopes :: ElementSymbol -> [Isotope]
isotopes = isotopes' . findElement
mostAbundantIsotope :: ElementSymbol -> Isotope
mostAbundantIsotope = elementMostAbundantIsotope . findElement
selectIsotope :: ElementSymbol -> MassNumber -> Maybe Isotope
selectIsotope sym massNum =
find (\iso -> (massNumber . nucleons) iso == massNum) isotopeList
where isotopeList = isotopes sym
isotopicMasses :: ElementSymbol -> [IsotopicMass]
isotopicMasses = elementIsotopicMasses . findElement
integerMasses :: ElementSymbol -> [IntegerMass]
integerMasses = elementIntegerMasses . findElement
isotopicAbundances :: ElementSymbol -> [IsotopicAbundance]
isotopicAbundances = elementIsotopicAbundances . findElement
class Formula a where
renderFormula :: a -> String
emptyFormula :: a
newtype ElementalComposition = ElementalComposition {
getElementalComposition :: Map ElementSymbol Int }
deriving (Show, Read, Eq, Ord)
class ToElementalComposition a where
toElementalComposition :: a -> ElementalComposition
charge :: a -> Maybe Charge
monoisotopicMass :: a -> MonoisotopicMass
nominalMass :: a -> NominalMass
averageMass :: a -> AverageMass
monoisotopicMass = getFormulaSum elementMonoisotopicMass
nominalMass = getFormulaSum elementNominalMass
averageMass = getFormulaSum elementAverageMass
getFormulaSum :: (Monoid a, Operators a, ToElementalComposition b)
=> (Element -> a) -> b -> a
getFormulaSum f m = fold $
Map.mapWithKey mapFunc (getElementalComposition (toElementalComposition m))
where mapFunc k v = (f . findElement) k |*| v
mkElementalComposition :: [(ElementSymbol, Int)] -> ElementalComposition
mkElementalComposition = ElementalComposition . filterZero . Map.fromList
instance Monoid ElementalComposition where
mempty = emptyFormula
mappend = (|+|)
instance Operators ElementalComposition where
ElementalComposition x |+| ElementalComposition y =
ElementalComposition $ combineMaps (+) x y
ElementalComposition x |-| ElementalComposition y =
ElementalComposition $ combineMaps () x y
m |*| n = ElementalComposition . filterZero $
(fromIntegral n *) <$> getElementalComposition m
instance ToElementalComposition ElementSymbol where
toElementalComposition sym = mkElementalComposition [(sym, 1)]
charge _ = Nothing
instance ToElementalComposition ElementalComposition where
toElementalComposition = id
charge _ = Nothing
instance Formula ElementalComposition where
renderFormula f = foldMap renderFoldfunc
((sortElementSymbolMap . getElementalComposition) f)
emptyFormula = mkElementalComposition []
renderFoldfunc :: (ElementSymbol, Int) -> String
renderFoldfunc (sym, num) = show sym <> if num == 1
then ""
else show num
sortElementSymbolMap :: Map ElementSymbol Int -> [(ElementSymbol, Int)]
sortElementSymbolMap m = sortBy (hillSystem fst) elementSymbolIntList
where
elementSymbolIntList = Map.toList m
elementSymbols = fst <$> elementSymbolIntList
containsC = C `elem` elementSymbols
hillSystem f a b = case (f a, f b) of
(C, _) -> LT
(_, C) -> GT
(H, b') -> if containsC then LT
else show H `compare` show b'
(a', H) -> if containsC then GT
else show a' `compare` show H
(a', b') -> show a' `compare` show b'
newtype MolecularFormula = MolecularFormula {
getMolecularFormula :: Map ElementSymbol Int }
deriving (Show, Read, Eq, Ord)
class ToElementalComposition a => ToMolecularFormula a where
toMolecularFormula :: a -> MolecularFormula
combineMaps :: (Int -> Int -> Int)
-> Map ElementSymbol Int -> Map ElementSymbol Int -> Map ElementSymbol Int
combineMaps f m1 m2 = filterZero $ Map.unionWith f m1 m2
mkMolecularFormula :: [(ElementSymbol, Int)] -> MolecularFormula
mkMolecularFormula = MolecularFormula . filterZero . Map.fromList
filterZero :: Map k Int -> Map k Int
filterZero = Map.filter (/= 0)
instance Monoid MolecularFormula where
mempty = emptyFormula
mappend = (|+|)
instance Operators MolecularFormula where
MolecularFormula x |+| MolecularFormula y =
MolecularFormula $ combineMaps (+) x y
MolecularFormula x |-| MolecularFormula y =
MolecularFormula $ combineMaps () x y
m |*| n = MolecularFormula . filterZero $
(fromIntegral n *) <$> getMolecularFormula m
instance ToElementalComposition MolecularFormula where
toElementalComposition (MolecularFormula m) = ElementalComposition m
charge _ = Nothing
instance Formula MolecularFormula where
renderFormula f = foldMap renderFoldfunc
((sortElementSymbolMap . getMolecularFormula) f)
emptyFormula = mkMolecularFormula []
newtype CondensedFormula = CondensedFormula {
getCondensedFormula :: [Either MolecularFormula (CondensedFormula, Int)] }
deriving (Show, Read, Eq, Ord)
class ToElementalComposition a => ToCondensedFormula a where
toCondensedFormula :: a -> CondensedFormula
instance Monoid CondensedFormula where
mempty = emptyFormula
CondensedFormula x `mappend` CondensedFormula y = CondensedFormula (x <> y)
instance ToElementalComposition CondensedFormula where
toElementalComposition =
ElementalComposition . getMolecularFormula . toMolecularFormula
charge _ = Nothing
instance ToMolecularFormula CondensedFormula where
toMolecularFormula c = foldMap foldFunc (getCondensedFormula c)
where foldFunc = \case
Left chemForm -> chemForm
Right (condForm, n) -> toMolecularFormula condForm |*| n
instance Formula CondensedFormula where
renderFormula c = foldMap foldFunc (getCondensedFormula c)
where foldFunc = \case
Left chemForm -> renderFormula chemForm
Right (chemFormList, n) ->
"(" <> renderFormula chemFormList <> ")"
<> formatNum n
where formatNum n' = if n' == 1 then ""
else show n'
emptyFormula = CondensedFormula []
newtype EmpiricalFormula = EmpiricalFormula {
getEmpiricalFormula :: Map ElementSymbol Int }
deriving (Show, Read, Eq, Ord)
class ToElementalComposition a => ToEmpiricalFormula a where
toEmpiricalFormula :: a -> EmpiricalFormula
mkEmpiricalFormula :: [(ElementSymbol, Int)] -> EmpiricalFormula
mkEmpiricalFormula l =
let m = filterZero (Map.fromList l)
in EmpiricalFormula $ (`div` greatestCommonDenom m) <$> m
instance ToEmpiricalFormula ElementalComposition where
toEmpiricalFormula (ElementalComposition m) =
EmpiricalFormula $ (`div` greatestCommonDenom m) <$> m
instance ToEmpiricalFormula MolecularFormula where
toEmpiricalFormula (MolecularFormula m) =
EmpiricalFormula $ (`div` greatestCommonDenom m) <$> m
instance ToEmpiricalFormula CondensedFormula where
toEmpiricalFormula = toEmpiricalFormula . toMolecularFormula
instance ToElementalComposition EmpiricalFormula where
toElementalComposition (EmpiricalFormula a) = ElementalComposition a
charge _ = Nothing
instance Formula EmpiricalFormula where
renderFormula f = foldMap renderFoldfunc
((sortElementSymbolMap . getEmpiricalFormula) f)
emptyFormula = mkEmpiricalFormula []
greatestCommonDenom :: (Integral v) => Map k v -> v
greatestCommonDenom = foldr gcd 0