示例#1
0
    def test_vector_prod_unit(self):
        # Two vectors corresponding to edges of tetrahedron in the positive octant
        v1 = p.Point(2, 0, -2)
        v2 = p.Point(0, 2, -2)

        k = 4. * math.sqrt(3.)
        assert g.vector_product(v1,
                                v2).unit() == p.Point(4. / k, 4. / k, 4. / k)
示例#2
0
    def test_area_normal_towards_y(self):
        c = [
            p.Point(1, 3, 0),
            p.Point(-1, 3, 0),
            p.Point(-1, 0, 4),
            p.Point(1, 0, 4)
        ]

        assert g.calculate_polygon_area(c) == 10.
示例#3
0
    def test_vol_tetrahedron(self):
        p1 = p.Point(1, 0, 0)
        p2 = p.Point(0, 1, 0)
        p3 = p.Point(0, 0, 0)
        p4 = p.Point(0, 0, 1)

        volume = g.calc_tetrahedron_volume(p1, p2, p3, p4)

        assert volume == 1.0 / 6.0
示例#4
0
    def test_area_normal_towards_z(self):
        c = [
            p.Point(3, -1, 0),
            p.Point(3, 1, 0),
            p.Point(0, 1, 1),
            p.Point(0, -1, 1)
        ]

        assert g.calculate_polygon_area(c) == 2. * math.sqrt(10.)
示例#5
0
    def test_area_normal_towards_x(self):
        c = [
            p.Point(3, -1, 0),
            p.Point(3, 1, 0),
            p.Point(0, 1, 4),
            p.Point(0, -1, 4)
        ]

        assert g.calculate_polygon_area(c) == 10.
示例#6
0
    def test_area_sq_closed(self):
        c = [
            p.Point(-2, -2, 0),
            p.Point(-1, -2, 0),
            p.Point(-1, -1, 0),
            p.Point(-2, -1, 0)
        ]

        c.append(c[0])

        assert g.calculate_polygon_area(c) == 1.
示例#7
0
    def get_cuboid(self, a, b, c):

        # node indices are as per FEBio representation of 8-node element

        vertices = list()
        vertices.append(p.Point(a, 0, 0))
        vertices.append(p.Point(a, b, 0))
        vertices.append(p.Point(0, b, 0))
        vertices.append(p.Point(0, 0, 0))
        vertices.append(p.Point(a, 0, c))
        vertices.append(p.Point(a, b, c))
        vertices.append(p.Point(0, b, c))
        vertices.append(p.Point(0, 0, c))

        # rely on the id so set it
        p.Point.point_id = 1

        for pt in vertices:
            pt.allocate_id()

        # List of faces
        faces = ((1, 4, 3, 2), (5, 6, 7, 8), (1, 5, 8, 4), (2, 3, 7, 6),
                 (3, 4, 8, 7), (1, 2, 6, 5))

        return vertices, faces
示例#8
0
    def _add_epidermal_cell_wall(self):
        """ Add the epidermal cell wall

        :param mesh:
        :return
        """

        # add an offset to see the wall away from the dorsal wall
        testing_offset = 0.01

        # TODO add a wall_height parameter
        wall_height_factor = 1.5
        wall_height = wall_height_factor * self.stoma_cfg.mid_gc_height

        num_pts_z = self.mesh_cfg.num_pts_on_epidermis_vert

        semi_maj_ax = self.stoma_cfg.dorsal_ellipse.semi_x_axis + 0.01 + testing_offset
        semi_min_ax = self.stoma_cfg.dorsal_ellipse.semi_y_axis + 0.01 + testing_offset

        th_e = self.stoma_cfg.wall_thickness.epidermal

        ellipse_i = el.Ellipse(semi_maj_ax, semi_min_ax)
        ellipse_o = el.Ellipse(semi_maj_ax + th_e, semi_min_ax + th_e)

        nn = 2 * self.mesh_cfg.num_slices

        pts_i = el.calculate_pts_for_equi_arc_spaced_t(ellipse_i, nn)
        pts_o = el.calculate_pts_for_equi_arc_spaced_t(ellipse_o, nn)

        for c_idx, z in enumerate(np.linspace(0.0, wall_height, num_pts_z)):
            for slice_idx, pt_io in enumerate(zip(pts_i, pts_o)):
                for t_idx in (0, 1):
                    pt = p.Point(pt_io[t_idx].x, pt_io[t_idx].y, z)

                    self.mesh.epidermal_nodes_grid[t_idx, c_idx,
                                                   slice_idx] = pt
                    self.mesh.add_node(pt)

        self.mesh.add_special_node_id(
            'epidermis', self.mesh.epidermal_nodes_grid[0, 0, 0].id)

        # index order is thickness, circumference and then slice
        #
        indices = ((0, 0, 0), (1, 0, 0), (1, 0, 1), (0, 0, 1), (0, 1, 0),
                   (1, 1, 0), (1, 1, 1), (0, 1, 1))

        for circumf_idx in range(num_pts_z - 1):
            for slice_idx in range(nn - 1):
                nid_indices = [(ii[0], ii[1] + circumf_idx, ii[2] + slice_idx)
                               for ii in indices]

                nids = [
                    self.mesh.epidermal_nodes_grid[t, c, s].id
                    for t, c, s in nid_indices
                ]

                ele = elem.Hex8Element(nids)
                self.mesh.add_element(ele)

        return
