Surface Slicer ============== The :class:`PGL.components.surfaceslicer.SlicedLoftedSurface` class resamples the 3D lofted surface generated by the :class:`PGL.components.loftedblade.LoftedBladeSurface` class. The ``LoftedBladeSurface()`` class defines the body cross-sections in surfaces normal to the body center-line. Whereas the surface resampled by ``SlicedLoftedSurface()`` class lies in parallel X-Y (Z = c) planes, where the X-Y-Z coordinate system is defined as the body coordinate system. As a consequence, the new cross-sectional surface definitions will no longer be normal to the body center-line, unless the body is straight with no rotations about either the body X-axis or the body Y-axis. The ``SlicedLoftedSurface()`` class utilizes an adaptive Newton-Rhapson numerical method to slice the 3D lofted surface. A bilinear interpolation method is used to obtain the points on the slice from the lofted surface input, for each iteration of the solver. As such, it is recommended that the surface discretization (i.e. number of spanwise and chordwise sections) desired in the resampled lofted surface be either the same or less than that of the lofted surface input. A walk-through of an example script to generate the re-sampled 3D lofted surface has been presented. SlicedLoftedSurface example --------------------------- In this example a DTU 10MW lofted blade surface is first generated using LoftedBladeSurface, which is then used as input to the SlicedLoftedSurface. The example is located in ``PGL/examples/surfaceslicer_example.py``. .. literalinclude:: ../PGL/examples/surfaceslicer_example.py Required modules ^^^^^^^^^^^^^^^^ The modules shown below are required to run the example. :class:`PGL.main.planform.read_blade_planform` and :class:`PGL.main.planform.redistribute_planform` are needed to read the file containing the blade planform information and to redistribute the planform as desired. .. code-block:: python import numpy as np from PGL.components.loftedblade import LoftedBladeSurface from PGL.main.planform import read_blade_planform, redistribute_planform from PGL.components.surfaceslicer import SlicedLoftedSurface Read blade planform and redistribute ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The code shown below reads the blade planform data stored in a textfile and redistributes the planform. .. code-block:: python pf = read_blade_planform('data/DTU_10MW_RWT_blade_axis_prebend.dat') dist = [[0, 0.01, 1], [0.05, 0.01, 8], [0.98, 0.001, 119], [1., 0.0005, 140]] pf = redistribute_planform(pf, dist=dist) LoftedBladeSurface ^^^^^^^^^^^^^^^^^^ The code block shown below first creates an object instance of the LoftedBladeSurface class. .. code-block:: python d = LoftedBladeSurface() The redistributed planform is then assigned as an instance variable. .. code-block:: python d.pf = pf The trailing edge can be opened by specifying the distance between the pressure side and suction side surfaces. It should be noted that this value is to be non-dimensionalized by the blade length. .. code-block:: python d.redistribute_flag = True d.minTE = 0.0 The airfoil data along with the blend order of the relative thicknesses are specified. .. code-block:: python d.blend_var = [0.241, 0.301, 0.36, 1.0] for f in ['data/ffaw3241.dat', 'data/ffaw3301.dat', 'data/ffaw3360.dat', 'data/cylinder.dat']: d.base_airfoils.append(np.loadtxt(f)) Finally, calling the ``update()`` method generates the 3D blade lofted surface with cross-sectional surfaces normal to the blade center line. .. code-block:: python d.update() NOTE: The generated lofted surface is stored in the instance variable ``d.surface``. Additionally, the chordwise discretization (ie the number of cross-sectional points) can be altered using the instance variable ``d.ni_chord``. By default this value is set to ``257``. SlicedLoftedSurface ^^^^^^^^^^^^^^^^^^^ Next, an object of the ``SlicedLoftedSurface()`` class is created. .. code-block:: python m = SlicedLoftedSurface() The lofted blade surface created by the ``LoftedBladeSurface()`` class, is assigned as input. .. code-block:: python m.surface = d.surface The spanwise (i.e. axial) and the chordwise discretizations are then assigned. The discretizations should be either equal to or less than their counterparts in the lofted surface generated by ``LoftedBladeSurface()``. The distributions are linear and as such the discrete quantities are equal for each discretized cross-section as well for the blade span. .. code-block:: python m.ni_span = d.ni_span m.ni_slice = d.ni_chord Next, a spanwise distribution of the parallel planes is generated. There are three options available to the user. Option 1: """"""""" Providing a list of control points as per the definition given in :class:`PGL.main.distfunc.distfunc`. ``dist`` can be the same as the one used to redistribute the planform for generating the lofted surface using ``LoftedBladeSurface()``. This ensures a preservation of the surface features in the sliced surface as captured by the lofted surface. .. code-block:: python dist = [[0, 0.01, 1], [0.05, 0.01, 8], [0.98, 0.001, 119], [1., 0.0005, 140]] m.dist = dist Option 2: """"""""" Providing a 1D numpy array consisting of normalised spanwise distribution. This can be the same as the spanwise distribution of the planform supplied to the ``LoftedBladeSurface()``. Again, this ensures a preservation of the surface features in the sliced surface as captured by the lofted surface. .. code-block:: python m.s = pf['s'] Option 3: """"""""" If neither Option 1 nor Option 2 is selected, then the spanwise distirbution of the sliced surface is chosen as a linear discretization from the blade root to the blade tip with the number of spanwise section equal to the user input: ``m.ni_span``. If both Option 1 and Option 2 are provided, then Option 1 takes precedence. NOTE: If the number of spanwise sections for Option 1 and Option 2 are either more or less than the user input, the inputted distribution is linearly varied such that the span sections match ``m.ni_span``. An optional flag is provided to include the tip in the discretization. The default value is set to ``False``. This flag is utilized if a linear spanwise distribution is used. It should be noted that the tip is subject to steep spanwise gradients which may lead to non-linearities in the Newton iteration causing the solver to not converge. If such a case occurs, the tip cros-section is generated through cubic spline extrapolation of the re-sampled blade surface. .. code-block:: python m.include_tip = True The blade length can be set. By default this value is set as unity, resulting in a solution that is scaled by the blade length. If this value is set to be either greater or less than unity, the lofted surface input is appropriately scaled with it and is subsequently re-sampled. .. code-block:: python m.blade_length = 1.0 The convergence criteria for the residual of the Newton iteration method can be set. This tolerance is the maximum of the absolute difference between the final and the previous state of the residual vector. It has an S.I. unit of metres. As such its value should be appropriately set in accordance with the inputted blade length. For example, a millimetre accuracy would suffice for a blade whose length is equal to or greater than 1 m and as such the tolerance could be set as ``0.001``. By default its value is set as ``0.00001``. NOTE: Lower the tolerance value higher will be the computation time. .. code-block:: python m.tol = 1e-4 The resampled is generated by calling the ``update()`` method. .. code-block:: python m.update() The resampled sliced surface can now be accessed through the instance variable ``m.sliced_surface``. Additionally, the surface can be outputted for visualization in software such as ParaView_ by including the code shown below. .. _Paraview: https://www.paraview.org/ .. code-block:: python m.domain.write_plot3d('exampleblade_sliced.xyz')