Skip to content

Commit

Permalink
add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
u-anurag committed May 12, 2022
1 parent dc47371 commit a22b032
Show file tree
Hide file tree
Showing 149 changed files with 24,825 additions and 0 deletions.
29 changes: 29 additions & 0 deletions vfo_docs/.readthedocs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"
# You can also specify other tool versions:
# nodejs: "16"
# rust: "1.55"
# golang: "1.17"

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:
# - pdf

# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt
154 changes: 154 additions & 0 deletions vfo_docs/Examples/vfo_for_tcl.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
##############################################################################################
## This script records the Nodes, Elements and the mode shape data in order to plot ##
## the model, mode shapes,the displaced structure using vfo (visualization for opensees ## ##
## library. The capability to visualize and animate element force, stress, strain is not ##
## available to OpenSees Tcl users yet. It will be added soon. ##
## ##
## Created By - Anurag Upadhyay, University of Utah, 06-28-2020. ##
## ##
## Submit bugs on the development GitHub page: https://github.com/u-anurag/OpenSeesPy ##
##############################################################################################

## How to use this file: Source this script into the main OpenSees file and then use the
# functions as described below in the examples. The function "createODB" takes three
# inputs and all of them are needed.

# modelName - Name of the opensees output folder will be named as "modelName_ODB".
# loadCaseName - "none" or "loadCaseName". Name of the sub-folder to store load case specific output.
# numModes - 0 or numModes (integer). Number of modeshapes to be recorded. Use 0 when recording output from a loadcase.

## Example 1 - To record 3 mode shapes : createODB "TwoSpan_Bridge" "none" 3
## Example 2 - To record output from Pushover : createODB "TwoSpan_Bridge" "Pushover" 0

proc createODB {modelName loadCaseName numModes} {
#########################################################
### DO NOT CHANGE anything beyond this line #
#########################################################

set odb "_ODB"
set ODB_Dir $modelName$odb
set LoadCaseDir $ODB_Dir/$loadCaseName

file mkdir $ODB_Dir

set NodeFile "$ODB_Dir/Nodes.out"
set fieldNodes [open $NodeFile w+]

set ele2nodeFile "$ODB_Dir/Elements_2Node.out"
set ele3nodeFile "$ODB_Dir/Elements_3Node.out"
set ele4nodeFile "$ODB_Dir/Elements_4Node.out"
set ele8nodeFile "$ODB_Dir/Elements_8Node.out"

set field_ele2node [open $ele2nodeFile w+]
set field_ele3node [open $ele3nodeFile w+]
set field_ele4node [open $ele4nodeFile w+]
set field_ele8node [open $ele8nodeFile w+]

set listNodes [getNodeTags] ; # Get all the node tags in the current domain
set listElements [getEleTags] ; # get all the element tags in the current domain

foreach nodeTag $listNodes {
set tempNode [nodeCoord $nodeTag]
puts $fieldNodes "$nodeTag $tempNode"
unset tempNode
}

foreach eleTag $listElements {
set tempEle [eleNodes $eleTag]
if {[llength $tempEle] == 2} {
puts $field_ele2node "$eleTag $tempEle"
}
if {[llength $tempEle] == 3} {
puts $field_ele3node "$eleTag $tempEle"
}
if {[llength $tempEle] == 4} {
puts $field_ele4node "$eleTag $tempEle"
}
if {[llength $tempEle] == 8} {
puts $field_ele8node "$eleTag $tempEle"
}

unset tempEle
}

close $fieldNodes
close $field_ele2node
close $field_ele3node
close $field_ele4node
close $field_ele8node

#####################################
## Record load case specific data ##
#####################################

if {$loadCaseName == "none"} {
puts "No load case folder name provided."
} else {

file mkdir $LoadCaseDir

set N [llength $listNodes]
set Nele [llength $listElements]
set NodeOne [nodeCoord [lindex $listNodes 0]]
if {[llength $NodeOne] == 2} {
puts "Recording output for 2D Model"
recorder Node -file $LoadCaseDir/NodeDisp_All.out -time -nodeRange [lindex $listNodes 0] [lindex $listNodes [expr $N-1]] -dof 1 2 disp; #
recorder Node -file $LoadCaseDir/Reaction_All.out -time -nodeRange [lindex $listNodes 0] [lindex $listNodes [expr $N-1]] -dof 1 2 reaction; #
# recorder Element -file $LoadCaseDir/EleForce_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 localForce; #
# recorder Element -file $LoadCaseDir/EleStress_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 stresses; #
# recorder Element -file $LoadCaseDir/EleStrain_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 strains; #
} else {
puts "Recording output for 3D model"
recorder Node -file $LoadCaseDir/NodeDisp_All.out -time -nodeRange [lindex $listNodes 0] [lindex $listNodes [expr $N-1]] -dof 1 2 3 disp; #
recorder Node -file $LoadCaseDir/Reaction_All.out -time -nodeRange [lindex $listNodes 0] [lindex $listNodes [expr $N-1]] -dof 1 2 3 reaction; #
# recorder Element -file $LoadCaseDir/EleForce_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 3 localForce; #
# recorder Element -file $LoadCaseDir/EleStress_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 3 stresses; #
# recorder Element -file $LoadCaseDir/EleStrain_All.out -time -eleRange [lindex $listElements 0] [lindex $listElements [expr $Nele-1]] -dof 1 2 3 strains; #
}
#
}

if {$numModes > 0} {

set DirName "ModeShapes"
set modeShapeDir $ODB_Dir/$DirName
file mkdir $modeShapeDir
set periodFile "$modeShapeDir/ModalPeriods.out"
set fieldperiodFile [open $periodFile w+]

set wa [eigen -genBandArpack $numModes];

for {set mode 1} {$mode <=$numModes} {incr mode} {
set wwa [lindex $wa [expr $mode-1]]
set Ta [expr 2*3.1415926535/sqrt($wwa)];
puts $fieldperiodFile "$Ta"
}
close $fieldperiodFile

proc getModeShapeData {modeNumber modeShapeDir} {

set nodeList [getNodeTags]
set nodeOne [lindex $nodeList 0]
set ndm [llength [nodeCoord $nodeOne]]

set prefix "ModeShape"
set ModeShapeFile "$modeShapeDir/$prefix$modeNumber.out"
set fieldModeShape [open $ModeShapeFile w+]

foreach nodeTag $nodeList {
set tempNodeData [nodeEigenvector $nodeTag $modeNumber]
puts $fieldModeShape "$nodeTag [lrange $tempNodeData 0 [expr $ndm-1]]"
}

close $fieldModeShape
}

for {set i 1} {$i <= $numModes} {incr i} {

getModeShapeData $i $modeShapeDir
}
#
}

}