示例#9
0
    def add_xz_reflection( self ):
        """ Perform a reflection in the x-z plane """

        exclude_point = lambda pt: pt.y == 0.0
        new_point = lambda pt: p.Point( pt.x, -pt.y, pt.z, allocate_id=True )

        self.add_plane_reflection( exclude_point, new_point, 'xz' )
示例#10
0
    def test_vol_tetrahedron_1(self):
        # Volume of a tetrahedron but using the general faces and vertices formula

        p1 = p.Point(1, 0, 0, 1)
        p2 = p.Point(0, 1, 0, 2)
        p3 = p.Point(0, 0, 0, 3)
        p4 = p.Point(0, 0, 1, 4)

        vertices = {1: p1, 2: p2, 3: p3, 4: p4}

        # Need a list of faces: vertices are labelled 1,2,3,4 so faces are 1-2-4, 2-3-4, 1-4-3 and 1-3-2
        # (all traversed anti-clockwise when looking from outside).
        #
        faces = ((1, 2, 4), (2, 3, 4), (1, 4, 3), (1, 3, 2))

        volume = g.calculate_volume(vertices, faces)

        assert volume == 1.0 / 6.0
示例#11
0
        def calc_fibre_vector( fv ):
            """ Calculate the fibre vector of the new element from the reference fibre vector """

            # don't bother with elements without fibres
            if fv is None:
                return None

            new_fv = p.Point( -fv.x if refl_plane == 'yz' else fv.x,
                              -fv.y if refl_plane == 'xz' else fv.y,
                              -fv.z if refl_plane == 'xy' else fv.z )

            # this negation orients the vector in the same sense
            if refl_plane == 'xy':
                new_fv = -new_fv

            return new_fv
示例#12
0
    def _add_periclinal_gc_points(self):
        """
        Add the periclinal points (outside -> inside) to the nodes grid

        :param mesh:
        :return:
        """
        def get_smoothed_z():
            """ Use the parametric angle for the pt to smooth the transition (using the sin function) from the tip to
                the middle - this results in a smooth outer surface around the mid-point """
            _t = self.stoma_cfg.mid_ellipse.calculate_ellipse_t_for_pt(mid_pt)
            _z = tip_para_z + (mid_para_z - tip_para_z) * np.sin(_t)

            return _z

        # z-coordinates at the tip and at the mid-point
        tip_para_z = 0.5 * self.stoma_cfg.tip_height
        mid_para_z = 0.5 * self.stoma_cfg.mid_gc_height

        # get the ventral and dorsal points from the grid
        ventral_wall_pts = self.mesh.nodes_grid[0, 0, :]
        dorsal_wall_pts = self.mesh.nodes_grid[0, -1, :]

        periclinal_idx = self.mesh_cfg.num_pts_on_qtr_circumference - 1

        for slice_idx, vd_pair in enumerate(
                zip(ventral_wall_pts, dorsal_wall_pts)):
            # periclinal point will lie on the mid ellipse but must also be coplanar with the slice
            mid_pt = el.calculate_ellipse_line_poi(self.stoma_cfg.mid_ellipse,
                                                   vd_pair[0], vd_pair[1])

            z = get_smoothed_z()

            # add the points through the periclinal wall
            z_values = np.linspace(
                z, z - self.stoma_cfg.wall_thickness.periclinal,
                self.mesh_cfg.num_pts_through_wall)

            for z_idx, z_coord in enumerate(z_values):
                periclinal_pt = p.Point(mid_pt.x, mid_pt.y, z_coord)

                self.mesh.add_node(periclinal_pt)
                self.mesh.nodes_grid[z_idx, periclinal_idx,
                                     slice_idx] = periclinal_pt

        return
