def export3d_grid_hmg(gid, fname, fmt="ascii", afields=[]): """Exports 3d grid to hybmesh native format. :param gid: single or list of grid identifiers :param str fname: output filename :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. :param list-of-str afields: additional data which should be placed to output file. To save additional data into grid file :ref:`user defined fields <udef-fields>` place any of these strings into **afields** list: * ``'face-vertices'`` - face vertex ordered connectivity, * ``'cell-faces'`` - cell face connectivity, * ``'cell-vertices'`` - cell vertex connectivity, * ``'linfem'`` - tries to write cells-vertex connectivity for cell types most widely used in linear fem solvers. Supported cell types are: tetrahedron (4 nodes), hexahedron (8), prism(6), pyramid(5). Record for each of those cells contains points in order prescribed by vtk file format. If a cell is not of one of those types then a zero length connectivity list will be written for it. .. figure:: vtk_cells3d.png :width: 500 px See :ref:`grid3d-file` for format description. """ if fmt == "binary": fmt = "bin" if fmt == "fbinary": fmt = "fbin" icheck(0, UListOr1(Grid3D())) icheck(1, String()) icheck(2, OneOf('ascii', 'bin', 'fbin')) icheck( 3, UList(OneOf('face-vertices', 'cell-faces', 'cell-vertices', 'linfem'))) names = gid if isinstance(gid, list) else [gid] grids = map(flow.receiver.get_grid3, names) cb = flow.interface.ask_for_callback() native_export.grid3_tofile(fname, grids, names, fmt, afields, cb)
def clip_domain(dom1, dom2, operation, simplify=True): """ Executes domain clipping procedure :param dom1: :param dom2: contour identifiers :param str operatrion: operation code * ``"union"`` * ``"difference"`` * ``"intersection"`` * ``"xor"`` :param bool simplify: whether to keep all source points (False) or return simplified contour :returns: created contour identifier or None if resulting domain is empty """ icheck(0, ACont2D()) icheck(1, ACont2D()) icheck(2, OneOf("union", "difference", "intersection", "xor")) icheck(3, Bool()) c = com.contcom.ClipDomain({"c1": dom1, "c2": dom2, "oper": operation, "simplify": simplify}) flow.exec_command(c) if len(c.added_contours2()) > 0: return c.added_contours2()[0] else: return None
def check_compatibility(vers, policy=1): """ Checks version compatibility. Notifies if current version of hymbesh is not fully compatible with input version. :param str vers: version in ``"0.1.2"`` format :param int policy: if versions are incompatible then: * 0 - do nothing (return False) * 1 - report warning to cout * 2 - raise ExecError :returns: False if versions are incompatible, True otherwise. """ icheck(0, String()) icheck(1, OneOf(1, 2, 3)) versc = progdata.HybMeshVersion.current() versi = progdata.HybMeshVersion(vers) # last checked for 0.2.1 version ret = True if (versi > versc): ret = False if (versi < progdata.HybMeshVersion("0.2.1")): ret = False if not ret: message = "Current version of hybmesh %s is not " \ "fully compatible with version %s" % (versc, vers) if policy == 1: print "WARNING:", message elif policy == 2: raise Exception(message) return ret
def export3d_surface_hmc(sid, fname, fmt="ascii"): """Exports 3d surface to hybmesh native format. :param sid: single or list of surface identifiers :param str fname: output filename :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. See :ref:`surface3d-file` for format description. """ if fmt == "binary": fmt = "bin" elif fmt == "fbinary": fmt = "fbin" icheck(0, UListOr1(ASurf3D())) icheck(1, String()) icheck(2, OneOf('ascii', 'bin', 'fbin')) names = sid if isinstance(sid, list) else [sid] surfs = [_surf3_from_id(n) for n in names] cb = flow.interface.ask_for_callback() native_export.surf3_tofile(fname, surfs, names, fmt, cb)
def export_contour_hmc(cid, fname, fmt="ascii"): """Exports contours to native format. :param cid: contour identifier or list of identifiers, :param str fname: output filename :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. :returns: None See :ref:`contour2d-file` for format description. """ if fmt == "binary": fmt = "bin" elif fmt == "fbinary": fmt = "fbin" icheck(0, UListOr1(ACont2D())) icheck(1, String()) icheck(2, OneOf('ascii', 'bin', 'fbin')) names = cid if isinstance(cid, list) else [cid] conts = [_cont2_from_id(n) for n in names] cb = flow.interface.ask_for_callback() native_export.cont2_tofile(fname, conts, names, fmt, cb)
def export_grid_hmg(gid, fname, fmt='ascii', afields=[]): """Exports 2d grid to hybmesh native format. :param gid: single or list of grid identifiers :param str fname: output filename :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. :param list-of-str afields: additional data which should be placed to output file. :returns: None To save additional data into grid file :ref:`user defined fields <udef-fields>` place any of these strings into **afields** list: * ``'cell-vertices'`` -- cell vertex connectivity. All vertices will be written in counterclockwise direction; * ``'cell-edges'`` -- cell edge connectivity. All edges will be written in counterclockwise direction. See :ref:`grid2d-file` for format description. """ if fmt == "binary": fmt = "bin" if fmt == "fbinary": fmt = "fbin" icheck(0, UListOr1(Grid2D())) icheck(1, String()) icheck(2, OneOf('ascii', 'bin', 'fbin')) icheck(3, UList(OneOf('cell-vertices', 'cell-edges'))) names = gid if isinstance(gid, list) else [gid] grids = map(flow.receiver.get_grid2, names) cb = flow.interface.ask_for_callback() native_export.grid2_tofile(fname, grids, names, fmt, afields, cb)
def add_circ_rect_grid(p0, rad, step, sqrside=1.0, rcoef=1.0, algo="linear"): """ Creates quadrangular cell grid in a circular area. See details in :ref:`circrect_grid`. :param list-of-floats p0: center point of circle area in [x, y] format. :param positive-float rad: radius of circle area. :param positive-float step: approximate partition step of the outer boundary. :param positive-float sqrside: side of the inner square normalized by the circle radius. Values greater than 1.4 are not allowed. :param positive-float rcoef: radius direction refinement of the ring part of the grid. Values less then unity lead to refinement towards outer boundary. :param str algo: Algorithms of assembling the ring part of the grid. * ``'linear'`` - use weighted approach for each ray partition * ``'laplace'`` - use algebraic mapping for building each 45 degree sector. * ``'orthogonal_circ'`` - build orthogonal grid keeping uniform grid at outer circle * ``'orthogonal_rect'`` - build orthogonal grid keeping uniform grid at inner rectangle :return: new grid identifier """ icheck(0, Point2D()) icheck(1, Float(grthan=0.0)) icheck(2, Float(grthan=0.0)) icheck(3, Float(within=[0., 1.4, '[)'])) icheck(4, Float(grthan=0.0)) icheck(5, OneOf('linear', 'laplace', 'orthogonal_circ', 'orthogonal_rect')) # call args = { 'algo': algo, 'p0': p0, 'rad': rad, 'step': step, 'sqrside': sqrside, 'rcoef': rcoef } c = com.gridcom.AddCirc4Grid(args) flow.exec_command(c) return c.added_grids2()[0]
def tab_grid2(obj, what): """ Returns plain table for the given grid. :param str obj: grid identifier :param str what: table name :returns: plain ctypes array representing requested table. Possible **what** values are: * ``'vert'`` - vertex coordinates table, * ``'edge_vert'`` - edge-vertex connectivity: indices of first and last vertices for each edge, * ``'edge_cell'`` - edge-cell connectivity: indices of left and right cell for each edge. If this is a boundary edge ``-1`` is used to mark boundary edge side, * ``'cell_dim'`` - number of vertices in each cell, * ``'cell_edge'`` - cell-edge connectivity: counterclockwise ordered edge indices for each cell. * ``'cell_vert'`` - cell-vertex connectivity: counterclockwise ordered vertex indices for each cell. * ``'bnd'`` - list of boundary edges indices, * ``'bt'`` - boundary types for all edges including internal ones, * ``'bnd_bt'`` - (boundary edge, boundary feature) pairs In case of grids with variable cell dimensions ``'cell_edge'`` and ``'cell_vert'`` tables require additional ``'cell_dim'`` table to subdive returned plain array by certain cells. """ icheck(0, Grid2D()) icheck( 1, OneOf( 'vert', 'edge_vert', 'edge_cell', 'cell_dim', 'cell_edge', 'cell_vert', 'bnd', 'bt', 'bnd_bt', )) return flow.receiver.get_grid2(obj).raw_data(what)
def connect_subcontours(sources, fix=[], close="no", shiftnext=True): """ Connects sequence of open contours into a single contour even if neighboring contours have no equal end points :param sources: list of open contour identifiers :param list-of-int fix: indicies of **sources** contours which could not be shifted or stretched. :param str close: last connection algorithm: ``no``, ``yes`` or ``force`` :param bool shiftnext: if True then each next contour will be shifted to the end point of previous one, otherwise both contours will be stretched to match average end point. To connect given contours this procedure implements stretching and shifting of those ones not listed in **fix** list. If two adjacent source contours are marked as fixed but have no common end points an exception will be raised. If **close** is ``yes`` then last contour of **sources** will be connected with the first one with algorithm depending on **fix** and **shiftnext** options. If **close** is ``no`` then ending contours will be left as they are. In that case resulting contour will be open until first and last points are exactly equal. **close** = ``force`` algorithm works like **close** = ``no`` but creates a section which explicitly connects first and last contours by a straight line. """ icheck(0, UList(Cont2D())) icheck(1, UList(UInt(maxv=len(sources) - 1), maxlen=len(sources))) icheck(2, OneOf('no', 'yes', 'force')) icheck(3, Bool()) args = {} args['src'] = sources args['fix'] = copy.deepcopy(fix) args['close'] = close args['shiftnext'] = shiftnext c = com.contcom.ConnectSubcontours(args) flow.exec_command(c) return c.added_contours2()[0]
def build_boundary_grid1(cont, partition, direction, pstart=None, pend=None, range_angles=[40, 125, 235, 275]): """Builds a singly-connected boundary grid near given contour. :param cont: source contour (or grid) identifier :param list-of-float partition: partition in perpendicular direction. :param str direction: 'left'/'right' :param pstart: :param pend: points in [x, y] format which define the exact segment of the contour for building grid. If both are None hence whole contour (or all subcontours) will be used. :param range_angles: list of 4 angle values (deg) which define algorithms for contour bends treatment. :returns: identifier of the newly created grid. This is a wrapper for a :func:`build_boundary_grid` with simplified interface. It allows to build a boundary grid with constant partition options using existing contour segmentation for horizontal stepping. """ icheck(0, ACont2D()) icheck(1, IncList(Float(), startfrom=0.0)) icheck(2, OneOf('left', 'right')) icheck(3, NoneOr(Point2D())) icheck(4, NoneOr(Point2D(noteq=pstart))) icheck(5, IncList(Float(within=[0, 360, '[]']))) bo = BoundaryGridOptions(cont, partition, direction, bnd_stepping='no', range_angles=range_angles, start_point=pstart, end_point=pend) return build_boundary_grid([bo])
def tab_cont2(obj, what): """ Returns plain table for the given contour. :param str obj: contour identifier :param str what: table name :returns: plain ctypes array representing requested table. Possible **what** values are: * ``'vert'`` - vertex coordinates table, * ``'edge_vert'`` - edge-vertex connectivity: indices of first and last vertices for each edge, * ``'bt'`` - boundary features of each edge. """ icheck(0, Cont2D()) icheck(1, OneOf('vert', 'edge_vert', 'bt')) return flow.receiver.get_contour2(obj).raw_data(what)
def save_project(fname, fmt="ascii"): """Saves current command flow and data to HybMesh project file. :param str fname: file name :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. See :ref:`hmp-file` for description. """ if fmt == "binary": fmt = "bin" elif fmt == "fbinary": fmt = "fbin" icheck(0, String()) icheck(1, OneOf('ascii', 'bin', 'fbin')) flow_export.flow_and_framework_tofile(fname, flow, fmt)
def extract_subcontours(source, plist, project_to="vertex"): """ Extracts singly connected subcontours from given contour. :param source: source contour identifier :param list-of-list-of-float plist: consecutive list of subcontours end points :param str project_to: defines projection rule for **plist** entries * ``"line"`` projects to closest point on the source contour * ``"vertex"`` projects to closest contour vertex * ``"corner"`` projects to closest contour corner vertex :returns: list of new contours identifiers Length of **plist** should be equal or greater than two. First and last points in **plist** define first and last points of **source** segment to extract. All internal points define internal division of this segment. Hence number of resulting subcontours will equal number of points in **plist** minus one. For closed **source** contour first and last **plist** points could coincide. In that case the sum of resulting subcontours will be equal to **source**. """ icheck(0, ACont2D()) icheck(1, List(Point2D(), minlen=2)) icheck(2, OneOf("line", "vertex", "corner")) c = com.contcom.ExtractSubcontours({ 'src': source, 'plist': plist, 'project_to': project_to }) flow.exec_command(c) return c.added_contours2()
def export_all_hmd(fname, fmt="ascii"): """Exports all geometrical data to native format. :param str fname: output filename :param str fmt: output data format: * ``'ascii'`` - all fields will be saved as text fields, * ``'bin'`` - all fields will be saved in binary section, * ``'fbin'`` - only floating point fields will be saved in binary section. See :ref:`nativeformat` for description. """ if fmt == "binary": fmt = "bin" elif fmt == "fbinary": fmt = "fbin" icheck(0, String()) icheck(1, OneOf('ascii', 'bin', 'fbin')) cb = flow.interface.ask_for_callback() native_export.export_all_tofile(fname, flow.receiver, fmt, cb)
def stripe(cont, partition, tip='no', bnd=0): """ Build a structured grid to the both sides of contour line :param cont: closed or open contour identifier :param ascending-list-of-double partition: partition perpendicular to source contour :param str tip: stripe endings meshing algorithm * ``"no"`` - no grid at endings * ``"radial"`` - radial grid at endings :param float-or-list-of-floats bnd: boundary types for input grid. List of four values provides respective values for bottom, left, right, top sides of resulting grid with respect to contour direction. :return: grid identifier Horizontal partition is taken from contour partition. Vertical partition is given by user with ``partition`` list parameter. If it starts with non zero value then grid will not contain contour nodes as its vertices. Use :func:`partition_segment` to define non-equidistant **partition** with any desired refinement if needed. """ icheck(0, ACont2D()) icheck(1, IncList(Float(grthan=0.0))) icheck(2, OneOf('no', 'radial')) icheck(3, ListOr1(ZType(), llen=4)) bnd = bnd[:4] if isinstance(bnd, list) else [bnd, bnd, bnd, bnd] arg = {"source": cont, "partition": partition, "tip": tip, "bnd": bnd} c = com.gridcom.StripeGrid(arg) flow.exec_command(c) return c.added_grids2()[0]
def triangulate_domain(domain, constr=[], pts=[], fill='3'): """Builds constrained triangulation within given domain :param domain: single or list of closed contours representing bounding domain :param constr: single or list of contours representing triangulation constraints :param pts: set of points in ``[len0, [x0, y0], ...]`` format where ``x, y`` are coordinates of internal vertices which should be embedded into the resulting grid, ``len`` - size of adjacent cells :param str fill: if '3' then triangulates area; '4' runs recombination algorithm to make mostly quadrangular mesh :return: grid identifier A contour tree will be built using all closed contours passed as **domain** parameter. Only the interior parts of this tree will be meshed. Contours passed by **domain** should not intersect each other, but could intersect **constr** contours. **constr** could contain any set of closed and open contours. See details in :ref:`unstructured-meshing`. """ icheck(0, UListOr1(ACont2D())) icheck(1, UListOr1(ACont2D())) icheck(2, CompoundList(Float(grthan=0.0), Point2D())) icheck(3, OneOf('3', '4')) if fill == '3': return _triquad(domain, constr, pts, '3') elif fill == '4': return _triquad(domain, constr, pts, '4')
def stdout_verbosity(verb): icheck(0, OneOf(0, 1, 2, 3)) flow.set_interface(flow.interface.reset(verb))
def partition_contour(cont, algo, step=1., angle0=30., keep_bnd=False, nedges=None, crosses=[], keep_pts=[], start=None, end=None): """ Makes connected contour partition :param cont: Contour or grid identifier :param str algo: Partition algorithm: * ``'const'``: partition with defined constant step * ``'ref_points'``: partition with step function given by a set of values refered to basic points * ``'ref_weights'``: partition with step function given by a set of values refered to local contour [0, 1] coordinate * ``'ref_lengths'``: partition with step function given by a set of values refered to local contour length coordinate :param step: For ``algo='const'`` a float number defining partition step; For ``algo='ref_points'`` - list of step values and point coordinates given as ``[ step_0, [x_0, y_0], step_1, [x_1, y_1], ....]``. For ``algo='ref_weights'`` - list of step values and point normalized 1d coordinates given as ``[ step_0, w_0, step_1, w_1, ....]``. For ``algo='ref_lengths'`` - list of step values and point 1d coordinates given as ``[ step_0, s_0, step_1, s_1, ....]``. Negative ``s_i`` shows length coordinate started from end point in reversed direction. :param float angle0: existing contour vertices which provide turns outside of ``[180 - angle0, 180 + angle0]`` degrees range will be preserved regardless of other options :param bool keep_bnd: if that is True than vertices which have different boundary features on their right and left sides will be preserved :param int nedges: if this parameter is not None then it provides exact number of edges in the resulting contour. To satisfy this condition **step** value will be multiplied by an appropriate factor. If it can not be satisfied (due to other restrictions) then an exception will be raised. :param crosses: represents set of contour which cross points with target contour will be present in resulting contour. :param keep_pts: list of points as ``[[x1, y1], [x2, y2], ...]`` list which should present in output partition. :param start: :param end: start and end points which define processing segment :returns: new contour identifier Points set defined by user for ``algo='ref_points'`` algorithm will not present in resulting contour (as well as points defined implicitly by other ``'ref_'`` algorithms). It just shows locations where step size of given length should be applied. If any point of this set is not located on the input contour then it will be projected to it. For constant stepping any contour including multiply connected ones could be passed. For ``ref_`` stepping only singly connected contours (open or closed) are allowed. If **start** and **end** points are defined then only segment between these points will be parted. Note that all closed contours are treated in counterclockwise direction. Given start/end points will be projected to closest contour vertices. ``ref_weights``, ``ref_lengths`` partition methods require definition of **start** point (To process whole contour ``end`` point could be omitted). Example: .. literalinclude:: ../../testing/py/fromdoc/ex_partcontour.py :start-after: vvvvvvvvvvvvvvvvvvvvvvvv :end-before: ^^^^^^^^^^^^^^^^^^^^^^^^ See also: :ref:`simplecontmeshing` """ if nedges <= 0: nedges = None icheck(0, ACont2D()) icheck(1, OneOf("const", "ref_points", "ref_weights", "ref_lengths")) if algo == "const": icheck(2, Float(grthan=0.0)) elif algo == "ref_points": icheck(2, CompoundList(Float(grthan=0.0), Point2D(), minlen=2)) elif algo == "ref_weights": icheck(2, CompoundList(Float(grthan=0.0), Float(within=[-1, 1, '[]']), minlen=2)) elif algo == "ref_lengths": icheck(2, CompoundList(Float(grthan=0.0), Float(), minlen=2)) icheck(3, Float()) icheck(4, Bool()) icheck(5, NoneOr(UInt(minv=1))) icheck(6, List(ACont2D())) icheck(7, List(Point2D())) icheck(8, NoneOr(Point2D())) icheck(9, NoneOr(Point2D())) if start is None and algo in ['ref_weights', 'ref_lengths']: raise InvalidArgument("Define start point for %s partition" % algo) # prepare arguments for command if algo == "const": plain_step = [step] elif algo == "ref_points": plain_step = [] for i in range(len(step) / 2): plain_step.append(step[2 * i]) plain_step.extend(step[2 * i + 1]) elif algo in ["ref_weights", "ref_lengths"]: plain_step = copy.deepcopy(step) sp, ep = None, None if start is not None: sp = [start[0], start[1]] if end is not None: ep = [end[0], end[1]] kp = [] if keep_pts is not None: for p in keep_pts: kp.append([p[0], p[1]]) args = {"algo": algo, "step": plain_step, "angle0": angle0, "keepbnd": keep_bnd, "base": cont, "nedges": nedges, "crosses": crosses, "start": sp, "end": ep, "keep_pts": kp} # call c = com.contcom.PartitionContour(args) flow.exec_command(c) return c.added_contours2()[0]
def add_custom_rect_grid(algo, left, bottom, right=None, top=None, hermite_tfi_w=[1.0, 1.0, 1.0, 1.0], return_invalid=False): """ Creates rectangular grid on the basis of four curvilinear contours using contour vertices for partition. See details in :ref:`custom_rect_grid`. :param str algo: Algorithms of building: * ``'linear'`` - connects respective points of opposite contours by straight lines. * ``'linear_tfi'`` - linear transfinite interpolation * ``'hermite_tfi'`` - hermite transfinite interpolation * ``'inverse_laplace'`` - * ``'direct_laplace'`` - connects points using solution of laplace equation with Dirichlet boundary conditions; * ``'orthogonal'`` - builds orthogonal grid based on **left** and **bottom** partition. Partitions of **right** and **top** are ignored. :param left: :param bottom: :param right: :param top: identifiers of curvilinear domain sides. **right** and **top** could be ``None``. If so right and top boundaries will be created by translation of **left** and **bottom**. :param list-of-floats hermite_tfi_w: perpendicularity weights for **left**, **bottom**, **right**, **top** contours respectively for **algo** = ``'hermite_tfi'`` :param bool return_invalid: if this flag is on then the procedure will return a grid even if it is not valid (has self-intersections). Such grids could be exported to simple formats (like vtk or tecplot) in order to detect bad regions and give user a hint of how to adopt input data to gain an acceptable result. .. warning:: Never use invalid grids for further operations. :return: new grid identifier """ icheck( 0, OneOf('linear', 'linear_tfi', 'hermite_tfi', 'inverse_laplace', 'direct_laplace', 'orthogonal')) icheck(1, Cont2D()) icheck(2, Cont2D()) icheck(3, NoneOr(Cont2D())) icheck(4, NoneOr(Cont2D())) icheck(5, List(Float(), llen=4)) icheck(6, Bool()) # call args = { 'algo': algo, 'left': left, 'right': right, 'bot': bottom, 'top': top, 'her_w': hermite_tfi_w, 'return_invalid': return_invalid } c = com.gridcom.AddCustomRectGrid(args) flow.exec_command(c) return c.added_grids2()[0]