Skip to content

Commit

Permalink
updated butterfly libraries and a half-broken prototype
Browse files Browse the repository at this point in the history
- Updated butterfly libraries. Added files for blockMehDict and
BFSurface
- Created a prototype for an interior case with the help of
@TheodoreGalanos. 💯

OpenFOAM gives an error for face area which is probably because of the
order of the points. Fortunately I have a working example that I can use
to debug the code.

Next steps is to add snappyHexMeshDict and then default system folder
for boundary condition.
  • Loading branch information
mostaphaRoudsari committed Jun 19, 2016
1 parent a507c06 commit c5d2cb3
Show file tree
Hide file tree
Showing 62 changed files with 1,939,325 additions and 386 deletions.
4 changes: 2 additions & 2 deletions butterfly/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__all__ = ["core", "fields", "foamfile", "solvers", "version", "stl"]
__all__ = ["core", "fields", "foamfile", "solvers", "version", "gh"]

import core, fields, foamfile, solvers, version, stl
import core, fields, foamfile, solvers, version, gh
48 changes: 48 additions & 0 deletions butterfly/blockMeshDict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"BlockMeshDict class."
from foamfile import FoamFile
import os

class BlockMeshDict(FoamFile):

def __init__(self, scale, BFSurfaces, blocks):
FoamFile.__init__(self, name='blockMeshDict', cls='dictionary')
self.scale = scale
self.blocks = blocks
# collect uniqe vertices from all BFSurfaces
self.vertices = tuple(set(v for f in BFSurfaces for vgroup in f.borderVertices for v in vgroup))
self.BFSurfaces = BFSurfaces

def toOpenFoam(self):
_hea = self.header()
_body = "\nconvertToMeters 1;\n" \
"\n" \
"vertices\n" \
"(\n%s\n);\n" \
"\n" \
"blocks\n" \
"(\n%s\n);\n" \
"\n" \
"edges\n" \
"(%s);\n" \
"\n" \
"boundary\n" \
"(%s);\n" \
"\n" \
"mergePatchPair\n" \
"(%s);\n"

return _hea + \
_body % (
"\n".join(tuple(str(ver).replace(",", "")
for ver in self.vertices)),
"\n".join(block.blockMeshDict(self.vertices)
for block in self.blocks), #blocks
"\n", # edges
"\n".join(srf.blockMeshDict(self.vertices)
for srf in self.BFSurfaces),
"\n" # merge patch pair
)

def save(self, folder):
with open(os.path.join(folder, "blockMeshDict"), "wb") as outf:
outf.write(self.toOpenFoam())
140 changes: 66 additions & 74 deletions butterfly/core.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,92 @@
"""Butterfly core library."""
import os
import solvers
from fields import BoundaryField as bouf
from blockMeshDict import BlockMeshDict

class BFProject:

def __init__(self, projectName):
self.projectName = projectName
class Case(object):
"""Butterfly case."""
def __init__(self, BFSurfaces, blockMeshDict, snappyHexMesh=False):
"""Init project."""
self.username = os.getenv("USERNAME")
self.__solvers = []