145 changes: 145 additions & 0 deletions vfo_docs/Plotting_Development_Guide.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@

.. include:: sub.txt

===============================
Visualization Development Guide
===============================

You are welcome to contribute to the plotting/post-processing commands. This documentation is to explain what is going on inside
the plotting library "Get_Rendering" and how you can enhance the functons. As of now, Get_Rendering has functions
to plot a structure, mode shapes and shape of a displaced structure and works for 2D (beam-column elements,
tri, and quad) and 3D (beam-column, tri, 4-node shell, and 8-node brick) elements.

As of now, all plotting functions should use Matplotlib only and should be able to produce interactive plots. Developers should test
the new functions extensively , including on Jupyter Notebook, before submitting a pull request.

**Note:** A list of test examples will be available soon.

The source code of all the plotting functions is located in `OpenSeesPy <https://github.com/zhuminjie/OpenSeesPy/tree/master/openseespy-pip/openseespy/postprocessing>`_ repository.

As an object oriented approach and to reduce the code repetition, Get_Rendering uses two types of functions.

Internal Database functions
---------------------------

These functions get, write to and read data from output database.

``_getNodesandElements()`` : Gets node and element tags from the active model, stores node tags with coordinates and element tags with connected nodes in numpy arrays.

``_saveNodesandElements()`` : Saves the node and element arrays from _getNodesandElements() to text files with ".out" extension.

``_readNodesandElements()`` : Reads the node and element data into numpy arrays from the saved files.

``_getModeShapeData()`` : Gets node deflection for a particular mode from the active model, stores node tags with modeshape data in numpy arrays.

``_saveModeShapeData()`` : Saves the modeshape data arrays from _getModeShapeData() to text files with ".out" extension.

``_readModeShapeData()`` : Reads the modeshape data into numpy arrays from the saved files.

``_readNodeDispData()`` : Reads the node displacement data into numpy arrays from the saved files (from createODB() command).

``_readFiberData2D()`` : Reads the section fiber output data into numpy arrays from the saved files (from saveFiberData2D() command).


Internal Plotting functions
---------------------------

These functions are helper functions that are called by the user functions once the updated
node coordinates are calculated.

