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
def dorsal_ellipse( self ): """ Ellipse that approximates the dorsal wall """ if self.__dorsal_ellipse is None: a_d = self.stoma_length / 2 b_d = self.stoma_width / 2 self.__dorsal_ellipse = el.Ellipse( a_d, b_d ) return self.__dorsal_ellipse
def test_calculate_ellipse_xy_for_t(self): a, b = 3.0, 2.0 ellipse = el.Ellipse(a, b) for t in (0.0, pi / 4, pi / 2): x, y = ellipse.calculate_ellipse_xy_for_t(t) assert abs((x / a)**2 + (y / b)**2 - 1.0) < TOLERANCE
def test_identity(self): a, b = 2, 1 ellipse = el.Ellipse(a, b) c = Point(0, 0, 0) ellipse3D = el.Ellipse3D(Point(a, 0, 0), Point(0, b, 0), c) assert ellipse.semi_x_axis == ellipse3D.axis_pt_1.x - c.x and \ ellipse.semi_y_axis == ellipse3D.axis_pt_2.y - c.y
def ventral_ellipse( self ): """ Ellipse that approximates the ventral wall """ if self.__ventral_ellipse is None: a_v = self.pore_length / 2 b_v = self.pore_width / 2 self.__ventral_ellipse = el.Ellipse( a_v, b_v ) return self.__ventral_ellipse
def mid_ellipse( self ): """ Ellipse that bisects the dorsal and ventral walls """ if self.__mid_ellipse is None: a_mid = ( self.pore_length + self.tip_length ) / 2 b_mid = ( self.pore_width + self.mid_gc_width ) / 2 self.__mid_ellipse = el.Ellipse( a_mid, b_mid ) return self.__mid_ellipse
def test_calculate_ellipse_y(self): a, b = 3.0, 2.0 ellipse = el.Ellipse(a, b) x = a / 2 y = ellipse.calculate_ellipse_y(x) assert abs((x / a)**2 + (y / b)**2 - 1.0) < TOLERANCE
def test_calculate_ellipse_x(self): a, b = 3.0, 2.0 ellipse = el.Ellipse(a, b) y = b / 2 x = ellipse.calculate_ellipse_x(y) assert abs((x / a)**2 + (y / b)**2 - 1.0) < TOLERANCE
def test_quadrant1_ellipse(self): a, b = 2, 1 ellipse = el.Ellipse(a, b) c = Point(1, 2, 3) ellipse3D = el.Ellipse3D(Point(a, 0, 0) + c, Point(0, b, 0) + c, c) assert ellipse.semi_x_axis == ellipse3D.axis_pt_1.x - c.x and \ ellipse.semi_y_axis == ellipse3D.axis_pt_2.y - c.y
def test_calculate_equi_arc_spaced_t(self): a, b = 2.0, 1.0 ellipse = el.Ellipse(a, b) num = 100 thetas = el.calculate_equi_arc_spaced_t(ellipse, num) # calculate the arc for each parametric angle cumulative_arcs = np.array( [el.calculate_ellipse_arc(ellipse, theta) for theta in thetas]) # calculate the length of each arc arcs = cumulative_arcs[1:] - cumulative_arcs[:-1] # the arcs should all be the same size for idx in range(num - 2): assert abs(arcs[idx] - arcs[idx + 1]) < TOLERANCE
def test_find_phi_for_arc_length(self): # Test on a circle (the function is used by calculate_equi_arc_spaced_t so it's tested already) # This is just for completeness (and also makes sure circles work too!) # circle radius a = 2.0 ellipse = el.Ellipse(a, a) # arc length at phi = 0, pi/4 and pi/2 arc_lengths = [0.0, pi * a / 4, pi * a / 2] # get the elliptic angles, phi, that are measured from the y-axis phis = [ el.EllipticIntegralHelper.find_phi_for_arc_length(ellipse, l) for l in arc_lengths ] for i, arc_length in enumerate(arc_lengths): assert arc_length == phis[i] * a
def test_calculate_m_for_ellipe(self): a, b = 3.0, 2.0 ellipse = el.Ellipse(a, b) assert ellipse.m == 1.0 - (b / a)**2
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