def createProject(self):
"""Create project folders and write input files
self.BFSurfaces = BFSurfaces
self.blockMeshDict = blockMeshDict
self.snappyHexMesh = snappyHexMesh

workingDir for Butterfly files will be under
"users/username/butterfy/"
@classmethod
def fromBlocks(cls, BFSurfaces, blocks, scale):
"""Create case from BFSurfaces and blocks.
OpenFOAM for windows uses users/username folder to share data
projectDir will be set to:
"users/username/butterfy/projectName/"
This case will only be meshed using blockMesh
"""
_blockMeshDict = BlockMeshDict(scale, BFSurfaces, blocks)
return cls(BFSurfaces, _blockMeshDict, snappyHexMesh=False)

def write(self, projectName, workingDir=None):
"""Create project folders and write input files.
Args:
projectName: A valid name for project. Avoid whitespace and special
charecters.
workingDir: By default workingDir for Butterfly files will be under
"users/<username>/butterfy/". Do not change the folder unless you
need to save the files in a different folder. OpenFOAM for windows
uses "users/<username>" folder to share data.
"""
self.projectName = projectName
self.workingDir = "c:/users/%s/butterfly/" % self.username if not workingDir \
else workingDir
self.projectDir = os.path.join(self.workingDir, self.projectName)

# This method will be only useful on new systems
self.__createWorkingDir()
self.__createCaseFolder()
# Create sub folders (0, constant, system)
self.__createSubFolders()

# Create porject folders (0, constant, system)
self.__createProjectDir()
print "Files are exported to:\n%s" % os.path.normpath(self.projectDir)

def __createWorkingDir(self):
baseDir = "c:/users/%s/butterfly/"%self.username
self.workingDir = self.__createDir(baseDir)

def __createProjectDir(self):
projectDir = self.workingDir + self.projectName + "/"
self.projectDir = self.__createDir(projectDir)
self.__createSubFolders()
def __createCaseFolder(self):
self.__createDir(self.workingDir)

def __createSubFolders(self):
# create zero directory
zeroDir = self.projectDir + "0/"
self.zeroDir = self.__createDir(zeroDir)
self.__writeFilesInZeroDir()

# create constant directory
constantDir = self.projectDir + "constant/"
constantDir = os.path.join(self.projectDir, "constant")
self.constantDir = self.__createDir(constantDir)
# create polyMesh folder under contstant
self.__createDir(os.path.join(self.constantDir, "polyMesh"))

# create system directory
systemDir = self.projectDir + "system/"
self.systemDir = self.__createDir(systemDir)
if self.snappyHexMesh:
self.__createDir(os.path.join(self.constantDir, "triSurface"))

def __writeFilesInZeroDir(self):
for solver in self.__solvers:
solver.writeToFile(self.zeroDir)
self.__writeConstantFiles()

# TODO: write files inside the folder
def createConstantDir(self):
pass
# create system directory
systemDir = os.path.join(self.projectDir, "system")
self.systemDir = self.__createDir(systemDir)

# TODO: write files inside the folder
def createSystemDir(self):
pass
# create time directory
timestepDir = os.path.join(self.projectDir, "0")
self.timestepDir = self.__createDir(timestepDir)
# TODO: write velocity and pressure boundary condition
# self.__writeFilesInZeroDir()

def __writeConstantFiles(self):
"""write files in constant folder."""
# write blockMeshDict to polyMesh
self.blockMeshDict.save(os.path.join(self.constantDir, "polyMesh"))
# write stl files to triSurface
# for surface in self
if self.snappyHexMesh:
for BFSurface in self.BFSurfaces:
BFSurface.writeToStl(os.path.join(self.constantDir, "triSurface"))

@staticmethod
def __createDir(directory, overwrite = True):
def __createDir(directory, overwrite=True):
if not os.path.isdir(directory):
try:
os.mkdir(directory)
except:
raise Exception("Failed to create %s"%directory)
else:
# TODO add one more step to ask for user permission
print "%s already existed! Files will be overwritten"%directory

except Exception as e:
raise ValueError("Failed to create %s:\n%s" % (directory, e))
# TODO add one more step to ask for user permission
# print "%s already existed! Files will be overwritten." % directory
return directory

# TODO: Check the solver to be valid
def add_solver(self, newSolver):
"""Add solver to the list of solvers"""
solverNames = [solver.FoamFile.object for solver in self.__solvers]

if newSolver.FoamFile.object not in solverNames:
self.__solvers.append(newSolver)
else:
raise ValueError("%s already exist in project."%newSolver.FoamFile.object + \
"\nUse Project.get_solverByName and update the solver")

def get_solverByName(self, name):
"""Return solver by name"""
try:
return [solver for solver in self.__solvers if solver.FoamFile.object == name][0]
except:
raise Exception("%s is not a solver in this project.\n"%name + \
"You can create additional solvers and add them to project using Project.addSolver")

@property
def solvers(self):
names = [solver.FoamFile.object for solver in self.__solvers]
return ", ".join(names)
70 changes: 35 additions & 35 deletions butterfly/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@
class BoundaryField:
"""OpenFoam Boundary Field
Attributes:
name : Name of boundary field as a string
bcType : Type of boundary field (e.g fixedFluxPressure)
value : Value as a string (e.g uniform (0 0 0), )
other : A dictionary of other optional fields as key, values
Usage:
# create boundary field
floor_bof = BoundaryField(name = "floor",
bfType = "alphatJayatillekeWallFunction",
value = "uniform 0")
# add a new field
floor_bof.add_properties(properties={"Prt" : "0.85"})
print "Property is added > " + str(bof.properties)
# update the value for
floor_bof.update_properties(properties={"Prt" : "0.80", "notValid" : "0"})
print "Value is updated to 0.80 > " + str(bof.properties)
# remove Prt
floor_bof.remove_property("Prt")
print "Prt is removed > " + str(bof.properties)
# get OpenFoam string
print "This is how it will be in OpenFoam File >\n" + floor_bof.get_OFString()
# add another boundary field
fixedWalls_bof = BoundaryField(name = "fixedWalls",
bfType = "alphatJayatillekeWallFunction",
value = "uniform 0",
other = {"prt":"0.85"})
# get full string
print BoundaryField.get_BoundaryFieldsOFString([floor_bof, fixedWalls_bof])
Attributes:
name : Name of boundary field as a string
bcType : Type of boundary field (e.g fixedFluxPressure)
value : Value as a string (e.g uniform (0 0 0), )
other : A dictionary of other optional fields as key, values
Usage:
# create boundary field
floor_bof = BoundaryField(name = "floor",
bfType = "alphatJayatillekeWallFunction",
value = "uniform 0")
# add a new field
floor_bof.add_properties(properties={"Prt" : "0.85"})
print "Property is added > " + str(bof.properties)
# update the value for
floor_bof.update_properties(properties={"Prt" : "0.80", "notValid" : "0"})
print "Value is updated to 0.80 > " + str(bof.properties)
# remove Prt
floor_bof.remove_property("Prt")
print "Prt is removed > " + str(bof.properties)
# get OpenFoam string
print "This is how it will be in OpenFoam File >\n" + floor_bof.get_OFString()
# add another boundary field
fixedWalls_bof = BoundaryField(name = "fixedWalls",
bfType = "alphatJayatillekeWallFunction",
value = "uniform 0",
other = {"prt":"0.85"})
# get full string
print BoundaryField.get_BoundaryFieldsOFString([floor_bof, fixedWalls_bof])
"""

#TODO: Value should be it's own object but I don't really know all the value
Expand Down
70 changes: 36 additions & 34 deletions butterfly/foamfile.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,50 @@
#Foam File Class
from version import Version
from version import Version, Header

class FoamFile:
"""FoamFile setting
class FoamFile(object):
"""FoamFile base class.
Read (http://cfd.direct/openfoam/user-guide/basic-file-format/) for
more information about FoamFile
Read (http://cfd.direct/openfoam/user-guide/basic-file-format/) for
more information about FoamFile
Attributes:
name : Filename (e.g. controlDict)
OFClass : OpenFOAM class constructed from the data file
concerned. Typically dictionary or a field, e.g. volVectorField
location : Path to the file (0, constant or system)
fileFormat : File format (ascii / binary) (default: ascii)
Attributes:
name: Filename (e.g. controlDict)
OFClass: OpenFOAM class constructed from the data file
concerned. Typically dictionary or a field, e.g. volVectorField
location: Folder name (0, constant or system)
fileFormat: File format (ascii / binary) (default: ascii)
Usage:
ff = FoamFile("k", "volScalarField", "0")
print ff.get_OFString()
"""

