API Reference
Complete reference for Ronin's exported API, grouped by topic. See the Concepts and Workflow Guide pages for how these fit together.
Configuration
The ModelConfig struct is the single source of truth; the rest construct, persist, reload, and migrate it.
Ronin.ModelConfig — Type
Stuct used to store configuration information for a given model
Required arguments
num_models:::Int64Number of ML models in the model chain. Can be one or more.
model_output_paths::Vector{String}Vector containing paths to each model in the model chain. Should be same length as the number of models
met_probs::Vector{Tuple{Float32,Float32}}Vector containing the decision range for a gate to be considered meteorological in each model in the chain. Example, if set to (.9, 1), > 90% of trees in the random forest must assign a gate a label of meteorological for it to be considered meteorological. The range is exclusive on both ends. That is, for a gate to be classified as non-meteorological, it must have a probability LESS THAN the low threshold, and for a gate to be classified as meteorological it must have a probability GREATER THAN the high threshold. For multi-pass models, gates between these thresholds (inclusive) will be sent on to the next pass. Form is (lowthreshold, highthreshold)
feature_output_paths::Vector{String}Vector containing paths representing the locations to output calculated features to for each model in the chain.
input_path::StringDirectory containing input radar data
task_mode::StringSelects the feature-engineering regime. Codebase behavior is not agnostic to this value — it branches across training, prediction, QC, and mask generation:
task_mode == "convolution"— convolution feature mode. Features are derived from a kernel bank applied toconv_variables(plus appended AHT/ELV/RNG/NRG scalars); see the Convolution Feature Mode documentation.run_hypertuningrequires this mode.task_mode == ""(or any value other than"convolution") — legacy hand-tuned predictor mode. Features come from thetask_paths/task_weightspredictor specification (STD/ISO/AVG/RNG/NRG/PGG/AHT); see the Legacy Hand-Tuned Mode documentation.
regenerate_masks is the only mode-agnostic pass utility.
file_preprocessed::Vector{Bool}For each model in the chain, contains a boolean value signifying if the correspondant feature output path has already been processed. If true, will open the file at this path instead of re-calculating input features.
Optional arguments
Input tasks and weights
The following arguments are only quasi-optional, one of them must be set.
task_list::Vector{String} = [""]
task_weights::Vector{Vector} = [[Matrix{Union{Float32, Missing}}(undef, 0,0)]]Currently only `task_paths` are supported. Contains a vector of the same length as the number of
models, with each entry being the path to a file contianing the tasks for the pass. Future plans involve
allowing a usesr to specify vectors of tasks in `task_list`.
`task_weights` must be a vector of vectors, with the first dimension the same length as the number of models in the
chain. The second dimension much either be 1, containing the default weight matrix `Matrix{Union{Float32, Missing}}(undef, 0,0)`,
or a secondary vector of matrixes - one matrix for each task in the passs. Sample weight matrixes are defined in RoninConstants.jlverbose::Bool = trueWhether to print out timing information, etc.
REMOVE_LOW_SIG_QUALITY::Bool = trueWhether to automatically remove gates that do not meet a basic Signal Quality threshold. Variable used to determine this specified in SIG_QUALITY_VAR
REMOVE_HIGH_PGG::Bool = trueWhether to automatically remove gates that do not meet a basic PGG threshold
HAS_INTERACTIVE_QC::Bool = falseWhether the radar data has already had interactive QC applied to it
QC_var::String = "VG"If radar data has interactive QC already applied, the name of a variable that the QC has been applied to
remove_var::String = "VV"Name of a raw variable in the radar data that can be used to determine the location of missing gates
FILL_VAL::Float32 = RoninConstants.FILL_VALFill value for output cfradials
replace_missing::Bool = falseFor spatial feature (AVG, STD, etc.) calculation, whether or not to replace MISSING gates in the mask area with FILL_VAL
write_out::Bool = trueWhether or not to write the calculated input features to disk, paths specified in featureoutputpaths
QC_mask::Bool = falseFor the first model in the chain, whether or not to mask gates considered for feature calculation using a mask specified by mask_name More details elsewhere in the documentation.
mask_names::Vector{String} = [""]List of names for masks in the model. Must be of same length as number of models in the chain. In the case of a model with QC_mask set to true, the first mask name in this vector should contain a string denoting the name of a field in all cfradial files that is dimensioned the same as the radar sweeps and contains values of missing where data is not to be considred, and values of float otherwise.
VARS_TO_QC::Vector{String} = ["VV", "ZZ"]List of variables to apply QC to to get mask for next model in chain
QC_SUFFIX::StringPostfix to apply to variable name once QC has been applied.
class_weights::String = ""Class weighting scheme to apply in the training of RF model. Currently only "balanced" is implemented.
n_trees::Int = 21Number of trees in the random forest
max_depth::Int = 14Maximum depth of any one tree in the random forest
overwrite_output::Bool = falseIf true, will remove/overwrite existing files when internal functionality attempts to write new data to them
SIG_QUALITY_THRESHOLD::Float32 = .2If REMOVELOWNCP is set to true, threshold at or below which to remove data.
PGG_THRESHOLD::Float32 = 1.If REMOVEHIGHPGG is set to true, threshold at or above which to remove data.
SIGNAL_QUALITY_VAR::String = "NCP"Name of variable in cfradial file representing signal quality. Most commonly "NCP" or "SQI"
Ronin.make_config — Function
make_config(; num_models, input_path, experiment_name="experiment", kwargs...)Convenience constructor for ModelConfig that auto-generates paths and mask names from num_models and experiment_name, reducing boilerplate.
Auto-generated fields (can be overridden via kwargs):
model_output_paths:["trained_model_<name>_<i>.jld2" for i in 1:num_models]feature_output_paths:["output_features_<name>_<i-1>.h5" for i in 1:num_models]mask_names:["mask_pass_<i-1>" for i in 1:num_models]met_probs:[(0.1f0, 0.9f0) for _ in 1:num_models]file_preprocessed:[false for _ in 1:num_models]
All other ModelConfig fields can be passed as keyword arguments.
Ronin.save_config — Function
save_config(path::String, config::ModelConfig)Save a ModelConfig to a JLD2 file in dict-keyed format: one key per field.
This format is robust to struct evolution. Adding a field to ModelConfig later just means a new key for fresh files; old files still load via load_config, which fills any missing key with the struct's default. No migration required on every shape change.
Replaces the legacy pattern JLD2.save_object(path, config), which pickled the struct shape and broke on every field addition (see issue #34). The legacy format is still readable by load_config.
Ronin.load_config — Function
load_config(path::String) -> ModelConfigLoad a ModelConfig from a JLD2 file, transparently handling both storage formats:
Dict-keyed format (written by
save_config): each ModelConfig field is stored under its own key. Missing keys fall back to the struct's@kwdefdefaults, so future field additions do not break old files.Legacy
save_objectformat (singlesingle_stored_objectkey holding a pickled struct): JLD2 may load these as aReconstructedMutableshadow type when the saved struct shape no longer matches the currentModelConfig. Each accessible field is copied viagetpropertyinto a fresh, realModelConfiginstance; defaults fill in any new fields the saved file lacks.
A real, mutable ModelConfig is returned regardless of source format — callers can then assign to fields (config.task_paths = [...]) without hitting setproperty! errors on ReconstructedMutable.
Ronin.migrate_model_config — Function
migrate_model_config(infile::String, outfile::String; key=nothing)One-shot utility: load a legacy save_object-format ModelConfig file and re-save it in the new dict-keyed format written by save_config. Returns the rebuilt ModelConfig.
Migration is not required for loading — load_config reads legacy files inline. Use this helper only when you want to upgrade a long-lived file on disk so future loads skip the legacy path (and the deprecation @info).
key may be passed to select a specific JLD2 key when the file contains multiple stored objects; defaults to the standard single_stored_object key used by JLD2.save_object.
Data preparation
Splitting cfradial directories into train/test/(validation) sets and related directory utilities.
Ronin.split_training_testing! — Function
Function to split a given directory or set of directories into training and testing files using the configuration described in DesRosiers and Bell 2023. This function assumes that input directories only contain cfradial files that follow standard naming conventions, and are thus implicitly chronologically ordered. The function operates by first dividing file names into training and testing sets following an 80/20 training/testing split, and subsequently softlinking each file to the training and testing directories. Attempts to avoid temporal autocorrelation while maximizing variance by dividing each case into several different training/testing sections.
An important note: Always use absolute paths, relative paths will cause issues with the simlinks
Required Arguments:
DIR_PATHS::Vector{String}List of directories containing cfradials to be used for model training/testing. Useful if input data is split into several different cases.
TRAINING_PATH::StringDirectory to softlink files designated for training into.
TESTING_PATH::StringDirectory to softlink files designated for testing into.
Ronin.split_training_testing_validation! — Function
split_training_testing_validation!(DIR_PATHS::Vector{String},
TRAINING_PATH::String,
TESTING_PATH::String,
VALIDATION_PATH::String)Split a directory or set of directories of cfradial files into training, testing, and held-out validation sets, following the methodology of DesRosiers and Bell 2023. This is the three-way analogue of split_training_testing!: it additionally carves out a validation partition for unbiased final evaluation.
The default split is 72% training / 20% testing / 8% validation. As with the two-way split, this function assumes input directories contain only cfradial files following standard naming conventions (thus implicitly chronologically ordered), divides each case into several sections to limit temporal autocorrelation while maximizing variance, and softlinks the files into the destination directories.
An important note: always use absolute paths — relative paths break the symlinks.
Required Arguments
DIR_PATHS::Vector{String}: directories of cfradials to split. Each directory is treated as a distinct case.TRAINING_PATH::String: directory to softlink training files into.TESTING_PATH::String: directory to softlink testing files into.VALIDATION_PATH::String: directory to softlink the held-out validation files into.
The destination directories are removed and recreated, so any existing contents are discarded.
Ronin.remove_validation — Function
Function used to remove a given subset of the rows from a feature set so that they may be used for model validation/tuning.
Currently configured to utilize the 90/10 split described in DesRosiers and Bell 2023.
Required arguments
input_dataset::StringPath to h5 files containing model features
Optional keyword arguments
training_output::String = "train_no_validation_set.h5"Path to output training features with validation removed to
validation_output::String = "validation.h5"Path to output validation features to
remove_original::Bool = trueWhether or not to remove the original file described by the input_dataset path.
NOTE: the split is a deterministic stride — every 10th row (indices 1, 11, 21, …) goes to the validation set and the remainder to training. This is not a randomized split; if the feature matrix is ordered (e.g. grouped by sweep/time), the validation set inherits that structure. remove_original=true (the default) deletes the input file after writing the outputs, so pass distinct output paths. See docs/KNOWN_ISSUES.md for the v1.2.1 follow-up (optional seeded random split + path-collision guard).
Ronin.parse_directory — Function
parse_directory(dir_path::String) Parses through directory specified by dir_path and ensures that files start with the prefix specified by Ronin.RADAR_FILE_PREFIX
Feature calculation — convolution mode
The recommended feature regime: a kernel bank convolved over conv_variables.
Ronin.calculate_features_conv — Function
calculate_features_conv(config::ModelConfig, output_file::String;
QC_mask::Bool=false, mask_name::String="",
write_out::Bool=true, return_idxer::Bool=false)Convolution-mode feature calculation. Iterates over all files in config.input_path and computes convolution features for each sweep.
Ronin.ConvolutionKernel — Type
ConvolutionKernelHolds a named convolution kernel matrix for spatial feature computation.
Ronin.build_kernel_bank — Function
build_kernel_bank(kernel_sizes::Vector{Int})Build a bank of convolution kernels at the specified scales.
Returns a Vector{ConvolutionKernel} containing:
- Mean kernels at each scale (uniform weights, normalized)
- Laplacian 3x3 (edge/texture detection)
- Sobel-like range gradient 3x3
- Sobel-like azimuth gradient 3x3
- Gaussian kernels at scales >= 5
Ronin.compute_convolution_features — Function
compute_convolution_features(cfrad, conv_variables::Vector{String},
kernel_bank::Vector{ConvolutionKernel},
valid_mask::AbstractMatrix{Bool},
SIG_QUALITY_VAR::String)Compute the full convolution feature matrix for a single sweep.
For each variable in conv_variables x each kernel in kernel_bank, produces 2 columns:
- The convolved value
- The valid fraction (ISO equivalent)
Additionally appends scalar (non-convolved) physical features: AHT, ELV, RNG, NRG.
Returns (X::Matrix{Float32}, feature_names::Vector{String}) where X is (numrange * numtime) x numfeatures, with FILLVAL for invalid gates.
Ronin.masked_convolve — Function
masked_convolve(data, kernel, valid; neighbor_mask=valid)Compute a masked convolution over data using kernel.
validcontrols which center gates receive a computed value (others get FILL_VAL).neighbor_maskcontrols which neighbors contribute to the convolution (default: same asvalid).
Using a separate neighbor_mask enables met_prob-masked convolutions: compute features for all valid gates, but only let high-confidence neighbors contribute to the spatial statistics.
Returns (result, valid_fraction) where:
result[i,j]= weighted sum of valid neighbors / sum of weights at valid neighborsvalid_fraction[i,j]= fraction of kernel footprint that had valid data (ISO equivalent)
Missing/invalid gates contribute nothing. Edges are zero-padded (treated as invalid).
NOTE: the weighted_sum / weight_sum normalization (where weight_sum is the sum of absolute kernel weights over valid neighbors) is applied uniformly to every kernel, including the zero-sum differential kernels (laplacian, sobel_*). This is intentional and is the behavior validated against real-world data for v1.2.0: for interior gates with a full neighborhood it scales the differential response by sum(abs.(kernel)), and near edges / missing gates it renormalizes by the valid footprint. Changing this normalization would alter every edge/texture feature fed to the classifier, so it must not be "fixed" without re-validation. See the v1.2.1 backlog (docs/KNOWN_ISSUES.md) for the open question of separate smoothing vs. differential normalization.
Ronin.get_convolution_feature_count — Function
get_convolution_feature_count(conv_variables, kernel_bank; masked_conv_variables, masked_conv_kernel_bank)Return the total number of features that will be produced: (nvariables * nkernels * 2) + (nmaskedvariables * nmaskedkernels * 2) + 4 scalar features.
Feature calculation — legacy hand-tuned mode
The v1.1.0 hand-crafted predictor pipeline and its spatial reducers.
Ronin.calculate_features — Function
Function to process a set of cfradial files and produce input features for training/evaluating a model
Required arguments
input_loc::StringPath to input cfradial or directory of input cfradials
argument_file::StringPath to configuration file containing which features to calculate
output_file::StringPath to output calculated features to (generally ends in .h5)
HAS_INTERACTIVE_QC::BoolSpecifies whether or not the file(s) have already undergone a interactive QC procedure. If true, function will also output a Y array used to verify where interactive QC removed gates. This array is formed by considering where gates with non-missing data in raw scans (specified by remove_variable) are set to missing after QC is performed.
Optional keyword arguments
verbose::Bool=falseIf true, will print out timing information as each file is processed
REMOVE_LOW_SIG_QUALITY::Bool=falseIf true, will ignore gates with Normalized Coherent Power/Signal Quality Index below a threshold specified in RQCFeatures.jl
SIG_QUALITY_THRESHOLD::Float32 = .2Theshold at or below which to remove data
SIG_QUALITY_VAR::String = "NCP"Name of variable containing signal quality parameter
REMOVE_HIGH_PGG::Bool=falseIf true, will ignore gates with Probability of Ground Gate (PGG) values at or above a threshold specified in RQCFeatures.jl
PGG_THRESHOLDThreshold at or above which to remove data
QC_variable::String="VG"Name of variable in input NetCDF files that has been quality-controlled.
remove_variable::String="VV"Name of a raw variable in input NetCDF files. Used to determine where missing data exists in the input sweeps. Data at these locations will be removed from the outputted features.
replace_missing::Bool=falseWhether or not to replace MISSING values with FILL_VAL in spatial parameter calculations Default value: False
write_out::Bool=trueWhether or not to write features out to file
return_idxer::Bool = falseIf true, will return IDXER, where IDXER is a
weight_matrixes::Vector{Matrix{Union{Missing, Float32}}} = [(undef, 0,0)]Vector containing a weight matrix for every task in the argument file. For non-spatial parameters, the weights are discarded, and so dummy/placeholder matrixes may be used.
Ronin.process_single_file — Function
###Wrapper version of processsinglefile that allows user to specify a vector of weight matrixes ###In this case will also pass the tasks to complete as a vector ###weight_matrixes are also implicitly the window size
Returns:
-X::Matrix{Float32}: Matrix that is dimensioned (numgates x numfeatures) where numgates is the number of valid (non-missing, meeting NCP/PGG thresholds, non-masked) gates the function finds, and numfeatures is the number of features specified in the argument file to calculate.
-Y::Matrix{Bool} : IF HASINTERACTIVEQC == true, will return Y, array containing 1 if a datapoint was retained during interactive QC, and 0 otherwise. Dimensioned as (num_gates x 1)
-INDEXER::Vector{Bool} : Based on removevariable as described above, contains boolean array specifiying where in the scan features valid data and where does not. Will also contain false where values in `featuremask` are false.
Driver function that calculates a set of features from a single CFRadial file. Features are specified in file located at argfile_path.
Will return a tuple of (X, Y, indexer) where X is the features matrix, Y, a matrix containing the verification
- where human QC determined the gate was meteorological (value of 1), or non-meteorological (value of 0),
and indexer contains a vector of booleans describing which gates met basic quality control thresholds and thus are represented in the X and Y matrixes
Weight matrixes are specified in file header, or passed as explicit argument.
Required arguments
cfrad::NCDataset Input NCDataset containing radar scan variables
tasks::Vector{String} Vector of inpuit features to calculate
Optional keyword arguments
HAS_INTERACTIVE_QC::Bool = falseIf the scan has already had a human apply quality control to it, set to true. Otherwise, false
REMOVE_LOW_SIG_QUALITY::Bool = falseWhether or not to ignore gates that do not meet a minimum NCP/SQI threshold. If true, these gates will be set to false in indexer, and features/verification will not be calculated for them.
SIG_QUALITY_THRESHOLD::Float32 = .2Theshold at or below which to remove data
SIG_QUALITY_VARName of variable in cfradials containing information about signal quality
REMOVE_HIGH_PGG::Bool = falseWhether or not to ignore gates that exceed a given Probability of Ground Gate(PGG) threshold. If true, these gates will be set to false in indexer, and features/verification will not be calculated for them.
PGG_THRESHOLDThreshold at or above which to remove data
QC_variable::String = "VG"Name of a variable in input CFRadial file that has had QC applied to it already. Used to calculate verification Y matrix.
remove_variable::String = "VV" Name of raw variable in input CFRadial file that will be used to determine where missing gates exist in the sweep.
replace_missing::Bool = falseFor spatial parameters, whether or not to replace missings values with FILL_VAL
Returns:
-X::Matrix{Float32}: Matrix that is dimensioned (num_gates x num_features) where num_gates is the number of valid
(non-missing, meeting NCP/PGG thresholds, non-masked) gates the function finds, and num_features is the
number of features specified in the argument file to calculate.
-Y::Matrix{Bool} : IF HAS_INTERACTIVE_QC == true, will return Y, array containing 1 if a datapoint was retained
during interactive QC, and 0 otherwise. Dimensioned as (num_gates x 1)
-INDEXER::Vector{Bool} : Based on remove_variable as described above, contains boolean array specifiying
where in the scan features valid data and where does not. Will also contain `false` where
values in `feature_mask` are false.Ronin.get_task_params — Function
Function to parse a given task list Also performs checks to ensure that the specified tasks are able to be performed to the specified CFRad file
Parses input parameter file for use in outputting feature names to HDF5 file as attributes. NOTE: Cfradial-unaware. If one of the variables is specified incorrectly in the parameter file, will cause errors
Passthrough when tasks are already provided as a vector of strings
Ronin.get_num_tasks — Function
get_num_tasks(params_file; delimeter = ",")Count the number of predictor tasks declared in a legacy hand-tuned-mode configuration file.
params_file is a path to a config file (e.g. config.txt) where each non-comment line lists delimeter-separated predictor tasks such as STD(VEL),AVG(ZZ),PGG. Lines beginning with # are treated as comments and skipped; empty tokens are not counted.
Returns the total number of tasks as an Int. This is legacy-mode (task_mode = "") machinery only — convolution mode derives its own feature count via get_convolution_feature_count. A second method, get_num_tasks(tasks::Vector{String}), simply returns length(tasks).
Return the number of tasks when tasks are already provided as a vector of strings
Ronin.calc_avg — Function
calc_avg(var::Matrix; weights = avg_weights, window = avg_window)Windowed mean of a radar field — the AVG(var) spatial reducer used by both the convolution and legacy hand-tuned feature modes.
For each gate, the mean is taken over the surrounding window neighbourhood (default Ronin.avg_window) after element-wise multiplication by weights (default Ronin.avg_weights). Gates whose value is missing are excluded from each window; a window that is entirely missing yields Ronin.FILL_VAL. Borders are padded with missing. The global REPLACE_MISSING_WITH_FILL flag, when set, substitutes FILL_VAL for missing inputs before reducing.
Returns a Float32 matrix the same size as var.
Ronin.calc_std — Function
calc_std(var::AbstractMatrix; weights = std_weights, window = std_window)Windowed standard deviation of a radar field — the STD(var) spatial reducer used by both the convolution and legacy hand-tuned feature modes.
For each gate, the standard deviation is taken over the surrounding window neighbourhood (default Ronin.std_window) after element-wise multiplication by weights (default Ronin.std_weights). Gates whose value is missing are excluded from each window; a window that is entirely missing yields Ronin.FILL_VAL. Borders are padded with missing.
The Union{Missing, Float32} method preserves missing-aware reduction; the generic-matrix method honours the global REPLACE_MISSING_WITH_FILL flag and substitutes FILL_VAL for missing inputs before reducing.
Returns a Float32 matrix the same size as var.
Ronin.calc_iso — Function
`calc_iso(var::AbstractMatrix{Union{Missing, T}};
weights = iso_weights,
window = iso_window)`
Calculates quantity of adjacent gates that contain no data (are missing)
This will be modulated by weights, and to a lesser degree window. For example, a weight matrix
with ones along a specific column could be thought of as an isolation calcuation in range
for a sweep dimensioned as time x rangeRonin.airborne_ht — Function
airborne_ht(elevation_angle::Float32, antenna_range::Float32, aircraft_height::Float32)Earth-curvature-corrected height of a radar gate above mean sea level for an airborne (or elevated) platform.
Arguments
elevation_angle: beam elevation angle in degrees (positive above the horizon).antenna_range: slant range from the antenna to the gate in metres.aircraft_height: platform height above mean sea level in metres.
Returns
The gate height in kilometres, accounting for the curvature of the Earth (Ronin.EarthRadiusKm) using the standard 4/3-Earth-style geometric relation.
This is the per-gate kernel behind the AHT derived feature; calc_aht applies it across a full sweep grid.
Ronin.prob_groundgate — Function
prob_groundgate(elevation_angle, antenna_range, aircraft_height, azimuth)Geometric probability that a radar gate is contaminated by the ground (the PGG derived feature, per-gate kernel).
Uses the beam/ground intersection geometry of Testud et al. to decide whether the beam can physically reach the surface, then attenuates by a Gaussian beam pattern (half-power beamwidth Ronin.beamwidth) of the offset between the beam axis and the ground-grazing elevation.
Arguments
elevation_angle: beam elevation angle in degrees (negative points toward the ground).antenna_range: slant range to the gate in metres.aircraft_height: platform height above the surface in metres.azimuth: beam azimuth in degrees.
Returns
A probability in [0, 1] (1 = certainly ground), or missing if any input is missing. Returns 0 early when the gate geometrically cannot intersect the ground (range shorter than platform height, or elevation at/above the horizon).
calc_pgg applies this across a full sweep grid.
Training
Fitting Random Forest classifiers, single-pass and multi-pass.
Ronin.train_model — Function
Function to train a random forest model using a precalculated set of input and output features (usually output from calculate_features). Returns nothing.
Required arguments
input_h5::StringLocation of input features/targets. Input features are expected to have the name "X", and targets the name "Y". This should be taken care of automatically if they are outputs from calculate_features
model_location::StringPath to save the trained model out to. Typically should end in .jld2
Optional keyword arguments
verify::Bool = falseWhether or not to output a separate .h5 file containing the trained models predictions on the training set (Y_PREDICTED) as well as the targets for the training set (Y_ACTUAL)
verify_out::String="model_verification.h5"If verify, the location to output this verification to.
col_subset=:Set of columns from input_h5 to train model on. Useful if one wishes to train a model while excluding some features from a training set.
row_subset=:Set of rows from input_h5 to train on.
n_trees::Int = 21Number of trees in the Random Forest ensemble
max_depth::Int = 14Maximum node depth in each tree in RF ensemble
class_weights::Vector{Float32} = Vector{Float32}([1.,2.])Vector of class weights to apply to each observation. Should be 1 observation per sample in the input data files
train_model(X::Matrix, Y::Union{Matrix, Vector}, model_location::String;
verify=false, verify_out="model_verification.h5",
n_trees=21, max_depth=14,
class_weights=Float32[1., 2.], max_threads=Threads.nthreads())In-memory overload of train_model: fit a DecisionTree RandomForestClassifier directly on a feature matrix X and target vector Y instead of reading them from an HDF5 file.
Arguments
X: feature matrix (rows = gates/samples, columns = features).Y: target labels (1/true= meteorological,0/false= non-met), reshaped to a vector internally.model_location: path the fitted model is written to viasave_object.
Keywords
n_trees,max_depth: random-forest hyperparameters.class_weights: per-sample weight vector; must matchlength(Y)or it is ignored (with a warning) and uniform weights are used.verify/verify_out: whenverify, write predicted vs. true labels to theverify_outHDF5 file.max_threads: cap on fitting threads (defaults to all available).
Prints training accuracy and timing. The file-path method train_model(input_h5, model_location; ...) simply loads X/Y (with optional row_subset/col_subset) and delegates here.
Ronin.train_multi_model — Function
train_multi_model(config::ModelConfig)All-in-one function to take in a set of radar data, calculate input features, and train a chain of random forest models for meteorological/non-meteorological gate identification.
#Required arguments
config::ModelConfigStruct containing configuration info for model training
#Returns -None
Ronin.train_single_pass — Function
train_single_pass(config::ModelConfig, pass::Int)Train a single pass of the multi-pass cascade. This is the building block for pass-by-pass tuning workflows:
- Pass 1: trains on all data (no mask required)
- Pass 2+: requires masks from prior passes to exist in the CfRadial files (written by
train_multi_modelorregenerate_masks)
After training, if this is not the final pass, saves met_prob predictions to CfRadials and generates the mask for the next pass.
Returns (X, Y) — the feature matrix and labels used for training.
Multi-pass masking
Generating and regenerating the inter-pass met-prob masks.
Ronin.generate_pass_masks — Function
generate_pass_masks(config::ModelConfig, pass::Int; data_path::String="")Run inference with the trained model for pass and write met_prob_pass_<pass> and mask_pass_<pass+1> to all CfRadial files. This bridges an existing trained pass to the next pass without retraining.
Use this when you have a trained Pass 1 model and want to prepare data for Pass 2 training, or any pass N → pass N+1 transition.
If data_path is provided, it overrides config.input_path (useful for generating masks on both training and testing sets).
The mask threshold is taken from config.met_probs[pass].
Ronin.regenerate_masks — Function
regenerate_masks(config::ModelConfig, pass::Int, met_probs_threshold::Tuple{Float32, Float32})Regenerate the mask for pass+1 using saved met_prob_pass_<pass> fields in CfRadials. This avoids re-running the model — it reads the previously-saved met_prob predictions and applies the new threshold to create an updated mask.
The metprob fields must have been written by a prior `trainmulti_model` call.
Feature importance / selection
Permutation and RF-native importance, and feature subsetting.
Ronin.compute_importance — Function
compute_importance(config::ModelConfig)Compute permutation-based feature importance for each pass using existing trained models and cached feature files. Does NOT retrain — loads the model from the JLD2 file and features from the HDF5 file.
This is the recommended way to compute importance after initial training (Step 2). It avoids redundant retraining and supports configurable n_importance_repeats and importance_subsample_fraction from the config.
Ronin.get_feature_importance — Function
Uses L1 regression with a variety of λ penalty values to determine the most useful features for
input to the random forest model.
Required Input
input_file_path::StringPath to .h5 file containing model training features under ["X"] parameter, and model targets under ["Y"] parameter. Also expects the h5 file to contain an attribute known as Parameters containing abbreviations for the feature types
λs::Vector{Float32}Vector of values used to vary the strength of the penalty term in the regularization.
Optional Keyword Arguments
pred_threshold::Float32Minimum cofidence level for binary classifier when predicting
Returns
Returns a DataFrame with each row containing info about a regression for a specific λ, the values of the regression coefficients for each input feature, and the Root Mean Square Error of the resultant regression.
Ronin.select_features — Function
select_features(importance_scores::Vector{Float64}, threshold_fraction::Float64)Given RF feature importance scores, return indices of features whose importance is above threshold_fraction of the maximum importance.
Used during training to prune low-value features. The returned indices are saved with the model for use at inference time.
Ronin.compute_rf_feature_importance — Function
compute_rf_feature_importance(model, X::Matrix{Float32}, Y::Vector;
n_repeats::Int=3, subsample_fraction::Float64=1.0)Compute permutation-based feature importance for a random forest ensemble. For each feature, randomly shuffle that column and measure the drop in accuracy. Higher drop = more important feature.
Performance optimizations:
- Features are evaluated in parallel using
Threads.@threads subsample_fraction< 1.0 evaluates on a random subset (e.g., 0.5 = 50% of samples) This is statistically stable for large datasets and provides significant speedup.- Each thread works on its own copy of the subsampled data to avoid race conditions.
Returns a Vector{Float64} of importance scores (accuracy drop), one per feature.
Hyperparameter tuning
Sweeping RF hyperparameters and inter-pass thresholds.
Ronin.run_hypertuning — Function
run_hypertuning(config, pass, training_path, testing_path; ...)Sweep RF hyperparameters (ntrees, maxdepth) for a single pass, evaluating on the testing set with AUC-ROC as the primary metric. Features are computed once, then the sweep trains and evaluates in-memory for each combination.
The caller should set up config.conv_variables, config.selected_features, and masked conv fields for the target pass before calling (e.g., via configure_pass!).
Returns (results=Vector{NamedTuple}, best=NamedTuple, best_model_path=String).
Ronin.sweep_pass2_met_probs — Function
sweep_pass2_met_probs(config::ModelConfig, testing_path::String;
met_prob_low_grid, met_prob_high_grid,
use_met_prob_as_feature::Bool=true,
sweep_inference::Bool=true,
infer_low_grid, infer_high_grid,
nmd_target::Float32=0.99f0,
secondary_metric::Symbol=:hss)Sweep met_prob thresholds for Pass 2 of a multi-pass cascade.
Pass 1 must already be trained (its model and met_prob_pass_1 fields must exist in the CfRadial files). For each threshold combination:
- Regenerates the Pass 1→2 mask from saved
met_prob_pass_1fields - Recalculates features on the filtered subset (spatial features change)
- Retrains Pass 2 on the "hard" data
- Evaluates the full cascade on the testing set
If sweep_inference=true, also sweeps inference thresholds for the best training configuration (cheap — no retraining needed).
Returns a DataFrame of results (requires DataFrames to be loaded).
Prediction & QC
Applying a trained cascade to radar data. See Choosing a QC Entry Point for which to use.
Ronin.composite_prediction — Function
composite_prediction(config::ModelConfig; write_features_out::Bool=false, feature_outfile::String="placeholder.h5", return_probs::Bool=false)Passes feature data through a model or series of models and returns model classifications. Applies configuration such as masking and basic QC (high PGG/low NCP) specified by config
Optional keyword arguments
write_predictions_out::Bool = falseIf true, will write the predictions to disk
prediction_outfile::String = "model_predictions.h5"Location to write predictions to on disk
return_probs::Bool = falseIf set to true, will return probability of meteorological gate for all gates. More detail below.
QC_mode::Bool = falseIf set to true, the function will instead be used to apply quality control to a (set of) scan(s)
Returns
predictions::Vector{Bool}Model classifications for gates that passed basic quality control thresholdsvalues::BitVectorVerification gates correspondant to predictionsinit_idxers::Vector{Vector{Float32}}Information about where original radar data did/did not meet basic quality control thresholds. Each vector contains a flattened vector describing whether or not a given gate was predicted on.total_met_probs::Vector{Float32}If kewyword argument returnprobs is set totrue, then `totalmet_probs` will be returned. Each entry into this vector corresponds to the gate represented by predictions and values, and denotes the fraction of trees in the random forest that classified the gate as meteorological.All values returned will be only those that passed quality control checks in the first pass of the model minimum NCP / PGG thresholds. In order to reconstruct a scan, user would need to use the values in the returned indexers.
Ronin.composite_QC — Function
composite_QC(config::ModelConfig, files::Vector{String},
models::Vector{Ronin.DecisionTree.RandomForestClassifier},
metadata::Vector{<:NamedTuple})
composite_QC(config::ModelConfig, files::Vector{String},
models::Vector{Ronin.DecisionTree.RandomForestClassifier})
composite_QC(config::ModelConfig, files::Vector{String})Streaming flavor of composite_prediction used to QC sweeps in a realtime setup. Operates on an explicit list of CfRadial files (not config.input_path), runs each pass of the cascade in turn, and writes *<QC_SUFFIX> fields back into each file via QC_scan.
Supports both task_mode = "" (hand-tuned task_paths) and task_mode = "convolution". In convolution mode, per-model metadata (selected_features, conv_variables, masked_conv_*) is read from each model_output_paths JLD2 file; the supplied models vector is used only for predict_proba.
The 4-arg form accepts pre-loaded metadata — a vector of NamedTuples as returned by load_model_with_metadata — and is intended for chunked pipelines (e.g. Sparrow.jl) that cache model and metadata per-worker so the JLD2 reads are paid once rather than per call. The 3-arg form loads the metadata internally and forwards; the 2-arg form loads both models and metadata internally — convenient for operational pipelines where the snippet is just composite_QC(load_config(path), files).
Throws ArgumentError if models or metadata length does not match length(config.model_output_paths).
composite_QC(config::ModelConfig, files::Vector{String},
models::Vector{Ronin.DecisionTree.RandomForestClassifier})Convenience 3-arg method that loads per-model metadata from config.model_output_paths internally and forwards to the 4-arg form. Preserves the v1.1 calling shape; equivalent to:
metadata = [load_model_with_metadata(p, config.task_mode) for p in config.model_output_paths]
composite_QC(config, files, models, metadata)composite_QC(config::ModelConfig, files::Vector{String})Convenience 2-arg method that loads both the random forests and their metadata from config.model_output_paths internally and forwards to the 4-arg form. Each JLD2 file is read once (not twice as the previous load_model + load_model_with_metadata sequence did).
Ronin.QC_scan — Function
QC_scan(input_cfrad::String, features::Matrix{Float32}, indexer::Vector{Bool}, config::ModelConfig, iter::Int64)
QC_scan(config::ModelConfig)Applies trained composite model to data within scan or set of scans. Will set gates the model deems to be non-meteorological to MISSING, including gates that do not meet initial basic quality control thresholds. Wrapper around composite_prediction.
Returns: None
Ronin.write_field — Function
write_field(filepath::String, fieldname::String, NEW_FIELD, overwrite::Bool = true, attribs::Dict = Dict(), dim_names::Tuple = ("range", "time"), verbose::Bool=true)
Helper function to write/overwrite a 2D field to a netCDF file
## Required arguments
* `filepath::String` Name of netCDF file to write data to
* `fieldname::String` What to call the data in the netCDF
* `NEW_FIELD` Data dimensioned by `dim_names` to write to netCDFEvaluation & inspection
Scoring models and inspecting saved model files.
Ronin.evaluate_model — Function
`evaluate_model(predictions::Vector{Bool}, targets::Vector{Bool})`
Given a vector of predictions and targets, calculates various scores and returns them in the order of
* `prec_score::Float32` -> Precision Score, defined as number of true positives divided by sum of true positives and false positives
* `recall::Float32` Recall, defined as number of true positives divided by sum of true positives and false negatives
* `f1::Float32` F1 score
* `true_positives::Int` Number of true positives
* `false_positives::Int` Number of false positives
* `true_negatives::Int` Number of true negatives
* `false_negatives::Int` Number of false negatives
* `num_gates::INt` Total number of classifications`evaluate_model(config::ModelConfig)`
Returns a row of a DataFrame with a variety of metrics about a given model.
#Arguments
```julia
config::ModelConfig
```
Struct containing information about model training
```julia
models_trained::Bool = false
```Ronin.run_evaluation — Function
run_evaluation(config::ModelConfig, dataset_name::String, dataset_path::String,
met_probs::Vector{Tuple{Float32, Float32}};
prediction_outfile::String="", verbose::Bool=true)Run composite_prediction on a dataset and compute classification metrics.
Temporarily sets config.input_path and config.met_probs for the evaluation, then restores them. Returns a NamedTuple with all metrics.
Ronin.get_contingency — Function
get_contingency(predictions::Vector{Bool}, verificaiton::Vector{Bool}; normalize::Bool = true)
Utility to return a DataFrame with the contingency matrix for a binary classificaiton model.
## Required Arguments
* `predictions::Vector{Bool}` Model predicted classes
* `verification::Vector{Bool}` Ground Truth Classes
## Optional Arguments
* `normalize::Bool = true` Whether or not to return the normalized form of the contingency matrix
## Return
* `DataFrame` containing contingency matrixRonin.compute_auc_roc — Function
compute_auc_roc(probabilities::Vector{Float32}, labels::Vector{<:Integer})Compute Area Under the ROC Curve from predicted probabilities and binary labels. Uses the trapezoidal rule on (FPR, TPR) points at each distinct threshold.
Labels should be 1 (positive/meteorological) or 0 (negative/non-meteorological). Returns AUC as Float64 in [0, 1], or NaN for empty input, 0.5 for single-class input.
Ronin.met_prob_histogram — Function
met_prob_histogram(config::ModelConfig, pass::Int; data_path::String="",
met_probs_threshold::Union{Nothing, Tuple{Float32,Float32}}=nothing)Read saved met_prob_pass_<pass> from CfRadial files and print a histogram of the probability distribution. Uses fine bins near 0 and 1 (where threshold choices are most sensitive) and coarser bins in the middle.
If met_probs_threshold is provided, marks the threshold positions and prints a summary of how many gates fall into each category. Otherwise shows the raw distribution to help choose thresholds.
Prints cumulative percentages from each tail to help identify where thresholds capture the most confident classifications.
Ronin.characterize_misclassified_gates — Function
characterize_misclassified_gates(config::ModelConfig; model_pretrained::Bool = true, features_precalculated::Bool = true)
Function used to apply composite model to a set of gates, returning information about gate classifications and their associated input features
Required inputs
config::ModelConfigModel configuration object containing setup information.
Optional Inputs
model_pretrained::Bool = trueModel training in this function not currently implemented, setting to false with untrained models will result in errors.
features_precalculated::Bool = trueWhether or not the input features for the model have already been written to disk.
Not currently implemented.
Returns
Vector of dataframes (one DataFrame for each model "pass"). DataFrames will only contain information about gates reciving their final classification during that pass of the model. That is, if a gate exceeds the met_probs thresholds and is not passed on to the next pass, it will be represented in the DataFrame corresponding to that present pass of the model.
Ronin.inspect_model_configuration — Function
inspect_model_configuration(path::String; io::IO=stdout)Pretty-print the contents of a JLD2 model file without exposing raw model weights. Shows feature names, importances, selected features, and any other saved metadata. Pass io keyword to redirect output (e.g., to an IOBuffer for testing).
Ronin.load_model — Function
load_model(path::String, task_mode::String)Load a trained model from a JLD2 file, handling both storage formats:
save_objectformat (single key"single_stored_object")JLD2.jldsaveformat (keyed:"model","selected_features", etc.)
Returns the model object regardless of which format was used. The task_mode argument is accepted for API compatibility but ignored; layout is inferred from the file's keys.
The return is intentionally untyped: a model file may hold either a DecisionTree.RandomForestClassifier (saved by train_model) or a raw DecisionTree.Ensemble (e.g. built directly via build_forest), so this is polymorphic over the saved representation. A comprehension over model_output_paths therefore infers Vector{Any}; callers that need a concrete Vector{RandomForestClassifier} (to match the composite_QC / composite_prediction signatures) should annotate the comprehension's element type, e.g. RandomForestClassifier[load_model(p, mode) for p in paths].
Ronin.load_model_with_metadata — Function
load_model_with_metadata(path::String, task_mode::String)Load a trained model and its metadata from a JLD2 file. Accepts either storage layout (single-key save_object or multi-key JLD2.jldsave). task_mode is kept for API compatibility but is ignored; layout is inferred from the file's keys.
Returns a NamedTuple with fields:
model: the trained RF ensembleselected_features: Vector{Int} of feature indices the model was trained on (empty = all features)recommended_features: Vector{Int} of features recommended by importance analysis (empty if not computed)feature_names: Vector{String} of feature names (empty if not saved)importances: Vector{Float64} of feature importance scores (empty if not saved)
Utilities
Ronin.compute_balanced_class_weights — Function
Helper function to compute balanced weights according to the
algoirthm described in https://scikit-learn.org/stable/modules/generated/sklearn.utils.class_weight.compute_class_weight.html