Question on seasonal LAI varibility and use of observed LAI in SUEWS

Hello Team,

In my simulation, the LAI for grass, evergreen trees and deciduous trees remains constant throughout the year, while MERRA2 shows strong seasonal variability. I have attached the LAI plot and LAI parameter file used in the model.

Could you please advise on the possible reason for this behaviour and how it can be corrected?

In addition, is it possible to prescribe observed satellite-based LAI as a time-varying input in SUEWS? If so, what is the recommended workflow, and does this input override the internal LAI calculation, or is it used only for calibration?

Cell output 33(2) [DW].csv (544 Bytes)

  1. Please confirm you set the LAI parameters for your study region-
  1. you can provide LAI as part of your model forcing file

@Sue.Grimmond Thank you for the information. I attempted to calibrate the LAI parameters with MERRA-2 LAI, but I realised that for my site, LAI is not solely a function of temperature, particularly during the summer season, as shown in the figure.
I then tried with the MERRA-2 LAI as input in my forcing file. However, the model still appears to simulate the LAI despite it being provided as input. It would be really helpful if you could kindly advise whether there is any specific configuration that I may need to adjust in the configuration file?

Hi @Divya — thanks for the clear figure. Quick clarification before I reply properly: what does “aTW” stand for in your legend (Winter/Monsoon/Combined aTW)? And roughly which region is the site in? That will help me tailor the guidance.

While you dig up the “aTW” definition, let me address the two substantive points directly — your diagnosis is correct on both counts.

On the physics: the LAI parameterisation in SUEWS is purely thermally driven. It uses growing-degree-day (GDD) and senescence-degree-day (SDD) thresholds on daily mean air temperature, with no precipitation or moisture term anywhere in the equations. So for a site where the annual LAI cycle is controlled by rainfall rather than heat, the scheme cannot reproduce that shape, regardless of how you tune BaseT / GDDFull / SDDFull / LAIPower.

This limitation is documented explicitly in Omidvar et al. (2022), GMD, 15, 3041–3078. Appendix D is particularly worth reading for your case — it contrasts two FLUXNET sites side by side:

  • Fig. D1 (US-MMS, deciduous broadleaf forest) — precipitation accumulates steadily all year; LAI tracks air temperature cleanly. The thermal scheme works here.
  • Fig. D2 (US-SRG, grassland) — precipitation is near-zero Jan–Jun, then jumps with the monsoon in July; LAI stays flat through the warm dry spring and only rises after the monsoon rainfall arrives. The thermal scheme cannot capture this.

Your MERRA-2 curve has the US-SRG signature rather than the US-MMS one, so these two figures essentially pre-diagnose your case — and they make it clear that what you are seeing is a known structural limitation of the current scheme, not a calibration issue on your side.

On the forcing side: you are also right, and this one is on us. There is a drift between the documentation (which still lists lai as an optional forcing column) and the current code (which no longer exposes the switch that would let the model consume a prescribed LAI). We will fix that — either by restoring the observed-LAI path or by correcting the docs — and I will link the tracking issue here once it is up.

1 Like

This topic has been tracked as a GitHub issue for the development team.

GitHub issue: Question on seasonal LAI varibility and use of observed LAI in SUEWS · Issue #1291 · UMEP-dev/SUEWS · GitHub

The team will follow up there. Updates will be posted in the GitHub issue.

1 Like

Thank you for the response and clarification. aTW is an asymmetric Tukey window.

I was trying to calibrate using the methodology adopted by Omidvar et al. (2022) by fitting the LAI with an asymmetric Tukey window. Since I was seeing two LAI cycles, I tried to do two sets of calibrations for each cycle, but it was not working.

Then I checked the temperature profile and found that LAI is not solely dependent on temperature at this site. Also, my site is in Delhi, India.

1 Like

Hi @Divya,

Quick follow-up. The fix for the silent-LAI issue has now landed on master and is available on TestPyPI if you’d like to try it ahead of the next release:

To prescribe MERRA-2 LAI from the forcing file, add to your YAML config:

model:
  physics:
    laimethod:
      value: 0    # 0 = OBSERVED, 1 = CALCULATED (default)

Forcing contract for the lai column under laimethod: 0:

  • Every timestep must be >= 0. Missing values, NaN, and the -999 sentinel are all rejected at pre-flight — the run will not start if any row is invalid, so gap-fill your MERRA-2 series first.
  • lai = 0 is accepted as a genuine observation. At runtime it is clamped up to each vegetation class’s laimin; if you need a true zero honoured (e.g. complete winter dieback), set that class’s laimin to zero in the site config.
  • The scalar lai column is applied uniformly to all three vegetation classes (grass / evergreen / deciduous). Per-class observed LAI is a separate enhancement.

