Scheduled Downtime
On Tuesday 24 October 2023 @ 5pm MT the forums will be in read only mode in preparation for the downtime. On Wednesday 25 October 2023 @ 5am MT, this website will be down for maintenance and expected to return online later in the morning.
Normal Operations
The forums are back online with normal operations. If you notice any issues or errors related to the forums, please reach out to help@ucar.edu

How to add a new Plant Functional Type to CLM?

shandong

Xiao
New Member
I am trying to define a new Plant Functional Type (PFT) in the land cover. I only want to plant this species in a particular area, so I thought directly change the existing PFT may not work, instead, I would need to define a new PFT. I checked the "PCT_NAT_PFT", which seem to be fully occupied by existing PFT.

Any suggestions to implement would be appreciated!
 

erik

Erik Kluzek
CSEG and Liaisons
Staff member
In order to properly do this you'd need to both modify the code, add a new PFT to the params file as well as adding it to the surface dataset (and landuse.timeseries file if relevant). If it's a crop PFT that exists in the 79 PFT datasets, but isn't used that would be somewhat easier to add, but you'd have to handle all the management of it. This is potentially quite a bit of work.
 

erik

Erik Kluzek
CSEG and Liaisons
Staff member
An alternative way to "hack" the system especially if you are doing regional simulations rather than global -- is to "take over" an existing PFT that isn't being used over your domain and use it for your new one. This would be a kludgy hack both to the software and the science, but you might be able to pull it off easier as a one off experiment.
 

shandong

Xiao
New Member
Thank you for your suggestions.

Here I briefly summarized what I have tried, and I hope to hear if you have any suggestions.
- The new PFT I am interested in is a new natural vegetation, and NOT a crop. Also, I want to keep all existing natural PFTs. I have tried to overwrite #17 irrigated crop, but I think this is not active when irrigation is not active, also I think this is still treated as a crop (for soil water calculation). Is there a easy way to overwrite this slot (#17 irrigated crop), and let CLM automatically treat it as a natural PFT?

- I was able to add a new PFT to params file, to surface dataset. But I am not sure which part of the code should be revised. But I am not sure about the comprehensive list of scripts to edit, besides pftconMod.F90. Looks like each PFT is hard coded in pftconMod.F90. Does this mean, I have to hard code a new PFT in pftconMod.F90? Should I also revise other modules when some special PFT are involved there?

Thank you very much!
 

shandong

Xiao
New Member
We have made progress in this. We have revised a series of code and data, and CESM could successfully run. However, we did not get expected results.

Specific steps our experiment include:
-add a new PFT in "pftvarcon.F90"
-revise numveg in "clm_varpar.F90"
-add parameters for the new PFT in "clm_params.c140423.nc"
-add distributions for the new PFT in "surfdata_1.9x2.5_simyr2000_c130927.nc"; specifically we make the distribution as 0 for the new PFT

We were expecting to the output the same as a control run (everything is default), but we did not get that results. Instead, we can see differences in day 2 between this experimental run vs. a control run. The differences are more obvious in some area of the map (see attached figure). We are not exactly sure what is the cause. Do you have any suggestions? Thank you!
 

Attachments

  • cesm_experiment_diff.png
    cesm_experiment_diff.png
    220.9 KB · Views: 9

oleson

Keith Oleson
CSEG and Liaisons
Staff member
It sounds like you didn't "take over" an existing pft, but instead added a new pft. What pft number did you assign to the new pft? Could this have ended up shifting the pft number for existing pfts? As Erik noted, there is code that handles the behavior of the model for specific pfts.
 

shandong

Xiao
New Member
in "pftvarcon.F90", the new PFT is added with index 2; everything else after this PFT moves down one step; the second-last PFT (soybean) is commented; the last PFT (irrigated_soybean) is kept the same. In our case, the crop and irrigation modules are not used.
expected_pftnames( 0) = 'not_vegetated '
expected_pftnames( 1) = 'needleleaf_evergreen_temperate_tree'
expected_pftnames( 2) = 'new_tree
'