示例#13
0
    def test_xyz(self):
        pt = p.Point(1, 2, 3)

        assert pt.xyz[0] == 1 and pt.xyz[1] == 2 and pt.xyz[2] == 3
示例#14
0
    def test_l2_norm(self):
        p1 = p.Point(1, 2, 3)

        assert p1.l2_norm() == math.sqrt(1 + 4 + 9)
示例#15
0
    def test_distance(self):
        p1 = p.Point(1, 2, 3)
        p2 = p.Point(2, 3, 4)

        assert p1.distance(p2) == math.sqrt(3.)
示例#16
0
    def test_div(self):
        p1 = p.Point(1, 2, 3)
        k = 2.

        assert p1 / k == p.Point(1 / k, 2 / k, 3 / k)
示例#17
0
    def test_unary_minus(self):
        p1 = p.Point(1, 2, 3)

        assert -p1 == p.Point(-1, -2, -3)
示例#18
0
    def test_pt_subtract_2(self):
        pt = p.Point(1, 2, 3)

        with pytest.raises(TypeError):
            1. - pt
示例#19
0
    def test_scalar_mult2(self):
        p1 = p.Point(1, 2, 3)
        k = 2.

        assert p1 * k == p.Point(k * p1.x, k * p1.y, k * p1.z)
示例#20
0
    def test_pt_add(self):
        p1 = p.Point(1, 2, 3)
        p2 = p.Point(2, 3, 4)

        assert p1 + p2 == p.Point(3, 5, 7)
示例#21
0
    def test_pt_subtract(self):
        p1 = p.Point(1, 2, 3)
        p2 = p.Point(2, 4, 6)

        assert p1 - p2 == p.Point(-1, -2, -3)
示例#22
0
 def from_xyz(x, y, z):
     """ helper function to construct a point """
     return gp.Point(x, y, z, allocate_id=True)
示例#23
0
    def test_pt_eq(self):
        p1 = p.Point(1, 2, 3)
        p2 = p.Point(1, 2, 3)

        assert p1 == p2
