Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deal with species attribution #17

Open
cboisvenue opened this issue Oct 18, 2024 · 2 comments
Open

Deal with species attribution #17

cboisvenue opened this issue Oct 18, 2024 · 2 comments
Assignees

Comments

@cboisvenue
Copy link
Contributor

cboisvenue commented Oct 18, 2024

The spinup function (libcbmr::cbm_exn_spinup()) requires species passed via the spinup_parameters object. In our current small raster example, these are hard coded (line 333 in CBM_core). We, on the spadesCBM side, attach species to growth curves in CBM_dataPrep_SK. It is my current assumption (Celine) that the species we give in the spinup via spinup_parameters would be used on the Python side to either figure out the Boudewyn parameters, or track species, or sw_hw. But since we give the $growth_increments out of CBM_vol2biomass and that the match to specific species is in $gcMetaAllCols (created in CBM_vol2biomass), and that we define the sw_hw flag also as part of the spinup_parameters, we don't use the species specified in spinup_parameters .

Regardless, the species in spinup_parameters needs to match the species in we associate with each growth curves. Currently, on line 333 of CBM_core, species are assigned "1" if sw and "62" if hw. Those refer to the two species table in the SQLight database that we read in CBM_defaults, we don't currently read in the species and species_tr tables but they match to 1 == Spruce and 62 == Poplar. The species table from the SQLight has a column genus which matches back to another pair of tables in the SQLight (genus just has an id and genus_tr which links it to poplar). Note that these (genus and genus_tr tables) do not seem to be linked to the $canfi_species object that is necessary to get the parameters for the Boudewyn equations in CBM_vol2biomass. My guess (Celine) is that this link (from genus to canfi_species) is internally done when people use libcbm with higher level functions than the ones we call from spadesCBM. For us, species in spinup_parameters have to have the right species_tr$species_id, and that has to match the species we attach to each growth curve. For spadesCBM, it will have to be something like a messy match between the species names in species_tr$name from the SQLight, and $gcMetaAllCols created in CBM_vol2biomass. When we get to LandRCBM (spadesCBM that gets its growth and cohort information from LandR), we will have to match it to cohort-species.

@camillegiuliano
Copy link
Contributor

camillegiuliano commented Oct 28, 2024

Would we want genus_id from the genus_tr table linked to species_tr, or would we only need the genus codes from canfi_species? I don't think we would need genus_id in the current CBM_vol2biomass if we match species_tr and canfi_species with names, but would both be needed for LandRCBM?

As you mentioned, species_tr$name and canfi_species$name are not 1 to 1 equivalent. species_tr has about double the entries of canfi_species. Naming is similar (and in most cases identical) for the entries that are shared between the two tables but there are some species in both tables that are found in one and not the other. How would we treat those without matches?

EDIT: trying to remove hardcoded 1 and 62 species IDs
None of this is in any modules at all, just testing using tables in the simlist to see if everything seemed right.

Of note:
species_tr has species_id and name
gcMeta has gcids, species (similar to name in species_tr), forest_type_id
spatialDT has pixelGroup, gcids
spinup_input$parameters has pixelGroup and hardcoded species_id

With these tables I did this:

## Here I match species names between species_tr and gcMeta
speciesMatch <- simPython$gcMeta[simPython$species_tr, on = .(species = name)]
speciesMatch <- speciesMatch[gcids >= 1,]
speciesMatch <- speciesMatch[,.(gcids, species_id)]
## Then match gcids to pixelGroups with spatialDT
speciesMatch <- speciesMatch[simPython$spatialDT, on =.(gcids=gcids)]
speciesToPixelG <- unique(speciesMatch[,.(pixelGroup, species_id)])
#then assign species to spinup_inputs
spinupParams <- simPython$spinup_input$parameters[speciesToPixelG, on=.(pixelGroup=pixelGroup)]

With this anything in simPython$spinup_inputs$parameters originally hardcoded to have a species_id of 1 is now either 2 (Black Spruce), 6 (White Spruce), 14 (Jack Pine). The hardcoded 62 is now 76 (White Birch).

Hopefully this all makes sense!

@camillegiuliano camillegiuliano self-assigned this Oct 28, 2024
@camillegiuliano
Copy link
Contributor

camillegiuliano commented Oct 29, 2024

Incorporated a version of this to spadesCBMpython.
Created and added speciesPixelGroup to the simlist in CBM_dataPrep:

 speciesPixelGroup <- sim$gcMeta[sim$species_tr, on = .(species = name)]
  speciesPixelGroup <- speciesPixelGroup[gcids >= 1,]
  speciesPixelGroup <- speciesPixelGroup[,.(gcids, species_id)]
  speciesPixelGroup <- speciesPixelGroup[spatialDT, on = .(gcids=gcids)]
  speciesPixelGroup <- unique(speciesPixelGroup[,.(pixelGroup, species_id)])
  sim$speciesPixelGroup <- speciesPixelGroup

Then link it to level3DT and setting it as the species column of spinup_input$parameters in CBM_core:

level3DT <- level3DT[sim$speciesPixelGroup, on=.(pixelGroup=pixelGroup)] #this connects species codes to PixelGroups.


  spinup_parameters <- data.table(
    pixelGroup = level3DT$pixelGroup,
    age = level3DT$ages,
    ##Notes: The area column will have no effect on the C dynamics of this
    ##script, since the internal working values are tonnesC/ha.  It may be
    ##useful to keep the column anyways for results processing since multiplying
    ##the tonnesC/ha, tonnesC/yr/ha values by the area is the CBM3 method for
    ##extracting the mass, mass/year values.
    area = 1.0,
    delay = sim$delays, ##user defined so CBM_dataPrep_SK
    return_interval = level3DT$return_interval,
    min_rotations = level3DT$min_rotations,
    max_rotations = level3DT$max_rotations,
    spatial_unit_id = level3DT$spatial_unit_id,
    sw_hw = as.integer(level3DT$is_sw),
    species = level3DT$species_id,
    mean_annual_temperature = level3DT$historic_mean_temperature,
    historical_disturbance_type = sim$historicDMtype,
    last_pass_disturbance_type =  sim$lastPassDMtype
  )

This runs on my machine but slightly changes results. For example, landscape average NPP was calculated at 7.38 MgC/ha/yr in previous runs, but is 6.933 MgC/ha/yr with this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants