Source code for Classes.Wired_Structures

# -*- coding: utf-8 -*-
from __future__ import print_function
try:
    import numpy as np
    import copy
    import sys
    from math import *
    from inPy.Classes.Assembly import Instance
    from inPy.inPy_Constants import PyVersion

except:
    print("Unable to import some modules\nfunctions and classes might not work properly")


[docs]class Strand: # Local imports from inPy.Classes.Path import path def __init__(self,InitShapeFunction,PathGenerationFunction,Line,Shargs = None,Shkwargs = None,Pthargs = None,Pthkwargs = None,**kwargs): """ The init shape function will be used to determine the starting points of the bundle (For example, in the case of a perfectly circular packing arrangemet) you can use the inPy circlespacking() function. This function should return a matrix with shape (Nx2) with N the number of filaments The PathGenerationFunction will be used to determine how to grow fibers from these seeds, and example function could be the inPy.Path.init3Dsinus() method. This function will be called on the matrix returned by the shape function Shapeargs should be a tuple of arguments to give to the shape generation funcion Pathargs the same but for the path generation. X0 gives the x coordinate of the plan that will be normal to the fibers the fiber axis is for now assumed to be along x """ self.ShapeFunction = InitShapeFunction self.PathGenerationFunction = PathGenerationFunction self.KwargsDict = kwargs self.pathTable = [] self.Shargs = Shargs self.Shkwargs = Shkwargs self.Pthargs = Pthargs self.Pthkwargs = Pthkwargs
[docs] def GeneratePaths(self): self.SeedMatrix = self.ShapeFunction(*self.Shargs,**self.Shkwargs) self.pathTable = [copy.deepcopy(self.PathGenerationFunction("Sinus",*self.Pthargs,**{"OffY": Seed[0], "OffZ": Seed[1]})) for Seed in self.SeedMatrix]
[docs] def Draw(self): import random from mayavi import mlab for path in self.pathTable: mlab.plot3d(path.Lx, path.Ly, path.Lz,line_width=self.Shargs[0],tube_sides=50,color=(random.random(),random.random(),random.random())) mlab.show()
[docs] def GenerateInpString(self,Config = ["Truss","Beam"],FileName=None): from inPy.Classes.FEM import BeamMesh self.BeamList = [] FileString = '' ID = 1 for Path in self.pathTable: NodeList = Path.MakeNodeList(ID0 = 100*ID)[0] self.BeamList.append(BeamMesh("Beam{}".format(ID),'B31',self.Shargs[0],"Beam","Out",NodeList=NodeList)) FileString = FileString + self.BeamList[-1].InpPart() ID = ID + 1 print("Beam0: {} Beam1: {}".format(self.BeamList[0].NodeList[0].Z,self.BeamList[100].NodeList[0].Z)) if FileName != None: File = open(FileName,"w") File.write(FileString) File.close() return FileString
[docs]class Braid(Instance): """ Class used to represent a braid, mandatory parameters are Pitch, Nby (number of strands, must always be even), Dbyin (internal radius) BraidThickness (Thickness of the braid), PlaitSegments (discretization of each beam) and R (number of radiuses in each strand). Valid optional paramters are: ``Config`` ---> Array used to configure the embeded beams configuration [2x1], Config[0] gives the external elements type, Config[1] give the internal element Type For example ``Config = ["Truss",None]`` will configure inPy to only use Truss elements, ``Config = ["Truss","Beam"]`` is the default embeded beam situation with external truss and internal beams, default to ["Beam",None] ``SparsingCoeff`` this parameter will be changed in future version, right now, it controlls the circlespacking call and defines the gap between each filaments center the smallest distance between each filament is defined as d = (1 + Filament_Diameter)*SparsingCoeff, default to 0 ``Imposed_FilR`` allows the user to specify a filament radius, default to None and in this case, the filament radius is defined as BraidThickness/2*R ``**kwargs`` --> used to defined the Instance master-class attributes if needed """ from inPy.Functions.Geometry import circlespacking def __init__(self,Pitch,Nby,Dbyin,BraidThickness,PlaitSegments,R,Config = ["Beam",None],SparsingCoeff=0,Imposed_FilR=None,**kwargs): # Local imports from inPy.inPy_Constants import PI from inPy.Classes.Path import path # Initialise the Instance attributes super().__init__(**kwargs) self.Pitch = Pitch # controls the angle of the braid self.R = R #number of radiuses in each strand self.BundleR = BraidThickness/2 # Radius of each strand if Imposed_FilR == None: # If the filament radius is not imposed, the program # can't know the inside radius and therefore takes # BundleR/R as default self.FilRIn = self.BundleR/self.R self.FilROut = self.BundleR/self.R else: # Filament radius (embeded beams radius) self.FilRIn = Imposed_FilR # external filament radius self.FilROut = self.BundleR/self.R if Nby %2 != 0: raise ValueError('Error: braid defined with un-even Nby') else: self.Nby = Nby # number of strands, should always be even self.Dbyin = Dbyin # internal radius of the braid self.BraidThickness = BraidThickness self.Dbyout = Dbyin+BraidThickness*2 # external radius of the Braid # Init the path tables self.CCWpath = [] self.CWpath = [] # ini the inp String self.inpString = "" self.PlaitSegments = PlaitSegments self.Config = Config self.SparsingCoeff = SparsingCoeff for k in range(int(Nby/2)): # Fill the path tables with path objects theta = 2*PI*(k-1)/(self.Nby/2) self.CCWpath.append(path()) # The Init3DHelix function of path objects # was developped for this purpose # Counter clockwise paths self.CCWpath[-1].Init3DHelix(theta,"CCW",self.Pitch,self.Nby,self.Dbyin,self.Dbyout,self.PlaitSegments) # Clockwise paths self.CWpath.append(path()) self.CWpath[-1].Init3DHelix(theta,"CW",self.Pitch,self.Nby,self.Dbyin,self.Dbyout,self.PlaitSegments)
[docs] def Draw(self,SectionFunction=circlespacking,Secargs = None,standalone=True,fig = None): """ Draws the braid for preview purposes, depends on the plot backend chosen by the end-user Valid parameters: ``SectionFunction`` --> python function that will be call on ``**Sceargs`` The section function should remains as default for now since the braid object is not yet compatible with other section shapes. ``Secargs`` --> tuple of arguments for the section function, if None, this will be set to (self.R,self.BundleR,self.SparsingCoeff) ``standalone`` ---> parameter that should always appear in draw functions for inPy.Instance subclasses, if True (default) the plot will be shown directly, if False, a figure object is returned ``fig`` ---> this is used if you want to add the braid to a previously existing figure object """ # Local imports import random import inPy.Backend.BackendPlot as PlotBundle # if the user did not specify Secargs, set to # (self.R,self.BundleR,self.SparsingCoeff) if Secargs == None: Secargs = (self.R,self.BundleR,self.SparsingCoeff) # R = 0 should not be Used # but just in case if self.R == 0: Rprime = 1 else: Rprime = self.R # if Rprime == 1 # this means only one filament in the strands if Rprime == 1: for path in self.CCWpath: fig = PlotBundle.Plot_Path(path.Lx, path.Ly, path.Lz,fig,tube_radius=self.FilR) for path in self.CWpath: fig = PlotBundle.Plot_Path(path.Lx, path.Ly, path.Lz,fig,tube_radius=self.FilR) else: # multiple filaments Coords = SectionFunction(*Secargs) for path in self.CCWpath: for Position in Coords: fig = PlotBundle.Plot_Path(np.array(path.Lx)+Position[0], np.array(path.Ly)+Position[1], path.Lz,fig,tube_radius=self.FilR) for path in self.CWpath: for Position in Coords: fig = PlotBundle.Plot_Path(np.array(path.Lx)+Position[0], np.array(path.Ly)+Position[1], path.Lz,fig,tube_radius=self.FilR) if standalone: PlotBundle.show() else: return fig
[docs] def Generate_PartINP_String(self,R=0,AddDummy = True): from inPy.Classes.FEM import BeamMesh, EmbededBeam from inPy.Functions.FEM import CreateDummyString NodeListCCW = [] NodeListCW = [] self.BeamList = [] if R == 0: Rprime = 1 else: Rprime = R for k in range(int(self.Nby/2)): #Node Generation CCW if self.R == 0: MakeNodeListRes = self.CCWpath[k].MakeNodeList(ID0=self.CurrentNode) NodeListCCW.append(MakeNodeListRes[0]) self.CurrentNode = MakeNodeListRes[1] #Mesh Generation CCW string = "BeamCCW"+str(k) if self.Config[0] == "Truss": self.BeamList.append(BeamMesh(string,"T3D2",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCCW[k],Elem0 = 10000*k+1)) if self.Config[0] == "Beam": self.BeamList.append(BeamMesh(string,"B31",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCCW[k],Elem0 = 10000*k+1)) else: MakeNodeListRes = self.CCWpath[k].MakeNodeList(ID0=self.CurrentNode,R=self.R,YarnR=self.BundleR,SparsingCoeff=self.SparsingCoeff) for i in range(len(MakeNodeListRes[0])): NodeListCCW.append(MakeNodeListRes[0][i]) self.CurrentNode = MakeNodeListRes[1] #Mesh Generation CCW string = "BeamCCW"+str(k)+"_"+str(i) if self.Config[0] == "Truss": self.BeamList.append(BeamMesh(string,"T3D2",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCCW[i+(k*len(MakeNodeListRes[0]))],Elem0 = 10000*k+1)) if self.Config[0] == "Beam": self.BeamList.append(BeamMesh(string,"B31",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCCW[i+(k*len(MakeNodeListRes[0]))],Elem0 = 10000*k+1)) print("------------------------------------------------------------------\n------------------------CCW Beams Generated------------------------") for k in range(int(self.Nby/2)): #Node Generation CW if self.R == 0: MakeNodeListRes = self.CWpath[k].MakeNodeList(ID0=self.CurrentNode) NodeListCW.append(MakeNodeListRes[0]) self.CurrentNode = MakeNodeListRes[1] #Mesh Generation CW string = "BeamCW"+str(k) if self.Config[0] == "Truss": self.BeamList.append(BeamMesh(string,"T3D2",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCW[k],Elem0 = 10000*k+1)) if self.Config[0] == "Beam": self.BeamList.append(BeamMesh(string,"B31",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCW[k],Elem0 = 10000*k+1)) else: MakeNodeListRes = self.CWpath[k].MakeNodeList(ID0=self.CurrentNode,R=self.R,YarnR=self.BundleR,SparsingCoeff=self.SparsingCoeff) for i in range(len(MakeNodeListRes[0])): NodeListCW.append(MakeNodeListRes[0][i]) self.CurrentNode = MakeNodeListRes[1] #Mesh Generation string = "BeamCW"+str(k)+"_"+str(i) if self.Config[0] == "Truss": self.BeamList.append(BeamMesh(string,"T3D2",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCW[i+(k*len(MakeNodeListRes[0]))],Elem0 = 10000*k+1)) if self.Config[0] == "Beam": self.BeamList.append(BeamMesh(string,"B31",self.FilROut,self.Config[0],"OUT",NodeList=NodeListCW[i+(k*len(MakeNodeListRes[0]))],Elem0 = 10000*k+1)) if AddDummy == True: self.inpString += CreateDummyString() for i in self.BeamList: Validation = EmbededBeam(i,self.FilROut,self.FilRIn) self.inpString += Validation.Generate(Config = self.Config) self.CurrentNode += 1 print("------------------------------------------------------------------\n------------------------CW Beams Generated------------------------") return self.inpString
[docs] def Generate_AssemblyINP_String(self,R=0,AddDummy = True): from inPy.inPy_Constants import PyVersion #Assembly self.inpString = "" if AddDummy == True: self.inpString += "**\n*Instance, name = DummyInstance, part = dummy\n*End Instance\n" self.inpString += "*Node\n {}, 0., 0., 0.\n".format(self.CurrentNode) self.inpString += "*Nset, nset=DummySet, internal\n{},\n".format(self.CurrentNode) self.inpString += "*Nset, nset=DummySet\n{},\n".format(self.CurrentNode) self.CurrentNode += 1 for i in self.BeamList: if self.Config[1] != None: self.inpString += "**\n" self.inpString += "*Instance, name="+i.Namestr+"IN,part="+i.Namestr+"IN\n" self.inpString += "*End Instance\n" self.inpString += "**\n" self.inpString += "*Instance, name="+i.Namestr+"OUT,part="+i.Namestr+"OUT\n" self.inpString += "*End Instance\n" return self.inpString
[docs] def Generate_CouplingINP_String(self,R=0,AddDummy = True): #Set creation for Embeded beams self.inpString = "" if self.Config[1] != None: self.inpString += "**\n" temp=0 for beam in self.BeamList: for node in beam.NodeList: self.inpString += "*Nset, nset=m_"+beam.Namestr+"_"+str(int(node.ID))+", instance="+beam.Namestr+"IN\n " self.inpString += str(int(node.ID+(len(beam.NodeList))))+",\n" self.inpString += "*Nset, nset=s_"+beam.Namestr+"_"+str(int(node.ID))+", instance="+beam.Namestr+"OUT\n " self.inpString += str(int(node.ID))+",\n" self.inpString += "*Surface, type=NODE, name ="+beam.Namestr+"_"+str(int(node.ID))+"_CNS, internal\ns_"+beam.Namestr+"_"+str(int(node.ID))+", 1\n" temp+=1 if PyVersion >= 3: print("\rSet creation for embeded beams: "+str(int(temp/(len(self.BeamList)*len(beam.NodeList))*1000)/10)+"%",end="\r") else: print("\rSet creation for embeded beams: "+str(int(temp/(len(self.BeamList)*len(beam.NodeList))*1000)/10)+"%") #Set creation for PBCs self.inpString += "**\n" temp=0 for beam in self.BeamList: ############################# # By convention, I always take the first node as the master # and the last as the Slave ############################# # Master node, Inside beam if self.Config[1] != None: self.inpString += "*Nset, nset=m_"+beam.Namestr+"_IN_PBC, instance="+beam.Namestr+"IN\n " self.inpString += str(int(beam.MinNodeID+(len(beam.NodeList))))+",\n" # Slave node, Inside beam self.inpString += "*Nset, nset=s_"+beam.Namestr+"_IN_PBC, instance="+beam.Namestr+"IN\n " self.inpString += str(int(beam.MaxNodeID+(len(beam.NodeList))))+",\n" # Surface creation self.inpString += "*Surface, type=NODE, name ="+beam.Namestr+"_IN_CNS, internal\ns_"+beam.Namestr+"_IN_PBC, 1\n" self.inpString += "**\n" # Master node, Inside beam self.inpString += "*Nset, nset=m_"+beam.Namestr+"_OUT_PBC, instance="+beam.Namestr+"OUT\n " self.inpString += str(int(beam.MinNodeID))+",\n" # Slave node, Inside beam self.inpString += "*Nset, nset=s_"+beam.Namestr+"_OUT_PBC, instance="+beam.Namestr+"OUT\n " self.inpString += str(int(beam.MaxNodeID))+",\n" # Surface creation self.inpString += "*Surface, type=NODE, name ="+beam.Namestr+"_OUT_CNS, internal\ns_"+beam.Namestr+"_OUT_PBC, 1\n" temp+=1 print("\rSet creation for PBCs: "+str(int(temp/(len(self.BeamList))*1000)/10)+"%",end="\r") print("------------------------------------------------------------------\n---------------------------Sets created---------------------------") #Coupling if self.Config[1] != None: count = 1 temp=0 for beam in self.BeamList: for node in beam.NodeList: self.inpString += "** Constraint"+str(count)+"\n" self.inpString += "*Coupling, constraint name=Constraint-"+str(count)+", ref node=m_"+beam.Namestr+"_"+str(int(node.ID))+", surface="+beam.Namestr+"_"+str(int(node.ID))+"_CNS\n" self.inpString += "*Kinematic\n" count+=1 temp+=1 if PyVersion >= 3: print("\rCoupling creation for embeded beams: "+str(int(temp/(len(self.BeamList)*len(beam.NodeList))*1000)/10)+"%",end="\r") else: print("\rCoupling creation for embeded beams: "+str(int(temp/(len(self.BeamList)*len(beam.NodeList))*1000)/10)+"%") count = 1 temp = 0 for beam in self.BeamList: for DL in range(6): # Outside Beams if DL == 2: self.inpString += "** Constraint: PBC_OUT_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" #Inside Beams if self.Config[1] != None: self.inpString += "** Constraint: PBC_IN_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" elif DL == 1: self.inpString += "** Constraint: PBC_OUT_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" #Inside Beams if self.Config[1] != None: self.inpString += "** Constraint: PBC_IN_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" else: self.inpString += "** Constraint: PBC_OUT_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_OUT_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" #Inside Beams if self.Config[1] != None: self.inpString += "** Constraint: PBC_IN_"+beam.Namestr+"_"+str(DL+1)+"\n" self.inpString += "*Equation\n3\nM_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",-1.\nS_"+beam.Namestr+"_IN_PBC,"+str(DL+1)+",1.\nDUMMYSET,"+str(DL+1)+",1\n" count+=1 temp+=1 if PyVersion >= 3: print("\rCoupling creation for PBCs: "+str(int(temp/(len(self.BeamList))*1000)/10)+"%",end="\r") else: print("\rCoupling creation for PBCs: "+str(int(temp/(len(self.BeamList))*1000)/10)+"%") self.inpString += "*Element, type=MASS, elset=DUMMYSET\n1, 1\n*Mass, elset=DUMMYSET\n1e-05,\n" self.inpString += "*End Assembly\n" #Materials self.inpString +="**\n" self.inpString +="** MATERIALS\n" self.inpString +="**\n" self.inpString +="*Material, name=FiberMat\n" self.inpString +="*Density\n" self.inpString +=" 3.21,\n" self.inpString +="*Elastic\n" self.inpString +="420000., 0.3\n" self.inpString +="** \n" #Set definitions for beam in self.BeamList: # First End, to apply BCs self.inpString +="*Nset, nset=BCSet, instance="+str(beam.Namestr)+beam.Position+"\n" self.inpString +=str(int(beam.NodeList[0].ID))+"\n" # Second End, to apply Forces self.inpString +="*Nset, nset=ForceSet, instance="+str(beam.Namestr)+beam.Position+"\n" self.inpString +=str(int(beam.NodeList[-1].ID))+"\n" return self.inpString
[docs] def Create_BCINP_String(self,Value,FrictionCoef,Type="Force"): self.inpString = "" self.inpString += "*Amplitude, name=Amp-1, definition=SMOOTH STEP\n 0., 0., 1., 1.\n**\n" self.inpString += "** INTERACTION PROPERTIES\n**\n*Surface Interaction, name=IntProp-1\n*Friction\n "+str(FrictionCoef)+",\n** ----------------------------------------------------------------\n**\n" self.inpString += "*Step, name=Step-1, nlgeom=YES\n*Dynamic, Explicit\n, 1.\n*Bulk Viscosity\n0.06, 1.2\n**\n" self.inpString += "** BOUNDARY CONDITIONS\n**\n** Name: BC-1 Type: Displacement/Rotation\n*Boundary, amplitude=Amp-1\n" self.inpString += "DUMMYSET, 1, 1\n" self.inpString += "DUMMYSET, 2, 2\n" self.inpString += "DUMMYSET, 4, 4\n" self.inpString += "DUMMYSET, 5, 5\n" self.inpString += "DUMMYSET, 6, 6\n**\n" if Type == "Displacement": self.inpString += "**\n** Name: BC-Imposed Type: Displacement/Rotation\n*Boundary, amplitude=Amp-1\n" self.inpString += "DUMMYSET, 3, 3, "+str(Value)+"\n**\n" elif Type == "Force": self.inpString += "** LOADS\n" self.inpString += "**\n" self.inpString += "** Name: Load-1 Type: Concentrated force\n" self.inpString += "*Cload, amplitude=AMP-1\n" self.inpString += "DUMMYSET, 3, "+str(Value)+"\n**\n" self.inpString += "** INTERACTIONS\n**\n** Interaction: general_contact\n*Contact, op=NEW\n*Contact Inclusions, ALL EXTERIOR\n" self.inpString += "*Contact Property Assignment\n , , INTPROP-1\n** \n" return self.inpString