# Python with CivilFEM All functions enabled by CivilFEM interface can be implemented through Python code, using the script editor or the command line. All Python functions can be used in CivilFEM, including Python libraries. ## Basic Types In addition to the basic Python types, CivilFEM includes some classes to make the script easier to use. - **Point**: Coordinates of points and units. ```{code-block} myPoint = Point(0,5,2,"m") print(myPoint.x()) # As a python float print(myPoint.y()) # As a python float print(myPoint.z()) # As a python float print(myPoint.getUnit()) # As a python string print(myPoint.getFormula()) # As CivilFEM class Formula ``` A subtype for 2d models is available, Point2d: ```{code-block} myPoint2d = Point2d(0,5,"m") ``` - **Vector**: Coordinates of vectors. ```{code-block} myVector = Vector(1,0,0) print(myVector.x()) # As a python float print(myVector.y()) # As a python float print(myVector.z()) # As a python float print(myVector.getUnit()) # As a python string print(myVector.getFormula()) # As CivilFEM class Formula ``` A subtype for 2d models is available, Vector2d: ```{code-block} myVector2d = Vector2d(0,5,"m") ``` - **Double**: It's a class like a float customized to manage units. ```{code-block} myDouble = Double(15,"mm") print(myDouble.getValue()) # As a python float print(myDouble.getValueUnit("m")) # As a python float with unit conversion print(myDouble.getUnit()) # As a python string print(myDouble.getFormula()) # As CivilFEM class Formula ``` - **Formula**: Creates a CivilFEM formula to write a formula for a point, vector or double. ```{code-block} myFormula = Formula("(8*9/6,0,0)") myPoint = Point(myFormula) # Creates a point object using the formula print(myPoint.getFormula()) # Obtains the Formula object of a point ``` - **Containers (List, Array, Table)**: Special classes used to pass arguments and modify properties of CivilFEM objects. Python lists are converted to these types for convenience when needed. ```{code-block} civilFEMList = List() civilFEMList.push(1) civilFEMList.push(2) civilFEMList.push(3) civilFEMList.front() # 1 civilFEMList.back() # 3 civilFEMList.size() # 3 civilFEMList.empty() # False # index access civilFEMList[0] # 1 civilFEMList[1] # 2 civilFEMList[2] # 4 ``` The Array structure is almost equivalent to a List. The difference is that the Array is more efficient in indexed access (constant access) while the List has to go through all the elements until it reaches the index value. ```{code-block} myList = List() myArray = Array() # Filling of both objects .... myList[17000] # Slow myArray[17000] # Faster ``` The Table structure is mostly used to access/edit existing data: ```{code-block} myMaterial = Material("C25/30") # Obtains the material object mySSList = myMaterial.DSSD.SSDList # Obtains the list of design diagrams mySSTable = mySSList[0].SSData # Access the design diagram table mySSTable.setTableUnit("kPa") # Change the unit of cell values mySSTable.set(6, 0, 7690.653573) # Change the value in row 6 and column 0 numRows = mySSTable.getNumRows() numColumns = mySSTable.getNumCols() # Iterate over the table for row in range(0, numRows): for col in range(0, numColumns): cellValue = mySSTable.get(row, col) print(cellValue) # Add a new column columnPosition = 2 mySSTable.insertCol(columnPosition) # Add a new row rowPosition = 4 mySSTable.insertRow(rowPosition) ``` ```{warning} These basic types are considered reserved words. ``` ## Script Editor and Command Line CivilFEM has its own Script Editor to run Python code and create it without requiring external editors. It is located in the main screen of CivilFEM, in "View" section, inside the "Windows" menu. Furthermore, CivilFEM has a Command Line that allows running Python code and some special commands for the script. This command line is located on the same place as the script editor. ```{figure} img/Python_with_CivilFEM/DockableActivation.png --- align: center --- Location of the activation tabs of Command Line and Script Editor ``` The Script Editor has its own menu, where the script can be saved; an existing script can be opened, or the script can be run and stop. Script Editor has several shortcuts, which are listed below. - F5 = run script - ctr+A = select all - ctr+S = save script - ctr+O = open script - ctr+N = new script - ctr+C = copy - ctr+V = paste - ctr+X = cut - ctr+Z = undo - ctr+y = redo - ctr+q = comment the line - shift+F10 = options In addition to these shortcuts, the Script Editor also has autocomplete function. This is enabled by pressing ctr+space when you start writing in the script editor. ```{figure} img/Python_with_CivilFEM/AutocompleteEditor.png --- align: center --- Autocomplete function ``` As a complement to autocompletion of the script editor, there is .help() function, with which the output attributes of each class are shown. For example, to show boundary conditions attributes, execute BCGroupsContainer.Find("BC").BCs[0].help() in the script editor o in the command line. In the Output window will be printed the attributes like this: ```{figure} img/Python_with_CivilFEM/HelpAttributes.png --- align: center --- BC attributes ``` The most characteristic feature in the command line is capability of executing only selected lines of scripts. With the command run you can execute certain lines of code, only is need to type run and the number of the lines in quotes. Something important to keep in mind is that you should always write the starting line and the end one, so if for example, you want to run only line 5 would be type as follows: run "5" "5" ```{figure} img/Python_with_CivilFEM/Views.png --- align: center --- Command Line and Script Editor Windows ``` ## Macro Recording CivilFEM has the option to record the processes, in Python language, involved to create the model using the interface, this recording is done by macros. The macro is located in the main screen of CivilFEM, in the "View" section inside "Macros", there you can start, stop and view it. ```{figure} img/Python_with_CivilFEM/MacrosLocation.png --- align: center --- Macros location ``` Keep in mind that the macro recording is performed in the document units and configuration. When using the CivilFEM script, it is not necessary to know each of the entities and their attributes beforehand. It is advisable to focus on what needs to be done and record commands through the interface performing the task at hand. This provides a template with the information needed to build parts of a script that will do what you are looking for. Suppose we have 30 springs, and we want to change the activation time according to their type. It is a repetitive task that would take a long time to be done through the user interface - how do we do it in Python? What attributes do we have to use? How do we access the entities? The best procedure is to carry out the operation once through the interface, recording macro, and from that create the script. For example, after activating the recording, modifying the spring type and the activation time, we force to record the access to these attributes: ```{code-block} # -*- coding: utf-8 -*- ConfigUnits.System = "IS" modelUtil0 = ModelUtil("Damper12") modelUtil0.ActTime = Double(2) modelUtil0.SpringType = "ToGround" modelUtil0.SpringType = "TrueDirection" ``` With this recording we already know how to obtain the entity and how to access its attributes, we can create a script like the following: ```{code-block} for mu in ModelUtilsContainer: if (mu.getType() == "Spring"): if (mu.ActTime.getValue() > 80.0): mu.SpringType = "TrueDirection" else: mu.SpringType = "ToGround" ``` ## Script Manual: API All necessary information to make Python code in CivilFEM (enumerates, commands, containers and other options) are covered in the Script Manual. The Script Manual is divided in the same way that CivilFEM program, to ensure easier and faster to find commands. It contains all commands and arguments to create the model, as well as all enumerates for units, results and CivilFEM's libraries. With macro recording and API search, it should be enough to automate tasks in CivilFEM, without having prior knowledge of their use. Enumerates and arguments All enumerates and name arguments used in Python with CivilFEM are default, and must be written as detailed in the Script Manual, because otherwise the program will not recognize them. It should also be in mind that each command has the same model restrictions as the interface model, being unable, for example, to execute 2-dimensions commands in three-dimensional models, or transient commands in harmonic models. Parameters CivilFEM has its own parameters, which are also available through Python code. To create, modify and delete a parameter, proceed as follows: ```{code-block} createParam("Param","VECTOR2D","Global Cartesian","[9, 0]","m") modifyParam("Param", "Global Cartesian","[5, 1]", "mm") deleteParam("P") ``` To get the parameter value, build the corresponding basic type with a Formula: ```{code-block} createParam("MyDouble","DOUBLE","5","m") example1 = Double("MyDouble") createParam("MyV3d","VECTOR3D","Global Cartesian","(9,0,1)","m") example2 = Vector("MyV3d") createParam("MyP3d","POINT3D","Global Cartesian","(9,0,1)","m") example3 = Point("MyP3d") createParam("MyV2d","VECTOR2D","Global Cartesian","[9, 0]","m") example4 = Vector2d("MyV2d") createParam("MyP2d","POINT2D","Global Cartesian","[9, 0]","m") example5 = Point2d("MyP2d") createParam("MyInteger","INTEGER","5","Undef") example6 = Int("MyInteger") ``` Then you can get the value with: ```{code-block} example1.getValue() print(example1.getValue()) ``` ## Containers All entities' properties are accessible through their containers. There are the following: - CoordSystemsContainer - GeometryContainer - MaterialsContainer - SectionsContainer - StructuralElementsContainer - ModelUtilsContainer - ContactsContainer - LoadGroupsContainer - BCGroupsContainer - LoadCasesContainer - ParametersContainer - SelectionGroupsContainer - UserViewsContainer - ClippingContainer - UserLabelContainer You can obtain an entity of a container by its name with the following helper commands: - CoordSystem - Geometry - Material - Section - StructualElement - ModelUtil - Contact - LoadGroup - BCGroup - LoadCase - Parameter - SelectionGroup - UserView - ClippingPlane - UserLabel ```{code-block} #.Find("Name of the Structural Element") mySE = StructuralElementsContainer.Find("Structural element") # Another way to find an object mySE = StructuralElement("Name of the Structural Element") # Properties can be accessed as attributes of mySE, and modified with assignment mySE.MeshTool2D.ParameterMesh.SizeEdges = Double(0.12) ``` If you want to change one or more properties of multiple entities at the same time, you can iterate the container. For example, if we have created several points and lines, and we want to change the name of the points without changing lines, the code would be as follows: ```{code-block} i = 0 for geom in GeometryContainer: if geom.GeomType == "VertexByCoord": geom.GeomName= "RenamePoint" + str(i+1) i = i + 1 ``` Pay special attention to the possibility of creating an infinite loop. If you have in the iterator a CivilFEM command, you can stop the execution with the stop running script bottom. Comparisons in the containers can be made by "==". To change the name of several point with x coordinate 2, proceed as follows: ```{code-block} i = 0 for g in GeometryContainer: if (g.GeomType == "VertexByCoord") and (geom.Pnt.x() == 2): g.GeomName="renamePoint" + str(i+1) i = i + 1 ``` In comparisons of Point(), Double() and Vector(), must be set the units. Another type of filtering can be done using the "getType" method of the entities. For example, to filter the type of structural elements when traversing them with the container: ```{code-block} for se in StructualElementsContainer: if (se.getType() == 'Beam'): print(se.Name + " is beam") else: print(se.Name + " is not beam) ``` ## Model Groups It is also possible to iterate on entities of a model group container. That is, the user may add a new model group to any of the predefined model groups, iterating on their entities, if required. For instance, a new model group might be added to the Structural elements container: ```{code-block} createModelGroup(StructuralElementsContainer,"Steel bars") ``` ```{image} img/Python_with_CivilFEM/ModelGroups.png --- align: center --- ``` So, for example, if it becomes necessary to test if any of the entities of the "Steel bars" Structural element model group is shaped by vector (1, 0, 0) in Z direction: ```{code-block} a = StructuralElementsModelGroup("Steel bars") steelBarsContainerList = a.getEntities() for steelBar in steelBarsContainerList: xVectorCoor = steelBar.KClinear.ZVector.x() yVectorCoor = steelBar.KClinear.ZVector.y() zVectorCoor = steelBar.KClinear.ZVector.z() if (xVectorCoor==1) and (yVectorCoor==0) and (zVectorCoor==0): return True ``` Therefore, in the event that this condition is fulfilled, program will output the "True" statement. To sum up, this utility allows the user working only on the required entities, instead of the whole amount of them, by entering these ones in a new model group and applying a loop along with a condition. Selection Groups The CivilFEM selection can also be handled from Python. You can get the selected entities for use in commands or change the value of attributes. Access to them is done as follows: ```{code-block} # Assuming that we have created these structural elements se0 = StructuralElement("BEAM5") se1 = StructuralElement("BEAM1") se2 = StructuralElement("BEAM9") # Perform a selection and create a selection group selectByPick("Structural","NewSelection",[se0,se1,se2]) # Set the current selection createSelectionGroup("SE") # Create a selection group from the current selection mySelectionGroup = SelectionGroup("SE") # You can get the selection group by its name mySelectionGroup = SelectionGroupsContainer.CurrentSelectionGroup # Another way to get the selection group by the current selection group mySEList = mySelectionGroup.getSelection() for se in mySEList: print(se.Name) ``` You can change the current selection using: selectByPick, selectByLoc/X/Y/Z, selectByNum, selectByNodeGroup, selectByLC, selectByMat. To check the arguments and additional information about these commands look at the API documentation. Logs These methods can be used to write to the CivilFEM output. Note that the error log will stop the execution of the script. ```{code-block} Log("Test message") if (criterion < 1.0): LogError("Invalid") if (thickness > 5.0): LogWarning("Thickness too high") ``` ## External editors Support for autocompletion functionality and help can be obtained in external editors as follows: - There is a cfdoc.py file that can be imported into user Python code. - The file cfdoc.py can be found in "CivilFEMInstallDir/manual/script/python/cfdoc.py" - This file provides the documented CivilFEM classes and functions with help, but no functionality, just for the purpose of helping you write code. ## User code at startup If you want user code to be executed when you open the program, it can be installed in the "CivilFEMInstallDir/res/Scripts/" directory. Every single Python file will be executed by CivilFEM. ```{warning} These files can affect the opening of CivilFEM if they contain code with errors. ```