示例#24
0
    def _add_tip_wall_points(self):
        """
        The tip wall will be hexahedra with wedges at the centre

        :return:
        """
        def calculate_inner_radial_points():
            """ Calculate points on the inside of the tip wall """

            _pts = list()

            for _circumf_idx in range(
                    self.mesh_cfg.num_pts_on_semi_circumference):
                pt_inner_on_wall = tip_wall_nodes[0, _circumf_idx, -1]
                pt_centre = tip_wall_nodes[-1, _circumf_idx, -1]

                # Use a straight line between the point on the wall and the tip wall centre to
                # space out the points and then drop them onto the wall by setting the y-coordinate
                l_wall_to_centre = line.Line(pt_inner_on_wall, pt_centre)

                inner_pts = list()
                for _t in np.linspace(0.0, 1.0, num_radial_pts):
                    inner_pt = l_wall_to_centre.get_point(_t)
                    inner_pt.y = pt_centre.y
                    inner_pts.append(inner_pt)

                _pts += inner_pts

            return _pts

        def get_interpolator(_pts):
            """ Create bivariate spline interpolator """

            x = [pt.x for pt in _pts]
            y = [pt.y for pt in _pts]
            z = [pt.z for pt in _pts]

            _interp_f = interpolate.SmoothBivariateSpline(x, z, y, kx=4, ky=4)

            return _interp_f

        # tip_wall_nodes
        # t - radial: 0 (neighbouring the wall)  -->  -1 (the centre)
        # c - circumference: 0 (neighbouring the ventral wall)  -->  -1 (dorsal)
        # s - slice: 0 (shared wall/external)  -->  -1 (internal / pressure surface)
        #
        tip_wall_nodes = self.mesh.tip_nodes_grid

        num_radial_pts = tip_wall_nodes.shape[0]
        num_pts_through_tip_wall = tip_wall_nodes.shape[2]

        # copy the inner ventral points into the tip wall nodes grid
        tip_wall_nodes[0, :, :] = self.mesh.nodes_grid[
            -1, :, 0:num_pts_through_tip_wall]

        # set the centre points (through the wall thickness) - repeated in the array
        #
        mid_pts = [
            p.Point(self.mesh_cfg.stoma_cfg.mid_ellipse.semi_x_axis, y, 0)
            for y in np.linspace(0.0,
                                 self.mesh_cfg.stoma_cfg.wall_thickness.polar,
                                 num=num_pts_through_tip_wall)
        ]

        for slice_idx, pt in enumerate(mid_pts):
            tip_wall_nodes[-1, :, slice_idx] = pt

        # add radial points on inside of tip wall using an ellipse
        #
        tip_wall_surface_pts = calculate_inner_radial_points()

        # get an interpolator for the inside of the tip wall
        interp_f = get_interpolator(tip_wall_surface_pts)

        # add points for the tip wall
        #
        for circumf_idx in range(self.mesh_cfg.num_pts_on_semi_circumference):
            # firstly, add points on the outside of the tip wall (along a line)

            pt_inner = tip_wall_nodes[0, circumf_idx, 0]
            pt_centre = tip_wall_nodes[-1, circumf_idx, 0]

            l_ic = line.Line(pt_inner, pt_centre)

            t_values = np.linspace(0.0, 1.0, num_radial_pts)[1:-1]

            for en_t_idx, t_value in enumerate(t_values):
                radial_idx = en_t_idx + 1

                pt_tip_wall_outside = l_ic.get_point(t_value)
                # pt_tip_wall_outside = p.from_triad( pt_tip_wall_outside.xyz )

                tip_wall_nodes[radial_idx, circumf_idx,
                               0] = pt_tip_wall_outside

                # join the outside of the tip wall to the inside

                # calculate the internal tip wall point by interpolation...
                inside_pt_y = interp_f(pt_tip_wall_outside.x,
                                       pt_tip_wall_outside.z)

                pt_tip_wall_inside = p.Point(
                    pt_tip_wall_outside.x,
                    max(self.stoma_cfg.wall_thickness.polar, inside_pt_y[0]),
                    pt_tip_wall_outside.z)

                tip_wall_nodes[radial_idx, circumf_idx,
                               -1] = pt_tip_wall_inside

                # ...and join it to the outside
                l_io = line.Line(pt_tip_wall_outside, pt_tip_wall_inside)

                for en_s_idx, s_value in enumerate(
                        np.linspace(0.0, 1.0, num_pts_through_tip_wall)[1:-1]):
                    slice_idx = en_s_idx + 1

                    pt_in_tip_wall = l_io.get_point(s_value)
                    pt_in_tip_wall = p.from_triad(pt_in_tip_wall.xyz)

                    tip_wall_nodes[radial_idx, circumf_idx,
                                   slice_idx] = pt_in_tip_wall

        # Overwrite the last tip wall node (that neighbours the GC wall) in case the dorsal wall pt juts into the wall
        for circumf_idx in range(self.mesh_cfg.num_pts_on_semi_circumference):
            for slice_idx in range(1, num_pts_through_tip_wall):
                # move the point that neighbours the wall
                new_pt_1 = sum(tip_wall_nodes[idx, circumf_idx, slice_idx]
                               for idx in (0, 2)) / 2
                tip_wall_nodes[1, circumf_idx, slice_idx] = new_pt_1

                # move the next point too - not always a problem but it can when the stoma is closed
                new_pt_2 = sum(tip_wall_nodes[idx, circumf_idx, slice_idx]
                               for idx in (1, 3)) / 2
                tip_wall_nodes[2, circumf_idx, slice_idx] = new_pt_2

        # add the nodes to the mesh (this will set the node id)
        for nodes_array in (tip_wall_nodes[1:, :, :], ):
            for idx_pt_pair in np.ndenumerate(nodes_array):
                self.mesh.add_node(idx_pt_pair[1])

        return
