diff --git a/doc/conf.py b/doc/conf.py index 7db72ce..de31196 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -21,4 +21,4 @@ numpydoc_show_class_members = False # mock import for autodoc -autodoc_mock_imports = ["numpy", "mpi4py"] +autodoc_mock_imports = ["numpy", "mpi4py", "baseclasses"] diff --git a/doc/cgns.rst b/doc/icem.rst similarity index 93% rename from doc/cgns.rst rename to doc/icem.rst index 9849b19..c793e2e 100644 --- a/doc/cgns.rst +++ b/doc/icem.rst @@ -1,28 +1,21 @@ -.. _pyhyp_cgns: +.. _pyhyp_icem: .. pyHyp boundary conditions example. Written by: Ney Secco (February 2016) Edited by: -Usage with CGNS Files -===================== +Specifying BCs using ICEM +========================= -If the initial surface is given in a CGNS file, we can specify boundary conditions -at each open edge of the geometry. The boundary conditions currently supported are: +This section will show how we can use ICEM to specify boundary conditions at each open edge of a CGNS surface geometry. +The boundary conditions currently supported are: * Constant X, Y, or Z planes; * Symmetry X, Y, or Z planes; * Splay (free edge). -This section will show how we can use ICEM to specify boundary conditions in a CGNS file. - -.. NOTE:: - It is still not possible to specify boundary conditions when plot3d files are - used as inputs. In this case, the surface should be entirely closed or it should - end at a symmetry plane with the 'mirror' option enabled. - Flat square example ------------------------------------ +------------------- .. NOTE:: If you have a surface geometry, this step is not required, and you @@ -135,7 +128,7 @@ is the one used as an example of boundary conditions setup. See if everything looks right in your Pre-mesh. Preparing to export the mesh ------------------------------------ +---------------------------- Just to recap, we have done the following procedures: @@ -301,15 +294,14 @@ Running pyHyp with the generated mesh ------------------------------------- Create another empty folder and copy the CGNS file exported by ICEM to it. We can add the following Python script to -the same folder (This script is also available in `examples/plate/generate_grid.py`, and just the file name was -adjusted for this example):: +the same folder:: from pyhyp import pyHyp fileName = 'plate.cgns' - fileType = 'CGNS' + fileType = 'cgns' - options= { + options = { # --------------------------- # Input File # --------------------------- @@ -321,14 +313,14 @@ adjusted for this example):: # --------------------------- 'N': 65, 's0': 1e-6, - 'rMin': 2.5, + 'marchDist': 2.5, # --------------------------- # Pseudo Grid Parameters # --------------------------- 'ps0': 1e-6, 'pGridRatio': 1.15, - 'cMax': 5, + 'cMax': 5.0, # --------------------------- # Smoothing parameters @@ -340,19 +332,12 @@ adjusted for this example):: 'volBlend': 0.001, 'volSmoothIter': 10, - # --------------------------- - # BC parameters - # --------------------------- - 'sigmaSplay': 0.4, - 'nuSplay': 0.95, - # --------------------------- # Solution Parameters # --------------------------- 'kspRelTol': 1e-15, 'kspMaxIts': 1500, - 'preConLag': 10, - 'kspSubspaceSize':50, + 'kspSubspaceSize': 50, 'writeMetrics': False, } @@ -376,7 +361,7 @@ You can also run pyHyp in parallel with the following command:: The option '-np 4' indicates that 4 processors will be used. The results may vary slight due to the parallel solution of the linear system. Visualizing the mesh in TecPlot 360 -------------------------------------- +----------------------------------- If you have TecPlot 360 installed in your computer you can visualize the volume mesh. Open a terminal and navigate to the folder than contains the newly generated CGNS file with the volume mesh. Then type the following command:: diff --git a/doc/index.rst b/doc/index.rst index 7ac49df..d10d3f1 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -20,7 +20,9 @@ line) corresponding to the geometry of interest and then *grow* or distance from the original surface. In the process, the entire space surrounding the geometry is meshed. -Most the theory for `pyHyp` was taken from `Chan and Steger `_. +.. _pyhyp_theory: + +Most of the theory for `pyHyp` was taken from `Chan and Steger `_. @@ -30,8 +32,8 @@ Contents: :maxdepth: 2 install - plot3d - cgns + tutorial + icem BC options API diff --git a/doc/install.rst b/doc/install.rst index 4f1b933..e585e7a 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -49,9 +49,6 @@ Finally, install the Python interface with:: pip install . - -.. _pyhyp_theory: - Testing Your Installation ------------------------- diff --git a/doc/options.rst b/doc/options.rst index f37c10b..dbef72a 100644 --- a/doc/options.rst +++ b/doc/options.rst @@ -3,164 +3,4 @@ Options ======= -Here are the options currently available in pyHyp. - -.. list-table:: - :widths: 5 5 90 - :header-rows: 1 - - * - Parameter - - Type - - Description - - * - ``inputFile`` - - ``str`` - - Name of the file that contains the surface mesh. - This is a file that has been generated in an external meshing program, typically ICEMCFD. - - * - ``fileType`` - - ``str`` - - Type of the input file. - Use either ``Plot3d`` or ``CGNS``. - - * - ``unattachedEdgesAreSymmetry`` - - ``bool`` - - Automatically applies symmetry boundary conditions to any edges that do not interface with another block. - This option works in many cases but does not work for all surface meshes. - If you encounter negative volumes near the symmetry plane, try explicitly setting the symmetry boundary conditions using the ``BC`` option. - - * - ``outerFaceBC`` - - ``str`` - - Specifies the boundary condition at the outermost face of the extruded mesh. - Use either ``farfield`` or ``overset``. - - * - ``BC`` - - ``dict`` - - Specifies boundary condition information for specific block edges. See :ref:`here` for details. - - * - ``families`` - - ``str`` / ``dict`` - - Name given to wall surfaces. - If a dictionary is submitted, each wall patch can be named separately. - This can help with applying operations to specific wall patches. - - * - ``N`` - - ``int`` - - Number of grid levels to march. - This determines the grid dimension in the off-wall direction. - Typically this should be a "multi-grid" friendly number. - - * - ``s0`` - - ``float`` - - Initial off-wall (normal) spacing of grid. - This is taken to be constant across the entire geometry. - The units are consistent with the rest of the geometry. - - * - ``rMin`` - - ``float`` - - Relative distance in the normal direction to march. - It is specified as a multiple of the radius of the sphere enclosing the initial surface geometry. - If symmetry is specified, the full mirrored geometry is used to compute the sphere's radius. - Most wing geometries will have ``rMin`` between 10 and 20, that is the farfield boundary is 20 spans away from the geometry. - - * - ``cMax`` - - ``float`` - - The maximum permissible ratio of marching direction length to the any other in-plane edge. - This parameter effectively operates as a CFL-type limit. - If a step would require a step which would result in a ratio ``c`` greater than ``cMax``, the step is automatically split internally to respect this user-supplied limit. - Typical values of ``cMax`` are around 6-8. - Increased robustness can be achieved at the expense of computational cost by lowering ``cMax``. - - * - ``nonLinear`` - - ``float`` - - Use the nonlinear formulation. - This is experimental and not currently recommended and may not work at all. - - * - ``slExp`` - - ``float`` - - Exponent for the :math:`S_l` computation. - The :math:`S_l` value serves the same purpose as found in Chan et al. but the computation is different. - The :math:`S_l` computation in Chan is given as :math:`\sqrt{\frac{N-1}{l-1}}` for :math:`l > 2`. - - * - ``ps0`` - - ``float`` - - Initial pseudo offwall spacing. - This spacing **must** be less than or equal to ``s0``. - This is actual spacing the hyperbolic scheme uses. - The solver may take many pseudo steps before the first real grid level at ``s0``. - - * - ``pGridRatio`` - - ``float`` - - The ratio between successive levels in the pseudo grid. - This will be typically somewhere between ~1.05 for large grids to 1.2 for small grids. - This number is **not** the actual grid spacing of the final grid; that spacing ratio is computed and displayed at the beginning of a calculation. - The ``pGridRatio`` **must** be smaller than that number. - - * - ``epsE`` - - ``float`` - - The explict smoothing parameter. - See the :ref:`Theory` section for more information. - Typical values are approximately 1.0. Increasing the explicit smoothing may result in a smoother grid, at the expense of orhtogonality. - If the geometry is very sharp corners, too much explicit smoothing will cause the solver to rapidly "soften" the corner and the grid will fold back on itself. - In concave corners, additional smoothing will prevent lines from crossing (avoiding negative cells). - - * - ``epsI`` - - ``float`` - - Implicit smoothing parameter. - See the :ref:`Theory` section for more information. - Typical values are from 2.0 to 6.0. - Generally increasing the implicit coefficient results in a more stable solution procedure. - Usually this value should be twice the explicit smoothing parameter. - - * - ``theta`` - - ``float`` - - Kinsley-Barth coefficient See the :ref:`Theory` section for more information. - Only a single theta value is used for both directions. - Typical values are ~2.0 to ~4.0. - - * - ``volCoef`` - - ``float`` - - Coefficient used in point-Jacobi local volume smoothing algorithm. - Typically this value is 0.16 and need not be modified. - Use more ``volSmoothIter`` for stronger local smoothing. - - * - ``volBlend`` - - ``float`` - - The global volume blending coefficient. - See the :ref:`Theory` section for more information. - This value will typically be very small, especially if you widely varying cell sizes. - Typically values are from ~0 to 0.001. - Default is 0.0001. - - * - ``volSmoothIter`` - - ``int`` - - The number of point-Jacobi local volume smoothing iterations to perform. - Typical values are ~5 to ~25. - Default is 10. - - * - ``kspRelTol`` - - ``float`` - - Tolerance for the solution of the linear system at each iteration. - Typically :math:`1\times 10^{-8}` is sufficient. - Very difficult cases may benefit from a tighter convergence tolerance. - - * - ``kspMaxIts`` - - ``int`` - - Maximum number of iterations to perform for each step. - Default is 500 which should be sufficient for most cases. - - * - ``preConLag`` - - ``int`` - - Lag the update of the preconditioner by this number of iterations. - The default value of 10 will typically not need to be changed. - - * - ``kspSubspaceSize`` - - ``int`` - - Size of the ksp subspace. - Default is 50. - Very large and difficult problems may befefit from a larger subspace size. - - * - ``writeMetrics`` - - ``bool`` - - Flag to write the mesh gradients to the solution file. - This option should only be used for debugging purposes. +.. optionstable:: pyhyp.pyHyp diff --git a/doc/options.yaml b/doc/options.yaml new file mode 100644 index 0000000..4514008 --- /dev/null +++ b/doc/options.yaml @@ -0,0 +1,250 @@ +inputFile: + desc: > + Name of the file that contains the surface mesh. + This is a file that has been generated in an external meshing program, typically ICEMCFD. + +patches: + desc: > + Explicitly assign arrays of patches as the input surface. + +fileType: + desc: > + Type of the input file. + cgns: CGNS format + plot3d: PLOT3D format + +skip: + desc: > + Flag to entirely skip the grid generation of this geometry. + +mode: + desc: > + Type of extrusion. + hyperbolic: Most commonly used + elliptic: Not typically used + +unattachedEdgesAreSymmetry: + desc: > + Automatically applies symmetry boundary conditions to any edges that do not interface with another block. + This option works in many cases but does not work for all surface meshes. + If you encounter negative volumes near the symmetry plane, try explicitly setting the symmetry boundary conditions using the ``BC`` option. + +outerFaceBC: + desc: > + Specifies the boundary condition at the outermost face of the extruded mesh. + farfield: Farfield BC + overset: Used for overset component meshes + +BC: + desc: > + Specifies boundary condition information for specific block edges. See :ref:`here` for details. + +families: + desc: > + Name given to wall surfaces. + If a dictionary is submitted, each wall patch can be named separately. + This can help with applying operations to specific wall patches. + +autoConnect: + desc: > + Run cgnsutilities connect function to add any necessary block to block connectivity. + +noPointReduce: + desc: > + Do not find duplicate nodes along edges. + This can only be used with single surface input files. + +N: + desc: > + Number of grid levels to march. + This determines the grid dimension in the off-wall direction. + Typically, this should be a "multi-grid" friendly number. + +s0: + desc: > + Initial off-wall (normal) spacing of grid. + This is taken to be constant across the entire geometry. + The units are consistent with the rest of the geometry. + +nConstantStart: + desc: > + Number of constant off-wall layers before beginning stretch. + +nConstantEnd: + desc: > + Number of constant layers at the end of the march. + +marchDist: + desc: > + Distance to march in the normal direction. + Most wing geometries will have a distance such that the farfield boundary is 10 to 20 span lengths away from the geometry. + +nodeTol: + desc: > + Tolerance for nodes to be treated as identical. + +splay: + desc: > + Splay BC spreading factor. + This controls how far the floating edges splay outwards. + +splayEdgeOrthogonality: + desc: > + How hard to try to force orthogonality at splay edges. + Should be between 0 and 0.5. + +splayCornerOrthogonality: + desc: > + How hard to try to force orthogonality at splay corners. + +cornerAngle: + desc: > + Maximum convex corner angle in degrees necessary to trigger the implicit node averaging scheme. + +coarsen: + desc: > + Automatically coarsen a surface mesh before starting extrusion. + ``1`` gives the same surface mesh. + ``2`` coarsens by a factor of 2 in each direction. + ``3`` coarsens by a factor of 4 in each direction, and so on. + +panelEps: + desc: > + Only used in elliptic mode. + Distance source panels are "below" nodes. + This parameter usually does not need to be changed. + +farFieldTolerance: + desc: > + Only used in elliptic mode. + The multiple of the panel length cutoff to use the approximation formula. + +useMatrixFree: + desc: > + Only used in elliptic mode. + Use matrix-free solution technique. + This is always True when evalMode is ``fast``. + +evalMode: + desc: > + Only used in elliptic mode. + Type of panel evaluation routine. + exact: Modifies the farfield tolerance to ensure that only the exact evaluations are used + slow: Uses farfield approximations but does not group panels + fast: Uses farfield approximations and panel groupings + +sourceStrengthFile: + desc: > + Only used in elliptic mode. + File to use to load/save the source strengths on the surface. + +cMax: + desc: > + The maximum permissible ratio of marching direction length to the any other in-plane edge. + This parameter effectively operates as a CFL-type limit. + If a step would require a step which would result in a ratio ``c`` greater than ``cMax``, the step is automatically split internally to respect this user-supplied limit. + Typical values of ``cMax`` are around 6-8. + Increased robustness can be achieved at the expense of computational cost by lowering ``cMax``. + +nonLinear: + desc: > + Use the nonlinear formulation. + This is experimental and not currently recommended and may not work at all. + +slExp: + desc: > + Exponent for the :math:`S_l` computation. + The :math:`S_l` value serves the same purpose as found in Chan et al. but the computation is different. + The :math:`S_l` computation in Chan is given as :math:`\sqrt{\frac{N-1}{l-1}}` for :math:`l > 2`. + +ps0: + desc: > + Initial pseudo off-wall spacing. + This spacing **must** be less than or equal to ``s0``. + This is actual spacing the hyperbolic scheme uses. + The solver may take many pseudo steps before the first real grid level at ``s0``. + This is computed internally if a non-positive value is provided. + +pGridRatio: + desc: > + The ratio between successive levels in the pseudo grid. + This will be typically somewhere between ~1.05 for large grids to 1.2 for small grids. + This number is **not** the actual grid spacing of the final grid; that spacing ratio is computed and displayed at the beginning of a calculation. + The ``pGridRatio`` **must** be smaller than that number. + This is computed internally if a non-positive value is provided. + +epsE: + desc: > + The explicit smoothing parameter. + See the :ref:`Theory` section for more information. + Typical values are approximately 1.0. Increasing the explicit smoothing may result in a smoother grid, at the expense of orthogonality. + If the geometry is very sharp corners, too much explicit smoothing will cause the solver to rapidly "soften" the corner and the grid will fold back on itself. + In concave corners, additional smoothing will prevent lines from crossing (avoiding negative cells). + +epsI: + desc: > + Implicit smoothing parameter. + See the :ref:`Theory` section for more information. + Typical values are from 2.0 to 6.0. + Generally increasing the implicit coefficient results in a more stable solution procedure. + Usually this value should be twice the explicit smoothing parameter. + +theta: + desc: > + Kinsley-Barth coefficient See the :ref:`Theory` section for more information. + Only a single theta value is used for both directions. + Typical values are ~2.0 to ~4.0. + +volCoef: + desc: > + Coefficient used in point-Jacobi local volume smoothing algorithm. + Typically this value is 0.16 and need not be modified. + Use more ``volSmoothIter`` for stronger local smoothing. + +volBlend: + desc: > + The global volume blending coefficient. + See the :ref:`Theory` section for more information. + This value will typically be very small, especially if you widely varying cell sizes. + Typical values are from ~0 to 0.001. + +volSmoothIter: + desc: > + The number of point-Jacobi local volume smoothing iterations to perform. + Typical values are ~5 to ~25. + +volSmoothSchedule: + desc: > + If provided, use a user-supplied volume smoothing schedule. + +kspRelTol: + desc: > + Tolerance for the solution of the linear system at each iteration. + Typically :math:`1\times 10^{-8}` is sufficient. + Very difficult cases may benefit from a tighter convergence tolerance. + +kspMaxIts: + desc: > + Maximum number of iterations to perform for each step. + The default should be sufficient for most cases. + +kspSubspaceSize: + desc: > + Size of the ksp subspace. + Very large and difficult problems may benefit from a larger subspace size. + +writeMetrics: + desc: > + Flag to write the mesh gradients to the solution file. + This option should only be used for debugging purposes. + +outputType: + desc: > + Output format for the volume mesh. + cgns: CGNS format + plot3d: PLOT3D format + +outputFile: + desc: > + Output filename. + If None, an automatic filename will be generated by appending "_hyp" to the input filename. diff --git a/doc/plot3d.rst b/doc/plot3d.rst deleted file mode 100644 index b631f73..0000000 --- a/doc/plot3d.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _pyhyp_plot3d: - -Usage with Plot3d Files -======================= - -A complete sample script to generate a grid is given below. This -particular example is available under `examples/sphere/runSphere.py`:: - - from pyhyp import pyHyp - fileName = 'even_sphere.fmt' - #fileName = 'uneven_sphere.fmt' - #fileName = 'uneven_sphere_large.fmt' - - options= { - - # --------------------------- - # Input File - # --------------------------- - 'inputFile':fileName, - 'fileType':'Plot3d', - - # --------------------------- - # Grid Parameters - # --------------------------- - 'N': 73, - 's0':1e-4, - 'rMin':10, - - # --------------------------- - # Pseudo Grid Parameters - # --------------------------- - 'ps0':1e-4, - 'pGridRatio':1.1, - 'cMax': 5, - - # --------------------------- - # Smoothing parameters - # --------------------------- - 'epsE': 1.0, - 'epsI': 2.0, - 'theta': 3.0, - 'volCoef': .16, - 'volBlend': 0.0001, - 'volSmoothIter': 20, - - # --------------------------- - # Solution Parameters - # --------------------------- - 'kspRelTol': 1e-10, - 'kspMaxIts': 1500, - 'preConLag': 5, - 'kspSubspaceSize':50, - } - - hyp = pyHyp(options=options) - hyp.run() - hyp.writeCGNS('sphere.cgns') - -Each section of the example is now described:: - - from pyhyp import pyHyp - -is the preferred way of importing the `pyHyp` module into python. - -The options dictionary is used to provide all run-time options to -pyHyp to control the generation of the grid. -A description of each option and its general effect on the grid generation process is -explained in :ref:`pyhyp_options`. - -The next line of code:: - - hyp = pyHyp(options=options) - -generates the pyHyp object. - -.. NOTE:: When exporting a surface mesh from ICEMCFD in plot3d format - use the following options: - - * Formatted - * Whole - * Double - * No IBLANK Array - -.. WARNING:: It is essential that the normals of each of the surface - patches point in the *OUTWARD* direction, i.e. the marching - direction. - -The next two lines perform the actual generation and write the -resulting grid to a cgns file:: - - hyp.run() - hyp.writeCGNS('sphere.cgns') - - -The output of the run should look similar to the following:: - - #--------------------# - Total Nodes: 150 - Unique Nodes: 98 - Total Faces: 96 - #--------------------# - Normal orientation check ... - Normals seem correct! - #--------------------# - Grid Ratio: 1.1420 - #--------------------# - #------------------------------------------------------------------------------------------------------------------------------------------- - # Grid | CPU | Sub | KSP | Sl | Grid | Grid | Min | deltaS | cMax | min R | max | - # Level | Time | Iter | Its | | Sensor Max | Sensor Min | Quality | | | | KStretch | - #------------------------------------------------------------------------------------------------------------------------------------------- - - 2 0.26410E-02 1 10 0.17783E+00 0.10000E+01 0.10000E+01 0.65528E+00 0.11000E-03 0.32833E-03 0.10000E-03 0.00000E+00 - 3 0.60689E-02 2 10 0.21280E+00 0.99943E+00 0.99923E+00 0.64792E+00 0.13310E-03 0.39724E-03 0.33100E-03 0.10552E+01 - 4 0.81701E-02 1 10 0.22387E+00 0.99941E+00 0.99919E+00 0.64731E+00 0.14641E-03 0.43693E-03 0.46410E-03 0.11350E+01 - 5 0.10073E-01 1 10 0.23327E+00 0.99938E+00 0.99915E+00 0.64681E+00 0.16105E-03 0.48059E-03 0.61051E-03 0.11364E+01 - 6 0.11975E-01 1 10 0.24160E+00 0.99934E+00 0.99910E+00 0.64637E+00 0.17716E-03 0.52861E-03 0.77156E-03 0.11371E+01 - 7 0.13715E-01 1 10 0.24921E+00 0.99930E+00 0.99904E+00 0.64596E+00 0.19487E-03 0.58143E-03 0.94872E-03 0.11376E+01 - 8 0.15457E-01 1 10 0.25630E+00 0.99926E+00 0.99898E+00 0.64558E+00 0.21436E-03 0.63951E-03 0.11436E-02 0.11379E+01 - 9 0.17204E-01 1 10 0.26299E+00 0.99921E+00 0.99891E+00 0.64521E+00 0.23579E-03 0.70340E-03 0.13579E-02 0.11381E+01 - 10 0.20547E-01 2 10 0.27554E+00 0.99909E+00 0.99874E+00 0.64482E+00 0.28531E-03 0.85092E-03 0.18531E-02 0.11379E+01 - < iterations skipped for brevity> - 70 0.17639E+00 1 13 0.94933E+00 0.91466E+00 0.90983E+00 0.44618E+00 0.70716E+00 0.85351E+00 0.70706E+01 0.10857E+01 - 71 0.17845E+00 1 13 0.96300E+00 0.91433E+00 0.90996E+00 0.44321E+00 0.77788E+00 0.89981E+00 0.77778E+01 0.10933E+01 - 72 0.18323E+00 2 15 0.99094E+00 0.91399E+00 0.91040E+00 0.44094E+00 0.94123E+00 0.99767E+00 0.94113E+01 0.10859E+01 - 73 0.18649E+00 1 15 0.10052E+01 0.91396E+00 0.91071E+00 0.43894E+00 0.10354E+01 0.10493E+01 0.10353E+02 0.10874E+01 - - -Several important parameters are displayed to inform the user of the -solution progress. The most of important of which is the `Min Quality` -column. This column displays the minimum quality of all the cells in -the most recently computed layer of cells. For a valid mesh, these -must be all greater than zero. \ No newline at end of file diff --git a/doc/tutorial.rst b/doc/tutorial.rst new file mode 100644 index 0000000..ea9c4e7 --- /dev/null +++ b/doc/tutorial.rst @@ -0,0 +1,87 @@ +.. _pyhyp_tutorial: + +Tutorial +======== + +A complete sample script to generate a grid is given below. This +particular example is available under `examples/BWB/runBWB.py`. + +.. literalinclude:: ../examples/BWB/runBWB.py + +Each section of the example is now described. + +.. literalinclude:: ../examples/BWB/runBWB.py + :start-after: # rst import (start) + :end-before: # rst import (end) + +This is the preferred way of importing the `pyHyp` module into python. + +The options dictionary is used to provide all run-time options to +pyHyp to control the generation of the grid. +A description of each option and its general effect on the grid generation process is +explained in :ref:`pyhyp_options`. + +The next line of code + +.. literalinclude:: ../examples/BWB/runBWB.py + :start-after: # rst object + :end-before: # rst run + +generates the pyHyp object. + +.. NOTE:: When exporting a surface mesh from ICEMCFD in plot3d format + use the following options: + + * Formatted + * Whole + * Double + * No IBLANK Array + +.. WARNING:: It is essential that the normals of each of the surface + patches point in the *OUTWARD* direction, i.e. the marching + direction. + +The next two lines perform the actual generation and write the +resulting grid to a cgns file: + +.. literalinclude:: ../examples/BWB/runBWB.py + :start-after: # rst run + +The output of the run should look similar to the following:: + + #--------------------# + Total Nodes: 14105 + Unique Nodes: 13457 + Total Faces: 13376 + #--------------------# + Normal orientation check ... + Normals are consistent! + Determining topology ... + Topology complete. + #--------------------# + Grid Ratio: 1.2532 + #--------------------# + #-------------------------------------------------------------------------------------------------------------------# + # Grid | CPU | Sub | KSP | nAvg | Sl | Sensor | Sensor | Min | Min | deltaS | March | cMax | Ratio | + # Lvl | Time | Its | Its | | | Max | Min | Quality | Volume | | Distance | | kMax | + #-------------------------------------------------------------------------------------------------------------------# + 2 0.1 2 11 0 0.055 1.00006 0.98387 0.38387 0.359E-10 0.314E-05 0.451E-05 0.0011 0.0000 + 3 0.2 2 11 0 0.064 1.00010 0.96703 0.35947 0.657E-10 0.493E-05 0.116E-04 0.0018 1.9184 + 4 0.3 1 11 0 0.067 1.00012 0.96111 0.35650 0.103E-09 0.618E-05 0.165E-04 0.0022 1.5882 + 5 0.4 2 11 0 0.074 1.00024 0.90864 0.35575 0.174E-09 0.787E-05 0.305E-04 0.0035 1.7282 + 6 0.4 1 11 0 0.076 1.00031 0.89199 0.35610 0.237E-09 0.987E-05 0.383E-04 0.0035 1.3561 + 7 0.5 1 11 0 0.079 1.00037 0.87508 0.35613 0.371E-09 0.124E-04 0.482E-04 0.0044 1.5634 + 8 0.5 2 11 0 0.084 1.00083 0.78268 0.35729 0.548E-09 0.155E-04 0.761E-04 0.0069 1.4708 + 9 0.6 1 11 0 0.087 1.00108 0.75129 0.36201 0.717E-09 0.194E-04 0.916E-04 0.0069 1.3003 + 10 0.6 1 11 0 0.089 1.00124 0.74002 0.36599 0.104E-08 0.243E-04 0.111E-03 0.0086 1.4222 + < iterations skipped for brevity > + 78 33.9 22 29 0 0.904 0.98475 0.97354 0.32556 0.347E+04 0.730E+01 0.562E+03 2.5000 1.2603 + 79 36.1 22 29 0 0.936 0.98435 0.97427 0.32565 0.688E+04 0.930E+01 0.708E+03 2.5000 1.2570 + 80 38.0 21 29 0 0.968 0.98388 0.97469 0.32573 0.138E+05 0.119E+02 0.885E+03 2.5000 1.2551 + 81 39.9 20 29 0 1.000 0.98341 0.97476 0.32579 0.276E+05 0.152E+02 0.110E+04 2.5000 1.2540 + +Several important parameters are displayed to inform the user of the +solution progress. The most of important of which is the `Min Quality` +column. This column displays the minimum quality of all the cells in +the most recently computed layer of cells. For a valid mesh, these +must be all greater than zero. \ No newline at end of file diff --git a/examples/2D/naca0012_euler.py b/examples/2D/naca0012_euler.py index bafcd67..9624e0d 100644 --- a/examples/2D/naca0012_euler.py +++ b/examples/2D/naca0012_euler.py @@ -6,36 +6,6 @@ from pyhyp import pyHyp import numpy -options = { - # --------------------------- - # Grid Parameters - # --------------------------- - "N": 129, - "s0": 0.1e-2, - "rMin": 100, - # --------------------------- - # Pseudo Grid Parameters - # --------------------------- - "ps0": 0.50e-7, - "pGridRatio": 1.02, - "cMax": 6.0, - # --------------------------- - # Smoothing parameters - # --------------------------- - "epsE": 1.0, - "epsI": 2.0, - "theta": 4.0, - "volCoef": 0.16, - "volBlend": 0.005, - "volSmoothIter": 25, - # --------------------------- - # Solution Parameters - # --------------------------- - "kspRelTol": 1e-15, - "kspMaxIts": 500, - "preConLag": 5, - "kspSubspaceSize": 50, -} alpha = numpy.linspace(0, 2 * numpy.pi, 257) x = numpy.cos(alpha) * 0.5 + 0.5 y = numpy.zeros_like(x) @@ -70,7 +40,7 @@ # --------------------------- "inputFile": "naca0012_euler.fmt", "unattachedEdgesAreSymmetry": False, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {1: {"jLow": "zSymm", "jHigh": "zSymm"}}, "families": "wall", @@ -79,12 +49,12 @@ # --------------------------- "N": 129, "s0": 5e-3, - "marchDist": 100, + "marchDist": 100.0, # --------------------------- # Pseudo Grid Parameters # --------------------------- "ps0": 1e-6, - "pGridRatio": -1, + "pGridRatio": -1.0, "cMax": 3.0, # --------------------------- # Smoothing parameters diff --git a/examples/2D/naca0012_rans.py b/examples/2D/naca0012_rans.py index e54342b..a0f1413 100644 --- a/examples/2D/naca0012_rans.py +++ b/examples/2D/naca0012_rans.py @@ -47,7 +47,7 @@ # --------------------------- "inputFile": "naca0012_rans.fmt", "unattachedEdgesAreSymmetry": False, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {1: {"jLow": "zSymm", "jHigh": "zSymm"}}, "families": "wall", @@ -56,12 +56,12 @@ # --------------------------- "N": 129, "s0": 1e-6, - "marchDist": 100, + "marchDist": 100.0, # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, + "ps0": -1.0, + "pGridRatio": -1.0, "cMax": 3.0, # --------------------------- # Smoothing parameters diff --git a/examples/717/run717.py b/examples/717/run717.py index edcc58a..64df574 100644 --- a/examples/717/run717.py +++ b/examples/717/run717.py @@ -17,7 +17,7 @@ # --------------------------- "inputFile": fileName, "unattachedEdgesAreSymmetry": True, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {}, "families": "wall", @@ -26,13 +26,13 @@ # --------------------------- "N": 81, "s0": 5e-6, - "marchDist": 325, + "marchDist": 325.0, # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, - "cMax": 4, + "ps0": -1.0, + "pGridRatio": -1.0, + "cMax": 4.0, # --------------------------- # Smoothing parameters # --------------------------- diff --git a/examples/BWB/runBWB.py b/examples/BWB/runBWB.py index 15c89f4..e52076e 100644 --- a/examples/BWB/runBWB.py +++ b/examples/BWB/runBWB.py @@ -1,5 +1,8 @@ +# rst import (start) from pyhyp import pyHyp +# rst import (end) + fileName = "bwb.fmt" options = { @@ -8,7 +11,7 @@ # --------------------------- "inputFile": fileName, "unattachedEdgesAreSymmetry": True, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {}, "families": "wall", @@ -17,12 +20,12 @@ # --------------------------- "N": 81, "s0": 4e-6, - "marchDist": 1100, + "marchDist": 1100.0, # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, + "ps0": -1.0, + "pGridRatio": -1.0, "cMax": 2.5, # --------------------------- # Smoothing parameters @@ -35,6 +38,8 @@ "volSmoothIter": 150, } +# rst object hyp = pyHyp(options=options) +# rst run hyp.run() hyp.writeCGNS("bwb.cgns") diff --git a/examples/corner/runCorner.py b/examples/corner/runCorner.py index ad41529..7338f0f 100644 --- a/examples/corner/runCorner.py +++ b/examples/corner/runCorner.py @@ -8,14 +8,13 @@ """ fileName = "corner.cgns" -fileType = "CGNS" commonOptions = { # --------------------------- # Input Parameters # --------------------------- "inputFile": fileName, - "fileType": "CGNS", + "fileType": "cgns", "unattachedEdgesAreSymmetry": False, "outerFaceBC": "farfield", "autoConnect": True, @@ -31,9 +30,9 @@ # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, - "cMax": 5, + "ps0": -1.0, + "pGridRatio": -1.0, + "cMax": 5.0, # --------------------------- # Smoothing parameters # --------------------------- diff --git a/examples/m6/runM6.py b/examples/m6/runM6.py index cff2680..b90af92 100644 --- a/examples/m6/runM6.py +++ b/examples/m6/runM6.py @@ -9,9 +9,9 @@ # Input Parameters # --------------------------- "inputFile": fileName, - "fileType": "Plot3D", + "fileType": "plot3d", "unattachedEdgesAreSymmetry": True, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {}, "families": "wall", @@ -20,13 +20,13 @@ # --------------------------- "N": 81, "s0": 1.5e-5, - "marchDist": 30, + "marchDist": 30.0, "nConstantStart": 1, # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, + "ps0": -1.0, + "pGridRatio": -1.0, "cMax": 5.0, # --------------------------- # Smoothing parameters diff --git a/examples/plate/runPlate.py b/examples/plate/runPlate.py index 55a1dc1..d2f0b9b 100644 --- a/examples/plate/runPlate.py +++ b/examples/plate/runPlate.py @@ -1,14 +1,13 @@ from pyhyp import pyHyp fileName = "plate_surf.cgns" -fileType = "CGNS" options = { # --------------------------- # Input Parameters # --------------------------- "inputFile": fileName, - "fileType": "CGNS", + "fileType": "cgns", "unattachedEdgesAreSymmetry": False, "outerFaceBC": "overset", "autoConnect": True, @@ -24,9 +23,9 @@ # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, - "cMax": 5, + "ps0": -1.0, + "pGridRatio": -1.0, + "cMax": 5.0, # --------------------------- # Smoothing parameters # --------------------------- diff --git a/examples/sphere/runSphere.py b/examples/sphere/runSphere.py index 182dcdd..c92d899 100644 --- a/examples/sphere/runSphere.py +++ b/examples/sphere/runSphere.py @@ -10,7 +10,7 @@ # --------------------------- "inputFile": fileName1, "unattachedEdgesAreSymmetry": True, - "outerFaceBC": "farField", + "outerFaceBC": "farfield", "autoConnect": True, "BC": {}, "families": "wall", @@ -19,13 +19,13 @@ # --------------------------- "N": 73, "s0": 1e-4, - "marchDist": 10, + "marchDist": 10.0, # --------------------------- # Pseudo Grid Parameters # --------------------------- - "ps0": -1, - "pGridRatio": -1, - "cMax": 5, + "ps0": -1.0, + "pGridRatio": -1.0, + "cMax": 5.0, # --------------------------- # Smoothing parameters # --------------------------- diff --git a/pyhyp/__init__.py b/pyhyp/__init__.py index 098dd3b..31ce938 100644 --- a/pyhyp/__init__.py +++ b/pyhyp/__init__.py @@ -1,3 +1,3 @@ -__version__ = "2.2.1" +__version__ = "2.3.0" from .pyHyp import pyHyp, pyHypMulti diff --git a/pyhyp/pyHyp.py b/pyhyp/pyHyp.py index c264007..243b72b 100644 --- a/pyhyp/pyHyp.py +++ b/pyhyp/pyHyp.py @@ -25,27 +25,8 @@ from . import MExt from collections import OrderedDict from copy import deepcopy - - -class Error(Exception): - """ - Format the error message in a box to make it clear this - was a explicitly raised exception. - """ - - def __init__(self, message): - msg = "\n+" + "-" * 78 + "+" + "\n" + "| pyHyp Error: " - i = 14 - for word in message.split(): - if len(word) + i + 1 > 78: # Finish line and start new one - msg += " " * (78 - i) + "|\n| " + word + " " - i = 1 + len(word) + 1 - else: - msg += word + " " - i += len(word) + 1 - msg += " " * (78 - i) + "|\n" + "+" + "-" * 78 + "+" + "\n" - print(msg) - Exception.__init__(self) +from baseclasses import BaseSolver +from baseclasses.utils import Error # ============================================================================= @@ -61,57 +42,68 @@ def __init__(self, comm=None, options=None, commonOptions=None, debug=False, ski """ The inititalization method will setup, run, and write all the results. - INPUTS: - options: ORDERED dictionary or list of dictionaries. - This contains options for the extrusion of all several grids. An example of - option dictionary is given below: - - options = {'epsE':4.0, - 'epsI':8.0, - 'outputFile':'corner_hyp.cgns', - 'skip':False} - - We can set a list of dictionaries as input: - - options1 = {'epsE':4.0, - 'epsI':8.0, - 'outputFile':'corner1_hyp.cgns', - 'skip':False} - options2 = 'cartesian.cgns' - options3 = {'epsE':2.0, - 'epsI':4.0, - 'outputFile':'corner2_hyp.cgns', - 'skip':False} - options = [options1, options2, options3] - - OOOORRRR ... We can also set an ORDERED dictionary of dictionaries as input: - - from collections import OrderedDict - options = OrderedDict() - options{'case1'} = {'epsE':4.0, - 'epsI':8.0, - 'outputFile':'corner1_hyp.cgns', - 'skip':False} - options{'block'} = 'cartesian.cgns' - options{'case2'} = {'epsE':2.0, - 'epsI':4.0, - 'outputFile':'corner2_hyp.cgns', - 'skip':False} - - Each element of the list/dictionary will be considered as a different case. - One of the elements can be a string specifying a CGNS file that should be combined - with the other grids in the end. pyHyp will not do anything with this file except - combine it with the generated grids in the corresponding order. - These options will overwrite the default options (defined in the pyHyp class) - and the common options (another argument of this method). - If the user gives a list, this will be converted to a dictionary with integers - as keys. Remember this when setting the skip list for unnamed cases. - - commomOptions: dictionary with options that should be applied to all cases in the - options dictionary. See the 'defaulOptions' dictionary defined in - the pyHyp class to see the available options. - - skip_list: list containing names of cases that should be skipped. + + Parameters + ---------- + options : object + ORDERED dictionary or list of dictionaries. + This contains options for the extrusion of all several grids. An example of + option dictionary is given below: + + .. code-block:: python + + options = {'epsE':4.0, + 'epsI':8.0, + 'outputFile':'corner_hyp.cgns', + 'skip':False} + + We can set a list of dictionaries as input: + + .. code-block:: python + + options1 = {'epsE':4.0, + 'epsI':8.0, + 'outputFile':'corner1_hyp.cgns', + 'skip':False} + options2 = 'cartesian.cgns' + options3 = {'epsE':2.0, + 'epsI':4.0, + 'outputFile':'corner2_hyp.cgns', + 'skip':False} + options = [options1, options2, options3] + + Alternatively, we can set an ORDERED dictionary of dictionaries as input: + + .. code-block:: python + + from collections import OrderedDict + options = OrderedDict() + options{'case1'} = {'epsE':4.0, + 'epsI':8.0, + 'outputFile':'corner1_hyp.cgns', + 'skip':False} + options{'block'} = 'cartesian.cgns' + options{'case2'} = {'epsE':2.0, + 'epsI':4.0, + 'outputFile':'corner2_hyp.cgns', + 'skip':False} + + Each element of the list/dictionary will be considered as a different case. + One of the elements can be a string specifying a CGNS file that should be combined + with the other grids in the end. pyHyp will not do anything with this file except + combine it with the generated grids in the corresponding order. + These options will overwrite the default options (defined in the pyHyp class) + and the common options (another argument of this method). + If the user gives a list, this will be converted to a dictionary with integers + as keys. Remember this when setting the skip list for unnamed cases. + + commomOptions : dict + Dictionary with options that should be applied to all cases in the + options dictionary. See the 'defOpts' dictionary defined in + the pyHyp class to see the available options. + + skip_list : list + List containing names of cases that should be skipped. """ # Set the possible MPI Intracomm @@ -367,7 +359,7 @@ def combineCGNS(self, combinedFile="combined.cgns", additionalGrids=[""], skipLi # ============================================================================= -class pyHyp(object): +class pyHyp(BaseSolver): def __init__(self, comm=None, options=None, debug=False): """ Create the pyHyp object. @@ -386,152 +378,16 @@ def __init__(self, comm=None, options=None, debug=False): set to true when using a symbolic debugger. """ + name = "pyHyp" + category = "Hyperbolic mesh generator" + # Set the possible MPI Intracomm if comm is None: comm = MPI.COMM_WORLD self.comm = comm # Default options for hyperbolic generation - defaultOptions = { - # --------------------------- - # Input Information - # --------------------------- - # Input surface file. - "inputFile": "", - # Explict numpy arrays of patches - "patches": [], - # Input file type - "fileType": "plot3d", - # Flag to entirely skip the grid generation of this block - "skip": False, - # Type of extrusion: hyperbolic or elliptic - "mode": "hyperbolic", - # Unattached edges are symmetry plane - "unattachedEdgesAreSymmetry": True, - # Outerface boundary condition: farfield or overset - "outerFaceBC": "farfield", - # Boundary condition information for specific block edges - "BC": {}, - # Optional names for wall families - "families": {}, - # AutoConnect: Run cgnsutilities connect function to add - # any necessary block to block connectivity - "autoConnect": True, - # noPointReduce. Do not find duplicate nodes along - # edges. This must ONLY be used with single surface input - # files. - "noPointReduce": False, - # --------------------------- - # Grid Parameters - # --------------------------- - # Number of layers: - "N": 65, - # Initial off-wall spacing - "s0": 0.01, - # Number of constant off-wall layers before beginning - # stretch - "nConstantStart": 1, - # Number of constant layers at the end of the march. - "nConstantEnd": 1, - # sMax': Distance to march. - "marchDist": 50, - # nodeTol: Tolerance for nodes to be treated as identical. - "nodeTol": 1e-8, - # splay: Splay BC spreading factor - "splay": 0.25, - # splayEdgeOrthogonality. How hard to try to force - # orthogonality. Range of 0 to 0.5 - "splayEdgeOrthogonality": 0.1, - # splayCornerOrthogonality - "splayCornerOrthogonality": 0.2, - # Maximum convex corner angle necessary to trigger the node averaging. - # It should be in degrees. - "cornerAngle": 60.0, - # Coarsen: Automatically coarsen a mesh before starting - # extrusion. Coarsen=1 gives the same mesh - # (default). Coarsen=2 gives half the nodes in each direction. - # Coarsen=3 gives *quarter* the nodes in each direction etc. - "coarsen": 1, - # --------------------------- - # Elliptic Parameters - # --------------------------- - # panelEps: Distance source panels are "below" nodes. This - # parameter usually doesn't need to be changed. - "panelEps": 1e-8, - # farFieldTolerance: The multiple of the panel length - # cutoff to use the approximation formula - "farFieldTolerance": 4.0, - # useMatrixFree: Use matrix-free solution - # technique. (Always matrix free when evalMode is 'fast'.) - "useMatrixFree": True, - # evalMode: Type of panel evaluation routine: One of - # exact, slow or fast. - "evalMode": "fast", - # sourceStrengthFile: File to use to load/save the source - # strengths on the surface. - "sourceStrengthFile": "panelStrength.source", - # ------------------------------------------ - # Pseudo Grid Parameters (Hyperbolic only) - # ------------------------------------------ - # Maximum permissible ratio of marching direction length - # to smallest in-plane edge. - "cMax": 1.0, - # nonLinear: True/False. Use nonlinear scheme. Not - # currently working. - "nonLinear": False, - # slExp: Exponent for Sl calc. Don't change this value - # unless you know what you are doing! - "slExp": 0.15, - # Initial off-wall spacing. Negative values will be - # calculated automatically. - "ps0": -1, - # Pseudo grid Spacing Ratio. Negative values will be - # caculated automatically. - "pGridRatio": -1, - # ---------------------------------------- - # Smoothing parameters (Hyperbolic only) - # ---------------------------------------- - # epsE: The explicit smoothing coefficient - "epsE": 1.0, - # epsI: The implicit smoothing coefficient - "epsI": 2.0, - # theta: The barth implicit smoothing coefficient - "theta": 3.0, - # volCoef: The volume smoothing coefficient for - # pointJacobi iterations - "volCoef": 0.25, - # volBlend: The volume blending coefficient to force - # uniform sizes in farfield - "volBlend": 0.0001, - # volSmoothIter: The number of point-jacobi volume - # smoothing iterations - "volSmoothIter": 100, - # volSmoothSchedule: If given, use a user-supplied volume - # smoothing schedule. - "volSmoothSchedule": None, - # ------------------------------- - # Solution Parameters (Common) - # ------------------------------- - # kspRelTol: Solution tolerance for linear system - "kspRelTol": 1e-8, - # Maximum number of iterations to run for linear system - "kspMaxIts": 500, - # Subspace size for GMRES. - "kspSubspaceSize": 50, - # --------------------------- - # Output Parameters - # --------------------------- - # Debugging option to write grid metrics. Hyperbolic only - "writeMetrics": False, - # Output format - "outputType": "cgns", - # Output filename (if None, an automatic one will be generated by - # appending "_hyp" to the input filename). - "outputFile": None, - } - - # Get keys for every option - self.defaultOptionKeys = set(k.lower() for k in defaultOptions) + defOpts = self._getDefaultOptions() # Import and set the hyp module curDir = os.path.dirname(os.path.realpath(__file__)) @@ -544,9 +400,8 @@ def __init__(self, comm=None, options=None, debug=False): if options is None: raise Error("The options = keyword argument is *NOT* optional. " "It must always be provided") - # Setup the options - self.options = {} - self._checkOptions(options, defaultOptions) + # Initialize the inherited BaseSolver + super().__init__(name, category, defOpts, options) # Set the fortan options self._setOptions() @@ -555,23 +410,23 @@ def __init__(self, comm=None, options=None, debug=False): # Convert file type to integer fileType = {"cgns": self.hyp.hypinput.cgnsfiletype, "plot3d": self.hyp.hypinput.plot3dfiletype} - intFileType = fileType[self._go("fileType").lower()] + intFileType = fileType[self.getOption("fileType")] # Determine how we are getting data: by Input file or # explictly by patches. patchInput = False - patches = self._go("patches") + patches = self.getOption("patches") if len(patches) > 0: patchInput = True nBlocks = len(patches) if not patchInput: - if not os.path.isfile(self._go("inputFile")): - raise Error("Input file '%s' not found." % self._go("inputFile")) + if not os.path.isfile(self.getOption("inputFile")): + raise Error("Input file '%s' not found." % self.getOption("inputFile")) # Determine the number of blocks we have so we can initialize # the BC array: - nBlocks = self.hyp.getnblocks(self._go("inputFile"), intFileType) + nBlocks = self.hyp.getnblocks(self.getOption("inputFile"), intFileType) self.hyp.allocatefamilies(nBlocks) if self.getOption("noPointReduce") and nBlocks > 1: @@ -582,7 +437,7 @@ def __init__(self, comm=None, options=None, debug=False): fBCs[:, :] = self.hyp.hypinput.bcdefault # The python BC information - BCs = self._go("BC") + BCs = self.getOption("BC") BCMap = { "splay": self.hyp.hypinput.bcsplay, "xsymm": self.hyp.hypinput.bcxsymm, @@ -633,7 +488,7 @@ def __init__(self, comm=None, options=None, debug=False): self.hyp.hypinput.bcs = fBCs # Now process the family information if we have any: - families = self._go("families") + families = self.getOption("families") fFamilies = [] # Set default a default name of "wall". @@ -645,7 +500,7 @@ def __init__(self, comm=None, options=None, debug=False): if intFileType == self.hyp.hypinput.cgnsfiletype: if self.comm.rank == 0: for i in range(nBlocks): - family, foundFam = self.hyp.readfamily(self._go("inputFile"), i + 1) + family, foundFam = self.hyp.readfamily(self.getOption("inputFile"), i + 1) if foundFam and len(family.strip()) > 0: fFamilies[i] = family.strip() fFamilies = self.comm.bcast(fFamilies) @@ -685,20 +540,90 @@ def __init__(self, comm=None, options=None, debug=False): intFileType = self.hyp.hypinput.patchinput # Now run the fortran setup. - self.hyp.setup(self._go("inputFile"), intFileType) + self.hyp.setup(self.getOption("inputFile"), intFileType) + + @staticmethod + def _getDefaultOptions(): + defOpts = { + # --------------------------- + # Input Information + # --------------------------- + "inputFile": [str, ""], + "patches": [list, []], + "fileType": [str, ["plot3d", "cgns"]], + "skip": [bool, False], + "mode": [str, ["hyperbolic", "elliptic"]], + "unattachedEdgesAreSymmetry": [bool, True], + "outerFaceBC": [str, ["farfield", "overset"]], + "BC": [dict, {}], + "families": [(str, dict), {}], + "autoConnect": [bool, True], + "noPointReduce": [bool, False], + # --------------------------- + # Grid Parameters + # --------------------------- + "N": [int, 65], + "s0": [float, 0.01], + "nConstantStart": [int, 1], + "nConstantEnd": [int, 1], + "marchDist": [float, 50.0], + "nodeTol": [float, 1e-8], + "splay": [float, 0.25], + "splayEdgeOrthogonality": [float, 0.1], + "splayCornerOrthogonality": [float, 0.2], + "cornerAngle": [float, 60.0], + "coarsen": [int, 1], + # --------------------------- + # Elliptic Parameters + # --------------------------- + "panelEps": [float, 1e-8], + "farFieldTolerance": [float, 4.0], + "useMatrixFree": [bool, True], + "evalMode": [str, ["fast", "exact", "slow"]], + "sourceStrengthFile": [str, "panelStrength.source"], + # ------------------------------------------ + # Pseudo Grid Parameters (Hyperbolic only) + # ------------------------------------------ + "cMax": [float, 1.0], + "nonLinear": [bool, False], + "slExp": [float, 0.15], + "ps0": [float, -1.0], + "pGridRatio": [float, -1.0], + # ---------------------------------------- + # Smoothing parameters (Hyperbolic only) + # ---------------------------------------- + "epsE": [float, 1.0], + "epsI": [float, 2.0], + "theta": [float, 3.0], + "volCoef": [float, 0.25], + "volBlend": [float, 0.0001], + "volSmoothIter": [int, 100], + "volSmoothSchedule": [(list, type(None)), None], + # ------------------------------- + # Solution Parameters (Common) + # ------------------------------- + "kspRelTol": [float, 1e-8], + "kspMaxIts": [int, 500], + "kspSubspaceSize": [int, 50], + # --------------------------- + # Output Parameters + # --------------------------- + "writeMetrics": [bool, False], + "outputType": [str, ["cgns", "plot3d"]], + "outputFile": [(str, type(None)), None], + } + return defOpts def run(self): """ Run given using the options given """ - if not self.options["skip"]: - if self._go("mode").lower() == "hyperbolic": + if not self.getOption("skip"): + if self.getOption("mode") == "hyperbolic": self.hyp.runhyperbolic() - elif self._go("mode").lower() == "elliptic": + elif self.getOption("mode") == "elliptic": self.hyp.setuppanels() self.hyp.runelliptic() - else: - raise Error("Invalid parameter value for mode. Must be one " "of 'elliptic' or 'hyperbolic'") self.gridGenerated = True else: print("Skipped generation of this grid") @@ -723,7 +648,7 @@ def writeCGNS(self, fileName): self.hyp.writecgns(fileName) # Possibly perform autoconnect using cgns_utils - if self.comm.rank == 0 and self._go("autoConnect"): + if self.comm.rank == 0 and self.getOption("autoConnect"): error = os.system("cgns_utils connect %s" % fileName) if error: raise Error( @@ -740,21 +665,21 @@ def writeOutput(self, fileName=None, fileType=None): # Get desired output type from options, unless provided if fileType is None: - outputType = self.options["outputtype"] + outputType = self.getOption("outputtype") else: outputType = fileType # Check if the user specified name in the options if fileName is None: - fileName = self.options["outputfile"] + fileName = self.getOption("outputfile") # If no name is specified even in the options, then # we generate one if fileName is None: - fileName = generateOutputName(self.options["inputfile"], outputType=outputType) + fileName = generateOutputName(self.getOption("inputfile"), outputType=outputType) # Update the name stored in the options for future uses - self.options["outputfile"] = fileName + self.setOption("outputfile", fileName) if outputType == "cgns": self.writeCGNS(fileName) @@ -780,49 +705,49 @@ def _setOptions(self): """ Internal function to set the options in pyHyp """ - self.hyp.hypinput.n = self._go("N") - self.hyp.hypinput.nconstantstart = self._go("nConstantStart") - self.hyp.hypinput.nconstantend = self._go("nConstantEnd") - self.hyp.hypinput.nopointreduce = self._go("noPointReduce") - self.hyp.hypinput.s0 = self._go("s0") - self.hyp.hypinput.marchdist = self._go("marchdist") - self.hyp.hypinput.ps0 = self._go("ps0") - self.hyp.hypinput.pgridratio = self._go("pGridRatio") - self.hyp.hypinput.slexp = self._go("slExp") - self.hyp.hypinput.epse = self._go("epsE") - self.hyp.hypinput.epsi = self._go("epsI") - self.hyp.hypinput.theta = self._go("theta") - self.hyp.hypinput.volcoef = self._go("volCoef") - self.hyp.hypinput.volblend = self._go("volBlend") - self.hyp.hypinput.cmax = self._go("cMax") - self.hyp.hypinput.volsmoothiter = self._go("volSmoothIter") - self.hyp.hypinput.splay = self._go("splay") - self.hyp.hypinput.splayedgeorthogonality = self._go("splayEdgeOrthogonality") - self.hyp.hypinput.splaycornerorthogonality = self._go("splayCornerOrthogonality") - self.hyp.hypinput.cornerangle = self._go("cornerangle") * numpy.pi / 180 - self.hyp.hypinput.coarsen = self._go("coarsen") - self.hyp.hypinput.kspreltol = self._go("kspRelTol") - self.hyp.hypinput.kspmaxits = self._go("kspMaxIts") - self.hyp.hypinput.nonlinear = self._go("nonLinear") - self.hyp.hypinput.kspsubspacesize = self._go("kspSubspaceSize") - self.hyp.hypinput.writemetrics = self._go("writeMetrics") - self.hyp.hypinput.nodetol = self._go("nodeTol") - self.hyp.hypinput.farfieldtol = self._go("farFieldTolerance") - self.hyp.hypinput.usematrixfree = self._go("useMatrixFree") - self.hyp.hypinput.unattachededgesaresymmetry = self._go("unattachEdedgesAreSymmetry") + self.hyp.hypinput.n = self.getOption("N") + self.hyp.hypinput.nconstantstart = self.getOption("nConstantStart") + self.hyp.hypinput.nconstantend = self.getOption("nConstantEnd") + self.hyp.hypinput.nopointreduce = self.getOption("noPointReduce") + self.hyp.hypinput.s0 = self.getOption("s0") + self.hyp.hypinput.marchdist = self.getOption("marchdist") + self.hyp.hypinput.ps0 = self.getOption("ps0") + self.hyp.hypinput.pgridratio = self.getOption("pGridRatio") + self.hyp.hypinput.slexp = self.getOption("slExp") + self.hyp.hypinput.epse = self.getOption("epsE") + self.hyp.hypinput.epsi = self.getOption("epsI") + self.hyp.hypinput.theta = self.getOption("theta") + self.hyp.hypinput.volcoef = self.getOption("volCoef") + self.hyp.hypinput.volblend = self.getOption("volBlend") + self.hyp.hypinput.cmax = self.getOption("cMax") + self.hyp.hypinput.volsmoothiter = self.getOption("volSmoothIter") + self.hyp.hypinput.splay = self.getOption("splay") + self.hyp.hypinput.splayedgeorthogonality = self.getOption("splayEdgeOrthogonality") + self.hyp.hypinput.splaycornerorthogonality = self.getOption("splayCornerOrthogonality") + self.hyp.hypinput.cornerangle = self.getOption("cornerangle") * numpy.pi / 180 + self.hyp.hypinput.coarsen = self.getOption("coarsen") + self.hyp.hypinput.kspreltol = self.getOption("kspRelTol") + self.hyp.hypinput.kspmaxits = self.getOption("kspMaxIts") + self.hyp.hypinput.nonlinear = self.getOption("nonLinear") + self.hyp.hypinput.kspsubspacesize = self.getOption("kspSubspaceSize") + self.hyp.hypinput.writemetrics = self.getOption("writeMetrics") + self.hyp.hypinput.nodetol = self.getOption("nodeTol") + self.hyp.hypinput.farfieldtol = self.getOption("farFieldTolerance") + self.hyp.hypinput.usematrixfree = self.getOption("useMatrixFree") + self.hyp.hypinput.unattachededgesaresymmetry = self.getOption("unattachEdedgesAreSymmetry") modes = { "exact": self.hyp.hypinput.eval_exact, "slow": self.hyp.hypinput.eval_slow, "fast": self.hyp.hypinput.eval_fast, } - self.hyp.hypinput.evalmode = modes[self._go("evalMode").lower()] + self.hyp.hypinput.evalmode = modes[self.getOption("evalMode")] ffType = {"farfield": self.hyp.hypinput.outerfacefarfield, "overset": self.hyp.hypinput.outerfaceoverset} - self.hyp.hypinput.outerfacetype = ffType[self._go("outerFaceBC").lower()] + self.hyp.hypinput.outerfacetype = ffType[self.getOption("outerFaceBC")] self.hyp.hypinput.sourcestrengthfile = self._expandString("") - f = self._go("sourceStrengthFile") + f = self.getOption("sourceStrengthFile") self.hyp.hypinput.sourcestrengthfile = self._expandString(f) - sch = self._go("volSmoothSchedule") + sch = self.getOption("volSmoothSchedule") if sch is not None: sch = numpy.array(sch, "d") # Make sure its normalized @@ -836,21 +761,6 @@ def _expandString(self, s): length so we can set them in fortran""" return s + " " * (512 - len(s)) - def _checkOptions(self, options, defaultOptions): - """ - Check the solver options against the default ones - and add option iff it is NOT in options - """ - # Set existing ones - for key in options: - self.setOption(key, options[key]) - - # Check for the missing ones - optionKeys = set(k.lower() for k in options) - for key in defaultOptions: - if not key.lower() in optionKeys: - self.setOption(key, defaultOptions[key]) - def __del__(self): """ Clean up fortran allocated values if necessary @@ -943,48 +853,6 @@ def surfaceSmooth(self, nIter, stepSize, surfFile=None): self.hyp.smoothwrap(nIter, stepSize) - def getOption(self, name): - """ - Return the value of the requested option. - - Parameters - ---------- - name : str - Name of option to get. Not case sensitive - - Returns - ------- - value : varries - Return the curent value of the option. - """ - - if name.lower() in self.defaultOptionKeys: - return self.options[name.lower()] - else: - raise Error("getOption: %s is not a valid pyHyp option." % name) - - def setOption(self, name, value): - """ - Set the value of the requested option. - - Parameters - ---------- - name : str - Name of option to get. Not case sensitive - - value : varries - Value to set - """ - - if name.lower() in self.defaultOptionKeys: - self.options[name.lower()] = value - else: - raise Error("setOption: %s is not a valid pyHyp option." % name) - - def _go(self, name): - """Internal short-cut function to make text a litle shorter""" - return self.getOption(name) - # =====================================================# @@ -1005,8 +873,6 @@ def generateOutputName(inputFile, outputType): outputFile = outputFile + ".cgns" elif outputType == "plot3d": outputFile = outputFile + ".fmt" - else: - raise Error("Output file type not recognized.") # Return the generated name return outputFile diff --git a/setup.py b/setup.py index 2bf8760..b4bb76a 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ install_requires=[ "numpy>=1.16", "mpi4py>=3.0", + "mdolab-baseclasses>=1.2", ], classifiers=["Operating System :: Linux", "Programming Language :: Python, Fortran"], )