#DOC-END define monodomain problem

#Create the problem control loop
problem.ControlLoopCreateStart()
controlLoop = iron.ControlLoop()
problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], controlLoop)
controlLoop.TimesSet(0.0, stimStop, pdeTimeStep)

# controlLoop.OutputTypeSet(iron.ControlLoopOutputTypes.TIMING)
controlLoop.OutputTypeSet(iron.ControlLoopOutputTypes.NONE)

controlLoop.TimeOutputSet(outputFrequency)
problem.ControlLoopCreateFinish()

#Create the problem solvers
daeSolver = iron.Solver()
dynamicSolver = iron.Solver()
problem.SolversCreateStart()
# Get the first DAE solver
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, daeSolver)
daeSolver.DAESolverTypeSet(integrationMethod)
daeSolver.DAETimeStepSet(odeTimeStep)
daeSolver.OutputTypeSet(iron.SolverOutputTypes.NONE)
# Get the second dynamic solver for the parabolic problem
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 2, dynamicSolver)
dynamicSolver.OutputTypeSet(iron.SolverOutputTypes.NONE)
problem.SolversCreateFinish()

#DOC-START define CellML solver
#Create the problem solver CellML equations
cellMLEquations = iron.CellMLEquations()
    iron.ProblemClasses.ELASTICITY, iron.ProblemTypes.FINITE_ELASTICITY,
    iron.ProblemSubtypes.FINITE_ELASTICITY_CELLML
]
problem.CreateStart(problemUserNumber, problemSpecification)
problem.CreateFinish()
#DOC-END define CellML finite elasticity problem

#Create the problem control loop
problem.ControlLoopCreateStart()
ControlLoop = iron.ControlLoop()
problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], ControlLoop)
ControlLoop.TypeSet(iron.ProblemControlLoopTypes.SIMPLE)
problem.ControlLoopCreateFinish()

#Create the problem solvers
nonLinearSolver = iron.Solver()
linearSolver = iron.Solver()
problem.SolversCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, nonLinearSolver)
nonLinearSolver.OutputTypeSet(iron.SolverOutputTypes.PROGRESS)
nonLinearSolver.NewtonJacobianCalculationTypeSet(
    iron.JacobianCalculationTypes.FD)
nonLinearSolver.NewtonLinearSolverGet(linearSolver)
#Use the DIRECT MUMPS solver
linearSolver.LinearTypeSet(iron.LinearSolverTypes.DIRECT)
#For large problems or problems with complex material behaviour, the direct solver may fail
#In such cases either preconditioners or the following solvers can be tried
#In case the matrix has zeros for some rows, SUPERLU is a good solver to try as it will report such errors
#linearSolver.LibraryTypeSet(iron.SolverLibraries.PASTIX)
#linearSolver.LibraryTypeSet(iron.SolverLibraries.SUPERLU)
problem.SolversCreateFinish()
Esempio n. 3
0
# Create Laplace problem
problem = iron.Problem()
problemSpecification = [
    iron.ProblemClasses.CLASSICAL_FIELD, iron.ProblemTypes.LAPLACE_EQUATION,
    iron.ProblemSubtypes.STANDARD_LAPLACE
]
problem.CreateStart(problemUserNumber, problemSpecification)
problem.CreateFinish()

# Create control loops
problem.ControlLoopCreateStart()
problem.ControlLoopCreateFinish()

# Create problem solver
solver = iron.Solver()
problem.SolversCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, solver)
solver.outputType = iron.SolverOutputTypes.SOLVER
solver.linearType = iron.LinearSolverTypes.ITERATIVE
solver.linearIterativeAbsoluteTolerance = 1.0E-12
solver.linearIterativeRelativeTolerance = 1.0E-12
problem.SolversCreateFinish()

# Create solver equations and add equations set to solver equations
solver = iron.Solver()
solverEquations = iron.SolverEquations()
problem.SolverEquationsCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, solver)
solver.SolverEquationsGet(solverEquations)
solverEquations.sparsityType = iron.SolverEquationsSparsityTypes.SPARSE
# Define the problem
problem = iron.Problem()
problemSpecification = [
    iron.ProblemClasses.ELASTICITY, iron.ProblemTypes.FINITE_ELASTICITY,
    iron.ProblemSubtypes.NONE
]
problem.CreateStart(problemUserNumber, problemSpecification)
problem.CreateFinish()