示例#25
0
def make_quarter_disc_vtk_hex_mesh():
    """
    Makes a quarter-circle mesh
    """

    # Create the points

    from numpy import sin, pi, sqrt, linspace

    num_r = 10

    dr = 0.2
    dz = 0.2

    sqrt2 = sqrt(2.0)

    point_array = list()

    # central point
    point_array.append(gp.Point(0, 0, 0))

    for ri in range(num_r):
        num_pts = 2 * ri + 3

        sint = [sin(t) for t in linspace(0.0, pi / 2, num_pts)]
        cost = reversed(sint)

        for st, ct in zip(sint, cost):
            x = (ri + 1) * dr * (ct + min(1.0, sqrt2 * ct)) / 2
            y = (ri + 1) * dr * (st + min(1.0, sqrt2 * st)) / 2

            point_array.append(gp.Point(x, y, 0))

    num_pts = len(point_array)

    dp = (0, 0, dz)
    point_array = point_array + [
        gp.translate_pt_by_xyz(pt, dp) for pt in point_array
    ]

    for pt in point_array:
        pt.allocate_id()

    # Create elements

    elements = list()

    for ri in range(num_r):
        riri = ri * ri
        tworip1 = 2 * ri + 1
        range_1 = range(riri, riri + tworip1)
        range_2 = range(range_1[-1] + 1, range_1[-1] + tworip1 + 3)

        for idx, ele_num in enumerate(range_1):
            if 2 * idx + 1 == len(range_1):
                array_indices = [
                    ele_num,
                ] + range_2[idx:idx + 3]
            elif 2 * idx < len(range_1):
                array_indices = [
                    ele_num, range_2[idx], range_2[idx + 1], range_1[idx + 1]
                ]
            else:
                array_indices = [
                    ele_num - 1, range_2[idx + 1], range_2[idx + 2],
                    range_1[idx]
                ]

            array_indices += [ai + num_pts for ai in array_indices]

            elements.append(
                [point_array[arr_idx].id for arr_idx in array_indices])

    return VTKMeshChecker.create_from_points_and_elements(
        point_array, elements)
示例#26
0
    def test_max_coord_2(self):
        pt = p.Point(1, 3, 3)

        assert pt.max_coord() == (3, 2)  # 2 because 0-based
