I am a high school intern, and I am trying to parse my mentor's code so that he can read in an XML file and call simple methods to edit or get information from his XML file.
I was hoping someone could provide me with some (any) feedback - ways to optimize the code perhaps?
The XML file that my mentor uses is: (It's not necessary to look at his code - it's just for reference / a general idea)
<global> <fringe_depth value="3"/> <ignore_direction dir="z"/> <minimize_overlap/> <operating_conditions velocity="0.99756405,0.069756473,0" pressure="0"/> <solver method="BlockImplicit" equations="IncompressibleEuler" num_time_steps="1" steady_state="yes" time_step="0.1" cfl="1280"> <block_implicit num_dual_time_steps="500" max_inviscid_order="5"/> </solver> <output> <grid_file filename="Plot/plot.g" style="p3d" frequency="-1" byte_order="little_endian" format="unformatted"/> <solution_file filename="Plot/plot.func" style="func" frequency="-1" byte_order="little_endian" format="unformatted"/> <grid_file filename="Plot/plot.xyz" style="p3dwib" frequency="-1" format="formatted"/> <solution_file filename="Plot/plot.q" style="p3dq" frequency="-1" format="formatted"/> <domain_connectivity filename="output++.dci" style="dci"/> </output> <body name="root"> <body name="airfoil"> <volume_grid name="left" style="p3d" filename="Grids/block_1.sp3dudl"> <skip_overlap_opt set_dsf_value="1e-20"/> <boundary_surface name="imin"> <region range1="min" range2="all" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="imax"> <region range1="max" range2="all" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="jmin"> <region range1="all" range2="min" range3="all"/> <boundary_condition type="solid"/> <solver_boundary_condition type="solid"/> </boundary_surface> <boundary_surface name="jmax"> <region range1="all" range2="max" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="kmin"> <region range1="all" range2="all" range3="min"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> <boundary_surface name="kmax"> <region range1="all" range2="all" range3="max"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> </volume_grid> <volume_grid name="right" style="p3d" filename="Grids/block_2.sp3dudl"> <skip_overlap_opt set_dsf_value="1e-20"/> <boundary_surface name="imin"> <region range1="min" range2="all" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="imax"> <region range1="max" range2="all" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="jmin"> <region range1="all" range2="min" range3="all"/> <boundary_condition type="solid"/> <solver_boundary_condition type="solid"/> </boundary_surface> <boundary_surface name="jmax"> <region range1="all" range2="max" range3="all"/> <boundary_condition type="overlap"/> <solver_boundary_condition type="overlap"/> </boundary_surface> <boundary_surface name="kmin"> <region range1="all" range2="all" range3="min"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> <boundary_surface name="kmax"> <region range1="all" range2="all" range3="max"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> </volume_grid> </body> <body name="box"> <volume_grid name="box" style="p3d" filename="Grids/block_3.sp3dudl" cartesian_grid="yes"> <boundary_surface name="imin"> <region range1="min" range2="all" range3="all"/> <boundary_condition type="farfield"/> <solver_boundary_condition type="farfield"/> </boundary_surface> <boundary_surface name="imax"> <region range1="max" range2="all" range3="all"/> <boundary_condition type="farfield"/> <solver_boundary_condition type="farfield"/> </boundary_surface> <boundary_surface name="jmin"> <region range1="all" range2="min" range3="all"/> <boundary_condition type="farfield"/> <solver_boundary_condition type="farfield"/> </boundary_surface> <boundary_surface name="jmax"> <region range1="all" range2="max" range3="all"/> <boundary_condition type="farfield"/> <solver_boundary_condition type="farfield"/> </boundary_surface> <boundary_surface name="kmin"> <region range1="all" range2="all" range3="min"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> <boundary_surface name="kmax"> <region range1="all" range2="all" range3="max"/> <boundary_condition type="symmetry"/> <solver_boundary_condition type="zero_gradient"/> </boundary_surface> </volume_grid> </body> </body> </global>
The code that I have written in Python is what I would like feedback on:
import xml.etree.ElementTree as ET import math def parse(fileName): global tree, root tree = ET.parse(fileName) root = tree.getroot() ''' Returns total number of 'volume_grid' elements ''' def getNumGrids(): count = 0 for volume_grid in root.iter('volume_grid'): count+=1 return count ''' Returns all of 'the volume_grid' name attributes as a list ''' def getGridNames(): att = [] for grid in root.iter('volume_grid'): att.append(grid.attrib) names = [] for n in att: names.append(n.get('name')) return names ''' Helper method for getBoundarySurfaceNamesForVolumeGrid(grid) Returns list of attributes for a particular 'volume_grid', which is given as parameter ''' def getGridBoundarySurfaceNameAttributes(volumeGridName): selectedAtt = [] att = [] names = [] for v in root.iter('volume_grid'): att.append(v.attrib) for a in att: names.append(a.get('name')) for n in names: if n == volumeGridName: for surface in v.iter('boundary_surface'): selectedAtt.append(surface.attrib) return selectedAtt ''' Returns a list of the names for a particular volume_grid, which is given as a parameter ''' def getBoundarySurfaceNamesForVolumeGrid(grid): g = getGridNames() n = [] for names in g: if names == grid: n = (getGridBoundarySurfaceNameAttributes(names)) return n ''' Changes 'solver_boundary_condition' type attribute in a specified volume_grid takes 3 parameters: 1. 'volumeGridName' -- name of the 'volume_grid' 2. 'boundarySurfaceName' -- 'boundary_surface' 'name' attribute 3. 'newType' -- the new 'type' for the 'solver_boundary_condition' ''' def setSolverBoundaryConditionType(volumeGridName, boundarySurfaceName, newType): for v in root.iter('volume_grid'): if v.get('name') == volumeGridName: for b in v.iter('boundary_surface'): if b.get('name') == boundarySurfaceName: for s in b.iter('solver_boundary_condition'): s.set('type', newType) ''' returns type of 'solver_boundary_condition' within a volume grid and boundary surface ''' def getSolverBoundaryConditionType(volumeGridName, boundarySurfaceName): for v in root.iter('volume_grid'): if v.get('name') == volumeGridName: for b in v.iter('boundary_surface'): if b.get('name') == boundarySurfaceName: for s in b.iter('solver_boundary_condition'): return s.get('type') ''' Changes all solver_boundary_condition 'type' attributes from the first parameter 'old' to the second 'new'. Only changes if 'type' originally contains 'old' ''' def setAllSameSolverBoundaryConditionTypes(old, new): for v in root.iter('volume_grid'): for b in v.iter('boundary_surface'): for s in b.iter('solver_boundary_condition'): if s.get('type') == old: s.set('type', new) ''' Changes 'boundary_condition' type attribute in a specified volume_grid Takes 3 parameters: 1. 'volumeGridName' -- name of the 'volume_grid' 2. 'boundarySurfaceName' -- 'boundary_surface' 'name' attribute 3. 'newType' -- the new 'type' for the 'solver_boundary_condition' ''' def setBoundaryConditionType(volumeGridName, boundarySurfaceName, newType): for v in root.iter('volume_grid'): if v.get('name') == volumeGridName: for b in v.iter('boundary_surface'): if b.get('name') == boundarySurfaceName: for s in b.iter('boundary_condition'): s.set('type', newType) ''' Changes all 'boundary_condition' 'type' attributes from the first parameter 'old' to the second 'new'. Only changes if 'type' originally contains 'old' ''' def setAllSameBoundaryConditionTypes(old, new): for v in root.iter('volume_grid'): for b in v.iter('boundary_surface'): for s in b.iter('boundary_condition'): if s.get('type') == old: s.set('type', new) ''' Given the volumeGrid name parameter (1st), the user can choose to edit either the style (2nd) or filename (3rd) parameters. If the user wants only to edit one of the two editable parameters, they can put in 'NC' (no change) for the unchanged parameter ''' def setVolumeGrid(name, style, fileName): for grid in root.iter('volume_grid'): if (grid.get('name') == name): if (style != 'NC'): grid.set('style', style) if (fileName != 'NC'): grid.set('filename', fileName) ''' helper method for setOperatingConditionsPolarVelocity() Changes operating conditions, takes in velocity and pressure parameters Velocity parameter is in form "x,y,z" 'NC' (no change) for any parameter that should not be changed ''' def setOperatingConditions(velocity, pressure): for cond in root.iter('operating_conditions'): if (velocity!= 'NC'): cond.set('velocity', velocity) if(pressure != 'NC'): cond.set('pressure', pressure) ''' Given a radius and theta as parameters, calculates the velocity for operating_conditions in xyz. Then sets the operating conditions attributes by calling setOperatingConditions() User can put in 'NC' (no change) for any parameter that should not be changed r = magnitude, theta = inflow angle ''' def setOperatingConditionsPolarVelocity(r, theta, pressure): x =str(r*math.cos(theta)) y = str(r*math.sin(theta)) z = str(0) velocity = ''.join(x + ',' + y + ',' + z) setOperatingConditions(velocity, pressure) ''' Returns the current operating conditions: velocity and pressure as a dictionary ''' def getOperatingConditions(): for cond in root.iter('operating_conditions'): return cond.attrib ''' Changes solver element attributes NC if no change ''' def setSolverType(method, equations, numTimeSteps, steadyState, timeStep, cfl): for sol in root.iter('solver'): if method!='NC': sol.set('method', method) if equations != 'NC': sol.set('equations', equations) if numTimeSteps != 'NC': sol.set('num_time_steps', numTimeSteps) if steadyState != 'NC': sol.set('steady_state', steadyState) if timeStep!='NC': sol.set('time_step', timeStep) if cfl !='NC': sol.set('cfl', cfl) ''' provides the attributes for output grid_file, given the filename The parameter filename is in the form Plot/Plot.name, but to make it easier for the user, he/she must only type in the name part For example, getOutputGridFileInfo(xyz) would work for the filename 'Plot/plot.xyz' ''' def getOutputGridFileInfo(filename): filename = 'Plot/plot.' + filename for file in root.iter('grid_file'): if (file.get('filename') == filename): return (file.attrib) ''' Allow the user to change the style, frequency, and format attributes within <output> <grid_file> given the filename The parameter filename is in the form Plot/Plot.name, but to make it easier for the user, he/she must only type in the name part Note: format is a built-in symbol, so formatting was used in place ''' def setOutputGridFile(filename, style, frequency, formatting): filename = 'Plot/plot.' + filename for g in root.iter('grid_file'): if g.get('filename') == filename: if style !='NC': g.set('style', style) if frequency != 'NC': g.set('frequency', frequency) if formatting != 'NC': g.set('format', formatting) ''' Returns all of the attricutes for a grid_file in output given a filename. The parameter filename is in the form Plot/Plot.name, but to make it easier for the user, he/she must only type in the name part ''' def getOutputSolutionFile(filename): filename = 'Plot/plot.' + filename for file in root.iter('solution_file'): if (file.get('filename') == filename): return (file.attrib) ''' returns the name of each body element in a list ''' def getBodyNames(): att = [] for body in root.iter('body'): att.append(body.attrib) names = [] for n in att: names.append(n.get('name')) return names ''' Changes the old body name (oldName parameter) to a new body name (newName parameter) ''' def setBodyName(oldName, newName): for body in root.iter('body'): if body.get('name') == oldName: body.set('name', newName) ''' Writes the file onto a new XML. Useful when importing this module because etree will not need to be imported/file re-parsed to write the file out from other module ''' def writeFile(name): tree.write(name)
My mentor would import my module in terminal and use that to call the methods.