# Create control loops
problem.ControlLoopCreateStart()
problem.ControlLoopCreateFinish()

# Create problem solver
nonLinearSolver = iron.Solver()
linearSolver = iron.Solver()
problem.SolversCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, nonLinearSolver)
nonLinearSolver.outputType = iron.SolverOutputTypes.PROGRESS
nonLinearSolver.NewtonJacobianCalculationTypeSet(
    iron.JacobianCalculationTypes.FD)
nonLinearSolver.NewtonLinearSolverGet(linearSolver)
linearSolver.linearType = iron.LinearSolverTypes.DIRECT
#linearSolver.libraryType = iron.SolverLibraries.LAPACK
problem.SolversCreateFinish()

# Create solver equations and add equations set to solver equations
solver = iron.Solver()
solverEquations = iron.SolverEquations()
problem.SolverEquationsCreateStart()
Esempio n. 5
0
def LidDriven(numberOfElements, cavityDimensions, lidVelocity, viscosity,
              density, outputFilename, transient, RBS, fdJacobian, analytic,
              basisList):
    """ Sets up the lid driven cavity problem and solves with the provided parameter values

          Square Lid-Driven Cavity

                  v=1
               >>>>>>>>>>
             1|          |
              |          |
         v=0  |          |  v=0
              |          |
              |          |
              ------------
             0    v=0    1
    """

    # Create a generated mesh
    generatedMesh = iron.GeneratedMesh()
    generatedMesh.CreateStart(generatedMeshUserNumber, region)
    generatedMesh.type = iron.GeneratedMeshTypes.REGULAR
    generatedMesh.basis = basisList
    generatedMesh.extent = cavityDimensions
    generatedMesh.numberOfElements = numberOfElements

    mesh = iron.Mesh()
    generatedMesh.CreateFinish(meshUserNumber, mesh)

    # Create a decomposition for the mesh
    decomposition = iron.Decomposition()
    decomposition.CreateStart(decompositionUserNumber, mesh)
    decomposition.type = iron.DecompositionTypes.CALCULATED
    decomposition.numberOfDomains = numberOfComputationalNodes
    decomposition.CreateFinish()

    # Create a field for the geometry
    geometricField = iron.Field()
    geometricField.CreateStart(geometricFieldUserNumber, region)
    geometricField.meshDecomposition = decomposition
    geometricField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 1, 1)
    geometricField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 2, 1)
    geometricField.CreateFinish()

    # Set geometry from the generated mesh
    generatedMesh.GeometricParametersCalculate(geometricField)

    # Create standard Navier-Stokes equations set
    equationsSetField = iron.Field()
    equationsSet = iron.EquationsSet()
    if RBS:
        equationsSetSpecification = [
            iron.EquationsSetClasses.FLUID_MECHANICS,
            iron.EquationsSetTypes.NAVIER_STOKES_EQUATION,
            iron.EquationsSetSubtypes.TRANSIENT_RBS_NAVIER_STOKES
        ]
    else:
        equationsSetSpecification = [
            iron.EquationsSetClasses.FLUID_MECHANICS,
            iron.EquationsSetTypes.NAVIER_STOKES_EQUATION,
            iron.EquationsSetSubtypes.TRANSIENT_NAVIER_STOKES
        ]
    equationsSet.CreateStart(equationsSetUserNumber, region, geometricField,
                             equationsSetSpecification,
                             equationsSetFieldUserNumber, equationsSetField)
    equationsSet.CreateFinish()

    if RBS:
        # Set max CFL number (default 1.0)
        equationsSetField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U1, iron.FieldParameterSetTypes.VALUES, 2,
            1.0E20)
        # Set time increment (default 0.0)
        equationsSetField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U1, iron.FieldParameterSetTypes.VALUES, 3,
            transient[2])
        # Set stabilisation type (default 1.0 = RBS)
        equationsSetField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U1, iron.FieldParameterSetTypes.VALUES, 4,
            1.0)

    # Create dependent field
    dependentField = iron.Field()
    equationsSet.DependentCreateStart(dependentFieldUserNumber, dependentField)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 1, 1)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 2, 1)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 3, 2)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.DELUDELN,
                                             1, 1)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.DELUDELN,
                                             2, 1)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.DELUDELN,
                                             3, 2)
    dependentField.DOFOrderTypeSet(iron.FieldVariableTypes.U,
                                   iron.FieldDOFOrderTypes.SEPARATED)
    dependentField.DOFOrderTypeSet(iron.FieldVariableTypes.DELUDELN,
                                   iron.FieldDOFOrderTypes.SEPARATED)
    equationsSet.DependentCreateFinish()
    # Initialise dependent field
    dependentField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 1, 0.0)

    # Create materials field
    materialsField = iron.Field()
    equationsSet.MaterialsCreateStart(materialsFieldUserNumber, materialsField)
    equationsSet.MaterialsCreateFinish()
    # Initialise materials field parameters
    materialsField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 1,
        viscosity)
    materialsField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 2,
        density)

    # If specified, use a sinusoidal waveform to ramp up lid velocity from 0 to 1
    if analytic:
        # yOffset + amplitude*sin(frequency*time + phaseShift))))
        # Set the time it takes to ramp velocity up to full lid velocity
        rampPeriod = 10.0
        frequency = math.pi / (rampPeriod)
        amplitude = 0.5 * lidVelocity[0]
        yOffset = 0.5 * lidVelocity[0]
        phaseShift = -math.pi / 2.0
        startSine = 0.0
        stopSine = rampPeriod
        analyticField = iron.Field()
        equationsSet.AnalyticCreateStart(
            iron.NavierStokesAnalyticFunctionTypes.SINUSOID,
            analyticFieldUserNumber, analyticField)
        equationsSet.AnalyticCreateFinish()
        analyticParameters = [
            1.0, 0.0, 0.0, 0.0, amplitude, yOffset, frequency, phaseShift,
            startSine, stopSine
        ]

    # Create equations
    equations = iron.Equations()
    equationsSet.EquationsCreateStart(equations)
    equations.sparsityType = iron.EquationsSparsityTypes.SPARSE
    equations.outputType = iron.EquationsOutputTypes.NONE
    equationsSet.EquationsCreateFinish()

    # Create Navier-Stokes problem
    problem = iron.Problem()
    if RBS:
        problemSpecification = [
            iron.ProblemClasses.FLUID_MECHANICS,
            iron.ProblemTypes.NAVIER_STOKES_EQUATION,
            iron.ProblemSubtypes.TRANSIENT_RBS_NAVIER_STOKES
        ]
    else:
        problemSpecification = [
            iron.ProblemClasses.FLUID_MECHANICS,
            iron.ProblemTypes.NAVIER_STOKES_EQUATION,
            iron.ProblemSubtypes.TRANSIENT_NAVIER_STOKES
        ]
    problem.CreateStart(problemUserNumber, problemSpecification)
    problem.CreateFinish()

    # Create control loops
    problem.ControlLoopCreateStart()
    controlLoop = iron.ControlLoop()
    problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], controlLoop)
    controlLoop.TimesSet(transient[0], transient[1], transient[2])
    controlLoop.TimeOutputSet(transient[3])
    problem.ControlLoopCreateFinish()

    # Create problem solver
    dynamicSolver = iron.Solver()
    problem.SolversCreateStart()
    problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, dynamicSolver)
    dynamicSolver.outputType = iron.SolverOutputTypes.NONE
    dynamicSolver.dynamicTheta = [0.5]
    nonlinearSolver = iron.Solver()
    dynamicSolver.DynamicNonlinearSolverGet(nonlinearSolver)
    if fdJacobian:
        nonlinearSolver.newtonJacobianCalculationType = iron.JacobianCalculationTypes.FD
    else:
        nonlinearSolver.newtonJacobianCalculationType = iron.JacobianCalculationTypes.EQUATIONS
    nonlinearSolver.outputType = iron.SolverOutputTypes.NONE
    nonlinearSolver.newtonAbsoluteTolerance = 1.0E-8
    nonlinearSolver.newtonRelativeTolerance = 1.0E-9
    nonlinearSolver.newtonSolutionTolerance = 1.0E-9
    nonlinearSolver.newtonMaximumFunctionEvaluations = 10000
    nonlinearSolver.newtonLineSearchType = iron.NewtonLineSearchTypes.QUADRATIC
    linearSolver = iron.Solver()
    nonlinearSolver.NewtonLinearSolverGet(linearSolver)
    linearSolver.outputType = iron.SolverOutputTypes.NONE
    linearSolver.linearType = iron.LinearSolverTypes.DIRECT
    linearSolver.libraryType = iron.SolverLibraries.MUMPS
    problem.SolversCreateFinish()

    # Create solver equations and add equations set to solver equations
    solver = iron.Solver()
    solverEquations = iron.SolverEquations()
    problem.SolverEquationsCreateStart()
    problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, solver)
    solver.SolverEquationsGet(solverEquations)
    solverEquations.sparsityType = iron.SolverEquationsSparsityTypes.SPARSE
    equationsSetIndex = solverEquations.EquationsSetAdd(equationsSet)
    problem.SolverEquationsCreateFinish()

    # Create boundary conditions
    boundaryConditions = iron.BoundaryConditions()
    solverEquations.BoundaryConditionsCreateStart(boundaryConditions)
    nodes = iron.Nodes()
    region.NodesGet(nodes)
    print("Total # of nodes: " + str(nodes.numberOfNodes))
    print("Analytic Parameters: " + str(analyticParameters))
    boundaryTolerance = 1.0e-6

    # Currently issues with getting generated mesh surfaces through python so easier to just loop over all nodes
    for node in range(nodes.numberOfNodes):
        nodeId = node + 1
        nodeNumber = nodes.UserNumberGet(nodeId)
        # print('node number: '+ str(nodeNumber))
        # Velocity nodes
        nodeDomain = decomposition.NodeDomainGet(nodeNumber, 1)
        if (nodeDomain == computationalNodeNumber):
            xLocation = geometricField.ParameterSetGetNodeDP(
                iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES,
                1, 1, nodeNumber, 1)
            yLocation = geometricField.ParameterSetGetNodeDP(
                iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES,
                1, 1, nodeNumber, 2)
            # rigid wall (left,right,bottom) conditions: v=0
            if (xLocation < boundaryTolerance
                    or cavityDimensions[0] - xLocation < boundaryTolerance
                    or yLocation < boundaryTolerance):
                boundaryConditions.SetNode(dependentField,
                                           iron.FieldVariableTypes.U, 1, 1,
                                           nodeNumber, 1,
                                           iron.BoundaryConditionsTypes.FIXED,
                                           0.0)
                boundaryConditions.SetNode(dependentField,
                                           iron.FieldVariableTypes.U, 1, 1,
                                           nodeNumber, 2,
                                           iron.BoundaryConditionsTypes.FIXED,
                                           0.0)
            # lid (top) conditions: v=v
            elif (cavityDimensions[1] - yLocation < boundaryTolerance):
                if not (xLocation < boundaryTolerance or
                        cavityDimensions[0] - xLocation < boundaryTolerance):
                    if analytic:
                        boundaryConditions.SetNode(
                            dependentField, iron.FieldVariableTypes.U, 1, 1,
                            nodeNumber, 1,
                            iron.BoundaryConditionsTypes.FIXED_INLET, 0.0)
                        boundaryConditions.SetNode(
                            dependentField, iron.FieldVariableTypes.U, 1, 1,
                            nodeNumber, 2,
                            iron.BoundaryConditionsTypes.FIXED_INLET, 0.0)
                        # Set analytic parameters
                        parameterNumber = 0
                        for parameter in analyticParameters:
                            parameterNumber += 1
                            analyticField.ParameterSetUpdateNodeDP(
                                iron.FieldVariableTypes.U,
                                iron.FieldParameterSetTypes.VALUES, 1, 1,
                                nodeNumber, parameterNumber, parameter)

                    else:
                        boundaryConditions.SetNode(
                            dependentField, iron.FieldVariableTypes.U, 1, 1,
                            nodeNumber, 1, iron.BoundaryConditionsTypes.FIXED,
                            lidVelocity[0])
                        boundaryConditions.SetNode(
                            dependentField, iron.FieldVariableTypes.U, 1, 1,
                            nodeNumber, 2, iron.BoundaryConditionsTypes.FIXED,
                            lidVelocity[1])

    # Pressure node
    nodeNumber = 1
    nodeDomain = decomposition.NodeDomainGet(nodeNumber, 2)
    if (nodeDomain == computationalNodeNumber):
        # bottom left node - reference pressure: p=0
        boundaryConditions.SetNode(dependentField, iron.FieldVariableTypes.U,
                                   1, 1, nodeNumber, 3,
                                   iron.BoundaryConditionsTypes.FIXED, 0.0)
        print('pressure node: ' + str(nodeNumber))

    solverEquations.BoundaryConditionsCreateFinish()

    # Solve the problem
    print("solving...")
    problem.Solve()

    print("exporting CMGUI data")
    # Export results
    fields = iron.Fields()
    fields.CreateRegion(region)
    fields.NodesExport(outputFilename, "FORTRAN")
    fields.ElementsExport(outputFilename, "FORTRAN")
    fields.Finalise()

    # Clear fields so can run in batch mode on this region
    generatedMesh.Destroy()
    nodes.Destroy()
    mesh.Destroy()
    geometricField.Destroy()
    if RBS:
        equationsSetField.Destroy()
    if analytic:
        analyticField.Destroy()
    dependentField.Destroy()
    materialsField.Destroy()
    equationsSet.Destroy()
    problem.Destroy()
