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

743 lines
30 KiB
Nix
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ core, document, physical, ... } @ libs:
let
inherit(core) debug indentation lambda list number path set string type;
inherit(document) ClearPage Heading' LaTeX LaTeX' PhantomHeading;
# T: ToString -> string
extensionOf
= path:
let
name = string.split "[.]" ( string path );
in
if name != null
then
list.get name ( ( list.length name ) - 1 )
else
null;
adjustSignals#: [ string ] -> [ string ]
= signals:
let
len-1 = ( list.length signals ) - 1;
in
debug.info "adjustSignals" { text = "called with"; data = signals; }
(
if signals != [ ]
then
( list.generate (x: "${list.get signals x},") len-1 ) ++ [ "${list.get signals len-1}." ]
else
[ ]
);
# LaTeX
formatNMRnucleus#: string -> string
= nucleus:
let
tex
= {
"1H" = "\\textsuperscript{1}H";
"13C" = "\\textsuperscript{13}C";
"13C{1H}" = "\\textsuperscript{13}C\\{\\textsuperscript{1}H\\}";
"15N" = "\\textsuperscript{15}N";
"15N{1H}" = "\\textsuperscript{15}N\\{\\textsuperscript{1}H\\}";
"19F" = "\\textsuperscript{19}F";
"19F{1H}" = "\\textsuperscript{19}F\\{\\textsuperscript{1}H\\}";
"31P" = "\\textsuperscript{31}P";
"31P{1H}" = "\\textsuperscript{31}P\\{\\textsuperscript{1}H\\}";
};
pdf
= {
"1H" = "¹H";
"13C" = "¹³C";
"13C{1H}" = "¹³C\\{¹H\\}";
"15N" = "¹N";
"15N{1H}" = "¹N\\{¹H\\}";
"19F" = "¹F";
"19F{1H}" = "¹F\\{¹H\\}";
"31P" = "³¹P";
"31P{1H}" = "³¹P\\{¹H\\}";
};
in
"\\texorpdfstring{${tex.${nucleus} or nucleus}}{${pdf.${nucleus} or nucleus}}";
# LaTeX
formatSpectrum#: Spectrum -> Chunk
= { acronyms, ... }:
{ file, label, method, sample, solvent, substance, title, name, ... }:
let
solvent'
= if solvent != null
then
solvent
else
"${acronyms.CDCl3.short}";
title'
= if title != null
then
"${method}-${acronyms.nuclearMagneticResonance.short}~${title} in ${solvent'}"
else
"${method}-${acronyms.nuclearMagneticResonance.short}~${substance.NameID}${sample} in ${solvent'}";
fileName = "\\source/resources/appendix/nmr/${substance.name or name}/${path.getBaseName file}";
label' = "nmr:${label}";
in
if ( extensionOf file == "pdf" )
then
Heading' "${title'}"
[
(
LaTeX
(
(
if label != null
then
[ "\\labelAppendix{nmr:${label}}%" ]
else
[ ]
)
++ (
if true
then
[
"\\vspace{-1\\normalbaselineskip}"
"\\begin{figure}[H]%" indentation.more
"\\centering%"
"\\begin{adjustbox}%" indentation.more
"{max width=\\textwidth,max height=.4\\textheight,keepaspectratio}%"
"\\includegraphics{${fileName}}%"
indentation.less "\\end{adjustbox}%"
indentation.less "\\end{figure}%" null
]
else
[
"\\begin{figure}[H]%" indentation.more
"\\centering%"
"\\begin{adjustbox}%" indentation.more
"{angle=90,min width=\\textwidth,min totalheight=\\textheightleft,max width=\\textwidth,max totalheight=\\textheightleft-2em}%"
"\\includegraphics{${fileName}}%"
indentation.less "\\end{adjustbox}%"
indentation.less "\\end{figure}%" null
]
)
)
)
]
{
clearPage = false;
# rotate = false;
before = "\\refstepcounter{ctrAppendix}%";
}
else
debug.panic
[ "formatSpectrum" ]
"File in the Portable Document Format (pdf) expected, got »${string file}«!";
# LaTeX
formatSpectrumName# Spectrum -> string
= { acronyms, ... }:
{ nucleus, kind, ... }:
let
nucleus'
= if nucleus == "1Hx13C"
then
"${formatNMRnucleus "1H"}-${formatNMRnucleus "13C"}"
else
formatNMRnucleus nucleus;
dept#: integer -> string
= degree:
"${formatNMRnucleus nucleus}-${acronyms.dept.short}-${string degree}";
in
{
"self" = formatNMRnucleus nucleus;
"dc" = formatNMRnucleus "${nucleus}{1H}";
"dept" = "${formatNMRnucleus nucleus}-${acronyms.dept.short}";
"dept45" = dept 45;
"dept90" = dept 90;
"dept135" = dept 135;
}.${kind} or "${nucleus'}-${acronyms.${kind}.short}";
genAppendix#: Product -> [ string ]
= resources:
{ failure ? false, substance ? {}, name ? null, nmr ? null, title ? null, identifier ? null, ... }:
let
nmr' = substance.nmr or nmr;
spectra
= list.concatMap
(
{ nucleus, data }:
if data != null
then
let
inherit(data) files;
in
list.map
(
spectrum:
spectrum
// {
inherit substance nucleus title name;
inherit(data) comment solvent;
}
)
(
{
"1H"
= [
{ kind = "self"; files = files.self or files."1H" or null; }
{ kind = "cosy"; files = files.cosy or null; }
{ kind = "tocsy"; files = files.tocsy or null; }
{ kind = "noesy"; files = files.noesy or null; }
{ kind = "roesy"; files = files.roesy or null; }
];
"13C"
= [
{ kind = "dc"; files = files.dc or files."13C{1H}" or null; }
{ kind = "self"; files = files.self or files."13C" or null; }
{ kind = "apt"; files = files.apt or null; }
{ kind = "dept"; files = files.dept or null; }
{ kind = "dept90"; files = files.dept90 or null; }
{ kind = "dept135"; files = files.dept135 or null; }
];
"15N"
= [
{ kind = "dc"; files = files.dc or files."15N{1H}" or null; }
{ kind = "self"; files = files.self or files."15N" or null; }
];
"19F"
= [
{ kind = "dc"; files = files.dc or files."19F{1H}" or null; }
{ kind = "self"; files = files.self or files."19F" or null; }
];
"31P"
= [
{ kind = "dc"; files = files.dc or files."31P{1H}" or null; }
{ kind = "self"; files = files.self or files."31P" or null; }
];
"1Hx13C"
= [
{ kind = "hsqc"; files = files.hsqc or null; }
{ kind = "hmbc"; files = files.hmbc or null; }
];
}.${nucleus}
)
else
[]
)
[
{ nucleus = "1H"; data = nmr'."1H" or null; }
{ nucleus = "13C"; data = nmr'."13C" or null; }
{ nucleus = "15N"; data = nmr'."15N" or null; }
{ nucleus = "19F"; data = nmr'."19F" or null; }
{ nucleus = "31P"; data = nmr'."31P" or null; }
{ nucleus = "1Hx13C"; data = nmr'."1Hx13C" or null; }
];
in
if nmr' != null
&& !failure
then
list.concatMap (genAppendixForSpectrum resources) spectra
else
[ ];
# LaTeX
genAppendixForSpectrum#: Spectrum -> [ Chunk ] | !
= resources:
{ nucleus, kind, files, comment, solvent, substance, title, name, ... } @ spectrum:
let
# string | null -> path -> string -> [ string ] | !
formatSpectrum'
= sample:
file:
label:
formatSpectrum resources
{
inherit file label substance solvent title name;
method = formatSpectrumName resources spectrum;
sample
= if sample != null
then
" (${string sample})"
else
"";
};
in
type.matchPrimitiveOrPanic files
{
lambda = debug.panic "genAppendixForSpectrum" "???";
list
= (
list.fold
(
state:
file:
state
// {
counter = state.counter + 1;
list
= state.list
++ [
(
type.matchPrimitiveOrPanic file
{
lambda
= debug.panic "genAppendix" "2???";
path
= formatSpectrum'
null
file
( spectrum.label or "${substance.name or name}_${nucleus}_${string state.counter}" );
set
= formatSpectrum'
( file.identifier or null )
file.file
( spectrum.label or "${substance.name or name}_${nucleus}_${string file.identifier}" );
}
)
];
}
)
{
counter = 1;
list = [ ];
}
files
).list;
null = [ ];
path
= let
kind'
= if kind == "self"
then
nucleus
else
"${nucleus}${kind}";
spectrum'
= formatSpectrum'
null
files
( spectrum.label or "${substance.name or name}_${kind'}" );
in
[ spectrum' ];
set
= let
identifier
= if files.identifier or null != null
then
"_${string files.identifier}"
else
"";
in
[
(
formatSpectrum'
( files.identifier or null )
files.file
( spectrum.label or "${substance.name or name}_${nucleus}${identifier}" )
)
];
};
genDependencies#: Product -> Dependencies
= { substance ? {}, identifier ? null, nmr ? null, name ? null, ... }:
let
nmr' = substance.nmr or nmr;
files
= list.concatMap
(
spectrum:
if spectrum != null
then
set.values spectrum.files
else
[]
)
[
( nmr'."1H" or null )
( nmr'."13C" or null )
( nmr'."15N" or null )
( nmr'."19F" or null )
( nmr'."31P" or null )
( nmr'."1Hx13C" or null )
];
files' = list.flat files;
getFileName = fileName: "resources/appendix/nmr/${substance.name or name}/${path.getBaseName fileName}";
in
if nmr' != null
then
list.concatMap
(
file:
type.matchPrimitiveOrDefault file
{
null = [];
path = [ { src = file; dst = getFileName file; } ];
set = [ { src = file.file; dst = getFileName file.file; } ];
}
)
files'
else
[ ];
# LaTeX
mapSignals#: string -> [ Signal ] -> [ string ]
= { acronyms, ... }:
nucleus:
list.map
(
{ assignment, charge, couplings, integral, multiplicity, other, protons, range } @ signal:
let
other'
= if other != null
then
if list.isInstanceOf other
then
string.concat (list.map (range: "×${prepareRange 1 range}") other)
else
"×${prepareRange 1 other}"
else
"";
precision = if nucleus == "1H" then 2 else 1;
prepareRange
= precision:
range:
if list.isInstanceOf range
then
let
from = list.get range 0;
till = list.get range 1;
in
"${number.toStringWithPrecision from precision}${number.toStringWithPrecision till precision}"
else if string.isInstanceOf range
then
range
else if range < 0
then
"\\minus${number.toStringWithPrecision (0 - range) precision}"
else
"${number.toStringWithPrecision range precision}";
mapCouplings
= set.mapToList
(
coupling:
list:
let
result = string.match "([0-9]+)([A-Za-z]+)" coupling;
bonds
= if result != null
then
"\\textsuperscript{${list.get result 0}}"
else
"";
nuclei
= if result != null
then
list.get result 1
else
coupling;
values = physical.formatValue { value = list; precision = 1; } "hertz";
in
"${bonds}${acronyms.couplingConstant.short}\\textsubscript{${nuclei}}~=~${values}"
);
element
= let
nucleus' = string.match "[0-9]*([A-Za-z]+).*" nucleus;
in
if nucleus' != null
then
list.head nucleus'
else
nucleus;
protons'
= let
charge'
= if charge == 0 then ""
else if charge == 1 then "\\textsuperscript{+}"
else if charge == -1 then "\\textsuperscript{\\minus}"
else if charge < 0 then "\\textsuperscript{\\minus${string (0 - charge)}}"
else "\\textsuperscript{+${string charge}}";
in
if protons == 0
then
let
saturated
= {
"C" = "quaternary";
"N" = "tertiary";
}.${element};
in
"${acronyms.${saturated}.short} \\textit{${element}}${charge'}"
else if protons == 1
then
"\\textit{${element}}H${charge'}"
else
"\\textit{${element}}H\\textsubscript{${string protons}}${charge'}";
details
= ( if false then [ protons' ] else [ ] )
++ ( if multiplicity != null then [ "${string multiplicity}" ] else [ ] )
++ ( mapCouplings couplings )
++ ( if integral != null then [ "${string integral}${element}" ] else [ ] )
++ ( if assignment != null then [ "\\ch{${string assignment}}" ] else [ ] );
in
if details == [ ]
then
"${prepareRange precision range}"
else
"${prepareRange precision range} (${string.concatWith ", " details})"
);
# LaTeX
reportSpectra#: NMRdata -> [ LaTeX ] | !
= { acronyms, ... } @ resources:
{ kind, nmrData }:
let
inherit(nmrData) method files signals;
solvent
= if nmrData.solvent != null
then
nmrData.solvent
else
"${acronyms.CDCl3.short}";
hyperlink
= if nmrData.label or null != null
then
"\\hyperlink{appendix:${nmrData.label}}"
else
"";
suffix
= let
methods
= list.filter
({ method, from }: from)
[
{ method = "apt"; from = method.apt or false; }
{ method = "dept"; from = method.dept or false; }
{ method = "dept45"; from = method.dept45 or false; }
{ method = "dept90"; from = method.dept90 or false; }
{ method = "dept135"; from = method.dept135 or false; }
# { method = "cosy"; from = method.cosy or false; }
# { method = "hmbc"; from = method.hmbc or false; }
{ method = "hsqc"; from = method.hsqc or false; }
# { method = "noesy"; from = method.noesy or false; }
# { method = "roesy"; from = method.roesy or false; }
# { method = "tocsy"; from = method.tocsy or false; }
];
dept = degree: "${acronyms.dept.short}-${string degree}";
formatMethod
= method:
{
"dept45" = dept 45;
"dept90" = dept 90;
"dept135" = dept 135;
}.${method} or "${acronyms.${method}.short}";
in
if methods != []
then
", aus ${string.concatMappedWith ({ method, ... }: formatMethod method) "/" methods}"
else
"";
nucleus
= {
"1H"
= if files ? self then "1H"
else null;
"13C"
= if files ? self then "13C"
else if files ? dc then "13C{1H}"
else null;
"15N"
= if files ? self then "15N"
else if files ? dc then "15N{1H}"
else null;
"19F"
= if files ? self then "19F"
else if files ? dc then "19F{1H}"
else null;
"31P"
= if files ? self then "31P"
else if files ? dc then "31P{1H}"
else null;
"1Hx13C" = null;
}.${kind};
sortSignals
= list.sort
(
first:
second:
let
first'
= if list.isInstanceOf first.range
then
list.head first.range
else
first.range;
second'
= if list.isInstanceOf second.range
then
list.head second.range
else
second.range;
in
first' > second'
);
in
if nucleus != null
&& signals != []
then
[
(
LaTeX
(
[
"\\mbox{}${hyperlink}{\\textbf{${formatNMRnucleus nucleus}-${acronyms.nuclearMagneticResonance.short}}}"
" (${solvent}, ${acronyms.chemShift.short}~/~${acronyms.ppm.short}${suffix}):"
indentation.more
]
++ ( adjustSignals ( mapSignals resources nucleus (sortSignals signals) ) )
++ [ indentation.less ]
)
)
]
else
[ ];
Signal
= range:
{ charge ? 0, couplings ? {}, integral ? null, multiplicity ? null, other ? null, protons ? null }:
assignment:
{
inherit assignment charge couplings integral multiplicity other protons range;
};
Spectrum
= { ... } @ files:
{ method ? {}, ... } @ config:
signals:
{
comment = null;
files = {};
solvent = null;
}
// config
// {
inherit files method signals;
};
in
{
inherit formatNMRnucleus;
inherit Spectrum;
Spectrum' = files: Spectrum files {};
inherit Signal;
Signal' = range: multiplicity: integral: Signal range { inherit integral multiplicity; };
SignalAP = range: protons: integral: Signal range { inherit protons integral; };
SignalDC = range: integral: Signal range { inherit integral; };
SignalJ = range: multiplicity: couplings: integral: Signal range { inherit couplings integral multiplicity; };
SignalX = range: other: Signal range { inherit other; };
# [ Synthsis ] -> arguments -> Document::Chunk.LaTeX
generateAppendix
= syntheses:
{ resources, ... } @ document:
let
syntheses'
= if path.isInstanceOf syntheses
then
import
syntheses
(libs // { chemistry = libs.chemistry; })
document
else
syntheses;
syntheses''
= if list.isInstanceOf syntheses'
then
syntheses'
else
syntheses'.list;
products
= list.concatMap
(
# Synthesis -> [ string ]
synthesis:
if synthesis ? product
then
let
product
= if lambda.isInstanceOf synthesis.product
then
synthesis.product { }
else
synthesis.product;
product'
= product
// {
name = product.name or null;
substance = product.substance or synthesis.substance or {};
};
in
if list.isInstanceOf product
then
product
else
[ product' ]
else
[ ]
)
syntheses'';
in
LaTeX'
(
[
"\\newgeometry"
"{" indentation.more
"top = (\\paperheight-\\textheight+\\headheight+\\headsep+\\footskip)/2 - 73.04765pt,"
"textheight = \\textheight+\\footskip,"
"footskip = 0cm,"
indentation.less "}%"
( ClearPage )
]
++ [
(
PhantomHeading
(
PhantomHeading
(
list.concatMap
(genAppendix resources)
products
)
)
)
"\\restoregeometry%" null
]
)
{
dependencies = list.concatMap genDependencies products;
};
# { string -> NMRdata } -> [ LaTeX ]
report
= resources:
{ ... } @ nmrData:
list.concatMap
(
{ nmrData, ... } @ spectra:
if nmrData != null
then
reportSpectra resources spectra
else
[]
)
[
{ kind = "1H"; nmrData = nmrData."1H" or null; }
{ kind = "13C"; nmrData = nmrData."13C" or null; }
{ kind = "15N"; nmrData = nmrData."15N" or null; }
{ kind = "19F"; nmrData = nmrData."19F" or null; }
{ kind = "31P"; nmrData = nmrData."31P" or null; }
];
}