Skip to content

Commit de5c432

Browse files
authored
Merge pull request PecanProject#4012 from anshul23102/fix/align-met-rep-each-length
fix(align.met): use length(stamps.hr) instead of stamps.hr as the rep() each argument
2 parents 3a8c485 + 86275ea commit de5c432

3 files changed

Lines changed: 86 additions & 1 deletion

File tree

modules/data.atmosphere/NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# PEcAn.data.atmosphere 1.9.1.9000
2+
3+
## Fixed
4+
5+
* `align.met()` now correctly calculates output timesteps in cases where the source data is at a coarser time step than the training data and `align == "repeat"` (#4012, @anshul23102).
6+
17
# PEcAn.data.atmosphere 1.9.1
28

39
## Added

modules/data.atmosphere/R/align_met.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ align.met <- function(train.path, source.path, yrs.train=NULL, yrs.source=NULL,
428428
dat.tem <- ncdf4::ncvar_get(ncT, v)
429429

430430
if(align=="repeat"){ # if we need to coerce the time step to be repeated to match temporal resolution, do it here
431-
dat.tem <- rep(dat.tem, each=stamps.hr)
431+
dat.tem <- rep(dat.tem, each=length(stamps.hr))
432432
}
433433
df.tem <- matrix(rep(dat.tem, n.src), ncol=1, byrow=F)
434434

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## Tests for align.met()
2+
##
3+
## The bug fixed in this PR (line 431, ensemble source path):
4+
## rep(dat.tem, each = stamps.hr)
5+
## where stamps.hr is a numeric *vector*. R silently takes stamps.hr[1]
6+
## and truncates to an integer.
7+
##
8+
## For hourly training data, stamps.hr = c(0.5) (the first centred hour stamp).
9+
## Truncating 0.5 to 0 makes rep() return an empty vector, so dat.source
10+
## ends up with zero rows -- silently discarding all source data.
11+
##
12+
## Fix: rep(dat.tem, each = length(stamps.hr))
13+
## The single-time-series source path (line 304) already used length() correctly.
14+
15+
## Helper: create a minimal single-variable NetCDF with a given number of
16+
## time steps placed in outdir/filename. Time dimension is in fractional days
17+
## since 2001-01-01, matching the step size implied by n_time.
18+
make_align_nc <- function(n_time, outdir, filename) {
19+
time_dim <- ncdf4::ncdim_def(
20+
name = "time",
21+
units = "days since 2001-01-01",
22+
vals = seq(0, by = 1 / (n_time / 365), length.out = n_time)
23+
)
24+
temp_var <- ncdf4::ncvar_def(
25+
name = "air_temperature",
26+
units = "K",
27+
dim = list(time_dim),
28+
missval = -9999
29+
)
30+
nc <- ncdf4::nc_create(file.path(outdir, filename), vars = list(air_temperature = temp_var))
31+
on.exit(ncdf4::nc_close(nc), add = TRUE)
32+
ncdf4::ncatt_put(nc, 0, "description", "synthetic data for align.met test")
33+
ncdf4::ncvar_put(nc, temp_var, vals = seq(280, length.out = n_time, by = 0.01))
34+
invisible(file.path(outdir, filename))
35+
}
36+
37+
test_that("align.met ensemble source path produces non-empty source data (bug: each=0 from stamps.hr truncation)", {
38+
train_dir <- withr::local_tempdir()
39+
source_dir <- withr::local_tempdir()
40+
41+
## Hourly training (8760 steps) produces stamps.hr[1] == 0.5, intentionally
42+
## chosen so that any truncation of the step count to integer yields 0.
43+
make_align_nc(n_time = 8760, outdir = train_dir, filename = "2001.nc")
44+
45+
## Source: daily (365 steps), placed inside an ensemble subfolder.
46+
ens_dir <- file.path(source_dir, "ens001")
47+
dir.create(ens_dir)
48+
make_align_nc(n_time = 365, outdir = ens_dir, filename = "2001.nc")
49+
50+
result <- align.met(
51+
train.path = train_dir,
52+
source.path = source_dir,
53+
n.ens = 1,
54+
seed = 20260602
55+
)
56+
57+
## 8760 hourly training rows; 365 source rows (one per day, repeated once each).
58+
expect_equal(nrow(result$dat.train$air_temperature), 8760)
59+
expect_equal(nrow(result$dat.source$air_temperature), 365)
60+
})
61+
62+
test_that("align.met single-series source matches training row count when already aligned", {
63+
train_dir <- withr::local_tempdir()
64+
source_dir <- withr::local_tempdir()
65+
66+
## Both training and source at the same 3-hourly resolution (2920 steps for 2001).
67+
make_align_nc(n_time = 2920, outdir = train_dir, filename = "2001.nc")
68+
make_align_nc(n_time = 2920, outdir = source_dir, filename = "2001.nc")
69+
70+
result <- align.met(
71+
train.path = train_dir,
72+
source.path = source_dir,
73+
n.ens = 1,
74+
seed = 20260602
75+
)
76+
77+
expect_equal(nrow(result$dat.source$air_temperature),
78+
nrow(result$dat.train$air_temperature))
79+
})

0 commit comments

Comments
 (0)