Source code for msepy.manifold.predefined.cylinder_channel
# -*- coding: utf-8 -*-# noinspection PyUnresolvedReferences,PyRedeclarationr""".. testsetup:: * import __init__ as ph from msepy.manifold.predefined.cylinder_channel import _make_an_illustration _make_an_illustration( './source/gallery/msepy_domains_and_meshes/msepy/cylinder_channel_2d.png' ) None_or_custom_path = './source/gallery/msepy_domains_and_meshes/msepy/cylinder_channel_example.png'.. testcleanup:: passThe cylinder channel is a mesh (or domain) in :math:`\mathbb{R}^n`, :math:`n\in\left\lbrace2,3\right\rbrace`.The 2d domain is illustrated in the following figure... figure:: cylinder_channel_2d.png :width: 100% The illustration of the 2d cylinder channel domain... autofunction:: msepy.manifold.predefined.cylinder_channel.cylinder_channelBoundary units==============The cylinder channel domain is divided into 7 regions. The topology of these regions is illusrated in thefollowing figure... figure:: cylinder_channel_2d_topology.png :width: 100% The illustration of the topology of regions in a 2d cylinder channel domain.Thus, the complete set of boundary units in 2 dimensions is>>> boundary_units_set = {... 0: [1, 0, 1, 0],... 1: [0, 0, 1, 1],... 2: [0, 1, 1, 0],... 3: [1, 1, 0, 0],... 4: [1, 1, 0, 0],... 5: [1, 0, 0, 1],... 6: [0, 0, 1, 1],... 7: [0, 1, 0, 1],... }And, for example, if we call the left side the inlet, we can pick up boundary units for the inlet by>>> boundary_units_inlet = {... 0: [1, 0, 0, 0],... 3: [1, 0, 0, 0],... 5: [1, 0, 0, 0]... }The cylinder surface is>>> boundary_units_inlet = {... 1: [0, 0, 0, 1],... 3: [0, 1, 0, 0],... 4: [1, 0, 0, 0],... 6: [0, 0, 1, 0]... }Examples========2d--We can generate a mesh in this domain by doing>>> ph.config.set_embedding_space_dim(2)>>> manifold = ph.manifold(2)>>> mesh = ph.mesh(manifold)>>> msepy, obj = ph.fem.apply('msepy', locals())>>> manifold = obj['manifold']>>> mesh = obj['mesh']>>> msepy.config(manifold)('cylinder_channel')>>> msepy.config(mesh)(3) # refining factor, a positive integer.>>> mesh.visualize(saveto=None_or_custom_path) # doctest: +ELLIPSIS<Figure size ..... figure:: cylinder_channel_example.png :width: 100% The cylinder_channel mesh of element factor 3.Note that we configure the mesh with a factor ``3``. Increasing this factor to refine the mesh."""importsysif'./'notinsys.path:sys.path.append('./')importnumpyasnpfrommsepy.manifold.predefined._helpersimport_LinearTransformation,_Transfinite2importmatplotlib.pyplotaspltdef_make_an_illustration(saveto,r=1,dl=10,dr=25,h=6):"""Make a picture illustrating the domain."""fig,ax=plt.subplots(figsize=(8,6))ax.set_aspect('equal')ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_visible(False)plt.tick_params(axis='both',which='both',left=False,bottom=False,labelbottom=False,labelleft=False)x=[-dl,dr,dr,-dl,-dl]y=[-h/2,-h/2,h/2,h/2,-h/2]angle=np.linspace(0,2*np.pi,100)rx=r*np.cos(angle)ry=r*np.sin(angle)plt.plot(x,y,'-k',linewidth=0.8)plt.plot(rx,ry,'-k',linewidth=0.8)_r=1.1*drplt.plot([0,_r],[0,0],'-',linewidth=0.8,color='lightgray')_=0.05*hplt.plot([_r-_,_r,_r-_],[_,0,-_],'-',linewidth=0.8,color='lightgray')plt.text(_r,0,r"$x$",c='gray',va='bottom',ha='left')_y=1.4*h/2plt.plot([0,0],[0,_y],'-',linewidth=0.8,color='lightgray')plt.plot([-_,0,_],[_y-_,_y,_y-_],'-',linewidth=0.8,color='lightgray')plt.text(0,_y,r"$y$",c='gray',va='bottom',ha='left')plt.text(0,0,r"$r$",c='k',va='bottom',ha='left')plt.plot([0,r],[0,0],c='k',linewidth=0.8)plt.plot([0,0],[0,-h/2],c='lightgray',linewidth=0.8)plt.text(-dl,0,r"$h$",va='center',ha='left')plt.text(-dl/2,-h/2,r"$d_l$",va='bottom',ha='center')plt.text(dr/2,-h/2,r"$d_r$",va='bottom',ha='center')plt.savefig(saveto,bbox_inches='tight',dpi=200)plt.close()fig,ax=plt.subplots(figsize=(8,6))ax.set_aspect('equal')ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_visible(False)plt.tick_params(axis='both',which='both',left=False,bottom=False,labelbottom=False,labelleft=False)plt.plot(x,y,'-k',linewidth=0.8)plt.plot([0,_r],[0,0],'-',linewidth=0.8,color='lightgray')_=0.05*hplt.plot([_r-_,_r,_r-_],[_,0,-_],'-',linewidth=0.8,color='lightgray')plt.text(_r,0,r"$x$",c='gray',va='bottom',ha='left')_y=1.4*h/2plt.plot([0,0],[0,_y],'-',linewidth=0.8,color='lightgray')plt.plot([-_,0,_],[_y-_,_y,_y-_],'-',linewidth=0.8,color='lightgray')plt.text(0,_y,r"$y$",c='gray',va='bottom',ha='left')plt.plot([-r,r,r,-r,-r],[-r,-r,r,r,-r],'-k',linewidth=0.8)plt.plot([-r,-dl],[-r,-r],'-',linewidth=0.5,color='gray')plt.plot([r,dr],[-r,-r],'-',linewidth=0.5,color='gray')plt.plot([-r,-dl],[r,r],'-',linewidth=0.5,color='gray')plt.plot([r,dr],[r,r],'-',linewidth=0.5,color='gray')plt.plot([-r,-r],[-r,-h/2],'-',linewidth=0.5,color='gray')plt.plot([-r,-r],[r,h/2],'-',linewidth=0.5,color='gray')plt.plot([r,r],[-r,-h/2],'-',linewidth=0.5,color='gray')plt.plot([r,r],[r,h/2],'-',linewidth=0.5,color='gray')plt.text(-(dl+r)/2,-(h/2+r)/2,r"$r_0$",c='k',va='center',ha='center')plt.text(0,-(h/2+r)/2,r"$r_1$",c='k',va='center',ha='center')plt.text((dr+r)/2,-(h/2+r)/2,r"$r_2$",c='k',va='center',ha='center')plt.text(-(dl+r)/2,0,r"$r_3$",c='k',va='center',ha='center')plt.text((dr+r)/2,0,r"$r_4$",c='k',va='center',ha='center')plt.text(-(dl+r)/2,(h/2+r)/2,r"$r_5$",c='k',va='center',ha='center')plt.text(0,(h/2+r)/2,r"$r_6$",c='k',va='center',ha='center')plt.text((dr+r)/2,(h/2+r)/2,r"$r_7$",c='k',va='center',ha='center')saveto=saveto.split('.png')[0]+rf"_topology.png"plt.savefig(saveto,bbox_inches='tight',dpi=200)plt.close()
[docs]defcylinder_channel(r=1,dl=8,dr=25,h=6,w=0,periodic=True):r""" Parameters ---------- r : float, default=1 The radius of the cylinder. dl : float, default=8 The :math:`x` distance from the left boundary to the cylinder center. dr : float, default=25 The :math:`x` distance from the right boundary to the cylinder center. h : float, default=6 The height (along :math:`y`-direction, :math:`[-h/2, h/2]`) of the channel; must have :math:`h/2 > r`. w : float, default=0 The width (along :math:`z`-direction, :math:`[-w/2, w/2]`) of the channel. periodic : bool, default=True When the domain is 3d, whether it is periodic along the :math:`z`-axis? It has no affect when ``w=0`` (the domain is 2d). """raiseException(r,dl,dr,h,w,periodic)
# noinspection PyPep8Namingclass_CylinderChannel(object):r""" ^ y | ______________|______________________________________ | | | |hu _|_ | | / |r\ | |----------| .--|----------------------------------|----------> x | \___/ | |hl | | |______dl_____|__________________dr_________________| hl + hu = h Regions are distributed as: ^ y | __________________________________________ | 5 | 6 | 7 | |_______|__________|_____________________| | 3 / \ 4 | --->x |_______\__________/_____________________| | 0 | 1 | 2 | |_______|__________|_____________________| """def__init__(self,mf,r=1,dl=8,dr=25,h=6,w=0,periodic=True,hl=None):""" Parameters ---------- mf r dl dr h w periodic : bool Only make sense in 3d. hl : ``hl + hu = h`` if ``hl`` is None, ``hl = 0.5 * h``. Returns ------- """self._mf=mfself._r=rself._dl=dlself._dr=drself._h=hself._w=wifhlisNone:hl=0.5*helse:passself._hl=hlhu=h-hlself._periodic=periodicassertmf.esd==mf.ndim,f"_cylinder_channel mesh only works for manifold.ndim == embedding space dimensions."assertmf.esdin(2,3),f"_cylinder_channel mesh only works in 2-, 3-dimensions."esd=mf.esdself._esd=esdifw==0:assertesd==2,f"w==0, space must be 2d"else:assertw>0andesd==3,f"w>0, space must be 3d"ifesd==2:region_map={0:[None,1,None,3],1:[0,2,None,None],2:[1,None,None,4],3:[None,None,0,5],4:[None,None,2,7],5:[None,6,3,None],6:[5,7,None,None],7:[6,None,4,None],}elifesd==3:ifperiodic:region_map={0:[None,1,None,3,0,0],1:[0,2,None,None,1,1],2:[1,None,None,4,2,2],3:[None,None,0,5,3,3],4:[None,None,2,7,4,4],5:[None,6,3,None,5,5],6:[5,7,None,None,6,6],7:[6,None,4,None,7,7],}else:region_map={0:[None,1,None,3,None,None],1:[0,2,None,None,None,None],2:[1,None,None,4,None,None],3:[None,None,0,5,None,None],4:[None,None,2,7,None,None],5:[None,6,3,None,None,None],6:[5,7,None,None,None,None],7:[6,None,4,None,None,None],}else:raiseException()hr=float(0.5*r*np.sqrt(2))ifesd==2:tf1=_Transfinite2(['straight line',[(-hr,-hl),(-hr,-hr)]],['straight line',[(hr,-hl),(hr,-hr)]],['straight line',[(-hr,-hl),(hr,-hl)]],['anticlockwise arc',[(0,0),(-hr,-hr),(hr,-hr)]],)tf3=_Transfinite2(['straight line',[(-dl,-hr),(-dl,hr)]],['clockwise arc',[(0,0),(-hr,-hr),(-hr,hr)]],['straight line',[(-dl,-hr),(-hr,-hr)]],['straight line',[(-dl,hr),(-hr,hr)]],)tf4=_Transfinite2(['anticlockwise arc',[(0,0),(hr,-hr),(hr,hr)]],['straight line',[(dr,-hr),(dr,hr)]],['straight line',[(hr,-hr),(dr,-hr)]],['straight line',[(hr,hr),(dr,hr)]],)tf6=_Transfinite2(['straight line',[(-hr,hr),(-hr,hu)]],['straight line',[(hr,hr),(hr,hu)]],['clockwise arc',[(0,0),(-hr,hr),(hr,hr)]],['straight line',[(-hr,hu),(hr,hu)]],)rm0=_LinearTransformation(-dl,-hr,-hl,-hr)rm1=tf1rm2=_LinearTransformation(hr,dr,-hl,-hr)rm3=tf3rm4=tf4rm5=_LinearTransformation(-dl,-hr,hr,hu)rm6=tf6rm7=_LinearTransformation(hr,dr,hr,hu)elifesd==3:raiseNotImplementedError()else:raiseException()mapping_dict={0:rm0.mapping,1:rm1.mapping,2:rm2.mapping,3:rm3.mapping,4:rm4.mapping,5:rm5.mapping,6:rm6.mapping,7:rm7.mapping,}Jacobian_matrix_dict={0:rm0.Jacobian_matrix,1:rm1.Jacobian_matrix,2:rm2.Jacobian_matrix,3:rm3.Jacobian_matrix,4:rm4.Jacobian_matrix,5:rm5.Jacobian_matrix,6:rm6.Jacobian_matrix,7:rm7.Jacobian_matrix,}ifesd==2:mtype_dict={0:rm0.mtype,1:rm1.mtype,# unique region2:rm2.mtype,3:rm3.mtype,# unique region4:rm4.mtype,# unique region5:rm5.mtype,6:rm6.mtype,# unique region7:rm7.mtype,}elifesd==3:raiseNotImplementedError()else:raiseException()default_element_layout=self._cylinder_channel_default_element_layoutself._para=(region_map,mapping_dict,Jacobian_matrix_dict,mtype_dict,default_element_layout)def__call__(self,*args,**kwargs):returnself._paradef_cylinder_channel_default_element_layout(self,characteristic_element_number):"""default_element_layout_maker must return a dict indicating the element layouts in all regions. When we config the mesh, if only one number argument is provided, this method will be called to make a default element layout with the only argument being the `characteristic_element_number`. For this mesh, ``characteristic_element_number`` indicating the element number of 1/4 of the cylinder. Thus, around the cylinder, there will be 4 * ``characteristic_element_number`` elements in total. """assertcharacteristic_element_number>0andcharacteristic_element_number%1==0, \
f"characteristic_element_number = {characteristic_element_number} is wrong, must be positive integer."arc_length=2*np.pi*self._r*0.25hr=0.5*self._r*np.sqrt(2)c_elements=characteristic_element_number# x-direction of #0, 3, 5left_elements=int(((self._dl-hr)/arc_length)*characteristic_element_number)+1# x-direction of #2, 4, 7right_elements=int(((self._dr-hr)/arc_length)*characteristic_element_number)+1# y-direction of #0, 1, 2, 5, 6, 7height_elements=int(((self._h/2-hr)/arc_length)*characteristic_element_number)+1ifself._esd==2:passelse:raiseNotImplementedError(f"compute z-direction elements.")element_layout=dict()ifself._esd==2:element_layout[0]=[left_elements,height_elements]element_layout[1]=[c_elements,height_elements]element_layout[2]=[right_elements,height_elements]element_layout[3]=[left_elements,c_elements]element_layout[4]=[right_elements,c_elements]element_layout[5]=[left_elements,height_elements]element_layout[6]=[c_elements,height_elements]element_layout[7]=[right_elements,height_elements]else:raiseNotImplementedError()returnelement_layoutif__name__=='__main__':# python msepy/manifold/predefined/cylinder_channel.py# _make_an_illustration('cylinder_channel.png')pass