import os
import shutil
from string import Template
import sys
import smtk
from smtk import attribute, io, mesh, model, simulation

print '====================================================================='
#print 'python', sys.version

def OpenFile(fileName, openFOAMObject, openFOAMClass='dictionary', openFOAMLocation=None):
    if not os.path.exists(os.path.dirname(fileName)):
        try:
            os.makedirs(os.path.dirname(fileName))
        except:
            print 'WARNING: Could not make', os.path.dirname(fileName), 'directory for exporting'
            return None

    f = open(fileName, 'w')
    f.write('/* Created with ModelBuilder (www.computationalmodelbuilder.org) */\n')
    f.write('FoamFile\n')
    f.write('{\n')
    f.write('    version     2.0;\n')
    f.write('    format      ascii;\n')
    f.write('    class       ' + openFOAMClass + ';\n')
    if openFOAMLocation:
        f.write('    location       ' + openFOAMLocation + ';\n')
    f.write('    object      '+openFOAMObject+';\n')
    f.write('}\n')
    print 'Created file %s' % fileName
    return f

def GenerateItemValuePairString(item, name=None):
    if not item.isEnabled():
        return None

    if type(item) == smtk.attribute._smtkPybindAttribute.VoidItem:
        return GenerateVoidItemString(item, name=name)

    if name:
        text = name
    else:
        text = item.name()
    if item.numberOfValues() > 1:
        text = text + '         ('
        for i in range(item.numberOfValues()):
            text = text + str(item.value(i)) + ' '
        text = text + ');\n'
    else:
        text = text + '         ' + str(item.value(0)) + ';\n'
    return text

def GenerateVoidItemString(item, options=None, name=None):
    text = None
    if name == None:
        name = item.name()
    if item.isEnabled():
        if options:
            text = name+'  '+options[1]+';\n'
        else:
            text = name+'  true;\n'
    else:
        if options:
            text = name+'  '+options[0]+';\n'
        else:
            text = name+'  false;\n'
    return text

def PrintItemValuePair(f, item, name=None):
    text = GenerateItemValuePairString(item, name)
    if text:
        f.write(text)

def PrintVoidItem(f, item, options=None, name=None):
    text = GenerateVoidItemString(item, options, name)
    f.write(text)

def GenerateAttributeBlockString(name, text):
    outString = name + '\n{\n' + text + '}\n'
    return outString

def PrintAttributeBlock(f, name, text):
    outString = GenerateAttributeBlockString(name, text)
    f.write(outString)

def CopyMotorBikeFile(filename, output_folder, path=''):
    '''Copies file from workflow 'motorBike' folder to output folder

    @input path: common to both source and output folders
    '''
    source_dir = os.path.dirname(os.path.abspath(__file__))
    source_path = os.path.join(source_dir, 'internal', 'motorBike', path, filename)
    dest_path = os.path.join(output_folder, path, filename)
    shutil.copy(source_path, dest_path)
    rel_path = '%s/%s' % (path,filename) if path else filename
    print 'Copied', rel_path

def GetObstacleName(model_manager):
    '''Figures out the name of the obstacle item

    @input model_manager

    Code requires that only ONE model face is the obstacle
    Code compares entity names with those known to be the 6 wind tunnel sides.
    '''
    wind_tunnel_names = set(
        ['back', 'ceiling', 'floor', 'front', 'inlet', 'outlet'])
    mask = int(smtk.model.FACE)
    model_ents = model_manager.entitiesMatchingFlags(mask, True)
    # Expect 13 faces: 12 for the wind tunnel and 1 for the obstacle
    if len(model_ents) != 13:
        msg = 'Unexpected number of model faces, expected 13 but got %s ' % len(model_ents)
        raise Exception(msg)
    for model_ent in model_ents:
        name = model_manager.name(model_ent)
        if not name in wind_tunnel_names:
            return name
    # else
    raise Exception('Unable to find obstacle name')


