Analysis API
The analysis layer provides inference tools that treat experiments as black boxes. It is composed of three source files:
analysis_tools.jl— core types, parameter utilities, likelihood generation, scanning, profiling, and data generation. All symbols are part of theNewtrinosmodule.molewhacker.jl— adaptive importance sampling via MGVI Gaussian mixture refinement. All symbols are part of theNewtrinosmodule.cli_common.jl— helper functions for CLI scripts. These are standalone utilities loaded viaincludeand are not exported from theNewtrinosmodule.
Parameter Utilities
These functions collect and merge parameters and priors across physics and experiment modules. condition and correlated_priors_vars allow fixing or correlating individual parameters before constructing a posterior.
Newtrinos.get_params — Function
get_params(x) -> NamedTupleExtract nominal parameter values as a sorted NamedTuple.
Dispatches on the type of x:
Physics: returnsx.paramssorted by key.Experiment: mergesx.paramswith the parameters of itsphysicsmodule.Wrapper: applies the alias translation fromWrapperto the keys.NamedTupleof modules: merges parameters from all modules viasafe_merge, raising an error on conflicts.
Arguments
x: aNewtrinos.Physics,Newtrinos.Experiment,Wrapper, orNamedTupleof such objects.
Returns
A sorted NamedTuple of parameter name → nominal value.
Newtrinos.get_priors — Function
get_priors(x) -> NamedTupleExtract prior distributions as a sorted NamedTuple.
Dispatches on the type of x:
Physics: returnsx.priorssorted by key.Experiment: mergesx.priorswith priors from itsphysicsmodule.Wrapper: applies the alias translation fromWrapperto the keys.NamedTupleof modules: merges priors from all modules viasafe_merge, raising an error on conflicts.
Arguments
x: aNewtrinos.Physics,Newtrinos.Experiment,Wrapper, orNamedTupleof such objects.
Returns
A sorted NamedTuple of parameter name → prior distribution.
Newtrinos.condition — Function
condition(priors, conditional_vars, params) -> NamedTupleFix a subset of parameters to specific values by replacing their prior distributions with constants (ConstValueDist).
Two dispatch methods:
Array form (conditionalvars is an array) — fixes each symbol in `conditionalvarsto its value inparams`:
condition(priors, [:theta23, :dm31_sq], params)Dict form (conditional_vars is a dict) — fixes each key to the paired value, or to params[key] when the value is nothing:
condition(priors, Dict(:theta23 => pi/4, :dm31_sq => nothing), params)Arguments
priors::NamedTuple: prior distributions to modify.conditional_vars:AbstractArray{Symbol}orAbstractDict{Symbol}of parameters to fix.params::NamedTuple: fallback parameter values used when a dict entry isnothingor when using the array form.
Returns
The modified priors NamedTuple with the specified parameters frozen.
Newtrinos.safe_merge — Function
safe_merge(nt_list::NamedTuple...) -> NamedTupleMerge NamedTuples, asserting that any key shared by two or more inputs has the same value in all of them.
Raises an error if a key conflict is detected. The result is sorted alphabetically by key.
Arguments
nt_list::NamedTuple...: one or more NamedTuples to merge.
Returns
A sorted NamedTuple containing all key-value pairs from the inputs.
Examples
a = (x = 1.0, y = 2.0)
b = (y = 2.0, z = 3.0)
safe_merge(a, b) # (x = 1.0, y = 2.0, z = 3.0)Newtrinos.correlated_priors_vars — Function
correlated_priors_vars(priors, vars, dist) -> (corr_prior, other_prior)Replace the independent priors for vars with a single correlated multivariate distribution, splitting the prior NamedTuple into two parts.
Useful when a set of parameters has a known covariance structure (e.g. from an external fit) that cannot be captured by independent marginals.
Arguments
priors::NamedTuple: the full prior NamedTuple.vars::Union{AbstractArray, Tuple}: parameter names to correlate.dist::Distributions.Distribution: a multivariate distribution overvars(must match the length ofvars).
Returns
A 2-tuple (corr_prior, other_prior) where:
corr_prior: a callable returning aReshapedDistovervars.other_prior: adistprodof the remaining (uncorrelated) priors.
Data Generation
Newtrinos.generate_asimov_data — Function
generate_asimov_data(experiment, params) -> data
generate_asimov_data(experiments::NamedTuple, params) -> NamedTupleGenerate Asimov (expected-value) data from the experiment forward model.
Evaluates mean(forward_model(params)). For Poisson-distributed observables the mean is rounded to the nearest integer so that the data type matches what a real run would produce.
Arguments
experiment: a singleNewtrinos.Experimentor a NamedTuple of them.params::NamedTuple: parameter values at which to evaluate the forward model.
Returns
- Single-experiment form: the expected-value data array (or NamedTuple of arrays).
- Multi-experiment form: a NamedTuple with the same keys as
experiments.
Newtrinos.generate_toy_data — Function
generate_toy_data(experiment, params) -> data
generate_toy_data(experiments::NamedTuple, params) -> NamedTupleGenerate random toy data by sampling from the experiment forward model.
Calls experiment.forward_model(params) to obtain the predictive distribution and draws one sample from it.
Arguments
experiment: a singleNewtrinos.Experimentor a NamedTuple of them.params::NamedTuple: parameter values at which to evaluate the forward model.
Returns
- Single-experiment form: one sample from the forward model distribution.
- Multi-experiment form: a NamedTuple with the same keys as
experiments, each entry holding one sample.
Adaptive Importance Sampling
The molewhacker tools implement an adaptive importance sampling strategy. Starting from an initial Gaussian mixture proposal, each iteration fits a new local MGVI Gaussian component at the highest-weight sample point and adds it to the mixture. This "whack-a-mole" strategy adaptively targets undersampled regions of the posterior. whack_many_moles is the recommended entry point for production runs.
Newtrinos.make_prior_samples — Function
make_prior_samples(posterior, nsamples::Int=10_000) -> NamedTupleInitialize importance samples by using a standard normal as the proposal distribution.
Transforms posterior to the standard-normal space via BAT's PriorToNormal reparameterization, then generates nsamples samples by calling importance_sampling with the transformed posterior and the standard normal $\mathcal{N}(0, I)$ as the proposal distribution.
Arguments
posterior: a BAT posterior measure.nsamples::Int: number of importance samples to draw (default:10_000).
Returns
A NamedTuple with fields:
approx_dist: the standard normal proposal used.samples_p:DensitySampleVectorin the transformed (normal) space.samples_user: samples back-transformed to the original parameter space.
Newtrinos.make_init_samples — Function
make_init_samples(posterior, nseeds::Int=10, nsamples::Int=10_000) -> NamedTupleInitialize importance samples by fitting a mixture of local Gaussian approximations at posterior modes.
Finds nseeds approximate modes via L-BFGS optimization (using Sobol-sequence starting points), fits a local_MGVI_approx at each mode, and combines them into a MixtureModel. The mixture model weights are calculated as
\[\begin{aligned} \log \tilde{w}_i &= \log p (\mu_i) - \log q (\mu_i) \\ \tilde{w}_i &= \exp\bigl(\log \tilde{w}_i - \max(\log \tilde{w})\bigr) \\ w_i &= \frac{\tilde{w}_i}{\sum_j \tilde{w}_j} \end{aligned}\]
where $\mu_i$ is the mode of the $i$-th component. Importance samples are then drawn from the mixture via importance_sampling.
Arguments
posterior: a BAT posterior measure.nseeds::Int: number of mode-finding restarts (default:10).nsamples::Int: number of importance samples to draw (default:10_000).
Returns
A NamedTuple with fields:
approx_dist::MixtureModel: the weighted Gaussian mixture proposal.samples_p:DensitySampleVectorin the transformed space.samples_user: samples back-transformed to the original parameter space.
make_init_samples(posterior, seed_points::DataFrame, nsamples::Int=10_000) -> NamedTupleInitialize importance samples from user-supplied seed points given as a DataFrame.
Like the integer-seed form but uses rows of seed_points as starting points for mode-finding instead of Sobol samples. Each row is projected into the transformed parameter space and L-BFGS is run from there.
This method contains hardcoded field names (Darkdim_radius, ca1, ca2, ca3) specific to Darkdim models. It must be generalized before use with other parameter sets.
Arguments
posterior: a BAT posterior measure.seed_points::DataFrame: each row provides the starting parameter values. Must contain columnsDarkdim_radius,ca1,ca2,ca3.nsamples::Int: number of importance samples to draw (default:10_000).
Returns
A NamedTuple with fields:
approx_dist::MixtureModel: the weighted Gaussian mixture proposal.samples_p:DensitySampleVectorin the transformed space.samples_user: samples back-transformed to the original parameter space.
Newtrinos.whack_a_mole — Function
whack_a_mole(posterior, init_samples, n_whack=100) -> NamedTupleRefine an importance sampling approximation by iteratively adding Gaussian components at high-weight sample points.
At each of n_whack iterations:
- The highest-weight sample in the current mixture is identified.
- A
local_MGVI_approxis fitted at that point. - The new component is added to the mixture with weight proportional to its posterior density at its mode relative to the mixture density.
- New samples are drawn from the new component and importance-reweighted.
This "whack-a-mole" strategy adaptively targets undersampled regions of the posterior. Use whack_many_moles for a parallelized variant with convergence criteria.
Arguments
posterior: a BAT posterior measure.init_samples: initialization NamedTuple as returned bymake_init_samplesormake_prior_samples.n_whack::Int: number of refinement iterations (default:100).
Returns
A NamedTuple with fields:
approx_dist::MixtureModel: the refined Gaussian mixture proposal.samples_p: accumulatedDensitySampleVectorin the transformed space.samples_user: samples back-transformed to the original parameter space.
Newtrinos.whack_many_moles — Function
whack_many_moles(posterior, init_samples;
target_efficiency=Inf, target_samplesize=Inf,
maxiter=100, n_parallel=Threads.nthreads(),
cache_dir=nothing) -> NamedTupleParallelized adaptive importance sampling with convergence criteria.
Like whack_a_mole but processes n_parallel high-weight sample points simultaneously per each iteration using Threads.@threads. Iteration stops when any of the following conditions is met:
- Effective sample size (ESS) exceeds
target_samplesize. - Efficiency (ESS / total samples) exceeds
target_efficiency. - Number of iterations reaches
maxiter.
Intermediate results can be saved to disk after each iteration for fault tolerance.
Arguments
posterior: a BAT posterior measure.init_samples: initialization NamedTuple as returned bymake_init_samplesormake_prior_samples.target_efficiency::Real: stop when ESS / n_samples exceeds this value (default:Inf, i.e. no efficiency target).target_samplesize::Real: stop when ESS exceeds this value (default:Inf, i.e. no ESS target).maxiter::Int: maximum number of refinement iterations (default:100).n_parallel::Int: number of new components to fit per iteration (default:Threads.nthreads()).cache_dir::Union{String,Nothing}: if provided, saves a JLD2 checkpoint after each iteration to this directory. (Default:nothing).
Returns
A NamedTuple with fields:
approx_dist::MixtureModel: the refined Gaussian mixture proposal.samples_p: accumulatedDensitySampleVectorin the transformed space.samples_user: samples back-transformed to the original parameter space.
Newtrinos.importance_sampling — Function
importance_sampling(pstr, approx_dist, nsamples) -> DensitySampleVectorDraw importance-weighted samples from pstr using approx_dist as the proposal.
Samples nsamples points from approx_dist, evaluates $\log p$ (pstr) and $\log q$ (approx_dist) at each point, and computes normalized importance weights. The evaluation of $\log p$ is parallelized over threads. The weights are calculated as:
\[\log \tilde{w}_i = \log p - \log q w_i = \exp\!\bigl( \log \tilde{w}_i - \max(\log \tilde{w}_i) \bigr)\]
with the $\max(\log \tilde{w}_i)$ substracted in the exponent such that $\max_i w_i = 1$ for numerical stability.
Arguments
pstr: BAT posterior (typically already transformed viaPriorToNormal).approx_dist: proposal distribution supportingbat_sampleandlogdensityof.nsamples::Int: number of samples to draw fromapprox_dist.
Returns
A DensitySampleVector with samples from approx_dist, their respective $\log p$, and their importance weights.
Newtrinos.local_MGVI_approx — Function
local_MGVI_approx(pstr, θ_sel) -> MvNormalFit a local Gaussian approximation to pstr at the selected point θ_sel.
Uses the MGVI (Metric Gaussian Variational Inference) approach: the covariance is
\[\Sigma = \bigl(J^\top\, F(\theta)\, J + I\bigr)^{-1}\]
where $F(\theta)$ is the Fisher information matrix of the likelihood model evaluated at $\theta$, and $J = \partial_\theta(\texttt{flat\_params} \circ m)$ is the Jacobian of the parameter reparameterization. The result is regularized with a Cholesky decomposition via PositiveFactorizations.
Arguments
pstr: BAT posterior with alikelihoodfield exposing the forward modelk.θ_sel: parameter vector (in the transformed space) at which to centre the Gaussian.
Returns
A MvNormal distribution centred at θ_sel with covariance $\Sigma$.
Likelihood Construction
Newtrinos.generate_likelihood — Function
generate_likelihood(experiments[, observed]) -> likelihoodConstruct a joint likelihood from a NamedTuple of configured experiments.
Combines all experiment forward models into a product distribution and pairs it with the observed data. The returned object supports DensityInterface.logdensityof(likelihood, params).
Arguments
experiments::NamedTuple: named collection of configuredNewtrinos.Experimentobjects.observed(optional): NamedTuple of observed data arrays matchingexperiments. Defaults to the observed data stored in each experiment'sassets.observedfield.
Returns
A likelihood object compatible with DensityInterface.logdensityof.
Examples
experiments = (deepcore = Newtrinos.deepcore.configure(),
dayabay = Newtrinos.dayabay.configure())
llh = generate_likelihood(experiments)
logdensityof(llh, params)Newtrinos.get_observed — Function
get_observed(experiments::NamedTuple) -> NamedTupleExtract the observed data from each experiment in a NamedTuple of experiments.
Arguments
experiments::NamedTuple: named collection ofNewtrinos.Experimentobjects.
Returns
A NamedTuple with the same keys as experiments, each entry holding the corresponding experiment.assets.observed data.
Newtrinos.get_fwd_model — Function
get_fwd_model(experiments::NamedTuple) -> FunctionCompose the forward models of all experiments into a single joint model.
Builds a NamedTuple of per-experiment forward models and composes them with ffanout and distprod so that calling the result with a parameter NamedTuple returns a joint product distribution over all experiments.
Arguments
experiments::NamedTuple: named collection ofNewtrinos.Experimentobjects.
Returns
A callable params -> joint_distribution.
Scanning and Profiling
scan evaluates the joint likelihood on a fixed grid without optimization. profile minimizes over nuisance parameters at each grid point. find_mle / find_mle_cached locate the global maximum-likelihood estimate.
Newtrinos.find_mle — Function
find_mle(likelihood, prior, params; adsel=AutoPolyesterForwardDiff())
-> (llh, log_posterior, result)Find the Maximum Likelihood Estimator (MLE) using L-BFGS optimization via BAT.jl.
Parameters whose prior is a ConstValueDist are held fixed during optimization. If the optimizer raises an ArgumentError (e.g. due to a degenerate starting point), returns (NaN, NaN, NaN-filled NamedTuple) instead of propagating the error.
Arguments
likelihood: a likelihood object supportingDensityInterface.logdensityof.prior: adistprod-style prior NamedTuple or distribution.params::NamedTuple: starting parameter values for the optimizer.adsel: AD backend selector (default:AutoPolyesterForwardDiff()).
Returns
A 3-tuple (llh, log_posterior, result) where:
llh::Float64: log-likelihood at the optimum.log_posterior::Float64: log-posterior at the optimum.result::NamedTuple: optimized parameter values.
Newtrinos.find_mle_cached — Function
find_mle_cached(likelihood, prior, params, cache_dir)
-> (llh, log_posterior, result)Like find_mle but caches results to disk using content hashing.
A hash of (prior, params) is computed with ContentHashes.hash; if a matching .jld2 file exists in cache_dir the optimization is skipped and the cached result is returned. Otherwise the result is computed and saved.
Arguments
likelihood: a likelihood object supportingDensityInterface.logdensityof.prior: prior distribution (same asfind_mle).params::NamedTuple: starting parameter values.cache_dir::Union{String,Nothing}: directory for cached.jld2files. Passnothingto disable caching.
Returns
A 3-tuple (llh, log_posterior, result) — see find_mle.
Newtrinos.profile — Function
profile(likelihood, priors, vars_to_scan, params;
cache_dir=nothing, map_func=nothing) -> NewtrinosResultRun a profile likelihood scan over a parameter grid.
Creates grid points defined by vars_to_scan with generate_scanpoints. At each grid point, all nuisance parameters are optimized with _profile , i.e. via find_mle_cached. If all non-scanned parameters have fixed (Number) priors, falls back to scan automatically. Also collects meta data of the profile process and attaches it the returned object.
Arguments
likelihood: a likelihood object supportingDensityInterface.logdensityof.priors::NamedTuple: prior distributions for all parameters.vars_to_scan::OrderedDict{Symbol,Int}: parameters to scan and grid sizes.params::NamedTuple: starting values for nuisance parameter optimization.cache_dir::Union{String,Nothing}: directory for caching MLE results (created if absent). Passnothingto disable (this is the default).map_func: custom mapping function for parallelism (e.g.pmapfor distributed workers). Defaults toThreads.@threads.
Returns
A NewtrinosResult NewtrinosResult(axes, values, meta) with the scan grid axes, per-point profiling results, and meta data.
Newtrinos.scan — Function
scan(likelihood, priors, vars_to_scan, params;
gradient_map=false) -> NewtrinosResultRun a simple likelihood scan on a parameter grid (NO nuisance optimization).
Generates grid with _generate_grid via vars_to_scan and then evaluates logdensityof(likelihood, params) at each grid point without optimizing over nuisance parameters. Faster than profile but does not account for nuisance parameter variations. Also collects meta data of the scan process and attaches it the returned object.
Arguments
likelihood: a likelihood object supportingDensityInterface.logdensityof.priors::NamedTuple: prior distributions used to place grid points at quantiles.vars_to_scan::OrderedDict{Symbol,Int}: parameters to scan and grid sizes.params::NamedTuple: nominal values; non-scanned parameters are held fixed.gradient_map::Bool: default=false; iftrue, also evaluatesForwardDiff.gradientat each grid point and includes per-parameter gradient arrays in the result.
Returns
A NewtrinosResult NewtrinosResult(axes, values, meta) with the scan grid axes, per-point scan results, and meta data.
Newtrinos.bestfit — Function
bestfit(result::NewtrinosResult) -> NamedTupleExtract the best-fit parameter values from a scan or profile result.
Finds the grid point with the highest log_posterior and returns both the scanned parameter values (from result.axes) and all optimized nuisance parameter values at that point.
Arguments
Returns
A NamedTuple containing all parameter values at the best-fit point, including the scanned axis values, nuisance parameters, llh, and log_posterior.
Newtrinos.generate_scanpoints — Function
generate_scanpoints(vars_to_scan, priors) -> (values, scanpoints)Build a grid of fixed-parameter priors for a profile likelihood scan.
For each variable in vars_to_scan, grid points are placed at evenly-spaced quantiles of its prior distribution. All combinations are formed via a Cartesian product. At each grid point, the prior for the scanned variables is replaced with a ConstValueDist fixing them to the grid values.
Arguments
vars_to_scan::OrderedDict{Symbol,Int}: maps each parameter name to the desired number of evenly spaced grid points within the prior range.priors::NamedTuple: prior distributions for all parameters.
Returns
A 2-tuple (values, scanpoints) where:
values: vector of grid-point vectors (one per scanned parameter).scanpoints: array ofdistprodpriors, one per grid point.
Newtrinos.assemble_profile_results — Function
assemble_profile_results(opt_results, result_size) -> NamedTupleCollect the 'raw' per-grid-point optimization results and structure them into flat arrays within a NamedTuple.
Stacks the (llh, log_posterior, params) 3-tuples returned by find_mle_cached into a NamedTuple of arrays with shape result_size.
Arguments
opt_results: iterable of(llh, log_posterior, NamedTuple)3-tuples.result_size: shape of the output arrays (matching the scan grid).
Returns
A NamedTuple with one array-entry per parameter (values across the grid) plus :llh and :log_posterior arrays.
Example
opt_results = [
(-10.0, -12.0, (a=1.0, b=2.0)), # llh, log_posterior, params output of find_mle
(-5.0, -7.0, (a=3.0, b=4.0))
]
res = Newtrinos.assemble_profile_results(opt_results, (2,))
# returns res = (a = [1.0, 3.0], b = [2.0, 4.0], llh = [-10.0, -5.0], log_posterior = [-12.0, -7.0])Utilities
Newtrinos.add_meta! — Function
add_meta!(meta::Dict)Populate a metadata dictionary with execution environment information. When Newtrinos is loaded from the julia package index, it marks the git-repo information as missing.
Adds the following keys in-place:
"hostname": result ofgethostname()."username": fromENV["USER"]orENV["USERNAME"]."date": current date-time formatted as"yyyy-mm-dd HH:MM:SS"."repo": path to the Newtrinos.jl root."package_version": loaded version of the Newtrinos.jl package."commit_hash": current HEAD commit hash."repo_clean":trueif the repository has no uncommitted changes.
Called automatically by profile and scan before returning their NewtrinosResult.
Arguments
meta::Dict: dictionary to populate in-place.
Returns
nothing (mutates meta).
Makie.plot! — Function
plot!(ax, result::NewtrinosResult;
max_llh=maximum(result.values.log_posterior),
levels=1 .- 2*ccdf(Normal(), 1:3),
label=nothing, color=:blue, linestyle=:solid,
cmap=:Blues, filled=false, edge=true,
transform_x=identity, transform_y=identity) -> AxisPlot a NewtrinosResult into an existing Makie Axis.
Dispatches on the dimensionality of result.axes:
- 1D: plots
-2Δllhas a line with horizontal dotted lines at the requested confidence levels. - 2D: plots confidence contours via
contour!and optionally a filled version viacontourf!.
Confidence levels are converted to -2Δllh thresholds using the appropriate chi-squared distribution (Chisq(1) for 1D, Chisq(2) for 2D).
Arguments
ax::Axis: the Makie axis to plot into.result::NewtrinosResult: scan or profile result to visualize.max_llh: reference log-posterior value for computing-2Δllh; defaults to the maximum inresult.values.log_posterior.levels: confidence levels to draw contours at; defaults to 1σ, 2σ, 3σ Gaussian intervals.label: legend label attached to the line or contour; defaultnothing.color: line/contour color; default:blue.linestyle: line style; default:solid.cmap: colormap used for the filled contours (2D only); default:Blues.filled::Bool: iftrue, draw filled contours viacontourf!(2D only); defaultfalse.edge::Bool: iftrue, draw contour edges viacontour!(2D only); defaulttrue.transform_x: function applied to the first axis before plotting; defaultidentity.transform_y: function applied to the second axis before plotting; defaultidentity.
Returns
The modified Axis ax.
Makie.plot — Function
plot(result::NewtrinosResult; kwargs...) -> FigureConvenience wrapper that creates a new [Figure] and [Axis] and calls plot! with all kwargs. Returns the Figure.
Internal API
Low-level helpers used internally by the scanning and profiling pipeline.
Newtrinos.sort_nt — Function
sort_nt(nt::NamedTuple) -> NamedTupleReturn a copy of a named tuple nt with keys sorted alphabetically.
Used internally by safe_merge, get_params, and get_priors to ensure a canonical key ordering across modules.
Arguments
nt::NamedTuple: input NamedTuple.
Returns
A NamedTuple with the same entries as nt, sorted alphabetically by key name.
Newtrinos._generate_grid — Function
_generate_grid(vars_to_scan, priors) -> (vars, values, mesh)Construct the Cartesian grid used by generate_scanpoints and scan.
Grid points for each variable are placed at evenly-spaced quantiles of its prior distribution. All combinations are formed via IterTools.product.
Arguments
vars_to_scan::OrderedDict{Symbol,Int}: maps parameter names to grid sizes.priors::NamedTuple: prior distributions used to compute quantiles.
Returns
A 3-tuple (vars, values, mesh) where:
vars:Vector{Symbol}of scanned parameter names.values: vector of grid-point vectors (one per variable).mesh: Cartesian product array of grid-point tuples.
Examples
priors = (a=Uniform(0.0, 2.0), b=Uniform(-1.0, 1.0))
vars_to_scan = OrderedDict(:a => 3, :b => 4)
vars, values, mesh = Newtrinos._generate_grid(vars_to_scan, priors)
# => mesh is a 3x4 grid of evenly spaced points from within the prior range of a and b Newtrinos._profile — Function
_profile(likelihood, scanpoints, params, cache_dir; map_func=nothing)
-> NamedTupleExecute find_mle_cached at every point in scanpoints, collect the results, and assemble them into a NamedTuple of result arrays with assemble_profile_results.
Uses Threads.@threads by default. Pass a custom map_func (e.g. pmap) to override the parallelism strategy.
Arguments
likelihood: a likelihood object supportingDensityInterface.logdensityof.scanpoints: array of prior objects, one per grid point.params::NamedTuple: starting values for nuisance optimization.cache_dir::Union{String,Nothing}: passed tofind_mle_cached.map_func: optional custom mapping function; default=nothinguses threaded loops.
Returns
A NamedTuple of result arrays as produced by assemble_profile_results.
CLI Usage
analysis.jl
src/analysis/analysis.jl is the main command-line entry point for running analyses. It is invoked with julia --project:
julia --project src/analysis/analysis.jl \
--experiments deepcore dayabay \
--name myrun \
--task scanCommand-line Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
--experiments | String... | Yes | Space-separated experiment names (e.g. deepcore dayabay) |
--name | String | Yes | Base name for output files |
--task | String | Yes | One of Scan, Profile, ImportanceSampling, NestedSampling |
--plot | flag | No | If set, render and save a PNG plot of the result |
--workers | Int | No | Number of distributed workers (default: 1) |
--threads | Int | No | Threads per worker when --workers > 1 (default: 1) |
Task Modes
scan— evaluates the joint likelihood on a fixed parameter grid defined in the script body. No nuisance-parameter optimization. Fast.profile— minimizes over nuisance parameters at each grid point via L-BFGS. Supports distributed execution via--workers. Results are checkpointed per row.importancesampling— runswhack_many_molesto produce importance-weighted posterior samples from a Gaussian mixture approximation.nestedsampling— runsReactiveNestedSamplingfrom UltraNest.
Output Files
| File | Contents |
|---|---|
<name>.jld2 | NewtrinosResult (scan/profile) or sample dict (sampling) |
<name>.png | Plot of the result (only with --plot) |
<name>/ | Per-iteration checkpoint directory (profile and importance sampling) |
Physics Configuration
To use non-default oscillation models (inverted ordering, sterile neutrinos, custom flux, etc.), uncomment and edit the override block near the top of the script.
Helper Functions (cli_common.jl)
The following functions are defined in src/analysis/cli_common.jl and loaded by CLI scripts via include. They are not exported from the Newtrinos module.
configure_experiments(experiment_list)
Configure a list of experiments using each experiment's built-in defaults. Looks up each name in the Newtrinos module (case-insensitive), calls its configure() method, and returns a NamedTuple keyed by lowercased experiment name.
experiments = configure_experiments(["deepcore", "dayabay"])
# (deepcore = ..., dayabay = ...)configure_experiments(experiment_list, physics)
Like the single-argument form but passes a shared physics object to each experiment's configure(physics) method, allowing a custom oscillation or cross-section configuration to be shared across all experiments.
experiments = configure_experiments(["deepcore", "dayabay"], physics)save_result(result, name)
Save a NewtrinosResult to <name>.jld2 in the current working directory using JLD2.
save_result(result, "myrun") # writes myrun.jld2plot_result(result, name, vars_to_scan; title=nothing)
Render a scan or profile result and save it as <name>.png. Requires a Makie backend (e.g. using CairoMakie) to be loaded in the caller's scope before calling this function. The x-axis is labelled with the first scanned parameter; the y-axis shows -2ΔLLH (1-D) or the second scanned parameter (2-D).
using CairoMakie
plot_result(result, "myrun", vars_to_scan; title="DeepCore scan")Examples
# 2-D scan over θ₂₃ and Δm²₃₁ with DeepCore + Daya Bay, save PNG
julia --project src/analysis/analysis.jl \
--experiments deepcore dayabay \
--name joint_scan \
--task scan \
--plot
# Profile likelihood using 4 distributed workers, 2 threads each
julia --project src/analysis/distributed_profile.jl \
--experiments deepcore \
--name dc_profile \
--workers 4 \
--threads 2
# Importance sampling posterior
julia --project src/analysis/analysis.jl \
--experiments deepcore \
--name dc_posterior \
--task importancesampling