Skip to main content

Object-oriented native Python version of OpenSees

Project description

Testing Status PyPi version https://coveralls.io/repos/github/o3seespy/o3seespy/badge.svg?branch=master https://readthedocs.org/projects/o3seespy/badge/?version=latest

o3seespy

Object-oriented native python version of OpenSees

Features

This package provides:

  1. A ‘pythonic’ version of OpenSees - all input parameters to create OpenSees objects are all lowercase key-value arguments - all class objects are CamelCase - static string variables defined in ALL_CAPS - Where possible the exact name used in the original TCL version has been kept

  2. Fully namespaced package allowing full auto-complete e.g. ‘o3.uniaxial_material.Steel01(…)’

  3. Replication of underlying object-oriented C++ source code using Python objects.

  4. Type checking of inputs before calling C++ OpenSees code, so that python debugging and errors can be viewed

  5. In code documentation using python docstrings - can view the documentation within your IDE

  6. Additional features for using OpenSees in python: - saving and loading data directly from OpenSees into numpy arrays - saving and loading data directly from OpenSees into json files - Save an entire model as a json file - allows efficient passing of models between servers

  7. All object numbering handled by objects - no need for number tags!

  8. Additional logic checking of optional inputs

How to Use

Installation

pip install o3seespy

Example: Dynamic inelastic SDOF analysis

import numpy as np
import matplotlib.pyplot as plt

import o3seespy as o3

from tests.conftest import TEST_DATA_DIR

# Load a ground motion
dt = 0.01
rec = np.loadtxt(TEST_DATA_DIR + 'test_motion_dt0p01.txt')

# Define inelastic SDOF
period = 1.0
xi = 0.05
mass = 1.0
f_yield = 1.5  # Reduce this to make it nonlinear
r_post = 0.0

# Initialise OpenSees instance
osi = o3.OpenSeesInstance(ndm=2, state=0)

# Establish nodes
bot_node = o3.node.Node(osi, 0, 0)
top_node = o3.node.Node(osi, 0, 0)

# Fix bottom node
o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED)
o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
# Set out-of-plane DOFs to be constrained
o3.EqualDOF(osi, top_node, bot_node, [o3.cc.DOF_Y, o3.cc.ROTZ])

# nodal mass (weight / g):
o3.Mass(osi, top_node, mass, 0., 0.)

# Define material
k_spring = 4 * np.pi ** 2 * mass / period ** 2
bilinear_mat = o3.uniaxial_material.Steel01(osi, fy=f_yield, e0=k_spring, b=r_post)

# Assign zero length element, # Note: pass actual node and material objects into element
o3.element.ZeroLength(osi, [bot_node, top_node], mats=[bilinear_mat], dirs=[o3.cc.DOF_X], r_flag=1)

# Define the dynamic analysis
load_tag_dynamic = 1
pattern_tag_dynamic = 1

# Define the dynamic analysis
acc_series = o3.time_series.Path(osi, dt=dt, values=-1 * rec)  # should be negative
o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series)

# set damping based on first eigen mode
angular_freq = o3.get_eigen(osi, solver='fullGenLapack', n=1)[0] ** 0.5
beta_k = 2 * xi / angular_freq
o3.rayleigh.Rayleigh(osi, alpha_m=0.0, beta_k=beta_k, beta_k_init=0.0, beta_k_comm=0.0)

# Run the dynamic analysis
o3.wipe_analysis(osi)

# Run the dynamic analysis
o3.algorithm.Newton(osi)
o3.system.SparseGeneral(osi)
o3.numberer.RCM(osi)
o3.constraints.Transformation(osi)
o3.integrator.Newmark(osi, gamma=0.5, beta=0.25)
o3.analysis.Transient(osi)

o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10)
analysis_time = (len(rec) - 1) * dt
analysis_dt = 0.001
outputs = {
    "time": [],
    "rel_disp": [],
    "rel_accel": [],
    "rel_vel": [],
    "force": []
}

while o3.get_time(osi) < analysis_time:
    o3.analyze(osi, 1, analysis_dt)
    curr_time = o3.get_time(osi)
    outputs["time"].append(curr_time)
    outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X))
    outputs["rel_vel"].append(o3.get_node_vel(osi, top_node, o3.cc.X))
    outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X))
    o3.gen_reactions(osi)
    outputs["force"].append(-o3.get_node_reaction(osi, bot_node, o3.cc.X))  # Negative since diff node
o3.wipe(osi)
for item in outputs:
    outputs[item] = np.array(outputs[item])


plt.plot(outputs['time'], outputs['rel_disp'], label='o3seespy')
periods = np.array([period])

# Compare closed form elastic solution
from eqsig import sdof
resp_u, resp_v, resp_a = sdof.response_series(motion=rec, dt=dt, periods=periods, xi=xi)
plt.plot(np.arange(len(rec)) * dt, resp_u[0], ls='--', label='Elastic')
plt.legend()
plt.savefig('readme_example.png')
plt.show()
Output from example

Useful material

Contributing

How do I get set up?

  1. Run pip install -r requirements.txt

Package conventions

  • All names should be the same as the OpenSees tcl version, except:
    • The name should be converted to snake_case for a parameter or function

    • The name should be converted to CamelCase for an Object

    • The name should be converted to ALL_CAPS for static variables

    • If the name matches a python special name (e.g. lambda, in) then it should be adjusted according to the dictionary

    • Objects should be namespaced based on the object type (e.g. element, material)

    • For parameter that are used across many objects (e.g. atmospheric pressure) a standard name should be used

    • OpenSees functions that collect a result are named ‘get_<function-name>’

    • OpenSees functions that generate results are named ‘gen_<function-name>’

  • How should youngs modulus be named?

  • Should all two node elements use i_node, j_node. Or make them all enter nodes as a list?

Testing

Tests are run with pytest

  • Locally run: pytest on the command line.

  • Tests are run on every push using travis, see the .travis.yml file

Deployment

To deploy the package to pypi.com you need to:

  1. Push to the pypi branch. This executes the tests on circleci.com

  2. Create a git tag and push to github, run: trigger_deploy.py or manually:

git tag 0.5.2 -m "version 0.5.2"
git push --tags origin pypi

Documentation

Built via Sphinx following: https://codeandchaos.wordpress.com/2012/07/30/sphinx-autodoc-tutorial-for-dummies/

For development mode

  1. cd to docs

  2. Run make html

Docstrings follow numpy convention (in progress): https://numpydoc.readthedocs.io/en/latest/format.html

To fix long_description in setup.py: pip install collective.checkdocs, python setup.py checkdocs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

o3seespy-3.4.0.7.tar.gz (249.5 kB view details)

Uploaded Source

File details

Details for the file o3seespy-3.4.0.7.tar.gz.

File metadata

  • Download URL: o3seespy-3.4.0.7.tar.gz
  • Upload date:
  • Size: 249.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.10.1

File hashes

Hashes for o3seespy-3.4.0.7.tar.gz
Algorithm Hash digest
SHA256 9c78782ef9f0fbbf0b914115c56599462424e4769b0eb8884ff9f93968fc727a
MD5 c8386b6b97bea49e734ef4a8170e6b91
BLAKE2b-256 486bffddfecb1bef3ffdc042744a5b0efaafa470904b8a95b126f070825f94ad

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page