Skip to content

toolTimeSpline Bug with Irregular Years #265

@mscrawford

Description

@mscrawford

In R/toolTimeSpline.R:37, the function calls smooth.spline(x, df = dof, ...) where x contains only the y-values (data values), not providing the actual year values. This causes smooth.spline() to assume the data points are at equally-spaced positions (1, 2, 3, 4, 5...) instead of their actual year values.

Demonstration

With years [2000, 2001, 2002, 2003, 2050] and values [100, 105, 110, 115, 300]:

  • Current (incorrect) behavior: Treats data as if at positions 1-5, producing [64.0, 105.0, 146.0, 187.0, 228.0]
  • Correct behavior: Should account for the 47-year gap, producing [101.5, 105.5, 109.5, 113.4, 300.1]

The current implementation completely ignores the large time gap between 2003 and 2050, resulting in fundamentally wrong interpolation.


Reproducible example:

# Minimal Reproducible Example: toolTimeSpline Bug with Irregular Years
# =======================================================================

library(madrat)
library(magclass)

# Create simple test data with irregular year spacing
# Years: 2000, 2001, 2002, 2003, 2050 (note the 47-year gap!)
# Values: 100, 105, 110, 115, 300
test_data <- new("magpie",
                 .Data = structure(c(100, 105, 110, 115, 300),
                                 .Dim = c(1L, 5L, 1L),
                                 .Dimnames = list(
                                   i = "REG1",
                                   t = c("y2000", "y2001", "y2002", "y2003", "y2050"),
                                   scenario = "test"
                                 )))

cat("INPUT DATA:\n")
print(test_data)

# Apply toolTimeSpline
result <- toolTimeSpline(test_data, dof = 3)

cat("\n\nOUTPUT FROM toolTimeSpline (INCORRECT):\n")
print(result)

# What smooth.spline SHOULD produce when given actual year values
years <- c(2000, 2001, 2002, 2003, 2050)
values <- c(100, 105, 110, 115, 300)
timespan <- 2050 - 2000  # 50 years
dof_adjusted <- timespan * 3 / 100  # 1.5

correct_spline <- smooth.spline(x = years, y = values,
                                df = dof_adjusted,
                                control.spar = list(high = 2))

cat("\n\nCORRECT OUTPUT (using actual year values):\n")
cat("Years: ", years, "\n")
cat("Values:", round(correct_spline$y, 1), "\n")

# What smooth.spline produces when NOT given year values (current bug)
wrong_spline <- smooth.spline(x = values, df = dof_adjusted,
                              control.spar = list(high = 2))

cat("\n\nINCORRECT OUTPUT (treating years as 1,2,3,4,5):\n")
cat("Years: ", years, "\n")
cat("Values:", round(wrong_spline$y, 1), "\n")

# Verify which method toolTimeSpline is using
result_vals <- as.numeric(result)
diff_from_correct <- sum(abs(correct_spline$y - result_vals))
diff_from_wrong <- sum(abs(wrong_spline$y - result_vals))

cat("\n\n=== DIAGNOSIS ===\n")
cat(sprintf("Difference from correct method: %.10f\n", diff_from_correct))
cat(sprintf("Difference from wrong method:   %.10f\n", diff_from_wrong))

if (diff_from_wrong < 0.001) {
  cat("\n❌ BUG CONFIRMED: toolTimeSpline ignores actual year spacing!\n")
  cat("\nThe function treats years as equally-spaced indices (1,2,3,4,5)\n")
  cat("instead of using their actual values (2000,2001,2002,2003,2050).\n")
  cat("\nThis causes incorrect interpolation for irregularly spaced data.\n")
} else {
  cat("\n✓ No bug detected.\n")
}

cat("\n=== THE FIX ===\n")
cat("In R/toolTimeSpline.R, line 37-38:\n\n")
cat("CURRENT (WRONG):\n")
cat("  tmpspline <- function(x, dof) return(smooth.spline(x, df = dof, control.spar = list(high = 2))$y)\n")
cat("  out <- apply(as.array(x), c(1,3), tmpspline , dof = dof)\n\n")
cat("SHOULD BE:\n")
cat("  tmpspline <- function(x, dof, years) return(smooth.spline(x = years, y = x, df = dof, control.spar = list(high = 2))$y)\n")
cat("  out <- apply(as.array(x), c(1,3), tmpspline, dof = dof, years = years)\n")

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions