Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions GRF_Representativeness/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Local data configuration
MyWRFdata.mat

# MATLAB artifacts
*.asv
*.autosave

# macOS / editor
.DS_Store
27 changes: 27 additions & 0 deletions GRF_Representativeness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# GRF_Representativeness

MATLAB project scaffold for evaluating representativeness of forecast days using KS-distance based selection, empirical alternatives, and UTCI impact analysis.

## Quick start
1. Open MATLAB in this folder.
2. Copy your local data configuration into `MyWRFdata.mat` (kept out of git by default).
3. Run:
```matlab
main
```

## Repository layout
- `config/`: path, parameter, and plotting configuration.
- `data_io/`: loading/saving interfaces for WRF, station, and intermediate data.
- `core/`: reusable methods (KS distance, UTCI, CV, perturbation).
- `stream1_forecast_based/`: forecast-driven representativeness workflow.
- `stream2_empirical_methods/`: empirical heuristics and comparison workflow.
- `stream3_utci_impact/`: UTCI-focused impact workflow.
- `figures/`: figure scripts and common save helper.
- `results/`: output folders by stream and final tables.
- `intermediate/`: cached intermediates.
- `tests/`: basic unit/smoke test scripts.

## Notes
- This scaffold provides function signatures and minimal defaults to accelerate implementation.
- Replace placeholder logic with your project-specific algorithms and data handling.
11 changes: 11 additions & 0 deletions GRF_Representativeness/config/config_parameters.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function params = config_parameters()
%CONFIG_PARAMETERS Set default analysis parameters.

params.random_seed = 42;
params.ks_alpha = 0.05;
params.cv_folds = 5;
params.representative_day_count = 10;
params.ensemble_perturbation_std = 0.1;

rng(params.random_seed);
end
15 changes: 15 additions & 0 deletions GRF_Representativeness/config/config_paths.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function paths = config_paths()
%CONFIG_PATHS Define project directory paths.

repoRoot = fileparts(fileparts(mfilename('fullpath')));
paths.repo_root = repoRoot;
paths.config_root = fullfile(repoRoot, 'config');
paths.data_io_root = fullfile(repoRoot, 'data_io');
paths.core_root = fullfile(repoRoot, 'core');
paths.results_root = fullfile(repoRoot, 'results');
paths.intermediate_root = fullfile(repoRoot, 'intermediate');
paths.figures_root = fullfile(repoRoot, 'figures');

% Optional local file with user-specific paths.
paths.local_data_file = fullfile(repoRoot, 'MyWRFdata.mat');
end
8 changes: 8 additions & 0 deletions GRF_Representativeness/config/config_plot.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function plotCfg = config_plot()
%CONFIG_PLOT Plotting defaults.

plotCfg.font_size = 11;
plotCfg.line_width = 1.5;
plotCfg.colormap = parula(64);
plotCfg.save_format = 'png';
end
13 changes: 13 additions & 0 deletions GRF_Representativeness/core/compute_distribution.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function dist = compute_distribution(x, nBins)
%COMPUTE_DISTRIBUTION Compute histogram-based distribution summary.

arguments
x (:,1) double
nBins (1,1) double {mustBePositive,mustBeInteger} = 20
end

[counts, edges] = histcounts(x, nBins, 'Normalization', 'probability');
dist.counts = counts;
dist.edges = edges;
dist.bin_centers = edges(1:end-1) + diff(edges)/2;
end
20 changes: 20 additions & 0 deletions GRF_Representativeness/core/compute_ks_distance.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function ks = compute_ks_distance(x, y)
%COMPUTE_KS_DISTANCE Compute two-sample KS distance.

arguments
x (:,1) double
y (:,1) double
end

x = sort(x(~isnan(x)));
y = sort(y(~isnan(y)));

if isempty(x) || isempty(y)
error('Inputs x and y must both contain at least one non-NaN value.');
end

vals = unique([x; y]);
Fx = arrayfun(@(v) mean(x <= v), vals);
Fy = arrayfun(@(v) mean(y <= v), vals);
ks = max(abs(Fx - Fy));
end
13 changes: 13 additions & 0 deletions GRF_Representativeness/core/compute_utci.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function utci = compute_utci(tAir, rh, wind, mrt)
%COMPUTE_UTCI Simplified UTCI proxy calculation.
% NOTE: Replace with the official UTCI polynomial for production use.

arguments
tAir (:,:) double
rh (:,:) double
wind (:,:) double
mrt (:,:) double
end

utci = tAir + 0.2*(mrt - tAir) - 0.02*(100-rh) - 0.7*wind;
end
20 changes: 20 additions & 0 deletions GRF_Representativeness/core/cross_validation_split.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function folds = cross_validation_split(nSamples, k)
%CROSS_VALIDATION_SPLIT Create k-fold index sets.