Please let us know how it goes on your site.

Hi @sunt05 ,

Thank you for the update. I am using supy 2026.4.18.dev0 and have manually added ‘laimethod’ in my YAML config file.

I am encountering the following error.

TypeError                                 Traceback (most recent call last)
Cell In\[2\], line 13
5 path_runcontrol = Path(
6     r".....\\Model\\SPD_LAI"
7 ) / "OG.yml"
9 forcing_path = Path(
10     r"......\\Model\\SPD_LAI"
11 ) / "OG_2002_data_60.txt"
---> 13 sim = SUEWSSimulation(path_runcontrol)
14 sim.update_forcing(forcing_path)

File c:\\ProgramData\\anaconda3\\envs\\supy_dev\\Lib\\site-packages\\supy\\suews_sim.py:87, in SUEWSSimulation.**init**(self, config)
84 self.\_run_completed = False
86 if config is not None:
---> 87     self.update_config(config)

File c:\\ProgramData\\anaconda3\\envs\\supy_dev\\Lib\\site-packages\\supy\\suews_sim.py:139, in SUEWSSimulation.update_config(self, config, auto_load_forcing)
136     raise FileNotFoundError(f"Configuration file not found: {config_path}")
138 # Load YAML
 -> 139 self.\_config = SUEWSConfig.from_yaml(str(config_path))
140 self.\_config_path = config_path
142 # Convert to initial state DataFrame

File c:\\ProgramData\\anaconda3\\envs\\supy_dev\\Lib\\site-packages\\supy\\data_model\\core\\config.py:3765, in SUEWSConfig.from_yaml(cls, path, use_conditional_validation, strict, auto_generate_annotated)
3761 logger_supy.debug(
3762     "Running comprehensive Pydantic validation with conditional checks."
3763 )
3764 try:
 -> 3765     return cls(\*\*config_data)
3766 except ValidationError as e:
3767     # Transform Pydantic validation error messages to use GRIDID instead of array indices
3768     transformed_error = cls.\_transform_validation_error(e, config_data)

File c:\\ProgramData\\anaconda3\\envs\\supy_dev\\Lib\\site-packages\\pydantic\\main.py:263, in BaseModel.**init**(self, \*\*data)
261 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
262 **tracebackhide** = True
 -> 263 validated_self = self.**pydantic_validator**.validate_python(data, self_instance=self)
264 if self is not validated_self:
265     warnings.warn(
266         'A custom validator is returning a value other than `self`.\\n'
267         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\\n"
268         'See the `model_validator` docs ( https://docs.pydantic.dev/latest/concepts/validators/#model-validators ) for more details.',
269         stacklevel=2,
270     )

TypeError: RefValue.**init**() got an unexpected keyword argument 'working_day'

Hi @Divya,

Apologies — the TypeError you’re hitting is YAML schema drift between an earlier release and current master, not an issue with your file. Between v2026.4.3 and 2026.4.18.dev0 we tightened a few data-model internals without a compatibility guard. Tracked as #1301; the YAML-upgrade converter is #1304.

Stable path for now — whenever you’re on TestPyPI or a dev build, start from the sample config bundled with your installed supy version and copy your site values in. That YAML always matches the validator you have:

import supy, pathlib
print(pathlib.Path(supy.__file__).parent / "sample_data" / "sample_config.yml")

If you can share your YAML here, it would help us with a real-world fixture to enhance the converter.

OG.yml (107.9 KB)

OG_2002_data_60.txt (1.4 MB)

Hi @sunt05 ,

Thank you for the clarification. Please find attached the YAML file for my site. I was working with supy 2026.1.28

Hi Divya,

Thanks for surfacing this. The migration path turns out to need broader work than we initially scoped, so we’re going to take a bit longer to land the converter properly rather than push out a partial fix.

In the meantime, the workaround we discussed earlier should keep you moving: start from the current release’s sample_config.yml and port your site-specific values across — forcing path, lat/lon, surface fractions, building archetype properties, and so on. The structural shape will be correct under the current validator, so you only need to copy over the values that are genuinely yours.

I’ll come back here as soon as the converter is ready so you can run it directly on your 2026.1.28 YAML.

Hi @sunt05 ,

Thank you for the update and suggestion. The sample_config.yml workaround is working well with my site-specific values, including the laimethod.

A future update to handle the schema version would be very helpful, especially for the multigrid simulation.

Thanks again, and I look forward to the converter when it’s ready.