Skip to content

Commit

Permalink
link properties and basic interactive database tools
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchell-tesch committed Mar 12, 2024
1 parent 702ecad commit b90acea
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/pytabs.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions examples/PyTABS_LinkSpringProp/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pytabs



def main():
# substantiate pyTABS EtabsModel
etabs_model = pytabs.EtabsModel()

# etabs_model.set_present_units(etabs_model.eUnits.kN_m_C)

# etabs_model.property.link.set_multi_linear_elastic(name='TestLinkProp',
# dof=[True, False, False, False, False, False],
# is_fixed=[False, True, False, False, False, False],
# nonlinear=[True, False, False, False, False, False],
# ke=[0., 0., 0., 0., 0., 0.],
# ce=[0., 0., 0., 0., 0., 0.],
# dj2=100., dj3=200.)

# etabs_model.property.link.set_spring_data(name='TestLinkProp', length=1.2, area=1.5)

# etabs_model.property.link.set_multi_linear_points(name='TestLinkProp',
# dof=etabs_model.property.link.eLinkDof.U1,
# action_values=[-1000., -500., 0., 100., 600., 1000],
# displacement_values=[-0.5, -0.4, 0., 0.2, 0.6, 0.8],
# hysteresis_type=etabs_model.property.link.eLinkHysteresisType.KINEMATIC)


# etabs_model.property.line_spring.set_line_spring_prop(name='TestLineSpringProp',
# stiffness=[1., 2., 3., 4.],
# nonlinear_option_2=etabs_model.property.line_spring.eSpringNonlinearOption.LINEAR,
# nonlinear_option_3=etabs_model.property.line_spring.eSpringNonlinearOption.COMPRESSION_ONLY)

# print(etabs_model.property.line_spring.get_line_spring_prop('TestLineSpringProp'))


table = etabs_model.database_tables.get_table_details('Spring Property Definitions - Line Springs')

table_data_array = etabs_model.database_tables.get_table_data_array(table, edit_mode=True)
print('')

if __name__ == '__main__':
main()
208 changes: 208 additions & 0 deletions src/pytabs/database_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,111 @@
from .error_handle import handle

# import custom enumerations
from .enumerations import eTableImportableType

# import typing
from typing import TypedDict


class DbEditLog(TypedDict):
num_fatal_errors: int
num_error_msgs: int
num_warn_msgs: int
num_info_msgs: int
import_log: str


class DbField:
def __init__(self, field_key: str, field_name: str,
description: str, units_string: str, is_importable: bool):
self._field_key = field_key
self._field_name = field_name
self._description = description
self._units_string = units_string
self._is_importable = is_importable

@property
def field_key(self):
return self._field_key

@property
def field_name(self):
return self._field_name

@property
def description (self):
return self._description

@property
def units_string(self):
return self._units_string

@property
def is_importable(self):
return self._is_importable


class DbTable:
def __init__(self, table_key: str, table_name: str, importable_type: eTableImportableType,
is_empty: bool):
self._table_key = table_key
self._table_name = table_name
self._importable_type = importable_type
self._is_empty = is_empty
self._fields: list[DbField] = []

@property
def table_key(self):
return self._table_key

@property
def table_name(self):
return self._table_name

@property
def importable_type(self):
return self._importable_type

@property
def is_empty(self):
return self._is_empty

@property
def fields(self):
return self._fields

def add_table_fields(self, fields: DbField):
self._fields.extend(fields)


class DbTableDataArray:
def __init__(self, table_version: int, fields_included: list[str], number_records: int,
records: list[str], group_name: str = ''):
self._table_version = table_version
self._fields_included = fields_included
self._group_name = group_name
self._num_fields = len(self._fields_included)
self._num_records = number_records
self._table_data = self._reshape_data(records)

@property
def table_version(self):
return self._table_version

@property
def fields_included(self):
return self._fields_included

@property
def group_name(self):
return self._group_name

