modelbound_data_support_procedures.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------------------------------------------------
! This file is part of ReMKiT1D.
!
! ReMKiT1D is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as 
! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
!
! ReMKiT1D is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License along with ReMKiT1D. If not, see <https://www.gnu.org/licenses/>. 
!
! Copyright 2023 United Kingdom Atomic Energy Authority (stefan.mijin@ukaea.uk)
!-----------------------------------------------------------------------------------------------------------------------------------
submodule (modelbound_data_support) modelbound_data_support_procedures
!! author: Stefan Mijin 
!! 
!! Contains modelbound data support procedures

implicit none

!-----------------------------------------------------------------------------------------------------------------------------------
contains
!-----------------------------------------------------------------------------------------------------------------------------------
module subroutine addModelboundDataToModel(modelObj,modelTag,envObj,normObj)
    !! Initialize modelbound data and add to corresponding model object

    type(Model)                ,intent(inout) :: modelObj
    character(*)               ,intent(in)    :: modelTag 
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    class(Normalization)        ,intent(in)    :: normObj
    
    type(NamedString) ,dimension(1) :: dataType 

    dataType(1) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyModelboundDataType,"")

    call envObj%jsonCont%load(dataType)
    call envObj%jsonCont%output(dataType)
    select case(dataType(1)%value)
    case (keyVarLikeMB)
        call addCustomVarlikeMBDataToModel(modelObj,modelTag,envObj)
    case (keyCRMData)
        call addCustomCRMDataToModel(modelObj,modelTag,envObj,normObj)
    case (keyLBCData)
        call addCustomLBCDataToModel(modelObj,modelTag,envObj,normObj)
    case default
        error stop "Unsupported modelbound data type detected by addModelboundDataToModel"
    end select