problem = iron.Problem()
problemSpecification = [iron.ProblemClasses.ELASTICITY,
        iron.ProblemTypes.FINITE_ELASTICITY,
        iron.ProblemSubtypes.FINITE_ELASTICITY_WITH_GROWTH_CELLML]
problem.CreateStart(problemUserNumber,problemSpecification)
problem.CreateFinish()

# Create control loops
timeLoop = iron.ControlLoop()
problem.ControlLoopCreateStart()
problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE],timeLoop)
timeLoop.TimesSet(startTime,stopTime,timeIncrement)
problem.ControlLoopCreateFinish()

# Create problem solvers
odeIntegrationSolver = iron.Solver()
nonlinearSolver = iron.Solver()
linearSolver = iron.Solver()
cellMLEvaluationSolver = iron.Solver()
problem.SolversCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE],1,odeIntegrationSolver)
problem.SolverGet([iron.ControlLoopIdentifiers.NODE],2,nonlinearSolver)
nonlinearSolver.outputType = iron.SolverOutputTypes.PROGRESS
nonlinearSolver.NewtonJacobianCalculationTypeSet(iron.JacobianCalculationTypes.FD)
nonlinearSolver.NewtonCellMLSolverGet(cellMLEvaluationSolver)
nonlinearSolver.NewtonLinearSolverGet(linearSolver)
linearSolver.linearType = iron.LinearSolverTypes.DIRECT
problem.SolversCreateFinish()