arguments
nSamples (1,1) double {mustBePositive,mustBeInteger}
k (1,1) double {mustBePositive,mustBeInteger}
end

indices = randperm(nSamples);
foldSize = ceil(nSamples/k);
folds = cell(k,1);

for i = 1:k
lo = (i-1)*foldSize + 1;
hi = min(i*foldSize, nSamples);
testIdx = indices(lo:hi);
trainIdx = setdiff(indices, testIdx);
folds{i} = struct('train', trainIdx, 'test', testIdx);
end
end
10 changes: 10 additions & 0 deletions GRF_Representativeness/core/generate_ensemble_perturbation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function perturbed = generate_ensemble_perturbation(baseField, sigma)
%GENERATE_ENSEMBLE_PERTURBATION Add Gaussian perturbation to base field.

arguments
baseField (:,:) double
sigma (1,1) double {mustBeNonnegative} = 0.1
end

perturbed = baseField + sigma .* randn(size(baseField));
end
11 changes: 11 additions & 0 deletions GRF_Representativeness/core/select_representative_days.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function idx = select_representative_days(scores, k)
%SELECT_REPRESENTATIVE_DAYS Select indices of best representative days.

arguments
scores (:,1) double
k (1,1) double {mustBePositive,mustBeInteger}
end

[~, order] = sort(scores, 'ascend');
idx = order(1:min(k, numel(order)));
end
9 changes: 9 additions & 0 deletions GRF_Representativeness/data_io/load_preprocessed_mat.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function S = load_preprocessed_mat(filePath)
%LOAD_PREPROCESSED_MAT Load intermediate MAT-file data.

arguments
filePath (1,:) char
end

S = load(filePath);
end
9 changes: 9 additions & 0 deletions GRF_Representativeness/data_io/load_station_data.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function stationData = load_station_data(filePath)
%LOAD_STATION_DATA Load station observations.

arguments
filePath (1,:) char
end

stationData = readtable(filePath);
end
12 changes: 12 additions & 0 deletions GRF_Representativeness/data_io/load_wrf_field.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function field = load_wrf_field(filePath, variableName)
%LOAD_WRF_FIELD Load a variable from a WRF data file.

arguments
filePath (1,:) char
variableName (1,:) char
end

% Placeholder implementation. Replace with ncread/readmatrix logic as needed.
S = load(filePath, variableName);
field = S.(variableName);
end
10 changes: 10 additions & 0 deletions GRF_Representativeness/data_io/save_intermediate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function save_intermediate(filePath, dataStruct)
%SAVE_INTERMEDIATE Save struct data to a MAT file.

arguments
filePath (1,:) char
dataStruct (1,1) struct
end

save(filePath, '-struct', 'dataStruct');
end
7 changes: 7 additions & 0 deletions GRF_Representativeness/figures/fig01_framework.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function fig01_framework()
%FIG01_FRAMEWORK Placeholder framework diagram figure.

figure;
text(0.1, 0.5, 'GRF Representativeness Framework', 'FontSize', 14);
axis off;
end
9 changes: 9 additions & 0 deletions GRF_Representativeness/figures/fig02_spatial_map.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function fig02_spatial_map(field)
%FIG02_SPATIAL_MAP Plot a spatial field.

figure;
imagesc(field);
colorbar;
title('Spatial Map');
axis image;
end
9 changes: 9 additions & 0 deletions GRF_Representativeness/figures/fig03_ks_comparison.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function fig03_ks_comparison(scoresA, scoresB)
%FIG03_KS_COMPARISON Compare two KS score sets.

figure;
plot(sort(scoresA), 'LineWidth', 1.5); hold on;
plot(sort(scoresB), 'LineWidth', 1.5);
legend('Method A', 'Method B');
title('KS Comparison');
end
8 changes: 8 additions & 0 deletions GRF_Representativeness/figures/fig04_utci_impact.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function fig04_utci_impact(utciValues)
%FIG04_UTCI_IMPACT Plot UTCI distribution.

figure;
histogram(utciValues(:), 20);
title('UTCI Impact Distribution');
xlabel('UTCI'); ylabel('Frequency');
end
14 changes: 14 additions & 0 deletions GRF_Representativeness/figures/save_figure.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function save_figure(figHandle, outPath)
%SAVE_FIGURE Save figure to disk, creating folder when needed.

arguments
figHandle (1,1) matlab.ui.Figure
outPath (1,:) char
end

outDir = fileparts(outPath);
if ~isempty(outDir) && ~exist(outDir, 'dir')
mkdir(outDir);
end
saveas(figHandle, outPath);
end
21 changes: 21 additions & 0 deletions GRF_Representativeness/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
%% main.m
% Entry point for the GRF_Representativeness workflow.

clear; clc;

addpath(genpath(fileparts(mfilename('fullpath'))));

