@@ -3815,156 +3815,104 @@ subroutine InsertPatch(currentSite, newPatch)
38153815
38163816 ! !LOCAL VARIABLES:
38173817 type (fates_patch_type), pointer :: currentPatch
3818- integer :: insert_method ! Temporary dev
3819- logical :: found_landuselabel_match
3820- integer , parameter :: unordered_lul_groups= 1
3821- integer , parameter :: primaryland_oldest_group = 2
3822- integer , parameter :: numerical_order_lul_groups = 3
3823- integer , parameter :: age_order_only = 4
3824-
3825- ! Insert new patch case options:
3826- ! Option 1: Group the landuse types together, but the group order doesn't matter
3827- ! Option 2: Option 1, but primarylands are forced to be the oldest group
3828- ! Option 3: Option 1, but groups are in numerical order according to land use label index integer
3829- ! (i.e. primarylands=1, secondarylands=2, ..., croplands=5)
3830- ! Option 4: Don't group the patches by land use label. Simply add new patches to the youngest end.
3831-
3832- ! Hardcode the default insertion method. The options developed during FATES V1 land use are
3833- ! currently being held for potential future usage.
3834- insert_method = primaryland_oldest_group
3835-
3836- ! Start from the youngest patch and work to oldest, regarless of insertion_method
3837- currentPatch = > currentSite% youngest_patch
3818+ logical :: patch_inserted
38383819
3839- ! For the three grouped cases, if the land use label of the youngest patch on the site
3840- ! is a match to the new patch land use label, simply insert it as the new youngest.
3841- ! This is applicable to the non-grouped option 4 method as well.
3842- if (currentPatch% land_use_label .eq. newPatch% land_use_label ) then
3843- newPatch% older = > currentPatch
3844- newPatch% younger = > null ()
3845- currentPatch% younger = > newPatch
3846- currentSite% youngest_patch = > newPatch
3847- else
3848-
3849- ! If the current site youngest patch land use label doesn't match the new patch
3850- ! land use label then work through the list until you find the matching type.
3851- ! Since we've just checked the youngest patch, move to the next patch and
3852- ! initialize the match flag to false.
3853- found_landuselabel_match = .false.
3854- currentPatch = > currentPatch% older
3855- select case (insert_method)
3820+ ! The goal here is to have patches ordered in a specific way. That way is to have them
3821+ ! looped as the following, where LU refers to the land use label, PFT refers to the
3822+ ! nocomp PFT label, and Y and O refer to continuous patch ages.
3823+ !
3824+ ! LU1 ---- LU2 ---- LU3 -- etc
3825+ ! / \ / \ / \
3826+ ! PFT1 --- PFT2 | PFT1 --- PFT2 | PFT1 --- PFT2 -- etc
3827+ ! / \ / \ / \ / \ / \ / \
3828+ ! O - Y O - Y O - Y O - Y O - Y O - Y -- etc
38563829
3857- ! Option 1 - order of land use label groups does not matter
3858- case (unordered_lul_groups)
3830+ ! I.e. to treat land use as the outermost loop element, then nocomp PFT as next loop element,
3831+ ! and then age as the innermost loop element. Visualizing the above as a linked list patches:
38593832
3860- do while (associated (currentPatch) .and. .not. found_landuselabel_match)
3861- if (currentPatch% land_use_label .eq. newPatch% land_use_label) then
3862- found_landuselabel_match = .true.
3863- else
3864- currentPatch = > currentPatch% older
3865- end if
3866- end do
3833+ ! LU1/PFT1/O <-> LU1/PFT1/Y <-> LU1/PFT2/O <- ... -> LU3/PFT2/O <-> LU3/PFT2/Y
38673834
3868- ! In the case where we've found a land use label matching the new patch label,
3869- ! insert the newPatch will as the youngest patch for that land use type.
3870- if (associated (currentPatch)) then
3871- newPatch% older = > currentPatch
3872- newPatch% younger = > currentPatch% younger
3873- currentPatch% younger% older = > newPatch
3874- currentPatch% younger = > newPatch
3875- else
3876- ! In the case in which we get to the end of the list and haven't found
3877- ! a landuse label match simply add the new patch to the youngest end.
3878- newPatch% older = > currentSite% youngest_patch
3879- newPatch% younger = > null ()
3880- currentSite% youngest_patch% younger = > newPatch
3881- currentSite% youngest_patch = > newPatch
3882- endif
3883-
3884- ! Option 2 - primaryland group must be on the oldest end
3885- case (primaryland_oldest_group)
3835+ ! Mapping this setup onto the existing "older/younger" scheme means that lower number
3836+ ! land use and pft labels are considered "older". Note that this matches the current
3837+ ! initialization scheme in which patches are created and linked in increasing pft
3838+ ! numerical order starting from 1. This also aligns with the current set_patchno scheme
3839+ ! in which patches are given an indexable number for the API iteration loops.
3840+
3841+ ! The way to accomplsh this most simply is to define a pseudo-age that includes all of the
3842+ ! above info and sort the patches based on the pseudo-age. i.e. take some number larger
3843+ ! than any patch will ever reach in actual age. Then take the LU, multiply it by the big
3844+ ! number squared, add it to the pft number multiplied by the big number, and add to the age.
3845+ ! And lastly to sort using that instead of the actual age.
38863846
3887- do while (associated (currentPatch) .and. .not. found_landuselabel_match)
3888- if (currentPatch% land_use_label .eq. newPatch% land_use_label) then
3889- found_landuselabel_match = .true.
3890- else
3891- currentPatch = > currentPatch% older
3892- end if
3893- end do
3847+ ! If land use is turned off or nocomp is turned off, then this should devolve to the prior
3848+ ! behavior of just age sorting.
38943849
3895- ! In the case where we've found a land use label matching the new patch label,
3896- ! insert the newPatch will as the youngest patch for that land use type.
3897- if (associated (currentPatch)) then
3898- newPatch% older = > currentPatch
3899- newPatch% younger = > currentPatch% younger
3900- currentPatch% younger% older = > newPatch
3901- currentPatch% younger = > newPatch
3902- else
3903- ! In the case in which we get to the end of the list and haven't found
3904- ! a landuse label match.
3905-
3906- ! If the new patch is primaryland add it to the oldest end of the list
3907- if (newPatch% land_use_label .eq. primaryland) then
3908- newPatch% older = > null ()
3909- newPatch% younger = > currentSite% oldest_patch
3910- currentSite% oldest_patch% older = > newPatch
3911- currentSite% oldest_patch = > newPatch
3912- else
3913- ! If the new patch land use type is not primaryland and we are at the
3914- ! oldest end of the list, add it to the youngest end
3915- newPatch% older = > currentSite% youngest_patch
3916- newPatch% younger = > null ()
3917- currentSite% youngest_patch% younger = > newPatch
3918- currentSite% youngest_patch = > newPatch
3919- endif
3920- endif
3850+ patch_inserted = .false.
3851+
3852+ if (GetPseudoPatchAge(newPatch) .le. GetPseudoPatchAge(currentSite% youngest_patch)) then
39213853
3922- ! Option 3 - groups are numerically ordered with primaryland group starting at oldest end.
3923- case (numerical_order_lul_groups)
3854+ ! insert new patch at the head of the linked list
3855+ newPatch% older = > currentSite% youngest_patch
3856+ newPatch% younger = > null ()
3857+ currentSite% youngest_patch% younger = > newPatch
3858+ currentSite% youngest_patch = > newPatch
39243859
3925- ! If the youngest patch landuse label number is greater than the new
3926- ! patch land use label number, the new patch must be inserted somewhere
3927- ! in between oldest and youngest
3928- do while (associated (currentPatch) .and. .not. found_landuselabel_match)
3929- if (currentPatch% land_use_label .eq. newPatch% land_use_label .or. &
3930- currentPatch% land_use_label .lt. newPatch% land_use_label) then
3931- found_landuselabel_match = .true.
3932- else
3933- currentPatch = > currentPatch% older
3934- endif
3935- end do
3860+ patch_inserted = .true.
3861+ else if (GetPseudoPatchAge(newPatch) .ge. GetPseudoPatchAge(currentSite% oldest_patch)) then
39363862
3937- ! In the case where we've found a landuse label matching the new patch label
3938- ! insert the newPatch will as the youngest patch for that land use type.
3939- if (associated (currentPatch)) then
3863+ ! insert new patch at the end of the linked list
3864+ newPatch% younger = > currentSite% oldest_patch
3865+ newPatch% older = > null ()
3866+ currentSite% oldest_patch% older = > newPatch
3867+ currentSite% oldest_patch = > newPatch
39403868
3941- newPatch% older = > currentPatch
3942- newPatch% younger = > currentPatch% younger
3869+ patch_inserted = .true.
3870+ else
3871+ ! new patch has a pseudo-age somewhere within the linked list. find the first patch which
3872+ ! has a pseudo age older than it, and put it ahead of that patch
3873+ currentPatch = > currentSite% youngest_patch
3874+ do while (associated (currentPatch) .and. ( .not. patch_inserted) )
3875+ if (GetPseudoPatchAge(newPatch) .lt. GetPseudoPatchAge(currentPatch)) then
3876+ newPatch% older = > currentPatch
3877+ newPatch% younger = > currentPatch% younger
39433878 currentPatch% younger% older = > newPatch
3944- currentPatch% younger = > newPatch
3945-
3946- else
3947-
3948- ! In the case were we get to the end, the new patch
3949- ! must be numerically the smallest, so put it at the oldest position
3950- newPatch% older = > null ()
3951- newPatch% younger = > currentSite% oldest_patch
3952- currentSite% oldest_patch% older = > newPatch
3953- currentSite% oldest_patch = > newPatch
3879+ currentPatch% younger = > newPatch
39543880
3881+ patch_inserted = .true.
39553882 endif
3883+ currentPatch = > currentPatch% older
3884+ end do
3885+ end if
39563886
3957- ! Option 4 - always add the new patch as the youngest regardless of land use label
3958- case (age_order_only)
3959- ! Set the current patch to the youngest patch
3960- newPatch% older = > currentSite% youngest_patch
3961- newPatch% younger = > null ()
3962- currentSite% youngest_patch% younger = > newPatch
3963- currentSite% youngest_patch = > newPatch
3964- end select
3887+ if ( .not. patch_inserted) then
3888+ ! something has gone wrong. abort.
3889+ write (fates_log(),* ) ' something has gone wrong in the patch insertion, because no place to put the new patch was found'
3890+ call endrun(msg= errMsg(sourcefile, __LINE__))
39653891 end if
39663892
3967- end subroutine InsertPatch
3893+ end subroutine InsertPatch
3894+
3895+ ! =====================================================================================
3896+
3897+ function GetPseudoPatchAge (CurrentPatch ) result(pseudo_age)
3898+
3899+ ! Purpose: we want to sort the patches in a way that takes into account both their
3900+ ! continuous and categorical variables. Calculate a pseudo age that does this, by taking
3901+ ! the integer labels, multiplying these by large numbers, and adding to the continuous age.
3902+ ! Note to ensure that lower integer land use label and pft label numbers are considered
3903+ ! "younger" (i.e higher index patchno) in the linked list, they are summed and multiplied by
3904+ ! negative one. The patch age is still added normally to this negative pseudoage calculation
3905+ ! as a higher age will result in a less negative number correlating with an "older" patch.
3906+
3907+ type (fates_patch_type), intent (in ), pointer :: CurrentPatch
3908+ real (r8 ) :: pseudo_age
3909+ real (r8 ), parameter :: max_actual_age = 1.e4 ! hard to imagine a patch older than 10,000 years
3910+ real (r8 ), parameter :: max_actual_age_squared = 1.e8
3911+
3912+ pseudo_age = - 1.0_r8 * (real (CurrentPatch% land_use_label,r8 ) * max_actual_age_squared + &
3913+ real (CurrentPatch% nocomp_pft_label,r8 ) * max_actual_age) + CurrentPatch% age
3914+
3915+ end function GetPseudoPatchAge
39683916
39693917 ! =====================================================================================
39703918
0 commit comments