# Create nonlinear equations and add equations set to solver equations
nonlinearEquations = iron.SolverEquations()
problem.CreateFinish()

# Create the problem control loops
# For static finite elasticity, there is just a
# single load increment control loop, and we set
# the number of load increments by setting the number of
# iterations of this control loop
problem.ControlLoopCreateStart()
controlLoop = iron.ControlLoop()
problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], controlLoop)
controlLoop.MaximumIterationsSet(numIncrements)
controlLoop.OutputTypeSet(iron.ControlLoopOutputTypes.PROGRESS)
problem.ControlLoopCreateFinish()

# Create the problem solver
solver = iron.Solver()
problem.SolversCreateStart()
problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, solver)
solver.OutputTypeSet(iron.SolverOutputTypes.PROGRESS)
solver.NewtonJacobianCalculationTypeSet(iron.JacobianCalculationTypes.EQUATIONS)
solver.NewtonRelativeToleranceSet(1.0e-8)
solver.NewtonAbsoluteToleranceSet(1.0e-8)
solver.NewtonSolutionToleranceSet(1.0e-8)
# Adjust settings for the line search solver
linesearchSolver = iron.Solver()
solver.NewtonLinearSolverGet(linesearchSolver)
linesearchSolver.LinearTypeSet(iron.LinearSolverTypes.DIRECT)
problem.SolversCreateFinish()

