Sebastian Walz 860d31cee1
Tohu vaBohu
2023-04-21 00:22:52 +02:00

278 lines
9.1 KiB
Nix

{ core, physical, ... }:
let
inherit(core) debug list number set string type;
inherit(physical) formatValue;
fullTable
= set.map (symbol: value: value // { inherit symbol; } )
{
# Period 1
H = { dalton = 1.0080; };
He = { dalton = 4.0026; };
# Period 2
Li = { dalton = 6.94; };
Be = { dalton = 9.0122; };
B = { dalton = 10.81; };
C = { dalton = 12.011; };
N = { dalton = 14.007; };
O = { dalton = 15.999; };
F = { dalton = 18.998; };
Ne = { dalton = 20.180; };
# Period 3
Na = { dalton = 22.990; };
Mg = { dalton = 24.305; };
Al = { dalton = 26.982; };
Si = { dalton = 28.085; };
P = { dalton = 30.974; };
S = { dalton = 32.06; };
Cl = { dalton = 35.45; };
Ar = { dalton = 39.948; };
# Period 4
K = { dalton = 39.098; };
Ca = { dalton = 40.078; };
Sc = { dalton = 44.956; };
Ti = { dalton = 47.867; };
V = { dalton = 50.942; };
Cr = { dalton = 51.996; };
Mn = { dalton = 54.938; };
Fe = { dalton = 55.845; };
Co = { dalton = 58.933; };
Ni = { dalton = 58.693; };
Cu = { dalton = 63.546; };
Zn = { dalton = 65.380; };
Ga = { dalton = 69.723; };
Ge = { dalton = 72.630; };
As = { dalton = 74.922; };
Se = { dalton = 78.971; };
Br = { dalton = 79.904; };
Kr = { dalton = 83.798; };
# Period 5
Rb = { dalton = 85.468; };
Sr = { dalton = 87.620; };
Y = { dalton = 88.906; };
Zr = { dalton = 91.224; };
Nb = { dalton = 92.906; };
Mo = { dalton = 95.950; };
Tc = { dalton = 97.4; };
Ru = { dalton = 101.07; };
Rh = { dalton = 102.91; };
Pd = { dalton = 106.42; };
Ag = { dalton = 107.87; };
Cd = { dalton = 112.41; };
In = { dalton = 114.82; };
Sn = { dalton = 118.71; };
Sb = { dalton = 121.76; };
Te = { dalton = 127.60; };
I = { dalton = 126.90; };
Xe = { dalton = 131.29; };
# Period 6
Cs = { dalton = 132.91; };
Ba = { dalton = 137.33; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
# = { dalton = ; };
Pb = { dalton = 207.20; };
Bi = { dalton = 208.98; };
Po = { dalton = 209.98; };
At = { dalton = 210; };
Rn = { dalton = 222; };
# Period 7
};
tableOfMasses = set.mapValues ( value: value.dalton ) fullTable;
normaliseMolecularFormula
= let
addElements
= { ... } @ elements:
previous:
count:
type.matchPrimitiveOrPanic previous
{
set
= set.fold
(
{ ... } @ elements:
name:
previous:
elements
// {
${name} = previous * count + ( elements.${name} or 0 );
}
)
elements
previous;
string
= elements
// {
${previous} = ( elements.${previous} or 0 ) + count;
};
null = elements;
};
getSymbol = foo: foo.symbol or foo;
parse
= { elements, previous } @ this:
token:
type.matchPrimitiveOrPanic token
{
int
= if previous != null
then
{
elements = addElements elements previous token;
previous = null;
}
else
debug.panic [ "normaliseMolecularFormula" "parse" ] "Unexpected Number!";
list
= {
elements = addElements elements previous 1;
previous = normalise token;
};
set
= {
elements = addElements elements previous 1;
previous = getSymbol token;
};
string
= {
elements = addElements elements previous 1;
previous = token;
};
};
defaultState
= {
elements = { };
previous = null;
};
finalise = { elements, previous }: addElements elements previous 1;
normalise
= this:
finalise ( list.fold parse defaultState this );
in
this: finalise (parse defaultState this);
calculateMassOfFormula
= formula:
debug.debug "calculateMassOfFormula"
{
text = "Molecular Formula";
data = formula;
}
(
type.matchPrimitiveOrPanic formula
{
null = null;
set
= set.fold
(
state:
symbol:
count:
( state + count * ( tableOfMasses.${symbol} or (debug.panic "calculateMassOfFormula" "Unknown symbol: ${symbol}")) )
)
0
formula;
}
);
formatMolecularFormula
= { ... } @ formula:
list.fold
(
result:
symbol:
let
count = formula.${symbol} or 0;
in
if count == 0
then
result
else if count == 1
then
"${result}${symbol}"
else
"${result}${symbol}${string count}"
)
""
(
if formula.C or 0 == 0
then
set.names fullTable
else
[
"C" "H"
"Ag" "Al" "Ar" "As" "At" "B" "Ba" "Be" "Bi" "Br" "Ca" "Cd" "Cl" "Co"
"Cr" "Cs" "Cu" "F" "Fe" "Ga" "Ge" "He" "I" "In" "K" "Kr" "Li" "Mg"
"Mn" "Mo" "N" "Na" "Nb" "Ne" "Ni" "O" "P" "Pb" "Pd" "Po" "Rb" "Rh"
"Rn" "Ru" "S" "Sb" "Sc" "Se" "Si" "Sn" "Sr" "Tc" "Te" "Ti" "V" "Xe"
"Y" "Zn" "Zr"
]
);
mapAnalysis
= { formula, ... } @ substance:
{ ... } @ gotElements:
if gotElements != { }
then
let
formula' = normaliseMolecularFormula formula;
format
= elements:
string.concatWith ", "
(
set.mapToList
(
symbol:
value:
"\\ch{${symbol}}:~${formatValue { inherit value; precision = 2; } "percent"}"
)
elements
);
calculated
= let
mapped = set.map (symbol: value: tableOfMasses.${symbol} * value) formula';
sum = number.sum (set.values mapped);
filtered = set.map (symbol: _: mapped.${symbol} or 0.0 ) gotElements;
calcElements = set.mapValues (value: value / sum * 100.0) filtered;
in
format calcElements;
found = format gotElements;
in
[ "Elementar\\-analyse berechnet für \\ch{${formatMolecularFormula formula'}}: ${calculated}; gefunden: ${found}." ]
else
[ ];
in
{
inherit normaliseMolecularFormula formatMolecularFormula calculateMassOfFormula;
inherit mapAnalysis;
inherit fullTable tableOfMasses;
}