[docs]defnetwork_to_stl(network,filename=None,maxsize='auto',fileformat='STL Format',logger_level=0):r""" Saves (transient/steady-state) data from the given objects into the specified file. Parameters ---------- network : Network. The network containing the desired data. phases : list[Phase] (place holder, default is None). List of phases containing the desired data. filename : str (optional). The name of the file containing the data to export. maxsize : a float or a string "auto" (optional). The maximum size of the mesh elements allowed. "auto" corresponds to an automatic determination based on pores and throats sizes. Any float value will be used as a maximum size. Small values result in finner meshes, but slower mesh calculations. fileformat : str (optional). Default is "STL Format" which corresponds to STL format. Other formats such as Gmsh and Fluent are supported (see ngsolve.org). logger_level : integer between 0 and 7 (optional). Default is 0. The logger level set in netgen package. Notes ----- The STL Format is a Standard Triangle (or Tessellation) Language supported by many CAD packages and used for 3D printing. Export to this format may be slow since a 3D closed surface mesh is built. Requires installation of "netgen". """try:importnetgen.csgascsgexceptModuleNotFoundError:raiseException('Module "netgen" not found.')try:fromnetgen.meshingimportSetMessageImportanceasloglog(logger_level)exceptModuleNotFoundError:logger.warning('Module "netgen.meshing" not found.'+' The "logger_level" will be ignored.')# Temporarily add endpoints to network so STL class worksnetwork["throat.endpoints.head"]=network.coords[network.conns[:,0]]network["throat.endpoints.tail"]=network.coords[network.conns[:,1]]filename=network.nameiffilenameisNoneelsefilenamepath=_parse_filename(filename=filename,ext='stl')# Path is a pathlib object, so slice it up as neededfname_stl=path.name# Correct connections where 'pore.diameter' = 'throat.diameter'dt=network['throat.diameter'].copy()dp=network['pore.diameter'][network['throat.conns']]dt[dp[:,0]==dt]*=0.99dt[dp[:,1]==dt]*=0.99scale=max(network['pore.diameter'].max(),dt.max(),network['throat.length'].max())ifmaxsize=='auto':maxsize=min(network['pore.diameter'].min(),dt.min(),network['throat.length'].min())geo=csg.CSGeometry()# Define poresgeometry=csg.Sphere(csg.Pnt(network['pore.coords'][0,0]/scale,network['pore.coords'][0,1]/scale,network['pore.coords'][0,2]/scale),network['pore.diameter'][0]/scale/2)forpinrange(1,network.Np):pore=csg.Sphere(csg.Pnt(network['pore.coords'][p,0]/scale,network['pore.coords'][p,1]/scale,network['pore.coords'][p,2]/scale),network['pore.diameter'][p]/scale/2)geometry+=pore# Define throatsfortinrange(network.Nt):A=network['throat.endpoints.tail'][t,:]/scaleB=network['throat.endpoints.head'][t,:]/scaleV=(B-A)/_np.linalg.norm(B-A)plane1=csg.Plane(csg.Pnt(A[0],A[1],A[2]),csg.Vec(-V[0],-V[1],-V[2]))plane2=csg.Plane(csg.Pnt(B[0],B[1],B[2]),csg.Vec(V[0],V[1],V[2]))cylinder=csg.Cylinder(csg.Pnt(A[0],A[1],A[2]),csg.Pnt(B[0],B[1],B[2]),dt[t]/scale/2)throat=cylinder*plane1*plane2geometry+=throat# Add pore and throats to geometry, build mesh, rescale, and exportgeo.Add(geometry)mesh=geo.GenerateMesh(maxh=maxsize/scale)mesh.Scale(scale)mesh.Export(filename=fname_stl,format=fileformat)# Remove endpoints label from networkdelnetwork["throat.endpoints"]