743 lines
30 KiB
Nix
743 lines
30 KiB
Nix
{ 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; }
|
||
];
|
||
} |