# Create solver equations for the problem and add
# the single equations set to solver equations.
Esempio n. 8
0
problem.CreateFinish()

# Create control loops and set the time parameters
timeLoop = iron.ControlLoop()
problem.ControlLoopCreateStart()
problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], timeLoop)
timeLoop.TimesSet(startTime, stopTime, timeIncrement)
# Disable time output as fluid_mechanics_IO_routines crashes
timeLoop.TimeOutputSet(0)
problem.ControlLoopCreateFinish()

# Create problem solvers
problem.SolversCreateStart()

# Set dynamic solver properties
dynamicSolver = iron.Solver()
dynamicSolverIndex = 1
problem.SolverGet(
    [iron.ControlLoopIdentifiers.NODE], dynamicSolverIndex, dynamicSolver)
dynamicSolver.outputType = iron.SolverOutputTypes.PROGRESS
dynamicSolver.dynamicTheta = [solverTheta]

# Set nonlinear solver properties
nonlinearSolver = iron.Solver()
dynamicSolver.DynamicNonlinearSolverGet(nonlinearSolver)
nonlinearSolver.newtonJacobianCalculationType = (
    iron.JacobianCalculationTypes.EQUATIONS)
nonlinearSolver.outputType = iron.SolverOutputTypes.NONE
nonlinearSolver.newtonAbsoluteTolerance = 1.0e-10
nonlinearSolver.newtonRelativeTolerance = 1.0e-10
Esempio n. 9
0
def solveProblem(transient, viscosity, density, offset, amplitude, period):
    """ Sets up the problem and solve with the provided parameter values


        Oscillatory flow through a rigid cylinder

                                     u=0
                  ------------------------------------------- R = 0.5
                                             >
                                             ->  
        p = offset + A*sin(2*pi*(t/period))  --> u(r,t)        p = 0
                                             ->
                                             >
                  ------------------------------------------- L = 10
                                     u=0
    """
    startTime = time.time()
    angularFrequency = 2.0 * math.pi / period
    womersley = radius * math.sqrt(angularFrequency * density / viscosity)
    if computationalNodeNumber == 0:
        print("-----------------------------------------------")
        print("Setting up problem for Womersley number: " + str(womersley))
        print("-----------------------------------------------")

    # Create standard Navier-Stokes equations set
    equationsSetField = iron.Field()
    equationsSet = iron.EquationsSet()
    equationsSetSpecification = [
        iron.EquationsSetClasses.FLUID_MECHANICS,
        iron.EquationsSetTypes.NAVIER_STOKES_EQUATION,
        iron.EquationsSetSubtypes.TRANSIENT_SUPG_NAVIER_STOKES
    ]
    equationsSet.CreateStart(equationsSetUserNumber, region, geometricField,
                             equationsSetSpecification,
                             equationsSetFieldUserNumber, equationsSetField)
    equationsSet.CreateFinish()
    # Set boundary retrograde flow stabilisation scaling factor (default 0.2)
    equationsSetField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.V, iron.FieldParameterSetTypes.VALUES, 1, 0.2)

    # Create dependent field
    dependentField = iron.Field()
    equationsSet.DependentCreateStart(dependentFieldUserNumber, dependentField)
    # velocity
    for component in range(1, 4):
        dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.U,
                                                 component,
                                                 meshComponentQuadratic)
        dependentField.ComponentMeshComponentSet(
            iron.FieldVariableTypes.DELUDELN, component,
            meshComponentQuadratic)
    # pressure
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.U, 4,
                                             meshComponentLinear)
    dependentField.ComponentMeshComponentSet(iron.FieldVariableTypes.DELUDELN,
                                             4, meshComponentLinear)
    dependentField.DOFOrderTypeSet(iron.FieldVariableTypes.U,
                                   iron.FieldDOFOrderTypes.SEPARATED)
    dependentField.DOFOrderTypeSet(iron.FieldVariableTypes.DELUDELN,
                                   iron.FieldDOFOrderTypes.SEPARATED)
    equationsSet.DependentCreateFinish()
    # Initialise dependent field to 0
    for component in range(1, 5):
        dependentField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES,
            component, 0.0)
        dependentField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.DELUDELN,
            iron.FieldParameterSetTypes.VALUES, component, 0.0)

    # Initialise dependent field to analytic values
    initialiseAnalytic = True
    if initialiseAnalytic:
        for node in range(1, numberOfNodes + 1):
            sumPositionSq = 0.
            nodeNumber = nodes.UserNumberGet(node)
            nodeDomain = decomposition.NodeDomainGet(nodeNumber,
                                                     meshComponentQuadratic)
            if (nodeDomain == computationalNodeNumber):
                for component in range(1, 4):
                    if component != axialComponent + 1:
                        value = geometricField.ParameterSetGetNodeDP(
                            iron.FieldVariableTypes.U,
                            iron.FieldParameterSetTypes.VALUES, 1,
                            iron.GlobalDerivativeConstants.NO_GLOBAL_DERIV,
                            nodeNumber, component)
                        sumPositionSq += value**2
                radialNodePosition = math.sqrt(sumPositionSq)
                for component in range(1, 4):
                    if component == axialComponent + 1:
                        value = womersleyAnalytic.womersleyAxialVelocity(
                            transient[0], offset, amplitude, radius,
                            radialNodePosition, period, viscosity, womersley,
                            length)
                    else:
                        value = 0.0
                    dependentField.ParameterSetUpdateNodeDP(
                        iron.FieldVariableTypes.U,
                        iron.FieldParameterSetTypes.VALUES, 1, 1, nodeNumber,
                        component, value)

    # Create materials field
    materialsField = iron.Field()
    equationsSet.MaterialsCreateStart(materialsFieldUserNumber, materialsField)
    equationsSet.MaterialsCreateFinish()
    # Initialise materials field parameters
    materialsField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 1,
        viscosity)
    materialsField.ComponentValuesInitialiseDP(
        iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 2,
        density)

    # Create analytic field (allows for time-dependent calculation of sinusoidal pressure waveform during solve)
    analytic = True
    if analytic:
        analyticField = iron.Field()
        equationsSet.AnalyticCreateStart(
            iron.NavierStokesAnalyticFunctionTypes.FlowrateSinusoid,
            analyticFieldUserNumber, analyticField)
        equationsSet.AnalyticCreateFinish()
        # Initialise analytic field parameters: (1-4) Dependent params, 5 amplitude, 6 offset, 7 period
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 1,
            0.0)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 2,
            0.0)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 3,
            0.0)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 4,
            1.0)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 5,
            amplitude)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 6,
            offset)
        analyticField.ComponentValuesInitialiseDP(
            iron.FieldVariableTypes.U, iron.FieldParameterSetTypes.VALUES, 7,
            period)

    # Create equations
    equations = iron.Equations()
    equationsSet.EquationsCreateStart(equations)
    equations.sparsityType = iron.EquationsSparsityTypes.SPARSE
    equations.outputType = iron.EquationsOutputTypes.NONE
    equationsSet.EquationsCreateFinish()

    # Create Navier-Stokes problem
    problem = iron.Problem()
    problemSpecification = [
        iron.ProblemClasses.FLUID_MECHANICS,
        iron.ProblemTypes.NAVIER_STOKES_EQUATION,
        iron.ProblemSubTypes.TRANSIENT_SUPG_NAVIER_STOKES
    ]
    problem.CreateStart(problemUserNumber, problemSpecification)
    problem.CreateFinish()

    # Create control loops
    problem.ControlLoopCreateStart()
    controlLoop = iron.ControlLoop()
    problem.ControlLoopGet([iron.ControlLoopIdentifiers.NODE], controlLoop)
    controlLoop.TimesSet(transient[0], transient[1], transient[2])
    controlLoop.TimeOutputSet(transient[3])
    problem.ControlLoopCreateFinish()

    # Create problem solver
    dynamicSolver = iron.Solver()
    problem.SolversCreateStart()
    problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, dynamicSolver)
    dynamicSolver.outputType = iron.SolverOutputTypes.NONE
    dynamicSolver.dynamicTheta = [1.0]
    nonlinearSolver = iron.Solver()
    dynamicSolver.DynamicNonlinearSolverGet(nonlinearSolver)
    nonlinearSolver.newtonJacobianCalculationType = iron.JacobianCalculationTypes.EQUATIONS
    nonlinearSolver.outputType = iron.SolverOutputTypes.PROGRESS
    nonlinearSolver.newtonAbsoluteTolerance = 1.0E-7
    nonlinearSolver.newtonRelativeTolerance = 1.0E-7
    nonlinearSolver.newtonSolutionTolerance = 1.0E-7
    nonlinearSolver.newtonMaximumFunctionEvaluations = 10000
    linearSolver = iron.Solver()
    nonlinearSolver.NewtonLinearSolverGet(linearSolver)
    linearSolver.outputType = iron.SolverOutputTypes.NONE
    linearSolver.linearType = iron.LinearSolverTypes.DIRECT
    linearSolver.libraryType = iron.SolverLibraries.MUMPS
    problem.SolversCreateFinish()

    # Create solver equations and add equations set to solver equations
    solver = iron.Solver()
    solverEquations = iron.SolverEquations()
    problem.SolverEquationsCreateStart()
    problem.SolverGet([iron.ControlLoopIdentifiers.NODE], 1, solver)
    solver.SolverEquationsGet(solverEquations)
    solverEquations.sparsityType = iron.SolverEquationsSparsityTypes.SPARSE
    equationsSetIndex = solverEquations.EquationsSetAdd(equationsSet)
    problem.SolverEquationsCreateFinish()

    # Create boundary conditions
    boundaryConditions = iron.BoundaryConditions()
    solverEquations.BoundaryConditionsCreateStart(boundaryConditions)
    # Wall boundary nodes u = 0 (no-slip)
    value = 0.0
    for nodeNumber in wallNodes:
        nodeDomain = decomposition.NodeDomainGet(nodeNumber,
                                                 meshComponentQuadratic)
        if (nodeDomain == computationalNodeNumber):
            for component in range(numberOfDimensions):
                componentId = component + 1
                boundaryConditions.SetNode(
                    dependentField, iron.FieldVariableTypes.U, 1,
                    iron.GlobalDerivativeConstants.NO_GLOBAL_DERIV, nodeNumber,
                    componentId, iron.BoundaryConditionsTypes.FIXED, value)
    # Note: inlet/outlet nodes are pressure-based so only defined on linear nodes
    # outlet boundary nodes p = 0
    value = 0.0
    for nodeNumber in outletNodes:
        nodeDomain = decomposition.NodeDomainGet(nodeNumber,
                                                 meshComponentLinear)
        if (nodeDomain == computationalNodeNumber):
            boundaryConditions.SetNode(
                dependentField, iron.FieldVariableTypes.U, 1,
                iron.GlobalDerivativeConstants.NO_GLOBAL_DERIV, nodeNumber, 4,
                iron.BoundaryConditionsTypes.FIXED_OUTLET, value)
    # inlet boundary nodes p = f(t) - will be updated in pre-solve
    value = 0.0
    for nodeNumber in inletNodes:
        nodeDomain = decomposition.NodeDomainGet(nodeNumber,
                                                 meshComponentQuadratic)
        if (nodeDomain == computationalNodeNumber):
            boundaryConditions.SetNode(
                dependentField, iron.FieldVariableTypes.U, 1,
                iron.GlobalDerivativeConstants.NO_GLOBAL_DERIV, nodeNumber, 4,
                iron.BoundaryConditionsTypes.FIXED_INLET, value)
    solverEquations.BoundaryConditionsCreateFinish()

    # Solve the problem
    print("solving problem...")
    problem.Solve()
    print("Finished. Time to solve (seconds): " + str(time.time() - startTime))

    # Clear fields so can run in batch mode on this region
    materialsField.Destroy()
    dependentField.Destroy()
    analyticField.Destroy()
    equationsSet.Destroy()
    problem.Destroy()