``_plotBeam2D()`` : A procedure to plot a 2D beam-column (or any element with 2 nodes) using iNode, jNode and some internal variables as input.

``_plotBeam3D()`` : A procedure to plot a 3D beam-column (or any element with 2 nodes) using iNode, jNode and some internal variables as input.

``_plotTri2D()`` : A procedure to render a 2D, three node shell (Tri) element using iNode, jNode, kNode in counter-clockwise order and some internal variables as input.

``_plotTri3D()`` : A procedure to render a 3D, three node shell (Tri) element using iNode, jNode, kNode in counter-clockwise order and some internal variables as input.

``_plotQuad2D()`` : A procedure to render a 2D, four node shell (Quad, ShellDKGQ etc.) element using iNode, jNode, kNode, lNode in counter-clockwise and some internal variables as input.

``_plotQuad3D()`` : A procedure to render a 3D, four node shell (Quad, ShellDKGQ etc.) element using iNode, jNode, kNode, lNode in counter-clockwise and some internal variables as input.

``_plotCubeSurf()`` : This procedure is called by the `plotCubeVol()` command to render each surface in a cube using four corner nodes.

``_plotCubeVol()`` : A procedure to render a 8-node brick element using a list of eight element nodes in bottom and top faces and in counter-clockwise order, and internal variables as input.

``_plotEle_2D()`` : A procedure to plot any 2D element by calling other internal plotting commands for 2D elements.

``_plotEle_3D()`` : A procedure to plot any 3D element by calling other internal plotting commands for 3D elements.

``_initializeFig()`` : Initializes a matplotlib.pyplot figure for each of the user plotting commands. This procedure reduced the code repetition.

``_setStandardViewport()`` : Sets a standard viewport for matplotlib.pyplot figure for each of the user plotting commands. This procedure reduced the code repetition.


User functions
-------------------

These are the functions available to users to call through OpenSeesPy script. The following table describes what they are and how they work.

``createODB()`` : Redords the model and loadcase data to be used by other plotting functions in a user defined output folder.

``saveFiberData2D()`` : Redords the output data from all the fibers in a particular section to plot the distribution.

``plot_model()`` : Gets the number of nodes and elements in lists by calling `getNodeTags()` and `getEleTags()`. Then plots the elements in a loop by checking if the model is 2D or 3D, and calling the `nodecoord()` command for each node to get its original coordinates and internal function `_plotBeam3D`.

``plot_modeshapes()`` : Gets the number of nodes and elements in lists by calling `getNodeTags()` and `getEleTags()`. In a loop, calls `nodecoord()` and `nodeEigenvector()` for each node to get original and eigen coordinates respectively. Then plots the mode shape by calling the internal functions.

``plot_deformedshape()``: Reads the displacement data from the output of `createODB()` function and original coordinates using `nodecoord()` function. Then plots the displaced shape of the structure using the internal functions in a manner similar to `plot_modeshapes()`.

``plot_fiberResponse2D()``: Reads the fiber output data from the output of `saveFiberData2D()` function and plots the distribution across the section.

``animate_deformedshape()``: Reads the displacement data from the output of `createODB()` function and original coordinates using `nodecoord()` function. Then animates the displaced shape of the structure.

``animate_fiberResponse2D()``: Reads the fiber output data from the output of `saveFiberData2D()` function and animates the stress/strain distribution across the section.


Example of an internal function
-----------------------------------

Here is an example of ``_plotQuad3D()`` internal function:

::

_plotQuad3D(iNode, jNode, kNode, lNode, ax, show_element_tags, element, eleStyle, fillSurface)

This function uses the following inputs:

==================== =============================================================================================================
*Nodes iNode, jNode, kNode, lNode : A list of four nodes in counter-clockwise order.
ax Reference to the Matplotlib fixure axes space. This should not be changed.
show_element_tags The default is set to "yes" for plotting the model with ``plot_model()`` and "no" while plotting mode shapes
or deformed shapes. This should not be changed.
element This is the tag of that particular element as a string which is displayed when show_element_tags="yes".
eleStyle Use eleStyle = "wire" for a wire frame, and "solid" for solid element lines. Wire frame is used when
overlapping the original shape of the structure with the mode shape or displaced shape.
fillSurface Use fillSurface = "yes" for color fill in the elements. fillSurface="no" for wireframe.
==================== =============================================================================================================
Naming conventions
----------------------

