API: NMRAnalysis
Top-level entry points (diffusion1d, relaxation1d, tract, r1rho, exchange1d, and the 2D analysis functions re-exported from GUI2D). See the sidebar for each submodule's own internal API.
NMRAnalysis.NMRAnalysis — Module
NMRAnalysisInteractive analysis of NMR relaxation, diffusion, exchange and 2D peak series. Set your working directory to the folder holding your experiments, call one of the routines below, and use ?name for help on any of them. Bruker experiment numbers work wherever a path does, and any parameter that is not given is read from the pulse-sequence annotations or acquisition parameters where possible, and otherwise asked for.
Automatic analysis
analyse(filename),analyse([filenames...]): choose a routine from the annotations
1D experiments
Each opens a window to pick integration and noise regions, fits live, and returns the results when the window closes.
relaxation1d(filename): R₁, R₂ and inversion recoverydiffusion1d(filename): diffusion coefficient and hydrodynamic radiustract(trosy, antitrosy): rotational correlation time from TRACTcalibration1d(filename): pulse-length calibration from a nutation experimentkinetics1d(filename, times): intensities of named regions against timepeaktrack1d(filenames): positions of peaks and multiplets across a series of spectrar1rho([directory]): R₁ρ relaxation dispersionexchange1d([filenames]): CEST and R₁ρ fitted by Bloch-McConnell simulation
2D experiments
Each opens a window to place and fit peaks, and returns the analysis when the window closes: results(expt) gives one row per peak and planeresults(expt) one per peak per plane. All take skipplanes to leave planes out of the fitting, and peaklist to load a saved peak list as the window opens.
fit2d(files): positions, linewidths and amplitudes, with no modelrelaxation2d(files): R₁ or R₂ from an exponential decayrecovery2d(files): inversion or saturation recoverymodelfit2d(files, x, equation, parameters): a model of your ownhetnoe2d(reference, saturated): heteronuclear NOEccr2d(decay, buildup, T): cross-correlated relaxation ratesmethylccr2d(buildup, decay, T): methyl S²τccest2d(file): CEST profilescpmg2d(file): CPMG relaxation dispersionpre2d(diamagnetic, paramagnetic; type): paramagnetic relaxation enhancement Γ₂lpre2d(diamagnetic, paramagnetic; type): Γ₁ and Γ₂ from a series of recycle delayspeaktrack2d(files): peaks that move from plane to planetitration2d(files): binding isotherms and a global Kdrdc2d(; isotropic, aligned): one-bond couplings and RDCssummaryplot(expt): a fitted parameter against residue number
Other tools
viscosity(solvent, T): solvent viscosityB1Calibration: B₁ calibrations, fromcalibration1dor a reference pulse
NMRAnalysis.DEFAULTINHOMOGENEITY — Constant
DEFAULTINHOMOGENEITYFractional B₁ inhomogeneity assumed when nothing has been measured: 5%, typical of a standard probe. Only a nutation calibration can do better than this guess.
NMRAnalysis.AnalysisCall — Type
AnalysisCallThe call that produced an analysis, recorded by the entry point so summary.txt can print a line that repeats it. reproducible is false where one of the positional arguments has no Julia literal - a spectrum passed as an NMRData rather than as a path - in which case no such line is printed at all rather than a misleading one.
NMRAnalysis.B1Calibration — Type
B1Calibration(power, ν1; nuc=nothing, inhomogeneity=DEFAULTINHOMOGENEITY, source="")
B1Calibration(spec, nuc; inhomogeneity=DEFAULTINHOMOGENEITY)The B₁ field a power level produces, and how widely that field is distributed across the sample.
The field follows the ideal square-root power law,
ν₁(p) = ν₁ref · 10^(−L·(dB(p) − dB(pref))/20),in which the linearity L is 1 for a perfectly linear amplifier. One measurement fixes ν₁ref and assumes L = 1; two or more fit both, so L is a direct diagnostic of amplifier compression, and departures from 1 are what a multi-power calibration is for.
The second form is the nominal calibration read from a spectrum's own reference pulse (p1/pl1, via referencepulse): one point, L = 1, and an assumed inhomogeneity. It reproduces hz(p, refpower, refpulse, 90) exactly, so an analysis given no calibration behaves as it always did.
Use hz(power, cal) to get a field from a power and Power(ν1, cal) to invert it.
Arguments
power: the power levels calibrated at, as NMRToolsPowers.ν1: the field measured at each, in Hz, with uncertainties.nuc: the nucleus (channel) this calibration applies to, for checking it is applied to the right one.inhomogeneity: fractional width of the B₁ distribution (0.05 for 5%).source: where the calibration came from, for provenance in saved results.
Example
cal = B1Calibration([Power(18.0, :dB), Power(12.0, :dB)], [1250.0 ± 5.0, 2480.0 ± 9.0])
hz(Power(15.0, :dB), cal) # field at an intermediate power, Hz
Power(2000.0, cal) # power needed for a 2 kHz fieldNMRAnalysis.B1Distribution — Type
B1Distribution(σ)
B1Distribution(calibration)
B1Distribution(scaling, weight)The distribution of B₁ across the sample, as the quadrature a simulation actually needs: a set of field scalings relative to nominal and the weight each carries.
σ is the fractional width of a Gaussian distribution, sampled at the three Gauss-Hermite nodes 1 ± √3σ with weights 1/6, 2/3, 1/6. σ = 0 gives the single nominal field, so a simulation with no inhomogeneity costs exactly what it did before.
Holding the quadrature rather than the distribution is what keeps this general: another family, or a B₁ profile measured on the probe, is a different set of scalings and weights and nothing downstream changes. The third form takes them directly.
Example
d = B1Distribution(0.05) # 91.3%, 100% and 108.7% of nominal
b1average(ν -> ν^2, d, 1000.0) # ⟨ν²⟩ over the distributionNMRTools.NMRBase.Power — Method
Power(ν1, calibration) -> PowerThe power level giving a field strength of ν1 Hz, inverting hz(power, cal). This is what turns a list of wanted spin-lock strengths into a list of powers to set.
NMRAnalysis.acqusvalue — Method
acqusvalue(spec, keys...) -> value or nothingAcquisition-parameter lookup returning nothing rather than throwing when the parameter is absent, or present but empty. The counterpart of annotation.
NMRAnalysis.analysiscall — Method
analysiscall(func, args...; kwargs...) -> AnalysisCallRecord a call. Keyword arguments whose values have no literal (a SeriesModel object, say) are left out, since the point of the record is that it can be pasted back into Julia.
NMRAnalysis.annotation — Method
Annotation lookup returning nothing rather than throwing when absent.
NMRAnalysis.ask — Method
ask(label, default; unit="", note="", type=Float64, prompt=true) -> value
ask(label; unit="", note="", type=Float64, prompt=true) -> valueAsk the user for a parameter value, on one line.
Given a default, the value is offered for confirmation and pressing enter accepts it; without one (or with default === nothing) a value must be typed. unit and note are shown alongside to say what is wanted and where the default came from. Re-asks until the answer parses as type.
With prompt=false nothing is printed: the default is returned, or an ArgumentError thrown if there is none.
NMRAnalysis.askchoice — Method
askchoice(question, options; default=1, prompt=true) -> IntAsk the user to pick one of options, returning its index. With prompt=false, or if the menu is cancelled, default is returned.
NMRAnalysis.askpath — Method
askpath(label) -> StringAsk for the path of an experiment folder, re-asking until it exists. Used by the entry points that can be called with no arguments at all.
NMRAnalysis.askvector — Method
askvector(label, n; unit="", prompt=true) -> Vector{Float64}Ask for the n values of an arrayed acquisition variable - a list of relaxation delays, say. They can be typed directly, separated by spaces or commas, or the name given of a file holding one per line, which is how Bruker writes a vdlist.
NMRAnalysis.b1average — Method
b1average(f, distribution, ν1)Average f(ν) over the B₁ distribution of a nominal field ν1.
This is the right average for anything linear in the observable, which is to say for a directly measured intensity: a CEST profile is the weighted sum of the profiles the separate parts of the sample give. For a quantity that reaches the data through a fit, see b1rate.
NMRAnalysis.b1rate — Method
b1rate(f, distribution, ν1, T)Apparent relaxation rate over a B₁ distribution, where f(ν) is the rate at field ν and T the evolution time the rate was measured over.
A spread of B₁ gives a spread of rates, so the decay is a sum of exponentials, and what a monoexponential fit to the data reports is
R = −ln(Σᵢ wᵢ exp(−Rᵢ T)) / Trather than the weighted mean of the rates ⟨R⟩. The two agree as T → 0 and diverge by about ½T·var(R) beyond that, which at the low spin-lock strengths of an R₁ρ dispersion is comparable with the uncertainty on the measurement. T is the time the experiment actually sampled, so the simulated quantity is the one the data reduction produced.
NMRAnalysis.backupfile — Method
backupfile(filepath)Rename an existing file to <name>.bak, so a save never silently destroys the last one.
NMRAnalysis.backupfolder — Method
backupfolder(folder) -> StringMove an existing output folder aside to <folder>_previous and return the (now empty) path, so that a save never silently destroys the last one and never leaves stale files from it behind. An earlier _previous is replaced.
Folder-level rather than file-level, because the stale files are the problem: a region or a peak deleted between one save and the next would otherwise leave its plot and its data in place, looking like part of the current result.
NMRAnalysis.calibrationfit — Method
calibrationfit(dB, ν1, dBref) -> (ν1ref, linearity)Weighted straight-line fit of log₁₀ν₁ against power, returning the field at dBref and the linearity (1 for an ideal amplifier).
The fit is linear because the ideal power law is a straight line in these coordinates, so there is nothing to iterate and no initial guess to get wrong. Written as the five weighted sums of the standard treatment (Numerical Recipes §15.2), with the abscissa centred on dBref so that the intercept is log₁₀ν₁ref and its variance comes straight from the covariance matrix. Uncertainties on ν₁ transform as σ(log₁₀ν) = σ(ν)/(ν ln10).
NMRAnalysis.callstring — Function
callstring(call, extra=[]) -> String or nothingcall as Julia code to paste back, with the keyword arguments in extra (names and already-rendered values) appended, one keyword to a line. nothing where the call has no literal form (see AnalysisCall).
NMRAnalysis.callvalue — Method
callvalue(x) -> String or nothingx as a Julia literal, or nothing where it has none. Vectors of numbers are written out in full: a gradient ramp or a delay list is exactly what has to be repeated, so abbreviating it would defeat the purpose.
NMRAnalysis.csvcolumn — Method
csvcolumn(name, unit) -> StringA CSV column header: the ASCII parameter or coordinate name, with its unit in parentheses where it has one ("R (s-1)", "A"). Units are ASCII so that a file survives being opened on any machine, and a reader locates a column by stripping the parenthesised part.
NMRAnalysis.csvcolumns — Method
csvcolumns(name, unit) -> (String, String)Value and uncertainty column headers for one parameter. The uncertainty repeats the unit, so the pair is symmetrical for anything reading them.
NMRAnalysis.csvvalue — Method
csvvalue(x) -> StringOne cell, at full precision - these are machine files, and rounding is irreversible. "NA" for anything absent or not applicable, which is distinct from a blank key (a blank key means the row applies to every value of it).
NMRAnalysis.fields — Method
The field strength measured at each power level, with its uncertainty.
NMRAnalysis.inhomogeneity — Method
inhomogeneity(calibration) -> Float64Fractional width of the B₁ distribution (0.05 for 5%).
NMRAnalysis.isexpt — Method
isexpt(directory) -> BoolCheck if the given directory contains an NMR experiment by verifying the existence of a 'pdata/1/title' file, which is typical for Bruker NMR data structure.
Return true if the directory has the expected title file structure, false otherwise.
NMRAnalysis.linearity — Method
linearity(calibration)Fitted power-law exponent relative to the ideal, so 1 means the amplifier follows ν₁ ∝ √W. Below 1 the field falls short of the ideal law as the power is raised, the usual signature of amplifier compression. Exactly 1, without uncertainty, where a single measurement left nothing to fit.
NMRAnalysis.midsentence — Method
A name as it reads mid-sentence: a lower-case first letter, unless it begins an acronym.
NMRAnalysis.parsevector — Method
parsevector(response) -> Vector{Float64} or nothingRead a whitespace- or comma-separated list of numbers, or the contents of a file named by response. Returns nothing if the response is neither.
NMRAnalysis.pick_expt_folders — Method
pick_expt_folders(directory_path; experiment_type_filter="") -> Vector{String}NMRAnalysis.powers — Method
The power levels a calibration was measured at.
NMRAnalysis.refpower — Method
The calibration's reference power.
NMRAnalysis.safename — Method
safename(label) -> StringA label made safe to use as a filename, so that an entity the user named anything at all still writes to <name>.csv beside its plot without escaping its folder.
NMRAnalysis.sanitizelabel — Method
sanitizelabel(label) -> StringStrip commas from a user-entered region or peak label. Labels are written unescaped into CSV cells (see writetable), so a comma in one would corrupt the row.
NMRAnalysis.select_expts — Method
select_expts(directory_path=""; experiment_type_filter="")Interactively select NMR experiment folders from a given directory path.
Arguments
directory_path::String: Path to start folder selection from. If empty, uses last selected folder or current directory.experiment_type_filter: Optional filter to apply for experiment types.
Returns
Vector{String}: Array of selected experiment folder paths. Returns empty array if no selection is made.
NMRAnalysis.shortpath — Method
shortpath(path) -> StringThe last two components of path, with a Bruker pdata/<n> tail dropped first: /Users/chris/NMR/crick-701/sophia_990_260823/10/pdata/1 → sophia_990_260823/10.
What identifies a spectrum to the person who recorded it is the dataset folder and the experiment number, not the fifty characters above them, and a full path overflows a GUI panel and pads every line of a summary. The call that produced an analysis is still recorded in full (see AnalysisCall), so nothing needed to repeat it is lost.
Anything that is not a path is returned as it stands.
NMRAnalysis.source — Method
Where the calibration came from, for provenance in saved results.
NMRAnalysis.stderrors — Method
stderrors(fit) -> Vector{Float64}Standard errors of a least-squares fit, or NaNs where the covariance matrix cannot be inverted.
LsqFit.stderror inverts JᵀJ, which is singular whenever the data leave a parameter unconstrained: an integration region dragged onto the baseline, an amplitude that has gone to zero, two coincident points on the fit axis. Throwing is the right answer in a script and the wrong one in an interactive fit, where the same exception arrives inside a Makie callback and takes the window's refit down with it. A NaN uncertainty instead propagates into the results and the plots, where it is visible and harmless.
The warning is capped: a fit re-run on every drag of a region would otherwise fill the console with the same line.
NMRAnalysis.viscosity — Method
viscosity(solvent, T)Calculate the viscosity of a solvent (in mPa s) at a given temperature.
Arguments
solvent: Should be either:h2oor:d2o.T: The temperature (in K) at which the viscosity is calculated.
Notes
The calculation is based on the formula proposed by Cho et al in the paper "J Phys Chem B (1999) 103 1991-1994".
NMRAnalysis.windowname — Method
windowname(analysis) -> StringThe title of an analysis window, naming the package and the analysis: windowname("1D peak tracking") == "NMRAnalysis.jl - 1D peak tracking".
NMRAnalysis.writetable — Method
writetable(filepath, comments, header, rows) -> StringWrite one CSV: each line of comments as a # comment (the experiment description), then the header row, then rows. Any existing file is backed up first. Returns the path.
NMRAnalysis.ν1ref — Method
Field strength (Hz) at the calibration's reference power, with its uncertainty.
NMRTools.NMRBase.hz — Method
hz(power, calibration) -> Float64The B₁ field strength (Hz) a power level produces, per calibration.
The calibration's own uncertainty is not propagated: it is far smaller than the B₁ inhomogeneity that B1Distribution accounts for, and the analyses downstream treat the nominal field as exact.
NMRTools.NMRBase.nucleus — Method
The nucleus (channel) a calibration was measured on, or nothing if not recorded.