示例#27
0
def plot_equatorial_points( cfg ):

    nnn = cfg.mesh_config.num_slices

    ellipse_d = el.Ellipse( cfg.a_d, cfg.b_d )
    ellipse_v = el.Ellipse( cfg.a_v, cfg.b_v )

    # Calculate the points on the ventral and dorsal walls
    xy_v = el.calculate_pts_for_equi_arc_spaced_t( ellipse_v, nnn )
    xy_d = el.calculate_pts_for_equi_arc_spaced_t( ellipse_d, nnn )

    # get the 'real' PM points s.t. the wall thickness is conserved
    xy_v_pm_2 = el.calculate_polyline_offset_from_ellipse( ellipse_v,  cfg.wall_thickness.ventral )
    xy_d_pm_2 = el.calculate_polyline_offset_from_ellipse( ellipse_d, -cfg.wall_thickness.dorsal  )

    # calculate equal-polar angle spaced points
    xy_th1 = el.calculate_pts_for_equi_spaced_t( ellipse_d, nnn )
    xy_th2 = el.calculate_pts_for_equi_spaced_t( ellipse_v, nnn )

    plt, ax = el.plot_initialise( )

    # plot the lines between the equi-arc spaced points
    for pts in zip( xy_d, xy_v ):
        plt.plot( (pts[0].x, pts[1].x), (pts[0].y, pts[1].y), 'r' )

    # plot the lines between the equi-polar angle spaced points
    for pts in zip( xy_th1, xy_th2 ):
        plt.plot( (pts[0].x, pts[1].x), (pts[0].y, pts[1].y), 'g' )

    for pts, pt_spec in zip( ( xy_v, xy_d, xy_v_pm_2, xy_d_pm_2 ),
                             ( '.r', '.r', '.r',      '.r' ) ):
        el.plot_add_pts( plt, pts, pt_spec )

    for a, b in zip( ( cfg.a_mid, cfg.a_d, cfg.a_v ),
                     ( cfg.b_mid, cfg.b_d, cfg.b_v ) ):
        ellipse = el.Ellipse( a, b )
        some_pts = el.calculate_pts_for_equi_spaced_t( ellipse, 100 )
        el.plot_add_pts( plt, some_pts, '-k' )

    for pt_pair in zip( xy_v, xy_d ):
        l = line.Line( pt_pair[0], pt_pair[1] )

        # find ventral PM points from v-d line intersection with offset points
        poi_v = g.find_point_of_intersection( l, xy_v_pm_2 )

        if poi_v is not None:
            plt.plot( poi_v.x, poi_v.y, 'ob' )

        # find dorsal PM points from v-d line intersection with offset points
        poi_d = g.find_point_of_intersection( l, xy_d_pm_2 )

        if poi_d is not None:
            plt.plot( poi_d.x, poi_d.y, 'ob' )

        if poi_d is not None and poi_v is not None:
            mid_pt = 0.5 * ( poi_d + poi_v )
            plt.plot( mid_pt.x, mid_pt.y, 'ob' )

    # draw a line based on the most troublesome point
    mtp = pt.Point( cfg.a_v + cfg.wall_thickness.ventral, cfg.wall_thickness.polar, 0.0 )
    mtp_n = mtp.unit()

    plt.plot( mtp.x, mtp.y, 'ok')
    plt.plot( (0.0, cfg.a_d * mtp_n.x), (0.0, cfg.a_d * mtp_n.y), 'k')

    plt.show()

    return
示例#28
0
def build_test_mesh( ):
    """ Build a tests mesh """

    mesh = Mesh( )

    # create the nodes
    pts = list( )
    pts.append( p.Point( 0, 0, 0 ) )
    pts.append( p.Point( 2, 0, 0 ) )
    pts.append( p.Point( 2, 3, 0 ) )
    pts.append( p.Point( 0, 3, 0 ) )
    pts.append( p.Point( 0, 0, 1 ) )
    pts.append( p.Point( 2, 0, 1 ) )
    pts.append( p.Point( 2, 3, 1 ) )
    pts.append( p.Point( 0, 3, 1 ) )

    pts.append( p.Point( 3, 0, 0 ) )
    pts.append( p.Point( 3, 3, 0 ) )
    pts.append( p.Point( 3, 0, 1 ) )
    pts.append( p.Point( 3, 3, 1 ) )

    p.Point.point_id = 1
    for pt in pts:
        pt.allocate_id( )

    mesh.add_nodes( pts )

    mesh.add_element( elem.Hex8Element( pts[ 0:8 ] ) )
    mesh.add_element( elem.Hex8Element( [ pts[ nid - 1 ] for nid in (2, 9, 10, 3, 6, 11, 12, 7) ] ) )

    # add the BCs
    #
    for axis in ('x', 'y', 'z'):
        for bc_node in (1, 2, 3, 4, 9, 10):
            mesh.add_bc_node( axis, bc_node )

    # Add the pressure facets
    #
    gc_id = 1
    mesh.add_pressure_facet( gc_id, (5, 6, 7, 8) )
    mesh.add_pressure_facet( gc_id, (6, 11, 12, 7) )

    # # Add the wall
    # #
    # mesh.add_polar_wall_facet( (1, 4,  3, 2) )
    # mesh.add_polar_wall_facet( (2, 3, 10, 9) )

    return mesh
示例#29
0
    def test_max_coord_3(self):
        pt = p.Point(-1, -4, 3)

        assert pt.max_coord() == (-4, 1)  # 2 because 0-based