The names of classes, variables, and functions should be self-explanatory. Look for names that give useful information about the meaning of the variable or function.
All the internal functions should start with "``_``" and be in camelCase (for example ``_plotCubeSurf``) to distinguish them from the user functions. There are two type of
user functions, 1) recorder functions and 2) plot functions. All the "recorder" functions should start with "record" and use camelCase (example: ``recordNodeDisp``) and
the plotting functions should start with "``plot_``" use snake_case (example: ``plot_deformedshape``). Try to keep the internal variables (see 3. Example) consistant. New internal variable should be
defined only if necessary.


Wish List
-------------

Some functions helpful to users might include, but not limited to,

* plot_stress() : Record stress in all the elements of a function and plot. This will be useful in visualization of shear walls, fluid-structure interaction and soil modeled as brick elements.

* plot_strain() : Similar functionality as above.

* plot_sectionfiber() : Visualize stress-strain distribution accross a fiber section in a non-linear beam-column element.

* plot_elementforces() : Element forces such as moment, shear, axial force.

* animate_elementstress() : Animation of the stress or strain in a structure.

Feel free to comment and discuss how to streamline your plotting code with the existing ``Get_Rendering`` library. Or contact me
`Anurag Upadhyay <https://github.com/u-anurag>`_.
Binary file added vfo_docs/_static/ModeShape_5_Plot3D.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added vfo_docs/_static/ModelVisualization_Intro.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added vfo_docs/_static/Model_Plot3D.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added vfo_docs/_static/plot_deformedshape_output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions vfo_docs/animate_deformedshape.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.. include:: sub.txt

===============================
animate_deformedshape command
===============================

.. function:: vfo.animate_deformedshape(Model='ModelName', LoadCase='LoadCaseName',
dt = dT, <tStart = 0>, <tEnd = 0>, <scale = 10>, fps = 24, FrameInterval = 0,
timeScale = 1, Movie='none')


Displays an animation of the deformed structure by reading data from a saved output database.
The animation object should be stored as an variable in order for the animation to run.
The input file should have approximately the same number of time between each step or the animation will appear to speed up or slow down.
The time step for the input data can be controlled by passing the a recorder time step.

For many larger models, the runtime of the code for each frame likely be larger than the frame interval, this will result in the animation running slower than the target fps.
**ffmpeg** codecs are required to save the animation as a movie (.mp4).



======================== =============================================================================================
``ModelName`` |str| Name of the model to read data from output database, created with `createODB()` command.
``LoadCaseName`` |str| Name of the subfolder with load case output data.
``dT`` |float| The time step between frames in the input file.
``tStart`` |float| The start time for animation. It can be approximate value and the program will find the closest matching time step. (optional, default is 0)
``tEnd`` |float| The end time for animation. It can be approximate value and the program will find the closest matching time step. (optional, default is last step)
``scale`` |int| Scale factor for to display mode shape. (optional, default is 10)
``fps`` |int| The target frames per second to be displayed. (optional, The default is 24)
``FrameInterval`` |int| The time interval between frames to be used. Used to update at intervals different than 1/fps. The default is 0. (optional)
``timeScale`` |int| A scale factor that increase or decrease the time between animation frames. Will not improve results if the animation speed is governed by performance limited.(optional, default is 1)
``Movie`` |str| Name of the movie file in the `LoadCadeName` folder if the user wants to save the animation as .mp4 file. (optional, default is "none")
======================== =============================================================================================


Examples:

.. raw:: html

<iframe width="560" height="315" src="https://www.youtube.com/embed/-inY2aDcT4c" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

::

ani = vfo.animate_deformedshape(Model="TwoSpan_Bridge", LoadCase="Dynamic_GM1", dt=0.01)
The above command animates the deformedshape of structure by reading data from `TwoSpan_Bridge_ODB` with a sub-folder `Dynamic_GM1` at dt=0.01.

::

ani = vfo.animate_deformedshape(Model="TwoSpan_Bridge", LoadCase="Dynamic_GM1", dt=0.01, tStart=10.0, tEnd=20.0,
scale=50, Movie="Bridge_Dynamic")

The above command animates the deformedshape of structure by reading data from `TwoSpan_Bridge_ODB` with a sub-folder `Dynamic_GM1` at dt=0.01, starting at t=10.0 s and ending at t=20.0 s of the earthquake input, using a scale factor of 50. The animation movie will be saved as `Bridge_Dynamic.mp4` in the `Dynamic_GM1` sub-folder.
Loading

0 comments on commit a22b032

Please sign in to comment.