Fortran introduction to CellML in OpenCMISSΒΆ
This example provides an entry level demonstration of creating fields in OpenCMISS to be defined using CellML models. This demonstration uses Fortran, see Python introduction to CellML in OpenCMISS for the corresponding Python example. The source code for this example is available here: src/FortranExample.f90
.
Following the usual OpenCMISS practices, you first need to declare the objects to be used in you application. For CellML, we would normally declare:
1 2 | TYPE(CMISSCellMLType) :: CellML
TYPE(CMISSFieldType) :: CellMLModelsField,CellMLStateField,CellMLIntermediateField,CellMLParametersField
|
which declares a single CellML environment that we will use and the fields that we will use with CellML. We also fetch the URL of the CellML model we will load from the command line arguments, if it is provided. Otherwise we fall back on the default Noble 1998
model.
1 2 3 4 5 6 7 8 | ! we want to get the CellML model from the command line
NUMBER_OF_ARGUMENTS = COMMAND_ARGUMENT_COUNT()
IF(NUMBER_OF_ARGUMENTS >= 1) THEN
CALL GET_COMMAND_ARGUMENT(1,ModelUrl,ARGUMENT_LENGTH,STATUS)
IF(STATUS>0) WRITE(*,'(">>ERROR: Error for command argument 1.")')
ELSE
ModelUrl="n98.xml"
ENDIF
|
We then create our CellML environment and import the model defined above. Having imported the model we are able to flag the parameters of interest, namely the stimulus current and the sodium channel conductance, as known variables. We also flag all the membrane currents as wanted variables in order to have access to their values from OpenCMISS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | !Create the CellML environment
CALL CMISSCellML_Initialise(CellML,Err)
CALL CMISSCellML_CreateStart(CellMLUserNumber,Region,CellML,Err)
!Import the specified model into the CellML environment
CALL CMISSCellML_ModelImport(CellML,ModelUrl,modelIndex,Err)
! Now we have imported all the models we are able to specify which variables from the model we want:
! - to set from this side
CALL CMISSCellML_VariableSetAsKnown(CellML,modelIndex,"fast_sodium_current/g_Na ",Err)
CALL CMISSCellML_VariableSetAsKnown(CellML,modelIndex,"membrane/IStim",Err)
! - to get from the CellML side (state variables are wanted by default and can not be changed)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_K1",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_to",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_K",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_K_ATP",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_Ca_L_K",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_b_K",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_NaK",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_Na",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_b_Na",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_Ca_L_Na",Err)
CALL CMISSCellML_VariableSetAsWanted(CellML,modelIndex,"membrane/i_NaCa",Err)
! - and override constant parameters without needing to set up fields
!> \todo Need to allow parameter values to be overridden for the case when user has non-spatially varying parameter value.
! CALL CMISSDiagnosticsSetOff(Err)
!Finish the CellML environment
CALL CMISSCellML_CreateFinish(CellML,Err)
|
Having flagged the desired variables, we finish the creation of the CellML environment. This triggers the instantion of the CellML model into a computable black box for use by solvers in OpenCMISS control loops.
We are then able to specify the actual field mapping, in this case assuming that we are going to perform an electrophysiology simulation with the CellML model so needing to map the membrane potential variable from the model to the OpenCMISS dependent field.
1 2 3 4 5 6 7 8 9 10 11 | !Start the creation of CellML <--> OpenCMISS field maps
CALL CMISSCellML_FieldMapsCreateStart(CellML,Err)
!Now we can set up the field variable component <--> CellML model variable mappings.
!Map Vm - field to CellML
CALL CMISSCellML_CreateFieldToCellMLMap(CellML,DependentField,CMISS_FIELD_U_VARIABLE_TYPE,1,CMISS_FIELD_VALUES_SET_TYPE, &
& modelIndex,"membrane/V",CMISS_FIELD_VALUES_SET_TYPE,Err)
! - and CellML to field
CALL CMISSCellML_CreateCellMLToFieldMap(CellML,modelIndex,"membrane/V",CMISS_FIELD_VALUES_SET_TYPE, &
& DependentField,CMISS_FIELD_U_VARIABLE_TYPE,1,CMISS_FIELD_VALUES_SET_TYPE,Err)
!Finish the creation of CellML <--> OpenCMISS field maps
CALL CMISSCellML_FieldMapsCreateFinish(CellML,Err)
|
Following the maps we create the CellML fields:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | !Start the creation of the CellML models field
CALL CMISSField_Initialise(CellMLModelsField,Err)
CALL CMISSCellML_ModelsFieldCreateStart(CellML,CellMLModelsFieldUserNumber,CellMLModelsField,Err)
!Finish the creation of the CellML models field
CALL CMISSCellML_ModelsFieldCreateFinish(CellML,Err)
!Start the creation of the CellML state field
CALL CMISSField_Initialise(CellMLStateField,Err)
CALL CMISSCellML_StateFieldCreateStart(CellML,CellMLStateFieldUserNumber,CellMLStateField,Err)
!Finish the creation of the CellML state field
CALL CMISSCellML_StateFieldCreateFinish(CellML,Err)
!Start the creation of the CellML intermediate field
CALL CMISSField_Initialise(CellMLIntermediateField,Err)
CALL CMISSCellML_IntermediateFieldCreateStart(CellML,CellMLIntermediateFieldUserNumber,CellMLIntermediateField,Err)
!Finish the creation of the CellML intermediate field
CALL CMISSCellML_IntermediateFieldCreateFinish(CellML,Err)
!Start the creation of CellML parameters field
CALL CMISSField_Initialise(CellMLParametersField,Err)
CALL CMISSCellML_ParametersFieldCreateStart(CellML,CellMLParametersFieldUserNumber,CellMLParametersField,Err)
!Finish the creation of CellML parameters
CALL CMISSCellML_ParametersFieldCreateFinish(CellML,Err)
|
We then define the spatial variation for the stimulus current variable flagged as known above. When setting up this spatial distribution we have to take into account the fact that this example application may be run in parallel and therefore only set values relevant to each specific computational node.
1 2 3 4 5 6 7 8 9 10 | CALL CMISSCellML_FieldComponentGet(CellML,modelIndex,CMISS_CELLML_PARAMETERS_FIELD,"membrane/IStim",stimcomponent,Err)
!Set the Stimulus at half the bottom nodes
DO node_idx=1,NUMBER_OF_ELEMENTS/2
CALL CMISSDecomposition_NodeDomainGet(Decomposition,node_idx,1,nodeDomain,Err)
IF(nodeDomain==ComputationalNodeNumber) THEN
CALL CMISSField_ParameterSetUpdateNode(CellMLParametersField,CMISS_FIELD_U_VARIABLE_TYPE,CMISS_FIELD_VALUES_SET_TYPE,1,1, &
& node_idx, &
& stimcomponent,STIM_VALUE,Err)
ENDIF
ENDDO
|
And finally, in a similar manner as the electrical stimulus above, we define the spatial distribution of the sodium channel conductance variable also flagged as known above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | !Set up the g_Na gradient
CALL CMISSCellML_FieldComponentGet(CellML,modelIndex,CMISS_CELLML_PARAMETERS_FIELD,"fast_sodium_current/g_Na", &
& gNacomponent,Err)
!Loop over the nodes
DO node_idx=1,(NUMBER_OF_ELEMENTS+1)*(NUMBER_OF_ELEMENTS+1)
CALL CMISSField_ParameterSetGetNode(GeometricField,CMISS_FIELD_U_VARIABLE_TYPE,CMISS_FIELD_VALUES_SET_TYPE,1,1,node_idx,1, &
& X,Err)
CALL CMISSField_ParameterSetGetNode(GeometricField,CMISS_FIELD_U_VARIABLE_TYPE,CMISS_FIELD_VALUES_SET_TYPE,1,1,node_idx,2, &
& Y,Err)
DISTANCE=SQRT(X**2+Y**2)/SQRT(2.0_CMISSDP)
gNa_VALUE=2.0_CMISSDP*(DISTANCE+0.5_CMISSDP)*385.5e-3_CMISSDP
CALL CMISSField_ParameterSetUpdateNode(CellMLParametersField,CMISS_FIELD_U_VARIABLE_TYPE,CMISS_FIELD_VALUES_SET_TYPE,1,1, &
& node_idx, &
& gNacomponent,gNa_VALUE,Err)
ENDDO
|