@property
def table_data(self):
return self._table_data

def _reshape_data(self, records):
return list(zip(*[iter(records)] * self._num_fields))


class DatabaseTables:
Expand All @@ -19,3 +124,106 @@ def __init__(self, sap_model: etabs.cSapModel) -> None:
self.database_tables = etabs.cDatabaseTables(sap_model.DatabaseTables)

# relate custom enumerations
self.eTableImportableType = eTableImportableType

def get_all_table_details(self) -> list[DbTable]:
number_tables, table_key, table_name, is_importable, is_empty = self._get_all_tables()
tables: list[DbTable] = []
for _t in range(number_tables):
table = DbTable(table_key[_t], table_name[_t], eTableImportableType(is_importable[_t]), is_empty[_t])
fields = self.get_table_fields(table_key[_t])
table.add_table_fields(fields)
tables.append(table)
return tables

def get_table_details(self, key) -> DbTable:
number_tables, table_key, table_name, is_importable, is_empty = self._get_all_tables()
for _t in range(number_tables):
table = DbTable(table_key[_t], table_name[_t], eTableImportableType(is_importable[_t]), is_empty[_t])
if key == table_key[_t]:
fields = self.get_table_fields(table_key[_t])
table.add_table_fields(fields)
return table

def get_table_fields(self, table_key) -> list[DbField]:
table_version = int()
number_fields = int()
field_key = [str()]
field_name = [str()]
description = [str()]
units_string = [str()]
is_importable = [bool()]
[ret, _table_version, number_fields,
field_key, field_name, description,
units_string, is_importable] = self.database_tables.GetAllFieldsInTable(table_key, table_version, number_fields,
field_key, field_name, description,
units_string, is_importable)
handle(ret)
fields: list[DbField] = []
for _f in range(number_fields):
fields.append(DbField(field_key[_f], field_name[_f], description[_f], units_string[_f], is_importable[_f]))
return fields

def get_table_data_array(self, table: DbTable, edit_mode: bool = False,
group_name: str = '', field_key: list[str] = ['']):
table_version = int()
field_keys_out = [str()]
number_records = int()
records = [str()]
if edit_mode:
# not active in current version of ETABS - refer manual.
group_name = ''
[ret, table_version, field_keys_out,
number_records, records] = self.database_tables.GetTableForEditingArray(table.table_key, group_name,
table_version, field_keys_out,
number_records, records)
handle(ret)
return DbTableDataArray(table_version, list(field_keys_out), number_records, records)

else:
[ret, field_key, table_version,
field_keys_out, number_records,
records] = self.database_tables.GetTableForDisplayArray(table.table_key, field_key, group_name,
table_version, field_keys_out, number_records,
records)
handle(ret)
return DbTableDataArray(table_version, list(field_keys_out), number_records, records, group_name)

def set_table_data_array_edit(self, table: DbTable, field_keys: list[str], table_data: list[list]) -> None:
table_version = int()
num_records = len(table(table_data))
records = [item for record in table_data for item in record]
[ret, _table_version,
_field_keys_out, _table_data] = self.database_tables.SetTableForEditingArray(table.table_key, table_version,
field_keys, num_records, records)
handle(ret)

def apply_table_edits(self, log_import: bool = False) -> DbEditLog:
num_fatal_errors = int()
num_error_msgs = int()
num_warn_msgs = int()
num_info_msgs = int()
import_log = str()
handle(self.database_tables.ApplyEditedTables(log_import, num_fatal_errors, num_error_msgs,
num_warn_msgs, num_info_msgs,
import_log))
return {'num_fatal_errors': num_fatal_errors,
'num_error_msgs': num_error_msgs,
'num_warn_msgs': num_warn_msgs,
'num_info_msgs': num_info_msgs,
'import_log': import_log}

def discard_table_edits(self):
handle(self.database_tables.CancelTableEditing())