end subroutine addModelboundDataToModel
!-----------------------------------------------------------------------------------------------------------------------------------
module subroutine addCustomVarlikeMBDataToModel(modelObj,modelTag,envObj)
    !! Initialize varlike modelbound data and add to corresponding model object

    type(Model)                ,intent(inout) :: modelObj
    character(*)               ,intent(in)    :: modelTag 
    type(EnvironmentWrapper)   ,intent(inout) :: envObj

    type(NamedStringArray) ,dimension(1) :: dataNames ,reqVars
    type(NamedLogical)     ,dimension(4) :: logicalParams 
    type(NamedString)      ,dimension(1) :: ruleName

    type(NamedInteger)     ,dimension(1) :: varPriority
    
    type(ModelboundDataVarlike) :: mbData 
    type(CalculationRule) ,allocatable ,dimension(:) :: cRules
    type(VariableList)                               :: varList 
    class(Derivation) ,allocatable                   :: method
    integer(ik) :: i 
    integer(ik) ,allocatable ,dimension(:) :: dataDerivIndices

    dataNames(1)%name = keyModels//"."//modelTag//"."//keyModelboundData//"."//keyDataNames
    allocate(dataNames(1)%values(0))

    call envObj%jsonCont%load(dataNames)
    call envObj%jsonCont%output(dataNames)

    call varList%init()
    allocate(cRules(size(dataNames(1)%values)))
    allocate(dataDerivIndices(0))

    do i = 1, size(dataNames(1)%values) 
        
        logicalParams(1) = &
        NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//keyIsDist,.false.)

        logicalParams(2) = &
        NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//keyIsScalar,.false.)

        logicalParams(3) = NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//&
                                        keyIsSingleHarmonic,.false.)

        logicalParams(4) = NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//&
                                        keyIsDerivedFromOtherData,.false.)
        
        ruleName(1) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//&
                                  keyRuleName,"")

        reqVars(1)%name = keyModels//"."//modelTag//"."//keyModelboundData//"."//dataNames(1)%values(i)%string//"."//keyReqVarNames
        allocate(reqVars(1)%values(0))

        varPriority(1) = NamedInteger(keyModels//"."//modelTag//"."//keyModelboundData//&
                                     "."//dataNames(1)%values(i)%string//"."//keyDerivationPriority,0)

        call envObj%jsonCont%load(ruleName)
        call envObj%jsonCont%output(ruleName)

        call envObj%jsonCont%load(logicalParams)
        call envObj%jsonCont%output(logicalParams)

        call envObj%jsonCont%load(reqVars)
        call envObj%jsonCont%output(reqVars)

        call envObj%jsonCont%load(varPriority)
        call envObj%jsonCont%output(varPriority)

        call varList%addVar(dataNames(1)%values(i)%string,isDist=logicalParams(1)%value,&
                            isScalar=logicalParams(2)%value,isSingleHarmonic=logicalParams(3)%value,priority=varPriority(1)%value)

        if (logicalParams(4)%value) dataDerivIndices = [dataDerivIndices,i]
        call envObj%textbookObj%copyDerivation(ruleName(1)%value,method)
        call cRules(i)%init(method,reqVars(1)%values)
        deallocate(reqVars(1)%values)

    end do

    call mbData%init(varList,cRules,envObj%partitionObj,envObj%indexingObj,envObj%mpiCont%getXHaloWidth(),&
                    envObj%externalVars,envObj%mpiCont%getWorldRank(),dataDerivIndices=dataDerivIndices)

    call modelObj%setModelData(mbData)

end subroutine addCustomVarlikeMBDataToModel
!-----------------------------------------------------------------------------------------------------------------------------------
module subroutine addCustomCRMDataToModel(modelObj,modelTag,envObj,normObj)
    !! Initialize custom CRM modelbound data and add to corresponding model object

    type(Model)                ,intent(inout) :: modelObj
    character(*)               ,intent(in)    :: modelTag 
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    class(Normalization)       ,intent(in)    :: normObj

    type(ModelboundCRMData) :: crmData
    type(InelasticGridData) :: inelData

    type(NamedStringArray) ,dimension(1) :: transitionTags
    type(NamedString) ,allocatable ,dimension(:) :: transitionType
    type(NamedRealArray) ,dimension(1) :: fixedTransitionEnergies
    type(NamedLogical) ,dimension(1) :: activeInelData
    type(NamedInteger) ,dimension(1) :: elStateID

    integer(ik) :: i

    transitionTags(1)%name = keyModels//"."//modelTag//"."//keyModelboundData//"."//keyTransitionTags
    allocate(transitionTags(1)%values(0))

    call envObj%jsonCont%load(transitionTags)
    call envObj%jsonCont%output(transitionTags)

    allocate(transitionType(size(transitionTags(1)%values)))

    activeInelData(1) = NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyInelGrid//"."//keyActive,.false.)

    fixedTransitionEnergies(1)%name = &
    keyModels//"."//modelTag//"."//keyModelboundData//"."//keyInelGrid//"."//keyFixedTransitionEnergies
    allocate(fixedTransitionEnergies(1)%values(0))

    call envObj%jsonCont%load(activeInelData)
    call envObj%jsonCont%output(activeInelData)

    call envObj%jsonCont%load(fixedTransitionEnergies)
    call envObj%jsonCont%output(fixedTransitionEnergies)

    if (activeInelData(1)%value) then 
        call inelData%init(envObj%vSpaceObj,fixedEnergies=fixedTransitionEnergies(1)%values)
        call crmData%setInelData(inelData)
    end if

    do i  = 1, size(transitionTags(1)%values)
        transitionType(i) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                        keyTransitions//"."//transitionTags(1)%values(i)%string//"."//keyType,"")
    end do

    call envObj%jsonCont%load(transitionType)
    call envObj%jsonCont%output(transitionType)

    call crmData%init(size(transitionTags(1)%values))

    elStateID(1) = NamedInteger(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyElState,0)

    call envObj%jsonCont%load(elStateID)
    call envObj%jsonCont%output(elStateID)

    call crmData%setElState(elStateID(1)%value)

    do i = 1,size(transitionTags(1)%values)

        select case (transitionType(i)%value)
        case (keySimpleTransition)
            call addSimpleTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                             keyTransitions//"."//transitionTags(1)%values(i)%string,&
                                                             fixedTransitionEnergies(1)%values)
        case (keyDerivedTransition)
            call addDerivedTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                             keyTransitions//"."//transitionTags(1)%values(i)%string,&
                                                             fixedTransitionEnergies(1)%values)
        case (keyFixedECSTransition)
            call addFixedECSTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                             keyTransitions//"."//transitionTags(1)%values(i)%string,&
                                                             fixedTransitionEnergies(1)%values)
        case (keyVariableECSTransition)
            call addVariableECSTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                                keyTransitions//"."//transitionTags(1)%values(i)%string)
        case (keyDBTransition)
            call addDBTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                                keyTransitions//"."//transitionTags(1)%values(i)%string,&
                                                                fixedTransitionEnergies(1)%values)
        case (keyJanevRadRecomb)
            call addJanevRadRecombTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                      keyTransitions//"."//transitionTags(1)%values(i)%string,normObj)
        case (keyJanevCollExIon)
            call addJanevCollExIonTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                      keyTransitions//"."//transitionTags(1)%values(i)%string,normObj)
        case (keyJanevCollDeexRecomb)
            call addJanevCollDeexRecombTransitionToCRMData(crmData,envObj,keyModels//"."//modelTag//"."//keyModelboundData//"."//&
                                                            keyTransitions//"."//transitionTags(1)%values(i)%string,normObj)
        case default 
            error stop "unsupported transition type detected in custom modelbound data"
        end select

    end do

    call modelObj%setModelData(crmData)

end subroutine addCustomCRMDataToModel
!-----------------------------------------------------------------------------------------------------------------------------------
module subroutine addCustomLBCDataToModel(modelObj,modelTag,envObj,normObj)
    !! Initialize custom LBC modelbound data and add to corresponding model object

    type(Model)                ,intent(inout) :: modelObj
    character(*)               ,intent(in)    :: modelTag 
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    class(Normalization)       ,intent(in)    :: normObj

    type(NamedLogical) ,dimension(1) :: leftBoundary
    type(NamedStringArray) ,dimension(1) :: derivReqVars
    type(NamedString) ,dimension(1) :: derivName ,ionCurrentVar, totalCurrentVar
    type(NamedReal) ,dimension(1) :: bisTol

    integer(ik) ,allocatable ,dimension(:) :: derivReqIndices

    integer(ik) :: i

    class(MatDerivation) ,allocatable :: derivObj

    type(ModelboundLBCData) :: mbData

    logical :: isActive


    derivName(1) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyRuleName,"")
    leftBoundary(1) = NamedLogical(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyLeftBoundary,.false.)
    derivReqVars(1)%name = keyModels//"."//modelTag//"."//keyModelboundData//"."//keyReqVarNames
    allocate(derivReqVars(1)%values(0))

    ionCurrentVar(1) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyIonCurrentVar,"")
    totalCurrentVar(1) = NamedString(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyTotalCurrentVar,keyNone)
    bisTol(1) = NamedReal(keyModels//"."//modelTag//"."//keyModelboundData//"."//keyBisTol,real(1.0d-12,kind=rk))

    call envObj%jsonCont%load(leftBoundary)
    call envObj%jsonCont%output(leftBoundary)
    call envObj%jsonCont%load(derivReqVars)
    call envObj%jsonCont%output(derivReqVars)
    call envObj%jsonCont%load(derivName)
    call envObj%jsonCont%output(derivName)
    call envObj%jsonCont%load(ionCurrentVar)
    call envObj%jsonCont%output(ionCurrentVar)
    call envObj%jsonCont%load(totalCurrentVar)
    call envObj%jsonCont%output(totalCurrentVar)
    call envObj%jsonCont%load(bisTol)
    call envObj%jsonCont%output(bisTol)

    allocate(derivReqIndices(size(derivReqVars(1)%values)))
    do i = 1,size(derivReqIndices)
        derivReqIndices(i) = envObj%externalVars%getVarIndex(derivReqVars(1)%values(i)%string)
    end do

    call envObj%textbookObj%copyMatDerivation(derivName(1)%value,derivObj)

    isActive = envObj%partitionObj%getMaxXAtInd(envObj%mpiCont%getWorldRank()+1) == envObj%gridObj%getNumX()
    if (leftBoundary(1)%value) isActive = envObj%partitionObj%getMinXAtInd(envObj%mpiCont%getWorldRank()+1) == 1
    select type (derivObj)
    type is (FScalingDerivation)

        if (totalCurrentVar(1)%value /= keyNone) then 
            call mbData%init(envObj%vSpaceObj,derivObj,derivReqIndices,envObj%externalVars%getVarIndex(ionCurrentVar(1)%value),&
                             isActive ,totalCurrentVarIndex= envObj%externalVars%getVarIndex(totalCurrentVar(1)%value),&
                             bisTol=bisTol(1)%value,isLeftBoundary=leftBoundary(1)%value)
        else
            call mbData%init(envObj%vSpaceObj,derivObj,derivReqIndices,envObj%externalVars%getVarIndex(ionCurrentVar(1)%value),&
                             isActive ,bisTol=bisTol(1)%value,isLeftBoundary=leftBoundary(1)%value)
        end if
    class default 
        error stop "Derivation object detected by addCustomLBCData to model must be of type FScalingDerivation"
    end select

    call modelObj%setModelData(mbData)
    
end subroutine addCustomLBCDataToModel
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addSimpleTransitionToCRMData(crmData,envObj,tTag,fixedEnergies)
    !! Add custom simple transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    real(rk) ,dimension(:)     ,intent(in)    :: fixedEnergies

    type(SimpleTransition) :: transitionObj 

    type(NamedInteger) ,dimension(1) :: inState, outState ,fixedEnergyIndex
    type(NamedReal) ,dimension(1) :: fixedEnergy ,fixedRate

    real(rk) :: usedEnergy
    
    integer(ik) :: locNumX ,locRank

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 

    inState(1) = NamedInteger(tTag//"."//keyIngoingState,1)
    outState(1) = NamedInteger(tTag//"."//keyOutgoingState,1)
    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyFixedEnergyIndex,0)

    fixedEnergy(1) = NamedReal(tTag//"."//keyFixedEnergy,real(0,kind=rk))
    fixedRate(1) = NamedReal(tTag//"."//keyRate,real(0,kind=rk))

    call envObj%jsonCont%load(inState)
    call envObj%jsonCont%output(inState)
    call envObj%jsonCont%load(outState)
    call envObj%jsonCont%output(outState)
    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)

    call envObj%jsonCont%load(fixedEnergy)
    call envObj%jsonCont%output(fixedEnergy)
    call envObj%jsonCont%load(fixedRate)
    call envObj%jsonCont%output(fixedRate)

    usedEnergy = fixedEnergy(1)%value 

    if (fixedEnergyIndex(1)%value > 0) usedEnergy = fixedEnergies(fixedEnergyIndex(1)%value)

    call transitionObj%init(locNumX,inState(1)%value,outState(1)%value,usedEnergy,fixedRate(1)%value)

    call crmData%addTransition(transitionObj)

end subroutine addSimpleTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addDerivedTransitionToCRMData(crmData,envObj,tTag,fixedEnergies)
    !! Add custom derived transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    real(rk) ,dimension(:)     ,intent(in)    :: fixedEnergies

    type(DerivedTransition) :: transitionObj 

    type(NamedIntegerArray) ,dimension(1) :: inStates, outStates
    type(NamedInteger) ,dimension(1) :: fixedEnergyIndex
    type(NamedReal) ,dimension(1) :: fixedEnergy 
    type(NamedString) ,dimension(3) :: ruleName 
    type(NamedStringArray) ,dimension(3) :: reqVars

    class(Derivation) ,allocatable :: deriv ,deriv2, deriv3

    real(rk) :: usedEnergy
    
    integer(ik) :: locNumX ,locRank, i

    integer(ik) ,allocatable ,dimension(:) :: reqVarIndices,reqVarIndices2,reqVarIndices3

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 

    inStates(1) = NamedIntegerArray(tTag//"."//keyIngoingStatePlural,[1])
    outStates(1) = NamedIntegerArray(tTag//"."//keyOutgoingStatePlural,[1])
    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyFixedEnergyIndex,0)

    fixedEnergy(1) = NamedReal(tTag//"."//keyFixedEnergy,real(0,kind=rk))

    ruleName(1) = NamedString(tTag//"."//keyRuleName,"")

    reqVars(1)%name = tTag//"."//keyReqVarNames
    allocate(reqVars(1)%values(0))

    ruleName(2) = NamedString(tTag//"."//keyMomentumRule,keyNone)
    reqVars(2)%name = tTag//"."//keyMomentumReqVarNames
    allocate(reqVars(2)%values(0))

    ruleName(3) = NamedString(tTag//"."//keyEnergyRule,keyNone)
    reqVars(3)%name = tTag//"."//keyEnergyReqVarNames
    allocate(reqVars(3)%values(0))

    call envObj%jsonCont%load(inStates)
    call envObj%jsonCont%output(inStates)
    call envObj%jsonCont%load(outStates)
    call envObj%jsonCont%output(outStates)
    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)

    call envObj%jsonCont%load(fixedEnergy)
    call envObj%jsonCont%output(fixedEnergy)

    call envObj%jsonCont%load(ruleName)
    call envObj%jsonCont%output(ruleName)

    call envObj%jsonCont%load(reqVars)
    call envObj%jsonCont%output(reqVars)

    usedEnergy = fixedEnergy(1)%value 

    if (fixedEnergyIndex(1)%value > 0) usedEnergy = fixedEnergies(fixedEnergyIndex(1)%value)

    allocate(reqVarIndices(size(reqVars(1)%values)))

    do i = 1,size(reqVars(1)%values)
        reqVarIndices(i) = envObj%externalVars%getVarIndex(reqVars(1)%values(i)%string)
    end do

    allocate(reqVarIndices2(size(reqVars(2)%values)))

    do i = 1,size(reqVars(2)%values)
        reqVarIndices2(i) = envObj%externalVars%getVarIndex(reqVars(2)%values(i)%string)
    end do

    allocate(reqVarIndices3(size(reqVars(3)%values)))

    do i = 1,size(reqVars(3)%values)
        reqVarIndices3(i) = envObj%externalVars%getVarIndex(reqVars(3)%values(i)%string)
    end do

    call envObj%textbookObj%copyDerivation(ruleName(1)%value,deriv)
    if (ruleName(2)%value /= keyNone) call envObj%textbookObj%copyDerivation(ruleName(2)%value,deriv2)
    if (ruleName(3)%value /= keyNone) call envObj%textbookObj%copyDerivation(ruleName(3)%value,deriv3)

    if (ruleName(2)%value /= keyNone) then
        if (ruleName(3)%value /= keyNone) then
            
            call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,usedEnergy,deriv,reqVarIndices,&
            momentumRateDeriv=deriv2,momentumRateDerivIndices=reqVarIndices2,&
            energyRateDeriv=deriv3,energyRateDerivIndices=reqVarIndices3)
        else
            call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,usedEnergy,deriv,reqVarIndices,&
            momentumRateDeriv=deriv2,momentumRateDerivIndices=reqVarIndices2)
        end if

    else

        if (ruleName(3)%value /= keyNone) then
            call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,usedEnergy,deriv,reqVarIndices,&
            energyRateDeriv=deriv3,energyRateDerivIndices=reqVarIndices3)
        else
            call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,usedEnergy,deriv,reqVarIndices)
        end if
    end if

    call crmData%addTransition(transitionObj)

end subroutine addDerivedTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addFixedECSTransitionToCRMData(crmData,envObj,tTag,fixedEnergies)
    !! Add custom fixed energy/cross-section transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    real(rk) ,dimension(:)     ,intent(in)    :: fixedEnergies

    type(FixedECSTransition) :: transitionObj 

    type(NamedIntegerArray) ,dimension(1) :: inStates, outStates ,csLIndices
    type(NamedInteger) ,dimension(1) :: fixedEnergyIndex ,maxCSl
    type(NamedString) ,dimension(1) :: distributionVarName
    type(NamedRealArray) ,allocatable ,dimension(:) :: csValues 
    type(NamedLogical) ,dimension(1) :: takeMomentumMoment

    integer(ik) :: locNumX ,locRank ,distVarIndex ,i ,numV ,maxL ,l1Index

    character(len=30) :: intToStrBuffer

    real(rk) ,allocatable ,dimension(:,:) :: crossSection

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 
    numV = envObj%gridObj%getNumV()
    maxL = envObj%gridObj%getMaxL()

    inStates(1) = NamedIntegerArray(tTag//"."//keyIngoingStatePlural,[1])
    outStates(1) = NamedIntegerArray(tTag//"."//keyOutgoingStatePlural,[1])
    csLIndices(1)%name = tTag//"."//keyCrossSectionData//"."//keyPresentHarmonics
    allocate(csLIndices(1)%values(0))

    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyFixedEnergyIndex,0)
    maxCSl(1) = NamedInteger(tTag//"."//keyCrossSectionData//"."//keyMaxCrossSectionL,0)

    call envObj%jsonCont%load(inStates)
    call envObj%jsonCont%output(inStates)
    call envObj%jsonCont%load(outStates)
    call envObj%jsonCont%output(outStates)
    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)

    call envObj%jsonCont%load(maxCSl)

    call envObj%jsonCont%load(csLIndices)

    if (size(csLIndices(1)%values)==0) csLIndices(1)%values=[(i,i=0,maxCSl(1)%value)]

    maxCSl(1)%value = maxval(csLIndices(1)%values)

    call envObj%jsonCont%output(maxCSl)
    call envObj%jsonCont%output(csLIndices)

    allocate(csValues(size(csLIndices(1)%values)))

    do i = 1,size(csLIndices(1)%values)
        intToStrBuffer=""
        write(intToStrBuffer,'(I0)') csLIndices(1)%values(i)
        csValues(i)%name = tTag//"."//keyCrossSectionData//"."//keyLPrefix//trim(intToStrBuffer)
        csValues(i)%values = real([(0,i=1,numV)],kind=rk)
    end do

    call envObj%jsonCont%load(csValues)
    call envObj%jsoncont%output(csValues)

    allocate(crossSection(numV,maxCSl(1)%value))

    crossSection = real(0,kind=rk)

    do i =1,size(csLIndices(1)%values)
        crossSection(:,csLIndices(1)%values(i)+1) = csValues(i)%values
    end do

    distributionVarName(1) = NamedString(tTag//"."//keyDistributionVarName,"")

    call envObj%jsonCont%load(distributionVarName)

    if (assertions .or. assertionLvl >= 0) call assert(envObj%externalVars%isVarNAmeRegistered(distributionVarName(1)%value),&
    distributionVarName(1)%value//" not registered in environment wrapper")

    call envObj%jsonCont%output(distributionVarName)

    distVarIndex = envObj%externalVars%getVarIndex(distributionVarName(1)%value)

    takeMomentumMoment(1) = NamedLogical(tTag//"."//keyTakeMomentumMoment,.false.)

    call envObj%jsonCont%load(takeMomentumMoment)

    if (assertions .or. assertionLvl >= 0) then 
        if (takeMomentumMoment(1)%value) call assert(maxCSl(1)%value>0,"Fixed energy/cross-section transition set to take momentum&
                                                    & moment when maximum cross-section harmonic is not 1 or higher")
    end if

    call envObj%jsonCont%output(takeMomentumMoment)

    l1Index = 1
    if (maxL > 0) l1Index = envObj%gridObj%getH(1,0,.false.)

    call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,fixedEnergies(fixedEnergyIndex(1)%value),&
                            crossSection,distVarIndex,envObj%vSpaceObj, &
                            fixedEnergyIndex(1)%value,momentumMoment=takeMomentumMoment(1)%value, l1Index=l1Index)

    call crmData%addTransition(transitionObj)

end subroutine addFixedECSTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addVariableECSTransitionToCRMData(crmData,envObj,tTag)
    !! Add custom variable energy/cross-section transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 

    type(VariableECSTransition) :: transitionObj 

    type(NamedIntegerArray) ,dimension(1) :: inStates, outStates ,csLIndices 
    type(NamedString) ,dimension(1) :: distributionVarName ,energyDerivName
    type(NamedStringArray) ,dimension(1) :: energyDerivationReqVars
    type(NamedString) ,allocatable ,dimension(:) :: csDerivs 
    type(NamedStringArray) ,allocatable ,dimension(:) :: csDerivsReqVars 
    type(NamedLogical) ,dimension(1) :: takeMomentumMoment

    integer(ik) :: locNumX ,locRank ,distVarIndex ,i ,j ,maxL ,l1Index

    type(DerivationContainer) ,allocatable ,dimension(:) :: csDerivCont
    class(Derivation) ,allocatable :: energyDeriv

    integer(ik) ,allocatable ,dimension(:) :: reqVarIndicesEnergy 
    type(IntArray) ,allocatable ,dimension(:) :: reqVarIndicesCS

    character(len=30) :: intToStrBuffer

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 
    maxL = envObj%gridObj%getMaxL()

    inStates(1) = NamedIntegerArray(tTag//"."//keyIngoingStatePlural,[1])
    outStates(1) = NamedIntegerArray(tTag//"."//keyOutgoingStatePlural,[1])
    csLIndices(1)%name = tTag//"."//keyCrossSectionDerivations//"."//keyCSDerivationHarmonics
    allocate(csLIndices(1)%values(0))


    call envObj%jsonCont%load(inStates)
    call envObj%jsonCont%output(inStates)
    call envObj%jsonCont%load(outStates)
    call envObj%jsonCont%output(outStates)

    call envObj%jsonCont%load(csLIndices)
    call envObj%jsonCont%output(csLIndices)

    allocate(csDerivsReqVars(size(csLIndices(1)%values)))
    allocate(csDerivs(size(csLIndices(1)%values)))

    do i = 1,size(csLIndices(1)%values)
        intToStrBuffer=""
        write(intToStrBuffer,'(I0)') csLIndices(1)%values(i)
        csDerivs(i)%name = tTag//"."//keyCrossSectionDerivations//"."//keyLPrefix//trim(intToStrBuffer)//"."//keyRuleName
        csDerivs(i)%value = ""
        csDerivsReqVars(i)%name = tTag//"."//keyCrossSectionDerivations//"."//keyLPrefix//trim(intToStrBuffer)//"."//keyReqVarNames
        allocate(csDerivsReqVars(i)%values(0))
    end do

    distributionVarName(1) = NamedString(tTag//"."//keyDistributionVarName,"")

    call envObj%jsonCont%load(distributionVarName)

    if (assertions .or. assertionLvl >= 0) call assert(envObj%externalVars%isVarNameRegistered(distributionVarName(1)%value),&
    distributionVarName(1)%value//" not registered in environment wrapper")

    call envObj%jsonCont%output(distributionVarName)

    distVarIndex = envObj%externalVars%getVarIndex(distributionVarName(1)%value)

    call envObj%jsonCont%load(csDerivs)
    call envObj%jsonCont%output(csDerivs)

    call envObj%jsonCont%load(csDerivsReqVars)
    call envObj%jsonCont%output(csDerivsReqVars)

    energyDerivName(1) = NamedString(tTag//"."//keyEnergyDerivationName,"")
    energyDerivationReqVars(1)%name = tTag//"."//keyEnergyDerivationReqVars
    allocate(energyDerivationReqVars(1)%values(0))

    call envObj%jsonCont%load(energyDerivName)
    call envObj%jsonCont%output(energyDerivName)

    call envObj%jsonCont%load(energyDerivationReqVars)
    call envObj%jsonCont%output(energyDerivationReqVars)

    allocate(reqVarIndicesEnergy(size(energyDerivationReqVars(1)%values)))

    do i = 1,size(energyDerivationReqVars(1)%values)
        reqVarIndicesEnergy(i) = envObj%externalVars%getVarIndex(energyDerivationReqVars(1)%values(i)%string)
    end do

    call envObj%textbookObj%copyDerivation(energyDerivName(1)%value,energyDeriv)

    allocate(csDerivCont(size(csDerivs)))
    allocate(reqVarIndicesCS(size(csDerivs)))

    do i = 1,size(csDerivs)
        call envObj%textbookObj%copyDerivation(energyDerivName(1)%value,csDerivCont(i)%entry)
        allocate(reqVarIndicesCS(size(csDerivsReqVars(i)%values)))
        do j =1,size(csDerivsReqVars(i)%values)
            reqVarIndicesCS(i)%entry(j) = envObj%externalVars%getVarIndex(csDerivsReqVars(i)%values(j)%string)
        end do
    end do

    takeMomentumMoment(1) = NamedLogical(tTag//"."//keyTakeMomentumMoment,.false.)

    call envObj%jsonCont%load(takeMomentumMoment)

    if (assertions .or. assertionLvl >= 0) then 
        if (takeMomentumMoment(1)%value) call assert(maxval(csLIndices(1)%values)>0,&
                                                    "Fixed energy/cross-section transition set to take momentum&
                                                    & moment when maximum cross-section harmonic is not 1 or higher")
    end if

    call envObj%jsonCont%output(takeMomentumMoment)

    l1Index = 1
    if (maxL > 0) l1Index = envObj%gridObj%getH(1,0,.false.)

    call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,energyDeriv,reqVarIndicesEnergy,csDerivCont,&
                            reqVarIndicesCS,csLIndices(1)%values+1,distVarIndex,envObj%vSpaceObj, &
                            momentumMoment=takeMomentumMoment(1)%value, l1Index=l1Index) 

    call crmData%addTransition(transitionObj)

end subroutine addVariableECSTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addDBTransitionToCRMData(crmData,envObj,tTag,fixedEnergies)
    !! Add custom detailed balance transition to CRM data object based on JSON file.

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    real(rk) ,dimension(:)     ,intent(in)    :: fixedEnergies

    type(DBTransition) :: transitionObj 

    type(NamedIntegerArray) ,dimension(1) :: inStates, outStates 
    type(NamedInteger) ,dimension(1) :: fixedEnergyIndex ,maxCSl ,directTransitionIndex &
                                       ,csUpdatePriority,directTransitionFixedEnergyIndex
    type(NamedString) ,dimension(1) :: distributionVarName, temperatureVarName ,degenRule
    type(NamedStringArray) ,dimension(1) :: degenRuleVars
    type(NamedLogical) ,dimension(1) :: takeMomentumMoment
    type(NamedReal) ,dimension(1) :: degeneracyRatio 

    class(Derivation) ,allocatable :: deriv

    integer(ik) :: locNumX ,locRank ,distVarIndex ,temperatureVarIndex,i ,maxL ,l1Index

    integer(ik) ,allocatable ,dimension(:) :: reqVarIndices

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 
    maxL = envObj%gridObj%getMaxL()

    inStates(1) = NamedIntegerArray(tTag//"."//keyIngoingStatePlural,[1])
    outStates(1) = NamedIntegerArray(tTag//"."//keyOutgoingStatePlural,[1])

    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyDirectTransitionEnergyIndex,0) 
    directTransitionFixedEnergyIndex(1) = NamedInteger(tTag//"."//keyDirectTransitionEnergyIndex,1)
    directTransitionIndex(1) = NamedInteger(tTag//"."//keyDirectTransitionIndex,0)
    maxCSl(1) = NamedInteger(tTag//"."//keyMaxCrossSectionL,0)

    csUpdatePriority(1) = NamedInteger(tTag//"."//keyCSUpdatePriority,0)

    call envObj%jsonCont%load(inStates)
    call envObj%jsonCont%output(inStates)
    call envObj%jsonCont%load(outStates)
    call envObj%jsonCont%output(outStates)
    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)
    call envObj%jsonCont%load(directTransitionFixedEnergyIndex)
    call envObj%jsonCont%output(directTransitionFixedEnergyIndex)
    call envObj%jsonCont%load(csUpdatePriority)
    call envObj%jsonCont%output(csUpdatePriority)

    call envObj%jsonCont%load(directTransitionIndex)
    call envObj%jsonCont%output(directTransitionIndex)

    call envObj%jsonCont%load(maxCSl)

    call envObj%jsonCont%output(maxCSl)


    distributionVarName(1) = NamedString(tTag//"."//keyDistributionVarName,"")
    temperatureVarName(1) = NamedString(tTag//"."//keyElectronTemperatureVar,"")

    call envObj%jsonCont%load(distributionVarName)
    call envObj%jsonCont%load(temperatureVarName)

    if (assertions .or. assertionLvl >= 0) then 
        call assert(envObj%externalVars%isVarNameRegistered(distributionVarName(1)%value),distributionVarName(1)%value&
                                //" not registered in environment wrapper")
        call assert(envObj%externalVars%isVarNameRegistered(temperatureVarName(1)%value),temperatureVarName(1)%value&
                                //" not registered in environment wrapper")
    end if
    call envObj%jsonCont%output(distributionVarName)

    distVarIndex = envObj%externalVars%getVarIndex(distributionVarName(1)%value)
    temperatureVarIndex = envObj%externalVars%getVarIndex(temperatureVarName(1)%value)

    takeMomentumMoment(1) = NamedLogical(tTag//"."//keyTakeMomentumMoment,.false.)

    call envObj%jsonCont%load(takeMomentumMoment)

    if (assertions .or. assertionLvl >= 0) then 
        if (takeMomentumMoment(1)%value) call assert(maxCSl(1)%value>0,"Fixed energy/cross-section transition set to take momentum&
                                                    & moment when maximum cross-section harmonic is not 1 or higher")
    end if

    call envObj%jsonCont%output(takeMomentumMoment)

    l1Index = 1
    if (maxL > 0) l1Index = envObj%gridObj%getH(1,0,.false.)

    degenRule(1) = NamedString(tTag//"."//keyDegeneracyRule,keyNone)

    degenRuleVars(1)%name = tTag//"."//keyDegeneracyRuleReqVars
    allocate(degenRuleVars(1)%values(0))

    degeneracyRatio = NamedReal(tTag//"."//keyFixedDegenRatio,real(1,kind=rk))

    call envObj%jsonCont%load(degeneracyRatio)
    call envObj%jsonCont%output(degeneracyRatio)

    call envObj%jsonCont%load(degenRule)
    call envObj%jsonCont%output(degenRule)

    call envObj%jsonCont%load(degenRuleVars)
    call envObj%jsonCont%output(degenRuleVars)

    allocate(reqVarIndices(size(degenRuleVars(1)%values)))

    do i = 1,size(degenRuleVars(1)%values)
        reqVarIndices(i) = envObj%externalVars%getVarIndex(degenRuleVars(1)%values(i)%string)
    end do

    if (degenRule(1)%value /= keyNone) then

        call envObj%textbookObj%copyDerivation(degenRule(1)%value,deriv)

        call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,fixedEnergies(fixedEnergyIndex(1)%value),&
                                distVarIndex,envObj%vSpaceObj,directTransitionIndex(1)%value,&
                                directTransitionFixedEnergyIndex(1)%value,fixedEnergyIndex(1)%value,&
                                temperatureVarIndex,maxCSl(1)%value,degeneracyRatio(1)%value,&
                                momentumMoment=takeMomentumMoment(1)%value, l1Index=l1Index,&
                                degeneracyFun=deriv,degeneracyFunIndices=reqVarIndices,csUpdatePriority=csUpdatePriority(1)%value)
    else
        call transitionObj%init(locNumX,inStates(1)%values,outStates(1)%values,fixedEnergies(fixedEnergyIndex(1)%value),&
                                distVarIndex,envObj%vSpaceObj,directTransitionIndex(1)%value,&
                                directTransitionFixedEnergyIndex(1)%value,fixedEnergyIndex(1)%value,&
                                temperatureVarIndex,maxCSl(1)%value,degeneracyRatio(1)%value,&
                                momentumMoment=takeMomentumMoment(1)%value, l1Index=l1Index,&
                                csUpdatePriority=csUpdatePriority(1)%value)
    end if

    call crmData%addTransition(transitionObj)

end subroutine addDBTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addJanevRadRecombTransitionToCRMData(crmData,envObj,tTag,normObj)
    !! Add Janev data radiative recombination transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    class(Normalization)       ,intent(in)    :: normObj

    type(NamedInteger) ,dimension(1) :: endState

    type(NamedString) ,dimension(1) :: temperatureVarName
    
    integer(ik) :: locNumX ,locRank ,temperatureVarIndex

    real(rk) :: tempNorm ,densNorm ,timeNorm

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 

    endState(1) = NamedInteger(tTag//"."//keyEndHState,1)

    call envObj%jsonCont%load(endState)
    call envObj%jsonCont%output(endState)

    temperatureVarName(1) = NamedString(tTag//"."//keyElectronTemperatureVar,"")

    call envObj%jsonCont%load(temperatureVarName)
    call envObj%jsonCont%output(temperatureVarName)

    if (assertions .or. assertionLvl >= 0) call assert(envObj%externalVars%isVarNameRegistered(temperatureVarName(1)%value),&
    temperatureVarName(1)%value//" not registered in environment wrapper")

    temperatureVarIndex = envObj%externalVars%getVarIndex(temperatureVarName(1)%value)

    tempNorm = normObj%getNormalizationValue(keyTempEVNorm)
    densNorm = normObj%getNormalizationValue(keyDensNorm)
    timeNorm = normObj%getNormalizationValue(keyTimeNorm)

    call addJanevRadRecombTransition(crmData,locNumX,endState(1)%value,temperatureVarIndex,tempNorm,densNorm,timeNorm)

end subroutine addJanevRadRecombTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addJanevCollExIonTransitionToCRMData(crmData,envObj,tTag,normObj)
    !! Add Janev data collisional excitation/ionization transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag
    class(Normalization)       ,intent(in)    :: normObj

    type(NamedInteger) ,dimension(1) :: startState, endState ,fixedEnergyIndex

    type(NamedString) ,dimension(1) :: distributionVarName
    
    integer(ik) :: locNumX ,locRank ,distVarIndex

    real(rk) :: tempNorm ,csNorm

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 

    startState(1) = NamedInteger(tTag//"."//keyStartHState,1)
    endState(1) = NamedInteger(tTag//"."//keyEndHState,1)
    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyFixedEnergyIndex,1)
    
    call envObj%jsonCont%load(startState)
    call envObj%jsonCont%output(startState)

    call envObj%jsonCont%load(endState)
    call envObj%jsonCont%output(endState)

    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)

    distributionVarName(1) = NamedString(tTag//"."//keyDistributionVarName,"")

    call envObj%jsonCont%load(distributionVarName)
    call envObj%jsonCont%output(distributionVarName)

    if (assertions .or. assertionLvl >= 0) call assert(envObj%externalVars%isVarNameRegistered(distributionVarName(1)%value),&
                                distributionVarName(1)%value//" not registered in environment wrapper")

    distVarIndex = envObj%externalVars%getVarIndex(distributionVarName(1)%value)

    tempNorm = normObj%getNormalizationValue(keyTempEVNorm)
    csNorm = normObj%getNormalizationValue(keyCrossSectionNorm)

    call addJanevCollExIonTransition(crmData,locNumX,startState(1)%value,endState(1)%value,distVarIndex,&
                                    tempNorm,csNorm,envObj%vSpaceObj,fixedEnergyIndex(1)%value)

end subroutine addJanevCollExIonTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
subroutine addJanevCollDeexRecombTransitionToCRMData(crmData,envObj,tTag,normObj)
    !! Add Janev data collisional deexcitation/recombination transition to CRM data object based on JSON file

    type(ModelboundCRMData)    ,intent(inout) :: crmData
    type(EnvironmentWrapper)   ,intent(inout) :: envObj
    character(*)               ,intent(in)    :: tTag 
    class(Normalization)       ,intent(in)    :: normObj

    type(NamedInteger) ,dimension(1) :: startState, endState &
                                       ,directTransitionFixedEnergyIndex ,directTransitionIndex ,csUpdatePriority,fixedEnergyIndex

    type(NamedString) ,dimension(1) :: distributionVarName ,temperatureVarName
    
    integer(ik) :: locNumX ,locRank ,distVarIndex ,tempVarIndex

    real(rk) :: tempNorm ,densNorm

    locRank = envObj%mpiCont%getWorldRank()
    locNumX = envObj%partitionObj%getMaxXAtInd(locRank+1) - envObj%partitionObj%getMinXAtInd(locRank+1) + 1 

    startState(1) = NamedInteger(tTag//"."//keyStartHState,1)
    endState(1) = NamedInteger(tTag//"."//keyEndHState,1)
    directTransitionFixedEnergyIndex(1) = NamedInteger(tTag//"."//keyDirectTransitionEnergyIndex,1)
    directTransitionIndex(1) = NamedInteger(tTag//"."//keyDirectTransitionIndex,1)
    fixedEnergyIndex(1) = NamedInteger(tTag//"."//keyFixedEnergyIndex,1)
    csUpdatePriority(1) = NamedInteger(tTag//"."//keyCSUpdatePriority,0)
    
    call envObj%jsonCont%load(startState)
    call envObj%jsonCont%output(startState)

    call envObj%jsonCont%load(endState)
    call envObj%jsonCont%output(endState)

    call envObj%jsonCont%load(directTransitionFixedEnergyIndex)
    call envObj%jsonCont%output(directTransitionFixedEnergyIndex)

    call envObj%jsonCont%load(fixedEnergyIndex)
    call envObj%jsonCont%output(fixedEnergyIndex)

    call envObj%jsonCont%load(csUpdatePriority)
    call envObj%jsonCont%output(csUpdatePriority)

    call envObj%jsonCont%load(directTransitionIndex)
    call envObj%jsonCont%output(directTransitionIndex)

    distributionVarName(1) = NamedString(tTag//"."//keyDistributionVarName,"")
    temperatureVarName(1) = NamedString(tTag//"."//keyElectronTemperatureVar,"")

    call envObj%jsonCont%load(distributionVarName)
    call envObj%jsonCont%output(distributionVarName)

    call envObj%jsonCont%load(temperatureVarName)
    call envObj%jsonCont%output(temperatureVarName)

    if (assertions .or. assertionLvl >= 0) then 
        call assert(envObj%externalVars%isVarNameRegistered(distributionVarName(1)%value),distributionVarName(1)%value//&
                                " not registered in environment wrapper")
        call assert(envObj%externalVars%isVarNameRegistered(temperatureVarName(1)%value),temperatureVarName(1)%value//&
                                " not registered in environment wrapper")
    end if

    distVarIndex = envObj%externalVars%getVarIndex(distributionVarName(1)%value)
    tempVarIndex = envObj%externalVars%getVarIndex(temperatureVarName(1)%value)

    tempNorm = normObj%getNormalizationValue(keyTempEVNorm)
    densNorm = normObj%getNormalizationValue(keyDensNorm)

    call addJanevCollDeexRecombTransition(crmData,locNumX,startState(1)%value,endState(1)%value,distVarIndex,tempVarIndex,&
                                          tempNorm,densNorm,envObj%vSpaceObj,directTransitionFixedEnergyIndex(1)%value,&
                                          fixedEnergyIndex(1)%value,&
                                          directTransitionIndex(1)%value,csUpdatePriority(1)%value)

end subroutine addJanevCollDeexRecombTransitionToCRMData
!-----------------------------------------------------------------------------------------------------------------------------------
end submodule modelbound_data_support_procedures
!-----------------------------------------------------------------------------------------------------------------------------------