Because we added an additional valid vegetation, we increased "numveg" by 1, in "clm_varpar.F90"

Also, the PFT index was also updated in "clm_params.c140423.nc" and "surfdata_1.9x2.5_simyr2000_c130927.nc". The dimensions of some variables in the two input nc files were also added by 1.

Short answers to your questions: we added an additional PFT, we excluded one crop PFT, the index of PFTs in the middle of the sequence were updated (shifted). We tried to update the PFT index (also, variables with a dimension that equals the number of PFTs) in the input file to match up with the revised code.

Our guess is that our revision to the code is not comprehensive, but not sure what additional changes shall be made. Or if this task is possible at all?
 

erik

Erik Kluzek
CSEG and Liaisons
Staff member
A problem of adding a new index in the middle as in your example is that there are hardcoded index numbers used in the code. So those hard coded numbers will be wrong. So you'd need to track down all the instances of this and fix it. This is a bad practice in the code, and we are trying to change them to using the indices stored in pftcon, but we know we haven't got all of the instances of this.

There's also some logic in pftcon to figure out things like which indices are tree and the like. The way you've added this, that should still work, but because we don't test this, I wouldn't be confident that it's all working correctly. And again there might be hardcoded indices in the code that assume all tree's are before a particular number. By shifting things like this all of those kind of hardcoded values will be wrong.

That's why I'd be more confident in "taking over" an existing PFT than adding a new one. For some discussion on this see this issue in CTSM...

 

oleson

Keith Oleson
CSEG and Liaisons
Staff member
You could double-check to make sure that you've properly shifted all of the pft-dependent values in the parameter file. You could print out the values read in from the parameter file and make sure they are the same as in the control simulation for each pft.
There also are a number of instances in the code where the pft numbers are checked and actions are taken. For example, there are instances of this:
if (ivt(p) >= npcropmin) then ! skip 2 generic crops
So if npcropmin is no longer consistent with your revised pft list, that could be a problem.
Another example would be instances in the code where a specific pft is checked such as:
if (ivt(p) == ntmp_soybean .or. ivt(p) == nirrig_tmp_soybean
I suggest checking the code for instances where ivt(p) is used to determine specific actions.
 

oleson

Keith Oleson
CSEG and Liaisons
Staff member
Here is an example of what Erik means by hardcoded values, in biogeochem/CNGapMortalityMod.F90:.

if (ivt(p) == 8) then
mort_max = 0.03_r8 ! BDT boreal
else
mort_max = 0.01_r8 ! original value for all patches
end if

In your case ivt(p) = 8 is probably no longer BDT boreal.
 

shandong

Xiao
New Member
Thank you for the kind suggestions.

We try to add an new PFT because of our experimental design.

We put the new PFT is in the middle of tree PFTs, trying to NOT break the existing logic in terms of PFT bounds, that were inferred from the sequence of PFTs or the first/last tree/grass/shrub type PFTs. So ideally, the soft coded PFT index or ivt should work well. We print the values of PFT index into the log file, the values are as expected (same as how we write them in the clm_params.c140423.nc file).

The hard coded index should definitely be avoided. Though, the example from Keith seems to be the only case I could found, using the following search terms.
'ivt(p) =='
'ivt(p) >='
'ivt(p) <='
'ivt(p) /='
'(ivt(p)) =='
'(ivt(p)) >='
'(ivt(p)) <='
'(ivt(p)) /='
'ivt(p)=='
'ivt(p)>='
'ivt(p)<='
'ivt(p)/='
'(ivt(p))=='
'(ivt(p))>='
'(ivt(p))<='
'(ivt(p))/='


After fixing that case in biogeochem/CNGapMortalityMod.F90, the CESM output (TSA in CLM) is still different from the control(default) run. It seems there are more things to check/revise...
 
Top