def _get_all_tables(self):
number_tables = int()
table_key = [str()]
table_name = [str()]
is_importable = [int()]
is_empty = [bool()]
[ret, number_tables, table_key,
table_name, is_importable, is_empty] = self.database_tables.GetAllTables(number_tables, table_key,
table_name, is_importable, is_empty)
handle(ret)
return number_tables, table_key, table_name, is_importable, is_empty
22 changes: 22 additions & 0 deletions src/pytabs/enumerations.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,25 @@ class eSpringNonlinearOption(IntEnum):
LINEAR = 0
COMPRESSION_ONLY = 1
TENSION_ONLY = 2


class eLinkDof(IntEnum):
U1 = 1
U2 = 2
U3 = 3
R1 = 4
R2 = 5
R3 = 6


class eLinkHysteresisType(IntEnum):
KINEMATIC = 1
TAKEDA = 2
PIVOT = 3


class eTableImportableType(IntEnum):
NOT_IMPORTABLE = 0
NOT_INTERACTIVE = 1
INTERACTIVE_IF_UNLOCKED = 2
INTERACTIVE_ALWAYS = 3
19 changes: 9 additions & 10 deletions src/pytabs/properties/prop_line_spring.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def get_names_list(self) -> list[str]:
handle(ret)
return list(line_spring_names)

def get_line_spring_prop(self, line_spring_name: str) -> LineSpringProperties:
def get_line_spring_prop(self, name: str) -> LineSpringProperties:
"""Retrieves the line spring property of an existing named line spring.
:param line_spring_name: name of an existing line spring property
Expand All @@ -69,12 +69,11 @@ def get_line_spring_prop(self, line_spring_name: str) -> LineSpringProperties:
notes = str()
guid = str()
[ret, u1, u2, u3, r1, nonlinear_option_2,
nonlinear_option_3, colour, notes, guid] = self.prop_line_spring.GetLineSpringProp(line_spring_name, u1, u2,
u3, r1, nonlinear_option_2,
nonlinear_option_3, colour,
notes, guid)
nonlinear_option_3, colour, notes, guid] = self.prop_line_spring.GetLineSpringProp(name, u1, u2, u3, r1,
nonlinear_option_2, nonlinear_option_3,
colour, notes, guid)
handle(ret)
return {'line_spring_name': line_spring_name,
return {'line_spring_name': name,
'u1': u1,
'u2': u2,
'u3': u3,
Expand All @@ -85,13 +84,13 @@ def get_line_spring_prop(self, line_spring_name: str) -> LineSpringProperties:
'notes': notes,
'guid': guid}

def set_line_spring_prop(self, line_spring_name: str, stiffness: list[float],
def set_line_spring_prop(self, name: str, stiffness: list[float],
nonlinear_option_2: eSpringNonlinearOption, nonlinear_option_3: eSpringNonlinearOption,
colour: int = 0, notes: str = '', guid: str = '') -> None:
"""Creates a new named line spring property, or modifies an existing named line spring property
:param line_spring_name: name of the new spring property to be defined or an existing line spring property to re-define
:type line_spring_name: str
:param name: name of the new spring property to be defined or an existing line spring property to re-define
:type name: str
:param stiffness: line spring stiffness matrix [U1, U2, U3, R1] in associated line element's local coordinate system
:type: list[float]
:param nonlinear_option_2: nonlinear option for the local 2 direction
Expand All @@ -110,5 +109,5 @@ def set_line_spring_prop(self, line_spring_name: str, stiffness: list[float],
u2 = stiffness[1]
u3 = stiffness[2]
r1 = stiffness[3]
handle(self.prop_line_spring.SetLineSpringProp(line_spring_name, u1, u2, u3, r1, nonlinear_option_2.value,
handle(self.prop_line_spring.SetLineSpringProp(name, u1, u2, u3, r1, nonlinear_option_2.value,
nonlinear_option_3.value, colour, notes, guid))
Loading

0 comments on commit b90acea

Please sign in to comment.