# TODO: Add set and get methods
def __init__(self, name, OFClass, location = None, fileFormat = "ascii"):
Usage:
ff = FoamFile("k", "volScalarField", "0")
print ff.header()
"""
def __init__(self, name, cls, location=None, fileFormat="ascii"):
self.__version = str(Version.OFVer())
self.format = str(fileFormat) # ascii / binary
self.OFClass = str(OFClass) #dictionary or field
self.cls = str(cls) # dictionary or field
self.object = str(name)
self.location = str(location) #location is optional
self.location = location #location is optional
if self.location == "0":
self.location = '"' + self.location + '"'

def get_OFString(self):
def header(self):
"""Return open foam style string"""
if self.location:
return "FoamFile\n{\n" + \
"\tversion\t\t%s;\n"%self.__version + \
"\tformat\t\t%s;\n"%self.format + \
"\tclass\t\t%s;\n"%self.OFClass + \
"\tlocation\t%s;\n"%self.location + \
"\tobject\t\t%s;\n"%self.object + \
"}\n"
return Header.header() + \
"FoamFile\n{\n" \
"\tversion\t\t%s;\n" \
"\tformat\t\t%s;\n" \
"\tclass\t\t%s;\n" \
"\tlocation\t%s;\n" \
"\tobject\t\t%s;\n" \
"}\n" % (self.__version, self.format, self.cls, self.location,
self.object)

else:
return "FoamFile\n{\n" + \
"\tversion\t\t%s;\n"%self.__version + \
"\tformat\t\t%s;\n"%self.format + \
"\tclass\t\t%s;\n"%self.OFClass + \
"\tobject\t\t%s;\n"%self.object + \
"}\n"
return Header.header() + \
"FoamFile\n{\n" \
"\tversion\t\t%s;\n" \
"\tformat\t\t%s;\n" \
"\tclass\t\t%s;\n" \
"\tobject\t\t%s;\n" \
"}\n" % (self.__version, self.format, self.cls, self.object)
Loading

0 comments on commit c5d2cb3

Please sign in to comment.