TUOiJ JCUiX ninq O C[nCA! [i[ n PViOU [ T 2 n wJ CJD in lnD wi U O DD X[O Ci[ T qnJiOn O 2 n i i UD[C O Jn O TUOiJ DOCUnn 'Jinq U[ JnD O[ninq 2 n 'J U[ JCUiX cgx -b cylinder3.fbd T nX [ i O w[ 2 n in 3 JnOnq J Ji in CJ O nD O [i[ O[ A nii ([Oin, in, UJC in[OD) J OD in J CiOn J Dqinninq W wi U J JnJiOn VCO O [0,0,`8 Z DiCiOn swep all top tra 0 0 18 ` TUOiJ JCUiX ninq O C[nCA! [i[ n C! wJ i DJU DiViiOn O in W wOUD i! O U XJDOn C, J 2 TUOiJ JCUiX ninq O C[nCA! [i[ n in wi D DiViDD DU O i DiViiOn DiniiOn T DiViiOn DiniiOn CJn D ViUJiZD O XJn[ O J in in nOD plot ld all NO J nw in On [JJ O Z JXi JV 4 J DiViiOn Jnq DiViiOn O in 'wiC +X Viw 3 TUOiJ JCUiX ninq O C[nCA! [i[ n NOw CJnq DiViiOn qdiv 'CiOn nOD J a in O[[Oi COn O CiOn CJnq r r 4 TUOiJ JCUiX ninq O C[nCA! [i[ n TV[ in nw DiViiOn DiniiOn (O wO Diqi DiniiOn V[ J <'PAh> DO nUnD) 99 (Ui DiViiOn DiniiOn COnnJnD q NOw Din C V[ wiC n OUD U J XJDOn elty all he8 'J ninq mesh all T [V i OOwinq please wait for 'ready' 5 Ht "r"! Ht "r"! TUOiJ JCUiX ninq O C[nCA! [i[ n numFaces:456192 numElems:76032 size:32845824 ready ViUJiZ nwV CJD nn plot e all TOqq On hnn hDq b TUOiJ JCUiX ninq O C[nCA! [i[ n 'wiC ViUJiZJiOn O nn JC ViUJiZJiOn O nJ nnOV UJq plot f all NOw CJ CiOn O in, OU JnD wJ TO DO CiOn i O nn nJn OUD D V[D in [ O [Oin, O in, O UJC, C O DOUnDJV COnDiiOn nn JC OUD D CD () Dqin wi in DOUnDJV (in) qadd in a r r f q 7 TUOiJ JCUiX ninq O C[nCA! [i[ n C! wJ wJ CD (wi qn COO) plot f all plus f in g 8 TUOiJ JCUiX ninq O C[nCA! [i[ n lnOV nOn nCJV JC On CiOn qrem in a r r f q J OU (OU) JnD wJ (wJ) CiOn On iniJ wJV ViUiZinq U in wi qn, OU wi D JnD wJ wi DU plot f all plus f in g plus f out r plus f wall b 9 TUOiJ JCUiX ninq O C[nCA! [i[ n C! wJ CiOn J Xiinq wi wJ COnn prnt se T [V i OOwinq 1 all stat:o n:80100 e:76032 f:7872 p:1602 l:3937 s:3104 b:768 L:0 S:0 se:0 2 top stat:c n:801 e:0 f:768 p:801 l:1568 s:768 b:0 L:0 S:0 se:0 3 in stat:c n:0 e:0 f:768 p:0 l:0 s:0 b:0 L:0 S:0 se:0 4 -NJBY stat:c n:0 e:0 f:0 p:0 l:0 s:0 b:0 L:0 S:0 se:0 5 out stat:c n:0 e:0 f:768 p:0 l:0 s:0 b:0 L:0 S:0 se:0 6 wall stat:c n:0 e:0 f:6336 p:0 l:0 s:0 b:0 L:0 S:0 se:0 hX[O n in C[nCA! OnJ wi Xiinq JC CiOn (in [JC V[, OU [JC V[ JnD wJ wJ V[) send all foam patch in patch out wall wall l[V please wait for 'ready' use boundary: type:patch set:in use boundary: type:patch set:out use boundary: type:wall set:wall `0 TUOiJ JCUiX ninq O C[nCA! [i[ n wrote foam mesh ready T n i JDV O D UD in C[nCA! nOw YOU CJn Ui JCUiX quit `` Combined Use of Blender with OpenFOAM G. Douglas Baldwin Abstract Blender from blender.org contains a powerful, widely accepted, open source, surface mesh generation tool that was developed for the digital arts community. Furthermore, Blender includes a robust and well documented Python application programming interface (API) which facilitates the development of user tools for mesh manipulation, layered manifolds, and import/export. The author developed a Python script and technique for manipulating and exporting Blender objects into CalculiX for hexagonal grid generation, which are then exported into OpenFOAM format. The benefit of this approach is that manifolds allow absolute control of maximum cell growth rates from the boundary layer out to the edge of the computational domain, while also directing the path of stacked hexagonal cells to avoid skew. This technique was used to streamline an aircraft fuselage using a pure hexagonal grid with OpenFOAM, and then import the grid into Scientific Simulations NSU3D for authoritative drag analysis. The technique is ripe with possibilities for developing meshes for many classes of simulations. Highlights of the hexahedral grids used in the aircraft streamlining effort will be shown and discussed below, followed by an illustrative grid that combines hexahedral cells at the boundary layer with tetrahedral cells in the bulk flow. This paper will conclude with a copy of the Python script and a discussion of how it may be further developed. The author has no intention at this time of leading further development of this script due to other demands on his time. It is hoped that others too will find value in this approach and perhaps carry it forward. Fuselage Streamlining In general, Blender meshes are comprised of both triangles and quadrilaterals. For the fuselage streamlining project, it was decided to use exclusively quadrilaterals for the surface. Illustrations of the final surface are provided below. Notice the pink vertices. The only verticies defined by the user are those shown in pink. All of the other verticies are automatically generated by Blender when the subsurf modifier is applied to the object. The strength of the lines connecting any two pink verticies is controlled by the crease feature. It is not the purpose of this paper to provide a tutorial on Blender, subsurf, and crease. Many excellent Blender tutorials are readily available on the internet. Notice however the technique of having evenly space pink verticies to maintain a relatively consistent grid size. The close-up illustration below reveals better the individual quadrilateral elements automatically generated by the Blender subsurf modifier. Also note the two different colored Blender materials used on the object. These Blender materials eventually translate to OpenFOAM patches. The decision to have two patches for this fuselage model is unrelated to the present topic and will not be discussed further to avoid a confusing digression. Presented at the 3 rd OpenFOAM Workshop, Milan, Italy, 10-11 July 2008. Manifolds surrounding this fuselage object were created by using the Python script that will be provided towards the end of this paper. The procedure for creating manifolds is that a copy of the base object is created by the user, and then an automatic algorithm moves each pink vertex along its normal by a user specified amount, making automatic adjustments until all computer generated verticies have also moved approximately along their normals by approximately the same distance. As a byproduct of this algorithm, color coded representations of cell height, aspect ratio, and skew are generated as a visual aid for manual tweaking of the manifold verticies. The first manifold surrounds the fuselage/base object as shown in the illustration below. The following illustrations show the color-coded representations of cell height, aspect ratio, and skew, in that order. The color codes for these illustrations have the following meanings. For the height and aspect ratio illustrations, blue represents the minimum within the range of values and red represents the maximum within the range of values. For skew, blue through red represent the range of zero to ninety degrees in 12.5 degree increments. The design goal for this fuselage grid was to have a cell height at the fuselage with y+ in the range of 1 to 10, and a cell growth factor of 1.15 extending to the edge of the computational domain, which was approximately 10 times the reference length away from the fuselage in all directions. A series of four manifolds were needed to avoid high skew angles. As can be seen in the following two illustrations, the manifolds further away from the fuselage become become more sphere-like. The first three manifolds are shown in the cutaway illustration below, followed by an illustration of the fourth manifold enclosing the third manifold. Notice that the fourth and largest manifold has two materials assigned, shown as blue and red, which represent the inlet patch and the outlet patch. The user interface for the Python script is shown below. So far, we have only discussed the manifold generation capabilities of this script which are controlled by the Displacement Slider and the Apply button. The units of the Displacement Slider are equivalent to the average edge length of the manifold quads. The procedure for creating a manifold is as follows: 1) duplicate the the Blender Object; 2) while in Edit Mode select the vertices that will be displaced; and 3) click on the Apply button. Only the selected vertices will be displaced. The standard Blender Undo command can be used to move the vertices back to their original position if needed. The column of buttons and sliders on the left side of the user interface are used to specify the grid characteristics, and then the Export button is pressed to export the selected manifolds as a solid geometry in CalculiX format. When the button labeled Mesh the boundary layer has been depressed, a boundary layer manifold will be automatically generated for the original/base object, with a displacement distance as specified by the Displacement slider. This button is useful for relatively simple geometries when performing multiple iterations of mesh generation and OpenFOAM analysis. The vertices of the base object can be tweaked, and then a new boundary layer manifold is automatically produced each time the Export button is clicked. For more complex geometries such as the fuselage shown above, the boundary layer manifold can be manually generated and then manually tweaked each time the fuselage vertices are tweaked. The next two sliders specify the cell height. The slider named Target max aspect ratio is used to specify the desired aspect ratio of the first cell. OpenFOAM rejects meshes having any cell aspect ratio that is greater than 1000. This slider is useful for achieving a small y+ while staying within an aspect ratio of 1000. Due to the nature of the meshing algorithms, the actual aspect ratio of the first cell may be slightly larger or smaller than the specified target. The slider Cell Growth Factor is used to specify the maximum cell height growth between any two stacked cells, and applies to the entire computational domain from the first cell at the base object out to the last manifold. The next three buttons are used to specify planes of symmetry normal to the X, Y, and Z axes, respectively. Under most circumstances these planes of symmetry will need to pass through the origin, but if necessary they can be offset by using the accompanying sliders. The units for these sliders are Blender units, which for the purposes of OpenFOAM will usually be meters. As will be seen in subsequent illustrations, a plane of symmetry normal to the Y-axis was applied when exporting the fuselage grid. When the Export button is clicked, the user is asked to specify the folder and file name for the CalculiX .fbd file. File generation usually takes only a few seconds for large models, and certainly less than a minute for the very largest of models. If Blender is initialized through a command line console interface, then some useful statistics related to the resulting mesh are printed in this console. Also, the height, aspect ratio, and skew illustrations as shown above are automatically generated and placed in Blenders layers 11, 12, and 13 respectively. The exported file can now be loaded into Calculix by using the command: cgx -b filename.fbd. For larger grids this load process can take a very long time because CalculiX automatically generates a geometric body for each pair of quads at each pair of manifolds. After generating the geometry, CalculiX automatically generates the mesh which also takes some time. Immediately after the file completes loading into CalculiX, you have a mesh ready to export in OpenFOAM format. First, type in the save command; this will save you the trouble of having CalculiX regenerate the geometry if you ever need to load this file again. A simple command for exporting to OpenFOAM a test mesh is: send all foam patch all. When you are satisfied with checkMesh, you will then want to specify the individual patches in your send command. These patches were defined earlier by using Blender materials. An example send command with patches is send all foam patch inlet patch outlet wall yourObject. Also, if plane(s) of symmetry were used in Blender, then one extra step is needed in CalculiX before sending the mesh with individual patches to OpenFOAM. Use the command setr symmetry se notSymmetry to remove the non-symmetry faces from the symmetry set, and then include the phrase symmetryPlane symmetry in your send command, e.g. send all foam patch inlet patch outlet wall yourObject symmetryPlane symmetry. Very little proficiency with CalculiX is necessary, though it would not hurt to learn some of the other features of this tool. Sample paraFoam plots of the final fuselage grid are shown below. The above four plots show: 1) the surface quads of the fuselage, 2) the symmetry plane close-in to the fuselage, revealing the fine structure at the boundary layer, 3) the symmetry plane showing the 1 st , 2 nd , and 3 rd manifolds, and 4) the symmetry plane of the full computational domain, out to the 4 th manifold. After several iterations between Blender and OpenFOAM, a fuselage geometry having no flow separation was achieved. The OpenFOAM Lift/Drag tool was used to estimate the drag coefficients. The grid was then delivered to Scientific Simulations LLC, where an import tool was developed for converting the OpenFOAM pure hex grid into a NSU3D grid for further CFD analysis. Using the same operating conditions and same Spalart Allmaras wall model, the difference in predicted drag was significant. NSU3D, which has been publicly validated for these kinds of streamlined fuselages at the AIAA CFD Drag Workshop, predicted 30% less drag than OpenFOAM. Furthermore, NSU3D accepts cell aspect ratios of at least 10,000, which allowed for a finer resolution of the grid at the wall without the need to further refine the fuselage surface mesh. Together, Blender and OpenFOAM were a powerful combination of free tools for developing this streamlined, low drag fuselage. Combining with tetrahedrals CalculiX can export to OpenFOAM only pure hexahedral grids, and as such is limited. Some cases cannot be modeled with pure hex, stacked grids. For instance, an effort was made to use the above techniques to develop a sample coarse grid of the Ahmed wind tunnel experiment. Unfortunately, the space between the bottom of the automobile and the test section floor became crowed with many high aspect ratio cells. A better approach is to have quadrahedrals at the boundary layer combined with tetrahedrals filling the remainder of the computational domain. An attempt at creating such a sample grid was undertaken, using Blender with CalculiX for the boundary layer and Netgen for the bulk flow field. Blender images from this grid generation experiment are shown below. The first image shows the Ahmed body and the first manifold. These two objects were exported to Calculix using the techniques described above. The second image shows the tunnel, which was created by extruding a copy of the first manifold and adjusting its verticies. The tunnel object was exported from Blender in stereo-lithography (STL) format, and then read into Netgen for tetrahedral mesh generation. Since the cavity of the tunnel object was originally a copy of the first manifold, this provides a perfect interface for potentially using the stitchMesh tool in OpenFOAM. Both the CalculiX generated boundary layer mesh and the Netgen bulk flow mesh were combined in OpenFOAM using mergeMeshes. An image of the combined meshes is shown below, which includes the tunnel inlet on the left, the symmetry plane, the surface of the Ahmed body, and the tunnel outlet on the right. The next image shows that the Ahmed body has a quad surface with hexahedral cells. Following this is a close-up image of the interface between the hexahedral cells and the tetrahedral cells. Unfortunately, stitchMesh was unable to remove the interface patches. It would appear that stitchMesh is under active development and should eventually be capable of removing this interface. Further uses and further developments Blender has the ability to import STL objects, and the Python script described in this paper can be used to create a boundary layer mesh on these STL objects. One approach is to let CalculiX convert each trilateral into three quadrilaterals, and then use the techniques described above for creating a hexahedral mesh. Another approach would be to modify the Python script to have it output the hexahedral grid directly to OpenFOAM format, which would dramatically speed up the mesh generation process. Direct export from Blender would allow generation of prism cells, which could be stacked directly onto the STL trilaterals. A key architectural feature of the Blender data model provides the foundation for manifold development. Each mesh object includes a linked list of vertices. When a mesh object is copied, the new mesh object contains the same verticies in the same linked list order. The coordinates of these verticies may be change without changing their order within the linked list. By strategic placement of the verticies of the new mesh relative to the original mesh, a collection of uniform, low skew hexahedrals and/or prisms can be generated. This architectural feature was exploited to generate the CalculiX bodies from the Blender manifolds. This same architectural feature could be exploited to directly generate an OpenFOAM mesh comprised of hexahedrals and/or prisms with a uniform growth factor extending from the body wall up to the first manifold, or further to a second manifold, etc. The outer two manifolds can then be exported as an STL mesh for tetrahedral mesh generation in Netgen. Blender has a very efficient mesh manipulation kernel, and when combined with Python scripts can rapidly export large objects. The script provided below is both useful as is, and potentially even more valuable with a direct export to OpenFOAM capability. Also worth noting, modifications to CalculiX were developed to reduce memory allocation requirements and increase precision. A modification was needed when generating the fuselage grid in order to avoid malloc errors on a 32-bit machine. The modified source file named foamFaces.c was posted to the CalculiX support group site on Yahoo. Also, CalculiX outputs OpenFOAM grid coordinates in float format, and the format statement in the file write2foam.c can easily be changed to exponential format for improved precision. Conclusions A combination of Blender and Calculix was used to generate pure hexahedral grids for the purpose of streamlining an aircraft fuselage. This technique can potentially be extended to mixed hexahedral/tetrahedral grids by employing Netgen. Furthermore, the Python script for exporting Blender geometry in CalculiX format could through modification directly export to OpenFOAM format, which would allow generation of a stacked prism boundary layer grid on top of an STL object. This Python script is very useful as-is, and its value to the OpenFOAM community could be significantly enhanced by adding these relatively minor modifications. Python script #!BPY ###################################################################### # Export_fbd v0.2 for Blender # This script lets you export manifolds to Calculix format (.fbd) # (c) 2007 G. Douglas Baldwin (doug AT baldwintechnology DOT com) # released under Blender Artistic License ###################################################################### """ Name: 'Calculix Export (.fbd)...' Blender: Group: 'Export' Tooltip: 'Export selected objects to Calculix Format (.fbd)' """ __author__ = "Doug Baldwin" __version__ = "0.2" __bpydoc__ = """\ This script exports manifolds to Calculix Format (.fbd). Usage: Create a base mesh object, then make a first copy of this object. After a copy is made vertices of any object may be repositioned, but vertices, lines, and faces may neither be added nor deleted. Successive copies should be stretched into ever larger manifolds. This script will create a 3D Calculix mesh successively from the base mesh to the first copy, then from the first copy to the second copy, etc. The Displacement button is useful for stretching the manifolds. This function displaces the selected vertices of the selected object in the direction normal to the local surface. The goal is to displace the vertices of each manifold generally normal to its preceding mesh, while also reshaping as needed. Graphic plots of first cell height, aspect ratio, and skew are output to layers 11, 12, and 13.
Blender Material names of the first and last object will be exported as Calculix sets for generating patches. The GUI parameters Target Aspect Ratio and Growth Factor are used for calculating the hex cell height at the base mesh object, and the ratio of successive cell heights extending to the outermost manifold. The values Target Aspect Ratio and Growth Factor are the maximum values for the entire hex mesh, regardless of any undulations in the manifolds. Aspect Ratio is calculated to be the square root of the quad surface divided by the first cell height normal to the quad surface. Symmetry planes may be toggled on/off and positioned along the X, Y, and Z axes. If one or more symmetry planes are toggled on, the exported file will include a set of external surfaces called "symmetry". Symmetry planes are generally useful only when vertices of the base object and manifolds lie on the symmetry plane. Select all objects to be exported, with the outermost object active. Press the Export button to export, then select the file location and filename. Press the Exit button to exit the script. """ import Blender from Blender import Scene, Window, Material from math import ceil, log, sqrt, floor, acos, pi # ================================= # === Write FBD Calculix Format === # ================================= from Blender.BGL import * from Blender.Draw import * import BPyMessages import bpy # Parameters X_Plane = Create(0) Y_Plane = Create(1) Z_Plane = Create(0) X_Location = Create(0.0) Y_Location = Create(0.0) Z_Location = Create(0.0) growth = Create(1.15) aspect = Create(1000) mesh_BL = Create(0) factor = Create(1.0) # Events EVENT_NOEVENT = 1 EVENT_EXPORT = 2 EVENT_EXIT = 3 EVENT_APPLY = 4 ###################################################### # GUI drawing ###################################################### def draw(): global X_Plane,Y_Plane,Z_Plane,X_Location,Y_Location,Z_Location global growth, aspect, mesh_BL, factor global EVENT_NOEVENT,EVENT_EXPORT,EVENT_EXIT ########## Titles glClear(GL_COLOR_BUFFER_BIT) glRasterPos2d(8, 183) Text("Export with optional symmetry plane(s)") glRasterPos2d(250, 85) Text("Displace selected vertices normal to the subsurf") ######### Parameters GUI Buttons X_Plane = Toggle("X: ", EVENT_NOEVENT, 10, 55, 18, 18, X_Plane.val, "Toggle X-symmetry plane"); X_Location = Slider("Location: ", EVENT_NOEVENT, 30, 55, 200, 18, X_Location.val, -20.000, 20.0000, 1, "X-plane location"); Y_Plane = Toggle("Y: ", EVENT_NOEVENT, 10, 75, 18, 18, Y_Plane.val, "Toggle Y-symmetry plane"); Y_Location = Slider("Location: ", EVENT_NOEVENT, 30, 75, 200, 18, Y_Location.val, -20.000, 20.0000, 1, "Y-plane location"); Z_Plane = Toggle("Z: ", EVENT_NOEVENT, 10, 95, 18, 18, Z_Plane.val, "Toggle Z-symmetry plane"); Z_Location = Slider("Location: ", EVENT_NOEVENT, 30, 95, 200, 18, Z_Location.val, -20.000, 20.0000, 1, "Z-plane location"); growth = Number("Cell Growth Factor:", EVENT_NOEVENT, 10, 115, 220, 18, growth.val, 1.00, 2.00, "Ratio of cell heights in direction normal to the base object") aspect = Number("Target max aspect ratio:", EVENT_NOEVENT, 10, 135, 220, 18, aspect.val, 100.0, 2000.0, "Target aspect ratio of first cell layer") mesh_BL = Toggle("Mesh the boundary layer", EVENT_NOEVENT, 10, 155, 220, 18, mesh_BL.val, "Generate a mesh extruded normal to the base object"); factor = Slider("Displacement: ", EVENT_NOEVENT, 250, 55, 260, 18, factor.val, -1.000, 10.000, 1, "Magnitude relative to average subsurf edge length"); ######### Export and Exit Buttons glRasterPos2d(8, 36) Text("Note: Select all manifolds") Button("Export",EVENT_EXPORT , 10, 10, 80, 18, "Export to Calculix file") Button("Apply",EVENT_APPLY , 250, 10, 80, 18, "Apply displacement to the active object") Button("Exit",EVENT_EXIT , 430, 10, 80, 18, "Exit script") def event(evt, val): if (evt == QKEY and not val): Exit() def bevent(evt): # global EVENT_NOEVENT,EVENT_EXPORT,EVENT_EXIT ######### Manages GUI events if (evt == EVENT_EXIT): Exit() elif (evt== EVENT_EXPORT): if not Blender.Object.GetSelected(): BPyMessages.Error_NoActive() return Blender.Window.FileSelector(write_ui, 'FBD Export', Blender.sys.makename(ext='.fbd')) Blender.Redraw() elif (evt == EVENT_APPLY): manDisplace(factor.val) Register(draw, event, bevent) def manDisplace(factor):
sce = bpy.data.scenes.active ob_act = sce.objects.active if not ob_act or ob_act.type != 'Mesh': BPyMessages.Error_NoMeshActive() return is_editmode = Window.EditMode() Window.EditMode(0) Window.WaitCursor(1) displace(ob_act, factor) # Restore editmode if it was enabled if is_editmode: Window.EditMode(1) Window.WaitCursor(0) def write_ui(filename): global growth, aspect, mesh_BL, factor # open file if not filename.lower().endswith('.fbd'): filename += '.fbd' file = open(filename, 'wb') file.write('asgn s C \n') # Calculix auto-generated surfaces to begin with "C" #initialize values t = Blender.sys.time() me = [] ratio = [] bl = None scn = Scene.GetCurrent() obs = [ob for ob in scn.objects.context] obList = obs if mesh_BL.val == 1: # create boundary layer object scn.objects.selected = [obs[len(obs)-1]] Blender.Object.Duplicate(mesh=1) bl = scn.objects.selected[0] # Select vertices in base mesh mesh = bl.getData(mesh=1) for v in mesh.verts: v.sel = 1 displace(bl, factor.val) obList.insert(len(obList)-1, bl)
n = len(obList) for i in range(n): me.append(Blender.Mesh.New()) # create a new mesh me[i].getFromObject(obList[i], 0, 0) # get subsurf mesh me[i].transform(obList[i].matrix) # scale and rotate as needed writePoints(file,me[i],i) # write mesh points writeLines(file,me[i],i) # write mesh lines writeSurfaces(file,me[i],i) # write mesh surfaces and patch names if i != 0: writeThickness(file,me[i],me[i-1],i) writeBodies(file,me[i],me[i-1],i)
# calculate and generate div and bia minH, maxH, ratio = heightAnalysis(me) dH = 1.0/aspect.val for i in reversed(range(0,n-1)): dH = dH/ratio[i] height = 0.0 div = 0 while height < 1.0: height += dH dH = dH*growth.val div += 1 if i == n-2: div -= 1 firstDiv = div bia = pow(growth.val,div-1) file.write('div %s%s %d\n' % ("thickness", i, div)) file.write('bia %s%s %f\n' % ("thickness", i, bia)) print "i, div, bia", i, div, bia if len(obList) >= 2: surfacePlots(obList, firstDiv, growth.val) # generate symmetry set while also generating 3-D mesh mats = Blender.Material.get() for mat in mats: file.write('comp %s d\n' % mat.name) file.write('SETA notSymmetry se %s\n' % mat.name) file.write('comp notSymmetry d\n') file.write('elty all he8\n') file.write('mesh all\n') file.write('seta symmetry se all\n') file.write('setr symmetry se notSymmetry\n') file.write('plot me all\n') file.write('plus s all\n') file.close() if mesh_BL == 1 and n == 2: PupMenu('Returning boundary layer object with base object') else: if bl != None: scn.objects.unlink(bl) scn.objects.selected = obs
# Timing the script is a good way to be aware on any speed hits when scripting print 'Script finished in %.2f seconds' % (Blender.sys.time()-t) def writePoints(file,mi,i): # write out all points in this mesh for v in mi.verts: file.write('PNT P%x%x ' % (i, v.index) ) file.write('%.6f %.6f %.6f\n' % tuple(v.co)) def writeLines(file,mi,i): # write out all lines in this mesh for e in mi.edges: file.write('LINE L%x%x P%x%x P%x%x 1\n' % \ (i, e.index, i, e.v1.index, i, e.v2.index)) def writeThickness(file,m1,m0,i): for j in range(len(m1.verts)): m1vji = m1.verts[j].index file.write('LINE M%x%x P%x%x P%x%x 2\n' % \ (i, m1vji, i, m1vji, i-1, m0.verts[j].index)) file.write('SETA %s%s l M%x%x\n' % \ ("thickness", i-1, i, m1vji)) def heightAnalysis(me): ratio = [] for i in range(len(me)-2): ratio.append(0.0) for f0,f1,f2 in zip(me[i].faces,me[i+1].faces,me[i+2].faces): upperH = abs((f0.cent - f1.cent)*(f0.no + f1.no)/2) lowerH = abs((f1.cent - f2.cent)*(f1.no + f2.no)/2) ratio[i] = max(ratio[i], upperH/lowerH) n = len(me)-2 f0 = me[n].faces[0] f1 = me[n+1].faces[0] h = abs((f0.cent - f1.cent)*(f0.no + f1.no)/2) minH = h maxH = h ratio.append(h/sqrt(f1.area)) for f0, f1 in zip(me[n].faces, me[n+1].faces): h = abs((f0.cent - f1.cent)*(f0.no + f1.no)/2) minH = min(minH, h) maxH = max(maxH, h) ratio[n] = min(ratio[n],h/sqrt(f1.area)) return minH, maxH, ratio def surfacePlots(obs, firstDiv, growth): heights = [] aspectRatios = [] skews = [] mat = [] factor = 0 for i in range(firstDiv): factor = factor + pow(growth,i) factor = 1/factor scn = Scene.GetCurrent() meH = Blender.Mesh.New('height') # create a new mesh meH.getFromObject(obs[len(obs)-1], 0, 0) # get subsurf mesh meH.transform(obs[len(obs)-1].matrix) # scale and rotate as needed obH = scn.objects.new(meH) obH.layers = [11] meAR = Blender.Mesh.New('aspectRatio') # create a new mesh meAR.getFromObject(obH, 1, 0) # copy mesh obAR = scn.objects.new(meAR) obAR.layers = [12] meSkew = Blender.Mesh.New('skew') # create a new mesh meSkew.getFromObject(obH, 1, 0) # copy mesh obSkew = scn.objects.new(meSkew) obSkew.layers = [13] me1 = Blender.Mesh.New() # create a new mesh me1.getFromObject(obs[len(obs)-2], 0, 0) # get subsurf mesh me1.transform(obs[len(obs)-2].matrix) # scale and rotate as needed for f0, f1 in zip(meH.faces, me1.faces): vC = f1.cent - f0.cent heights.append(abs(vC*(f0.no + f1.no)/2)*factor) aspectRatios.append(sqrt(f0.area)/heights[len(heights)-1]) cosine = min(1, vC*f0.no/sqrt(vC*vC)) skews.append(acos(cosine)) minH = min(heights) maxH = max(heights) minAR = min(aspectRatios) maxAR = max(aspectRatios) print "min/max first cell height", minH, maxH print "min/max first cell AR", minAR, maxAR mat.append(Material.New()) mat[0].rgbCol = [0.,0.,1.] mat.append(Material.New()) mat[1].rgbCol = [0.,0.5,1.] mat.append(Material.New()) mat[2].rgbCol = [0.,1.,1.] mat.append(Material.New()) mat[3].rgbCol = [0.,1.,5.] mat.append(Material.New()) mat[4].rgbCol = [0.,1.,0.] mat.append(Material.New()) mat[5].rgbCol = [1.,1.,0.] mat.append(Material.New()) mat[6].rgbCol = [1.,0.5,0.] mat.append(Material.New()) mat[7].rgbCol = [1.,0.,0.] meH.materials = mat meAR.materials = mat meSkew.materials = mat obH.setMaterials(mat) obAR.setMaterials(mat) obSkew.setMaterials(mat) hRange = maxH - minH for f0, h in zip(meH.faces, heights): f0.mat = int(floor(7.999*(h-minH)/hRange)) ARRange = maxAR - minAR for f0, AR in zip(meAR.faces, aspectRatios): f0.mat = int(floor(7.999*(AR-minAR)/ARRange)) for f0, s in zip(meSkew.faces, skews): if s > pi/2.0: f0.mat = 7 else: f0.mat = int(floor(7.999*(2.0*s/pi))) Blender.Redraw() def writeSurfaces(file,m,i): key_index = {} for e in m.edges: key_index[e.key] = e.index for j in range(len(m.faces)): mfi = m.faces[j].index file.write('GSUR A%x%x + BLEND ' % (i, mfi)) for k in m.faces[j].edge_keys: file.write(' + L%x%x' % (i, key_index[k])) file.write('\n') if m.materials != []: mat = m.materials[m.faces[j].mat] if mat != None: file.write('SETA %s s A%x%x\n' % (mat.name, i, mfi)) def writeBodies(file,m1,m0,i): global X_Plane,Y_Plane,Z_Plane,X_Location,Y_Location,Z_Location for j in range(len(m1.faces)): m1fi = m1.faces[j].index # cut at symmetry planes as specified by GUI if ( (X_Plane.val == 0 or m1.faces[j].cent[0] > X_Location.val) and \ (Y_Plane.val == 0 or m1.faces[j].cent[1] > Y_Location.val) and \ (Z_Plane.val == 0 or m1.faces[j].cent[2] > Z_Location.val) ): file.write('body B%x%x A%x%x A%x%x\n' % \ (i, m1fi, i, m1fi, \ i-1, m0.faces[j].index)) file.write('SETA bods b B%x%x\n' % \ (i, m1fi)) def displace(ob, factor): # Get subsurf mesh and calculate its normals me0 = Blender.Mesh.New() me0.getFromObject(ob, 0, 0) me0.calcNormals() # Create dictionary of subsurf vertices to faces vert_faces = dict([(v.index, []) for v in me0.verts]) for f in me0.faces: for v in f.verts: vert_faces[v.index].append(f.index) # Calculate target heights of selected subsurf vertex normals heights = [] displacements = [] totalH = 0 nFaces = 0 for vi in me0.verts.selected(): for fi in vert_faces[vi]: totalH += sqrt(me0.faces[fi].area) nFaces += 1 hFace = totalH/nFaces for vi in me0.verts.selected(): hTotal = 0 nFaces = 0 for fi in vert_faces[vi]: hTotal += hFace/abs(me0.verts[vi].no*me0.faces[fi].no) nFaces += 1 hNormal = hTotal/nFaces heights.append(abs(hNormal*factor)) displacements.append(hNormal*factor) loop = 1 count = 0 # Iterate base mesh displacements needed to achieve target heights while loop == 1 and count <= 100: # Copy base mesh and displace scn = Scene.GetCurrent() scn.objects.selected = [ob] Blender.Object.Duplicate(mesh=1) obCopy = scn.objects.selected[0] meCopy = obCopy.getData(mesh=1) for vi, d in zip(meCopy.verts.selected(), displacements): meCopy.verts[vi].co += meCopy.verts[vi].no*d # Subsurf displaced mesh meCopy0 = Blender.Mesh.New() meCopy0.getFromObject(obCopy, 0, 0) loop = 0 sumErrorSquare = 0 # Measure differences, correct displacements, and sum errors for vi, i in zip(meCopy0.verts.selected(), range(len(heights))): dv = meCopy0.verts[vi].co - me0.verts[vi].co correction = heights[i]/sqrt(dv*dv) displacements[i] = displacements[i]*correction sumErrorSquare += (1-correction)*(1-correction) if sumErrorSquare/len(heights) > 1e-8: loop=1 count += 1 scn.objects.unlink(obCopy) print "Average Error Square=", sumErrorSquare/len(heights) print "Loop count=", count # Apply displacements to base mesh me = ob.getData(mesh=1) for vi, d in zip(me.verts.selected(), displacements): me.verts[vi].co += me.verts[vi].no*d scn.objects.active = ob Local:Gmsh tutorial From AMCGMedia Contents 1 AMCG Gmsh tutorial 2 Online Gmsh tutorial 2.1 A two dimensional example 2.1.1 Getting started 2.1.2 Setting up the geometry 2.1.3 Physical groups: boundaries and regions 2.1.4 Editing the geometry by hand 2.1.5 Producing a mesh 2.1.6 Converting the mesh to triangle for use in fluidity 2.2 Extruding a pseudo-2D mesh 2.2.1 Editing the extrusion 2.2.2 Setting the physical groups 2.2.3 Generating the mesh 2.3 A structured mesh 2.3.1 Hexahedral mesh 2.4 A three dimensional structured example 2.4.1 Getting started 2.4.2 Setting up the geometry: Creating a radial line 2.4.3 Setting up the geometry: Forming an annulus with extrusions 2.4.4 Physical groups 2.4.5 Final customisation of the geometry 2.4.6 Producing a mesh AMCG Gmsh tutorial This document is a tutorial on the GMSH mesh generator. It is aimed towards complete beginners; only some basic knowledge of the Linux terminal and a text editor is assumed. We first define what a mesh is and then introduce the reader to the basics of the GMSH graphical user interface. A basic, two-dimensional, geometry is then constructed within GMSH and a mesh is constructed. A more complicated three-dimesional annulus is also constructed and meshed, demonstrating some more advanced features of GMSH. Having mastered the basic usage of the graphical user interface, users are introduced to generating simple meshes on the sphere. Knowledge is further built to produce meshes of realistic domains of the oceans to include boundaries extracted from a high resolution shorelines database. Online Gmsh tutorial A two dimensional example This tutorial illustrates the process of meshing a square domain and specifying boundary flags on it. Getting started Run gmsh on the command line: gmsh The following windows appear: Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 1 of 13 11/03/2012 9:33 PM Setting up the geometry Choose "Elementary entities" then "Add", "New", "Point" It is now possible to set points either by clicking the main window or by typing coordinates in the pop-up box. It is generally easier and more accurate to use the latter approach. After adding the points (0,0), (1,0), (0,1) and (1,1) we have: Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 2 of 13 11/03/2012 9:33 PM Now choose "Straight line" and select each pair of points in turn until the outside lines of the square are complete. This figure illustrates the during the adding of the third side: Finally, we need to specify the plane surface which we will mesh. Click "Plane surface" and then select any line. The whole edge of the square will be highlighted and you press "e" to complete the selection. Physical groups: boundaries and regions In order to apply boundary conditions it is necessary to specify "physical groups" to which the boundaries belong. Since gmsh will only export to the .msh file those elements which are associated with a physical entity, it is also necessary to identify the interior of the domain with a physical group. Click on "Geometry" to return to the first menu and then select "Physical group", "add", line. Now suppose that we want to run a driven cavity. We'll need one boundary condition on the top and, depending on whether we use free or no slip boundary conditions we might need one boundary for all the rest of the sides together or one for the sides and a different one for the bottom. We therefore make one physical group for the top of the square, one for the sides together and one for the bottom. Click on the top line and then press "e" to end the selection and form the first physical group. Next do this for the sides. The following figure shows the selected sides immediately before pressing "e": Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 3 of 13 11/03/2012 9:33 PM Finally select the bottom of the box as a physical group. Next select "Surface" and select the dashed cross in the centre of the figure to identify the interior of the domain as a physical group. Editing the geometry by hand Gmsh writes all the elementary entities and physical groups to a human-editable text file with the suffix .geo. This can be useful for cleaning up the results of using the gui, adding comments and, as we shall see later, for more complex options which are difficult or impossible to do via the GUI. Return to the first menu by clicking on "Geometry". Next select "Edit" and a text editor will open containing the current geometry. In this case the file is as follows: Point(1) = {0,0,0,0.1}; Point(2) = {0,1,0,0.1}; Point(3) = {1,1,0,0.1}; Point(4) = {1,0,0,0.1}; Line(1) = {3,4}; Line(2) = {4,1}; Line(3) = {1,2}; Line(4) = {2,3}; Line Loop(5) = {1,2,3,4}; Plane Surface(6) = {5}; Physical Line(7) = {4}; Physical Line(8) = {3,1}; Physical Line(9) = {2}; Physical Surface(10) = {6}; The format is basically pretty simple. For most objects the syntax is: New_entity(id number) = {list of component entities} So, the fifth line above says that line 1 is composed of points 3 and 4. The exception is Point the format of which is {x, y, z, dx} where dx is the mesh spacing at that point. gmsh determines the mesh spacing during mesh generation by interpolating between these points. Entity numbers are only required to be unique within that entity type - as evidenced by the reuse of the numbers 1-4 for points and lines above. Suppose we would like different boundary markers (these are the numbers we will access boundaries by in fluidity) and that we would like to double the resolution. We'll also add some comments for the benefit of our fellow creatures: Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 4 of 13 11/03/2012 9:33 PM Point(1) = {0,0,0,0.05}; Point(2) = {0,1,0,0.05}; Point(3) = {1,1,0,0.05}; Point(4) = {1,0,0,0.05}; Line(1) = {3,4}; Line(2) = {4,1}; Line(3) = {1,2}; Line(4) = {2,3}; Line Loop(5) = {1,2,3,4}; Plane Surface(6) = {5}; // Top of the box Physical Line(666) = {4}; // Box sides Physical Line(333) = {3,1}; // Box bottom Physical Line(444) = {2}; // This is just to ensure all the interior // elements get written out. Physical Surface(10) = {6}; Now save the file and quit the editor. Now click "Reload" to load the changes you just made into the gui. Producing a mesh To produce the mesh simply select "Mesh" from the dropdown menu and click "2D". The result looks something like this: Now select "save mesh" from the "file" menu to save your masterpiece and you are done! Converting the mesh to triangle for use in fluidity Fluidity can directly read gmsh output if mesh/from_file/format(gmsh) is specified in the options file instead of format(triangle). Otherwise, it is possible convert the mesh into triangle format. This is easily accomplished using the gmsh2triangle script. The following example assumes that your mesh is in the src directory of a test case. In other cases you'll need to adjust paths accordingly: ../../tools/gmsh2triangle --2d src/driven_cavity.msh In case you want to convert a 3D mesh, type: ../../tools/gmsh2triangle src/driven_cavity.msh Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 5 of 13 11/03/2012 9:33 PM Extruding a pseudo-2D mesh Many fluidity users run pseudo-2D simulations in a very thin 3D domain. gmsh supports this sort of mesh using extrusion. Starting from the geometry above we can select "Elementary entities", "Extrude", "Translate". Set the Z component to the width of the extruded dimension (I chose 0.01) and click on the surface to extrude followed by "e". Editing the extrusion The extrusion commands above only extrude the domain, to cause the mesh generator to produce an extruded mesh in which the surface triangles on the front and back of the slice line up we have to edit the .geo file a little. The extrusion is the command: Extrude {0,0,0.01} { Surface{6}; } (your surface ID may be different). You need to change this to: Extrude {0,0,0.01} { Surface{6}; Layers{1}; } which specifies that there is 1 layer of elements in the Z direction (specifying a different number of layers works in the obvious way). Setting the physical groups For a 3d mesh, including this pseudo-2D domain, the boundaries are obviously faces and the interior is a volume. Otherwise it's just like the 2D case. Don't forget to specify the boundaries on the front and back of the domain! Generating the mesh Obviously this time you use the "3D" button on the meshing menu which results in the following mesh: Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 6 of 13 11/03/2012 9:33 PM A structured mesh One can also use extrusion to generate a structured mesh. Rather than step through the gui, which is the same process as for the pseudo-2D mesh, we can just detail the steps: Set up a point at the origin. 1. Extrude in the direction (1,0,0). 2. Extrude in the direction (0,1,0). 3. Extrude in the direction (0,0,1). 4. Set the physical boundaries. 5. This approach results in the following .geo file: Point(1) = {0,0,0,0.1}; Extrude {1,0,0} { Point{1}; Layers{5}; } Extrude {0,1,0} { Line{1}; Layers{5}; } Extrude {0,0,0.1} { Surface{5}; Layers{5}; } Physical Surface(28) = {27,5}; Physical Surface(29) = {14,22}; Physical Surface(30) = {26}; Physical Surface(31) = {18}; and the following structured mesh: Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 7 of 13 11/03/2012 9:33 PM Hexahedral mesh To generate a hexahedral mesh the command 'Recombine' is added as a part of line and surface extrusions. Taking the structured tetrahedral example above the line and surface extrusions are edited like so: Extrude {0,1,0} { Line{1}; Layers{5}; Recombine; } Extrude {0,0,1} { Surface{5}; Layers{5}; Recombine; } A three dimensional structured example The following tutorial explains how to generate a structured 3D annulus mesh using gmsh. Getting started Run gmsh on the command line: gmsh Create a new gmsh geometry file, by selecting "New" from the "File" menu and choosing an appropriate filename. Setting up the geometry: Creating a radial line We will start by adding a radial line. In thermally driven rotating annulus experiments it is often a good idea to start with resolution concentrated towards the annulus boundaries. We will concentrate resolution towards the inner and outer walls. This can be achieved by setting the "Characteristic lengths" of points. From the gmsh control window, select "Geometry" (or press "G"). Select "Elementary entities", "Add", "New", "Point". Create three points as follows (by entering the values in the relevant boxes and clicking "Add"). Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 8 of 13 11/03/2012 9:33 PM x = 2.5, y = 0.0, z = 0.0, Characteristic length = 0.1 x = 5.25, y = 0.0, z = 0.0, Characteristic length = 1.0 x = 8.0, y = 0.0, z = 0.0, Characteristic length = 0.1 The snapping grid spacing can be left at 0.1 in all directions. Select "Geometry", "Elementary entities", "Add", "New", "Straight line", and join the three points with two lines to form an annulus radial. Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 9 of 13 11/03/2012 9:33 PM Setting up the geometry: Forming an annulus with extrusions This radial line can now be used to form an annulus, by first extruding in the vertical to form a vertical slice, and then using a rotational extusion. Select "Geometry", "Elementary entities", "Extrude", "Translate", "Line". Select the two lines forming the annulus radial, and enter the following values for the extrusion: x = 0.0, y = 0.0, z = 14.0 Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 10 of 13 11/03/2012 9:33 PM Select "Geometry", "Elementary entities", "Extrude", "Rotate", "Surface". Select the two surfaces in the annulus slice, and enter the following values for the extrusion: Axis point x = 0.0, Axis point y = 0.0, Axis point z = 0.0 Axis direction x = 0.0, Axis direction y = 0.0, Axis direction z = 1.0 Angle = Pi/2 Repeat this four times to form an annulus. Note that on the final extrusion a true annulus geometry is created (rather than an annulus with two nearby radial walls). Physical groups As in earlier examples physical surfaces and volumes must be specified. Select "Geometry", "Physical groups", "Add", "Surface". Select the 8 surfaces comprising the top of the annulus and press "e". Repeat for the bottom of the annulus, the inner wall, and the Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 11 of 13 11/03/2012 9:33 PM outer wall (in order). Select "Geometry", "Physical groups", "Add", "Volume", select all volumes comprising the annulus and press "e". Final customisation of the geometry At this point the geometry can be used to generate a mesh. However, as we are aiming to create a structed mesh, the extusions performed earlier must be converted to layered extrusions. From the gmsh control window select "Geometry", "Edit". This will open the gmsh geometry file in a text editor. Make the alterations highlighted in red below and save the edited file. // Gmsh project created on Fri Feb 08 14:43:37 2008 Point(1) = {2.5,0.0,0.0,0.1}; Point(2) = {5.25,0.0,0.0,1.0}; Point(3) = {8.0,0.0,0.0,0.1}; Line(1) = {1,2}; Line(2) = {2,3}; Extrude {0,0,14} { Line{1,2}; Layers{25}; } Extrude {{0,0,1}, {0,0,0}, Pi/2} { Surface{10,6}; Layers{30}; }Extrude {{0,0,1}, {0,0,0}, Pi/2} { Surface{32,54}; Layers{30}; } Extrude {{0,0,1}, {0,0,0}, Pi/2} { Surface{76,98}; Layers{30}; } Extrude {{0,0,1}, {0,0,0}, Pi/2} { Surface{120,142}; Layers{30}; } // Top Physical Surface(185) = {41,19,151,172,129,107,63,85}; // Bottom Physical Surface(186) = {180,49,93,137,115,71,159,27}; // Inner wall Physical Surface(187) = {53,184,141,97}; // Outer wall Physical Surface(189) = {111,67,23,155}; Physical Volume(190) = {1,2,8,7,6,5,4,3}; Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 12 of 13 11/03/2012 9:33 PM This converts the vertical extrusion to a layered extrusion with 25 intervals (equivalent to a "zone" command with 25 intervals in GEM) and the rotational extrusions to layered rotational extrusions with 30 intervals per pi/2 of arc. The comments before the physical surface definitions are a good idea, as the physical surface numbers in brackets, (185) - (189), are the IDs that will be entered in Diamond to assign boundary conditions. Select "Geometry", "Reload" to apply your changes. If gmsh displays an error then there is a mistake somewhere in your gmsh geometry file. Producing a mesh From the gmsh control window select "Mesh" and click "3D" to generate the mesh. This mesh can now be exported by selecting "Save Mesh" from the "File" menu, and can then be converted to triangle format for use with Fluidity. Retrieved from "http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial" Categories: Mesh | Fluidity Local:Gmsh tutorial - AMCGMedia http://amcg.ese.ic.ac.uk/index.php?title=Local:Gmsh_tutorial 13 of 13 11/03/2012 9:33 PM Introduction Sometimes it's the small events that are the most exciting. Like the day I made three cents. Not three dollars. Not thirty dollars. Just three cents. And yet it was a very exciting event because of what those three cents represented. I made those three cents the first time someone clicked an advertisement on one of my Web pages. And it was just the beginning. Every time an ad was clicked, I'd make money. The more visitors I had, the more money I'd make. The pages that I had created purely out of interest and paid for out of my own pocket could pay for themselves, or possibly even turn a profit. That's what was so exciting about those three cents. The great thing was that it was really easy, because Google was doing all the hard work for me, through their free AdSense program. All I had to do was give them space on my pages to display the ads. They chose the ads, tracked the clicks, and charged the advertisers. Even better, they analyzed my pages and selected ads that were relevant to the topic of each page. All I had to do was keep my pages updated and do my best to attract a steady stream of visitors, which I was already doing. The truth was, anyone could do what I was doing! Just as exciting was the day a few months later when the first check from Google arrived in my mailbox. It was a small check, but it was real. I almost framed it instead of cashing it! That's what this book is all aboutthe excitement of making money with Google without having to be a computer expert. You'll need some Web pages, but I'll show you how to build those. Don't worry, there's no programming required! All you need is a computer and a connection to the Internet. Can It Really Be Done by Anyone? You're skeptical. Maybe you're thinking, "This author is an experienced writer and an experienced Web page and application developer, so of course to him it all seems very simple." While there's no denying that having a background like mine helps, it's definitely not a requirement. Making money with Google is easy to do with the right guidance. The concepts are not hard and can be mastered by anyone with the patience to learn them. Kind of like most things, really. I think what scares most people about computers and the Web is the terminology involved, not the concepts. I'll be the first to admit that technical people use a lot of buzzwords and obscure terms when they're talking about technology. It really is a specialized vocabulary. But specialized vocabularies aren't unique to the computer industry. Look at medicine: Doctors talk to one another in technical terms that the average person doesn't understand. This is good; specialized vocabularies are concise and more precise than general, everyday vocabularies. They can make communication quicker and more accurateas long as all parties to the communication speak the same language. What if you don't understand the language? That's where technical people often come up short compared to medical personnel. Doctors and nurses learn to talk to their patients using terms the patients can understand. Many techies don't learn this skill, which is why technology can seem so foreign and unapproachable to nontechies. But there are people like me who can bridge the gap and write books like this one. Please understand that there are no secrets in this book: Like many things, everything discussed here is already described somewhere on the Webyou just have to find it and understand it. Not only do I Page 1 of 4 Introduction 04/04/2012 file:///C:/Users/deepak/AppData/Local/Temp/~hhCD3D.htm save you the hassle of finding the material, I also make sure you understand it. That's the primary value of this book. Is This the Book for You? If you're reading this book because you've read one of my previous works, be aware that this book is something of a departure for me. My previous books have all been programming books. This book is different, because it's written for the average computer user, not the average computer programmerpeople like my wife or my father, not my co-workers. If you're looking for a technically oriented book, you're reading the wrong bookyou can safely put the book back on the shelf and keep browsing. The rest of you are about to begin an interesting journey, because Make Easy Money with Google is as much about understanding the Web as it is about making money on the Web. The Web may seem mysterious to you now, but it's built on simple (yet powerful) foundations. It's a tool for finding and sharing information, and that's exactly how you'll make your money. The book is written as a narrative, which is not the typical format for a "computer" or "digital lifestyle" book. Though the stories are fictional, the characters you'll encounter are composites of people I've interacted with before. They all have nontechnical backgrounds, and you should relate to them quite easily. The light, conversational style will, I hope, make the book a pleasure to read. Please note that I didn't title this book Make Oodles and Oodles of Money with Google. I'm sure there are people who make lots of money using the techniques I describe, but I'd be lying to you if I said this book is going to make you rich. I'm not rich. But I have made money with Google, and so can you. And you can have fun doing it! How to Use This Book Before we get started with our adventure, here's some important information about using this bookthe resources you'll need to gather, descriptions of each chapter, and information about the companion Web sites. Resources You'll Need As I've already said, this is a book for nontechnical people. If you can surf the Web, you can understand this book. The only resources you'll need are these: z A computer. Regular access to a computer is essential. Not only do you need a place where you can sit and create your Web pages, you'll want to have a copy of the pages stored locally for safekeeping and for testing. The operating system doesn't matter, though the examples and software discussed in this book are for Windows XP or Macintosh OS X only. z A high-speed Internet connection. This should be a given, but it's worth mentioning. You can still build and maintain your Web site using a slow-speed dial-up connection, but a faster connection is so much more pleasurable. z A credit card. You'll need a way to pay for some expenses. There aren't many, and they're not large expenses, but a credit card is the easiest way to pay for them. Page 2 of 4 Introduction 04/04/2012 file:///C:/Users/deepak/AppData/Local/Temp/~hhCD3D.htm What you don't need to do is buy high-priced software to help you build Web pages. There's enough free software available on the Internet to make those kinds of purchases unnecessary. We'll be looking at some of this free software later in the book. Chapter Descriptions As a narrative, this book is meant to be read sequentially, so please follow the chapters in the order in which they're presented: 1. Making Money with Google. Introduces the four-step process for making money with Google and reviews important concepts like Web sites, Web servers, and blogs. 2. Understanding AdSense. Describes Google's AdSense program: what it is, how it works, and how to join the program. Also discusses why advertising is so important to the Web. 3. Finding Something to Say. Lists techniques for choosing page topics and building content that attracts visitors. 4. Getting Ready to Say It. Explains how to register a good name for your site and find a hosting service. 5. Designing Your Site. Discusses how to design your site: choosing a look and feel, handling site navigation issues, and making the site attractive to humans and Google. 6. Building Your Site. Shows how to build Web pages from scratch using HTML and CSSdon't worry, it's not programmingand how to ensure that viewers see the site you want them to see. 7. Becoming an AdSense Publisher. Describes how to become an AdSense publisher, how to manage your AdSense account, and how and when you can expect to be paid. 8. Publishing Ads on Your Site. Discusses the different ad formats and how to track page performance. Also lists tips and tricks for making effective use of AdSense. 9. Making Money from Your Site. Explains how to drive traffic to your site and how to optimize your pages to get better clickthrough rates and better-paying ads. 10. Expanding Your Horizons. Wraps things up with a brief discussion of affiliate and referral programs. As you can see, there's a deliberate progression that takes you from learning the basic concepts to building your site to making money with the site. Companion Web Sites Not only have you purchased a great book, you also get access to four great Web sites, including www,MakeEasyMoneyWithGoogle.com, the official companion site for this book. On the companion site you'll find additional information that updates or enriches the material you're reading. The other sites are example sites built to complement the narrative. You can register yourself with the main site to download your own copies of the other sites for use as additional study material. The companion site can also be accessed using the short form www.memwg.com, an unremarkable name derived from the initial letters of each word in the book's title. Within the book, links to the companion site always use this shorter form to save you finger strain and to avoid difficulties in typesetting the text. Page 3 of 4 Introduction 04/04/2012 file:///C:/Users/deepak/AppData/Local/Temp/~hhCD3D.htm And as a bonus, registered readers who build Web pages using this book can also apply for a link from the companion site back to their pages, with no strings attached. This is an easy way to get some extra traffic to those pages. (See www.memwg.com/free-listing for the full details, but please note that I reserve the right not to link to inappropriate or otherwise unsuitable pages.) Let's Get Ready It's time to start our narrative. If you don't already have a computer and a high-speed Internet connection, now would be a great time to get yourself set up. In the meantime, let's begin the story. Page 4 of 4 Introduction 04/04/2012 file:///C:/Users/deepak/AppData/Local/Temp/~hhCD3D.htm