[docs]@_geodocsdefspheres_and_cylinders(network,pore_diameter='pore.diameter',throat_diameter='throat.diameter',throat_centroid='throat.centroid',):r""" Computes the endpoints of throats when pores are spherical. The endpoints lie inside the sphere, defined by the lens formed between the intersection of the sphere and cylinder. Parameters ---------- %(network)s %(Dp)s %(Dt)s %(Tcen)s Returns ------- endpoints : ndarray An array containing the Nt-2-3 coordinates of the end points of each throat. """xyz=network.coordscn=network.connsL=network['throat.spacing']Dt=network[throat_diameter]D1=network[pore_diameter][cn[:,0]]D2=network[pore_diameter][cn[:,1]]L1=_np.zeros_like(L)L2=_np.zeros_like(L)# Handle the case where Dt > Dpmask=Dt>D1L1[mask]=0.5*D1[mask]L1[~mask]=_np.sqrt(D1[~mask]**2-Dt[~mask]**2)/2mask=Dt>D2L2[mask]=0.5*D2[mask]L2[~mask]=_np.sqrt(D2[~mask]**2-Dt[~mask]**2)/2# Handle non-colinear pores and throat centroidstry:TC=network[throat_centroid]LP1T=_np.linalg.norm(TC-xyz[cn[:,0]],axis=1)+1e-15LP2T=_np.linalg.norm(TC-xyz[cn[:,1]],axis=1)+1e-15unit_vec_P1T=(TC-xyz[cn[:,0]])/LP1T[:,None]unit_vec_P2T=(TC-xyz[cn[:,1]])/LP2T[:,None]exceptKeyError:unit_vec_P1T=(xyz[cn[:,1]]-xyz[cn[:,0]])/L[:,None]unit_vec_P2T=-1*unit_vec_P1T# Find throat endpointsEP1=xyz[cn[:,0]]+L1[:,None]*unit_vec_P1TEP2=xyz[cn[:,1]]+L2[:,None]*unit_vec_P2T# Handle throats w/ overlapping poresL1=(4*L**2+D1**2-D2**2)/(8*L)L2=(4*L**2+D2**2-D1**2)/(8*L)h=(2*_np.sqrt(D1**2/4-L1**2)).realoverlap=L-0.5*(D1+D2)<0mask=overlap&(Dt<h)EP1[mask]=(xyz[cn[:,0]]+L1[:,None]*unit_vec_P1T)[mask]EP2[mask]=(xyz[cn[:,1]]+L2[:,None]*unit_vec_P2T)[mask]return{'head':EP1,'tail':EP2}