示例#30
0
    def _add_intermediate_gc_points(self):
        """
        Calculate the points on a GC cross-section so that they are coplanar:
        1) First we calculate the ventral and dorsal points from the equi-arc spaced angles).
        2) Next we calculate the points on the (ventral and dorsal) PM ellipse and the central
           ellipse by finding the intersection point of the line joining the ventral and dorsal
           points and the relevant ellipse

        By coplanar we mean in the same plane as that defined by line joining the dorsal and
        ventral points with normal orthogonal to the line and in the x-y plane.
        """
        def get_ventral_periclinal_points():
            """ Calculate the ventral to periclinal points """

            if thickness_idx == -1 and self.stoma_cfg.wall_thickness.is_thicken_vp_on:
                # thicken cell wall between ventral and periclinal walls

                vp_ellipse = el.SuperEllipse3D(pt_v, pt_p, pt_mid,
                                               r=1.5)  # r=2 => ellipse

                _pts = vp_ellipse.calculate_equi_t_spaced_pts(
                    self.mesh_cfg.num_pts_on_qtr_circumference)

                # TODO: Try this alternative parameterisation of the inner ventral-periclinal curve to get thickening...
                #   (x/a)**2 + (1 + exp(-c * x**2))/2 * (y/b)**2 = 1
                # where 'c' dictates the distance from the ellipse: c=0 => ellipse, c=1 => max deflection.
                #
                # gnuplot:
                # >> a=2; b=1; ai=1.5; bi=0.5
                # >> p [0:2][0:2] for [ al = 0:10 ] bi * sqrt( (1+exp(-0.1*al*x**2))/2 * (1.0 - (x/ai)**2) ) t "".al, \
                #     b * sqrt( 1.0 - (x/a)**2  )
                #
                # The curve is similar to the SuperEllipse but lies closer to the outer ellipse at its ends
                #
                # Note: the super ellipse is: (x/a)**r + (y/b)**r = 1
            else:
                vp_ellipse = el.Ellipse3D(pt_v, pt_p, pt_mid)

                _pts = vp_ellipse.calculate_equi_arc_spaced_pts(
                    self.mesh_cfg.num_pts_on_qtr_circumference)

            return _pts

        def get_periclinal_dorsal_points():
            """ Calculate the periclinal to dorsal points """
            pd_ellipse = el.Ellipse3D(pt_p, pt_d, pt_mid)
            _pts = pd_ellipse.calculate_equi_arc_spaced_pts(
                self.mesh_cfg.num_pts_on_qtr_circumference)
            return _pts

        # circumferential index of the periclinal points
        periclinal_idx = self.mesh_cfg.num_pts_on_qtr_circumference - 1

        for slice_idx in range(self.mesh_cfg.num_slices):
            slice_pts = np.ndarray(
                shape=(self.mesh_cfg.num_pts_through_wall,
                       self.mesh_cfg.num_pts_on_semi_circumference),
                dtype=p.Point)

            for thickness_idx in (0, -1):
                # 0 - the outside, -1 - the inside

                # get ventral, periclinal and dorsal points
                pt_v = self.mesh.nodes_grid[thickness_idx, 0, slice_idx]
                pt_p = self.mesh.nodes_grid[thickness_idx, periclinal_idx,
                                            slice_idx]
                pt_d = self.mesh.nodes_grid[thickness_idx, -1, slice_idx]

                pt_mid = p.Point(pt_p.x, pt_p.y, 0.0)

                vp_pts = get_ventral_periclinal_points()
                pd_pts = get_periclinal_dorsal_points()

                # join the circumferential points
                #
                slice_pts[thickness_idx, :] = vp_pts[:-1] + pd_pts[:]

            # join the points through the wall thickness
            #
            for circumf_idx in range(
                    self.mesh_cfg.num_pts_on_semi_circumference):
                pt_o = slice_pts[0, circumf_idx]
                pt_i = slice_pts[-1, circumf_idx]

                line_oi = line.Line(pt_o, pt_i)

                slice_pts[:, circumf_idx] = [
                    line_oi.get_point(t_param) for t_param in np.linspace(
                        0.0, 1.0, num=self.mesh_cfg.num_pts_through_wall)
                ]

            # add the points to the mesh
            #
            for thickness_idx in range(self.mesh_cfg.num_pts_through_wall):
                self._add_points_along_circumference(
                    thickness_idx, slice_idx, slice_pts[thickness_idx, :])

        return