def ExportCMB(spec):
    # Get the attribute managers
    sim_atts = spec.getSimulationAttributes()
    export_atts = spec.getExportAttributes()

    # Workaround: Next line is needed; otherwise smtk not always defined.
    # No idea why this occurs.
    import smtk

    # Get the model manager
    model_manager = sim_atts.refModelManager()

    # Get the mesh
    att_list = export_atts.findAttributes('ExportSpec')
    att = att_list[0]
    model_item = att.find('model')

    obstacle_name = GetObstacleName(model_manager)
    print 'obstacle_name is:', obstacle_name

    #if model_item and model_item.numberOfValues() > 0 and model_item.isSet(0):
    #    model = model_item.value(0)
    #    print 'model_collection', model

    #if model is None:
    #   raise Exception('Model not found (is the model item set?)')
    #    print 'Model not found (is the model item set?)'


    # Get output directory
    # ProjectDir item for overriding the default case
    dir_item = att.findDirectory('ProjectDir')
    if dir_item.isSet(0):
        baseDirectory = dir_item.value(0) + '/'
    else:
        # Default case - get working directory from current session
        import smtk.bridge.openfoam
        model_ent = model_item.value(0).entity()
        session_uuid = model_manager.sessionOwningEntity(model_ent)
        session_ref = smtk.model.SessionRef(model_manager, session_uuid)
        session = session_ref.session()

        if session.workingDirectoryExists():
            baseDirectory = session.workingDirectory() + '/'
        else:
            raise Exception('No project directory specified in OpenFOAM session')


    actualDirectory = baseDirectory + 'system/'
    if not os.path.exists(actualDirectory):
        try:
            os.makedirs(actualDirectory)
        except:
            print 'Could not make', actualDirectory, 'directory for exporting'
            return

    # write out stuff in analysis.sbt
    application_att = sim_atts.findAttributes('application')[0] # a list that we get the first item of...
    #print 'application_att=', application_att
    application_item = application_att.findString('application')
    #print 'application_type=', application_item.value(0) #prints out simpleFoam


    #create controlDict
    f = OpenFile(actualDirectory+'controlDict', 'controlDict')
    PrintItemValuePair(f, application_item)

    timeControl_att = sim_atts.findAttributes('timeControl')[0]
    start_item = timeControl_att.findString('start')
    PrintItemValuePair(f, start_item)
    if start_item.value(0) == 'latestTime' or start_item.value(0) == 'startTime':
        startTime_groupItem = start_item.findChild('startTime', smtk.attribute.ACTIVE_CHILDREN)
        if not startTime_groupItem:
            startTime_groupItem = start_item.findChild('latestTime', smtk.attribute.ACTIVE_CHILDREN)
        time_item = startTime_groupItem.find('time')
        PrintItemValuePair(f, time_item, 'startTime')

    stop_item = timeControl_att.findString('stop')
    PrintItemValuePair(f, stop_item, 'stopAt')
    if stop_item.value(0) == 'endTime':
        endTime_groupItem = stop_item.findChild('endTime', smtk.attribute.ACTIVE_CHILDREN)
        time_item = endTime_groupItem.find('time')
        PrintItemValuePair(f, time_item, 'endTime')

    deltaT_item = timeControl_att.findDouble('deltaT')
    PrintItemValuePair(f, deltaT_item)

    dataWriting_att = sim_atts.findAttributes('dataWriting')[0]
    PrintItemValuePair(f, dataWriting_att.findString('writeControl') )
    PrintItemValuePair(f, dataWriting_att.findDouble('writeInterval') )
    PrintItemValuePair(f, dataWriting_att.findInt('purgeWrite') )
    PrintItemValuePair(f, dataWriting_att.findString('writeFormat') )
    PrintItemValuePair(f, dataWriting_att.findInt('writePrecision') )
    PrintVoidItem(f, dataWriting_att.findVoid('writeCompression'), ['uncompressed', 'compressed'] )
    # missing time format in attributes
    f.write('timeFormat     general;\n')
    PrintItemValuePair(f, dataWriting_att.findInt('timePrecision') )

    otherControl_att = sim_atts.findAttributes('otherControl')[0]
    PrintItemValuePair(f, otherControl_att.findVoid('adjustTimeStep') )
    PrintItemValuePair(f, otherControl_att.findDouble('maxCo') )
    PrintVoidItem(f, otherControl_att.findVoid('runTimeModifiable'))

    f.write( \
"""
functions
{
    #include "streamLines"
    #include "cuttingPlane"
    #include "forceCoeffs"
}
""")
    f.close()

    # create fvSchemes
    f = OpenFile(actualDirectory+'fvSchemes', 'fvSchemes')

    ddtSchemes_att = sim_atts.findAttributes('ddtSchemes')[0]
    ddtScheme_item = ddtSchemes_att.findString('ddtScheme')
    if not ddtScheme_item.isEnabled():
        text = 'default  steadyState;\n'
    else:
        text = GenerateItemValuePairString(ddtScheme_item, 'default')
    PrintAttributeBlock(f, 'ddtSchemes', text)

    gradSchemes_att = sim_atts.findAttributes('gradSchemes')[0]
    text = GenerateItemValuePairString(gradSchemes_att.findString('gradScheme'), 'default')
    gradU_item = gradSchemes_att.findVoid('grad(U)')
    if gradU_item.isEnabled():
        text = text + '    grad(U)         cellLimited Gauss linear 1;\n'
    PrintAttributeBlock(f, 'gradSchemes', text)

    # other "Schemes"
    text = """
divSchemes
{
    default         none;
    div(phi,U)      bounded Gauss linearUpwindV grad(U);
    div(phi,k)      bounded Gauss upwind;
    div(phi,omega)  bounded Gauss upwind;
    div((nuEff*dev2(T(grad(U))))) Gauss linear;
}

laplacianSchemes
{
    default         Gauss linear corrected;
}

interpolationSchemes
{
    default         linear;
}

snGradSchemes
{
    default         corrected;
}

wallDist
{
    method meshWave;
}
"""
    f.write(text)
    f.close()

    # create fvSolution
    f = OpenFile(actualDirectory+'fvSolution', 'fvSolution')

    psolver_att = sim_atts.findAttributes('psolver')[0]
    solver_item = psolver_att.findString('solver')
    text = GenerateItemValuePairString(solver_item)
    if solver_item.value() == 'pcg':
        pcg_item = solver_item.findChild('pcg', smtk.attribute.ACTIVE_CHILDREN)
        preconditioner_item = pcg_item.find('preconditioner')
        text = text + GenerateItemValuePairString(preconditioner_item)
    elif solver_item.value() == 'smoother' or solver_item.value() == 'GAMG':
        smootherOptions_item = solver_item.findChild('smootherOptions', smtk.attribute.ACTIVE_CHILDREN)
        nSweeps_item = smootherOptions_item.find('nSweeps')
        text = text + GenerateItemValuePairString(nSweeps_item)
        smoother_item = smootherOptions_item.find('smoother')
        text = text + GenerateItemValuePairString(smoother_item)

    tolerance_item = psolver_att.findDouble('tolerance')
    text = text + GenerateItemValuePairString(tolerance_item)
    relTol_item = psolver_att.findDouble('relTol')
    text = text + GenerateItemValuePairString(relTol_item)
    blockString = GenerateAttributeBlockString('p', text)

    usolver_att = sim_atts.findAttributes('usolver')[0]
    solver_item = usolver_att.findString('solver')
    text = GenerateItemValuePairString(solver_item)
    #print 'solveritem ------ ', solver_item.value()
    if solver_item.value() == 'PBiCG':
        pbicg_item = solver_item.findChild('pbicg', smtk.attribute.ACTIVE_CHILDREN)
        preconditioner_item = pbicg_item.find('preconditioner')
        text = text + GenerateItemValuePairString(preconditioner_item)
    elif solver_item.value() == 'smoothSolver' or solver_item.value() == 'GAMG':
        smootherOptions_item = solver_item.findChild('smootherOptions', smtk.attribute.ACTIVE_CHILDREN)
        nSweeps_item = smootherOptions_item.find('nSweeps')
        text = text + GenerateItemValuePairString(nSweeps_item)
        smoother_item = smootherOptions_item.find('smoothSolver')
        text = text + GenerateItemValuePairString(smoother_item, 'smoother')

    tolerance_item = usolver_att.findDouble('tolerance')
    text = text + GenerateItemValuePairString(tolerance_item)
    relTol_item = usolver_att.findDouble('relTol')
    text = text + GenerateItemValuePairString(relTol_item)

    blockString = blockString + GenerateAttributeBlockString('U', text)
    # Phi, k and/or omega are probably only for kOmegaSST turbulence model
    blockString = blockString + """
    Phi
    {
        $p;
    }
    k
    {
        solver           smoothSolver;
        smoother         GaussSeidel;
        tolerance        1e-8;
        relTol           0.1;
        nSweeps          1;
    }

    omega
    {
        solver           smoothSolver;
        smoother         GaussSeidel;
        tolerance        1e-8;
        relTol           0.1;
        nSweeps          1;
    }
"""
    PrintAttributeBlock(f, 'solvers', blockString)

    text = """
SIMPLE
{
    nNonOrthogonalCorrectors 0;
    consistent yes;
}

potentialFlow
{
    nNonOrthogonalCorrectors 10;
}

relaxationFactors
{
    equations
    {
        U               0.9;
        k               0.7;
        omega           0.7;
    }
}

cache
{
    grad(U);
}
"""
    f.write(text)
    f.close()

    #create constant/transportProperties
    actualDirectory = baseDirectory+'constant/'
    if not os.path.exists(actualDirectory):
        try:
            os.makedirs(actualDirectory)
        except:
            print 'Could not make', actualDirectory, 'directory for exporting'
            return

    f = OpenFile(actualDirectory+'transportProperties', 'transportProperties')
    f.write('transportModel  Newtonian;\n')
    material_att = sim_atts.findAttributes('material')[0]
    KinematicViscosity_item = material_att.findDouble('KinematicViscosity')
    PrintItemValuePair(f, KinematicViscosity_item, 'nu   [0 2 -1 0 0 0 0] ')
    f.close()

    #create U file
    actualDirectory = baseDirectory+'0/'
    if not os.path.exists(actualDirectory):
        try:
            print 'trying to make directory '
            os.makedirs(actualDirectory)
        except:
            print 'Could not make', actualDirectory, 'directory for exporting'
            return

    f = OpenFile(actualDirectory+'U', 'U', 'volVectorField', '"0"')
    f.write('dimensions      [0 1 -1 0 0 0 0];\n')
    initialCondition_att = sim_atts.findAttributes('initialCondition')[0]
    velocityIC_item = initialCondition_att.findDouble('velocityIC')
    PrintItemValuePair(f, velocityIC_item, 'internalField    uniform')
    boundaryFieldString = '    #includeEtc "caseDicts/setConstraintTypes"\n'

    boundaryCondition_atts = sim_atts.findAttributes('boundaryCondition')
    for b in boundaryCondition_atts:
        model_ent_item = b.associations()
        if model_ent_item is None:
            print 'WARNING: BC is missing a model entity...'
            continue

        variable_item = b.findString('variable')
        print 'got a bc of type ', variable_item.value(0)
        if variable_item.value(0) == 'velocity':
            velocity_item = variable_item.findChild('velocity-values', smtk.attribute.ACTIVE_CHILDREN)
            if velocity_item.value(0) == 0. and velocity_item.value(1) == 0. and velocity_item.value(2) == 0.:
                text = 'type noSlip;\n'
            else:
                text = 'type fixedValue;\n'
                text = text + GenerateItemValuePairString(velocity_item, 'value uniform')
        elif variable_item.value(0) == 'inletOutlet':
            velocity_item = variable_item.findChild('velocity-values', smtk.attribute.ACTIVE_CHILDREN)
            text = 'type inletOutlet;\n'
            text = text + 'inletValue uniform (0 0 0);\n' # not sure about this one
            text = text + GenerateItemValuePairString(velocity_item, 'value uniform')
        elif variable_item.value(0) == 'slip':
            text = 'type slip;\n'
        else:
            text = None

        if text:
            for i in range(model_ent_item.numberOfValues()):
                ent_ref = model_ent_item.value(i)
                print "entity", ent_ref.name()
                boundaryFieldString = boundaryFieldString + GenerateAttributeBlockString(ent_ref.name(), text)

    PrintAttributeBlock(f, 'boundaryField', boundaryFieldString)


    #create p file
    f = OpenFile(actualDirectory+'p', 'p', 'volScalarField')
    f.write('dimensions      [0 2 -2 0 0 0 0];\n')
    initialCondition_att = sim_atts.findAttributes('initialCondition')[0]
    pressureIC_item = initialCondition_att.findDouble('pressureIC')
    PrintItemValuePair(f, pressureIC_item, 'internalField    uniform')
    boundaryFieldString = '    #includeEtc "caseDicts/setConstraintTypes"\n'

    boundaryCondition_atts = sim_atts.findAttributes('boundaryCondition')
    for b in boundaryCondition_atts:
        model_ent_item = b.associations()
        if model_ent_item is None:
            print 'WARNING: BC is missing a model entity...'
            continue

        variable_item = b.findString('variable')
        if variable_item.value(0) == 'pressure':
            pressure_item = variable_item.findChild('pressure-bc-type', smtk.attribute.ACTIVE_CHILDREN)
            text = 'type fixedValue;\n'
            text = text + GenerateItemValuePairString(pressure_item, 'value  uniform')
        elif variable_item.value(0) == 'zeroGradient':
            text = 'type zeroGradient;\n'
        elif variable_item.value(0) == 'slip':
            text = 'type slip;\n'
        else:
            text = None

        if text:
            for i in range(model_ent_item.numberOfValues()):
                ent_ref = model_ent_item.value(i)
                #print "entity id", entityid, ent_ref.name()
                boundaryFieldString = boundaryFieldString + GenerateAttributeBlockString(ent_ref.name(), text)

    PrintAttributeBlock(f, 'boundaryField', boundaryFieldString)

    # turbulence stuff
    TurbulenceModelSelector_att = sim_atts.findAttributes('TurbulenceModelSelector')[0]
    selector_item = TurbulenceModelSelector_att.findString('Selector')
    actualDirectory = baseDirectory+'constant/'
    f = OpenFile(actualDirectory+'turbulenceProperties', 'turbulenceProperties', 'dictionary')
    PrintItemValuePair(f, selector_item, 'simulationType')
    if selector_item.value(0) == 'LES':
        print 'LES turbulence model output not currently supported'
    elif selector_item.value(0) == 'RAS':
        printCoeffs_attr = sim_atts.findAttributes('printCoeffs')[0]
        printCoeffs_item = printCoeffs_attr.findVoid('printCoeffs')
        if printCoeffs_item.isEnabled():
            text = 'printCoeffs   on;\n'
        else:
            text = 'printCoeffs   off;\n'

        rasModels_att = sim_atts.findAttributes('rasModels')[0]
        rasModel_item = rasModels_att.findString('rasModel')
        text = text + GenerateItemValuePairString(rasModel_item, 'RASModel')
        text = text + 'turbulence   on;\n'
        PrintAttributeBlock(f, 'RAS', text)

        # print out turbulence model parameters
        if rasModel_item.value(0) != 'kOmegaSST':
            print 'Only the kOmegaSST model is fully supported'

        text = str()
        turbulenceParameters_att = sim_atts.findAttributes(rasModel_item.value(0))[0]
        for i in range(turbulenceParameters_att.numberOfItems()):
            if turbulenceParameters_att.item(i).name()[0:7] != 'initial':
                text = text + GenerateItemValuePairString(turbulenceParameters_att.item(i))
        PrintAttributeBlock(f, rasModel_item.value(0)+'Coeffs', text)
        f.close()


        if rasModel_item.value(0) == 'kOmegaSST':
            actualDirectory = baseDirectory+'0/'
            f = OpenFile(actualDirectory+'k', 'k', 'volScalarField')
            f.write('dimensions      [0 2 -2 0 0 0 0];\n')
            kOmegaSST_att = sim_atts.findAttributes('kOmegaSST')[0]
            initialTurbulentKE_item = kOmegaSST_att.findDouble('initialTurbulentKE')
            PrintItemValuePair(f, initialTurbulentKE_item, 'internalField    uniform')

            # skip the turbulent BCs for now.
            kString ='''
boundaryField
{
    //- Set patchGroups for constraint patches
    #includeEtc "caseDicts/setConstraintTypes"

inlet
{
    type  fixedValue;
    value $internalField;
}

    outlet
    {
        type            inletOutlet;
        inletValue      $internalField;
        value           $internalField;
    }

    floor
    {
        type            kqRWallFunction;
        value           $internalField;
    }

    ${obstacle_name}
    {
        type            kqRWallFunction;
        value           $internalField;
    }

    ceiling
    {
        type slip;
    }

    front
    {
        type slip;
    }

    back
    {
        type slip;
    }
}
'''

            tpl = Template(kString)
            # Use safe_substitute in order to ignore $internalField
            content = tpl.safe_substitute(obstacle_name=obstacle_name)
            f.write(content)
            f.close()

            f = OpenFile(actualDirectory+'omega', 'omega', 'volScalarField')
            f.write('dimensions      [0 0 -1 0 0 0 0];\n')
            kOmegaSST_att = sim_atts.findAttributes('kOmegaSST')[0]
            initialTurbulentOmega_item = kOmegaSST_att.findDouble('initialTurbulentOmega')
            PrintItemValuePair(f, initialTurbulentOmega_item, 'internalField    uniform')
            # skip the turbulent BCs for now
            omegaString ='''
boundaryField
{
    //- Set patchGroups for constraint patches
    #includeEtc "caseDicts/setConstraintTypes"

inlet
{
    type  fixedValue;
    value $internalField;
}

    outlet
    {
        type            inletOutlet;
        inletValue      $internalField;
        value           $internalField;
    }

    floor
    {
        type            omegaWallFunction;
        value           $internalField;
    }

    ${obstacle_name}
    {
        type            omegaWallFunction;
        value           $internalField;
    }

    ceiling
    {
        type slip;
    }

    front
    {
        type slip;
    }

    back
    {
        type slip;
    }
}

'''
            tpl = Template(omegaString)
            content = tpl.safe_substitute(obstacle_name=obstacle_name)
            f.write(content)
            f.close()

            f = OpenFile(actualDirectory+'nut', 'nut', 'volScalarField', '"0"')
            nutString = '''
dimensions      [0 2 -1 0 0 0 0];

internalField   uniform 0;

boundaryField
{
    //- Set patchGroups for constraint patches
    #includeEtc "caseDicts/setConstraintTypes"

    front
    {
        type            calculated;
        value           uniform 0;
    }

    back
    {
        type            calculated;
        value           uniform 0;
    }

    inlet
    {
        type            calculated;
        value           uniform 0;
    }

    outlet
    {
        type            calculated;
        value           uniform 0;
    }

    floor
    {
        type            nutkWallFunction;
        value           uniform 0;
    }

    ceiling
    {
        type            calculated;
        value           uniform 0;
    }

    ${obstacle_name}
    {
        type            nutkWallFunction;
        value           uniform 0;
    }
}
'''
            tpl = Template(nutString)
            content = tpl.substitute(obstacle_name=obstacle_name)
            f.write(content)
            f.close()

            f = OpenFile(actualDirectory+'R', 'R', 'volScalarField', '"0"')
            RString = '''
dimensions      [0 2 -2 0 0 0 0];

internalField   uniform 0;

boundaryField
{
    //- Set patchGroups for constraint patches
    #includeEtc "caseDicts/setConstraintTypes"

    front
    {
        type            calculated;
        value           uniform 0;
    }

    back
    {
        type            calculated;
        value           uniform 0;
    }

    inlet
    {
        type            calculated;
        value           uniform 0;
    }

    outlet
    {
        type            calculated;
        value           uniform 0;
    }

    floor
    {
        type            calculated;
        value           uniform 0;
    }

    ceiling
    {
        type            calculated;
        value           uniform 0;
    }

    ${obstacle_name}
    {
        type            calculated;
        value           uniform 0;
    }
}
'''
            tpl = Template(RString)
            content = tpl.substitute(obstacle_name=obstacle_name)
            f.write(content)
            f.close()

            # Write forceCoeffs using template
            source_dir = os.path.dirname(os.path.abspath(__file__))
            source_path = os.path.join(source_dir, 'internal', 'motorBike', 'system', 'forceCoeffs')
            with open(source_path) as inp:
                source_data = inp.read()
            tpl = Template(source_data)
            content = tpl.substitute(obstacle_name=obstacle_name)

            output_path = os.path.join(baseDirectory, 'system', 'forceCoeffs')
            with open(output_path, 'w') as f:
                f.write(content)
                print 'Created file', output_path

    print "wrote in ", baseDirectory

    # copying over some files that we don't generate in ModelBuilder...
    top_filenames = ['Allrun']
    for filename in top_filenames:
        CopyMotorBikeFile(filename, baseDirectory)

    # Note we are skipping 'decomposeParDict' and working on single-threaded only
    system_filenames = ['cuttingPlane', 'streamLines']
    for filename in system_filenames:
        CopyMotorBikeFile(filename, baseDirectory, 'system')

    # Last step is to create an empty file in the base directory,
    # which is the entry point for ParaView.
    filename = '%s.foam' % obstacle_name
    output_path = os.path.join(baseDirectory, filename)
    with open(output_path, 'w') as f:
        f.write('Use this file to load data into ParaView.\n')
        print 'Created file', output_path


    print 'Finished writing OpenFOAM files'
    return True