paths = config_paths();
params = config_parameters();
plotCfg = config_plot(); %#ok<NASGU>

fprintf('Running GRF_Representativeness pipeline...\n');

stream1Results = run_stream1(paths, params);
stream2Results = run_stream2(paths, params, stream1Results);
stream3Results = run_stream3(paths, params, stream1Results, stream2Results);

save(fullfile(paths.results_root, 'final_tables', 'pipeline_summary.mat'), ...
'stream1Results', 'stream2Results', 'stream3Results');

fprintf('Pipeline complete. Results saved in %s\n', paths.results_root);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function daily = build_daily_summary(paths, params)
%BUILD_DAILY_SUMMARY Build daily summaries from forecast data.

daily = struct();
daily.info = 'Placeholder daily summary';
daily.params = params;
daily.generated_at = datetime('now');

outFile = fullfile(paths.intermediate_root, 'daily_summaries', 'stream1_daily_summary.mat');
save(outFile, 'daily');
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function results = evaluate_forecast_representativeness(daily, params)
%EVALUATE_FORECAST_REPRESENTATIVENESS Evaluate representativeness scores.

n = params.representative_day_count * 3;
scores = rand(n,1);
selected = select_representative_days(scores, params.representative_day_count);

results = struct('daily', daily, 'scores', scores, 'selected_days', selected);
end
7 changes: 7 additions & 0 deletions GRF_Representativeness/stream1_forecast_based/run_stream1.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function results = run_stream1(paths, params)
%RUN_STREAM1 Execute stream 1 (forecast-based workflow).

daily = build_daily_summary(paths, params);
results = evaluate_forecast_representativeness(daily, params);
results.summary = summarize_stream1_results(results);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function summary = summarize_stream1_results(results)
%SUMMARIZE_STREAM1_RESULTS Summarize stream 1 outputs.

summary = table(numel(results.selected_days), mean(results.scores), ...
'VariableNames', {'n_selected','mean_score'});
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function empirical = apply_empirical_heuristics(stream1Results, params)
%APPLY_EMPIRICAL_HEURISTICS Create heuristic ranking of days.

scores = stream1Results.scores;
empirical.rank = tiedrank(scores + 0.01*randn(size(scores)));
empirical.top = find(empirical.rank <= params.representative_day_count);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function comparison = compare_with_ks_method(empirical, stream1Results)
%COMPARE_WITH_KS_METHOD Compare empirical top days with KS-based selection.

ksDays = stream1Results.selected_days(:);
empDays = empirical.top(:);
overlap = intersect(ksDays, empDays);

comparison.overlap_count = numel(overlap);
comparison.overlap_fraction = numel(overlap) / max(1, numel(ksDays));
comparison.overlap_days = overlap;
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function results = run_stream2(paths, params, stream1Results)
%RUN_STREAM2 Execute stream 2 (empirical methods workflow).

empirical = apply_empirical_heuristics(stream1Results, params);
comparison = compare_with_ks_method(empirical, stream1Results);
results = summarize_stream2_results(empirical, comparison);

save(fullfile(paths.results_root, 'stream2', 'stream2_results.mat'), 'results');
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function results = summarize_stream2_results(empirical, comparison)
%SUMMARIZE_STREAM2_RESULTS Build stream 2 summary payload.

results = struct();
results.empirical = empirical;
results.comparison = comparison;
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function utciData = compute_utci_for_selected_days(stream1Results, params)
%COMPUTE_UTCI_FOR_SELECTED_DAYS Compute UTCI for selected days.

n = numel(stream1Results.selected_days);
gridSize = [10, 10];

tAir = 30 + randn([gridSize n]);
rh = 50 + 20*rand([gridSize n]);
wind = 2 + rand([gridSize n]);
mrt = tAir + 5*randn([gridSize n]);

utci = compute_utci(tAir, rh, wind, mrt);
utciData = struct('utci', utci, 'n', n, 'params', params);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function bias = quantify_utci_bias(utciData, stream2Results)
%QUANTIFY_UTCI_BIAS Quantify UTCI bias metrics.

utci = utciData.utci;
bias.mean_utci = mean(utci, 'all');
bias.std_utci = std(utci, 0, 'all');
bias.empirical_overlap_fraction = stream2Results.comparison.overlap_fraction;
end
9 changes: 9 additions & 0 deletions GRF_Representativeness/stream3_utci_impact/run_stream3.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function results = run_stream3(paths, params, stream1Results, stream2Results)
%RUN_STREAM3 Execute stream 3 (UTCI impact workflow).

utci = compute_utci_for_selected_days(stream1Results, params);
bias = quantify_utci_bias(utci, stream2Results);
results = summarize_stream3_results(utci, bias);

save(fullfile(paths.results_root, 'stream3', 'stream3_results.mat'), 'results');
end
Loading