Ejemplo n.º 1
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()
CellMLIntermediateField = iron.Field()
CellML.IntermediateFieldCreateStart(CellMLIntermediateFieldUserNumber,
                                    CellMLIntermediateField)
CellML.IntermediateFieldCreateFinish()
#DOC-END define CellML parameters and intermediate fields

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

#DOC-START define CellML finite elasticity problem
#Define the problem
problem = iron.Problem()
problemSpecification = [
    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()
Ejemplo n.º 3
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()