Source code for opstool.vis.get_model_data

import os
import h5py
import numpy as np
import openseespy.opensees as ops
from typing import Union
from numpy.typing import ArrayLike

from ..utils import (ELE_TAG_Beam, ELE_TAG_Link,
                     ELE_TAG_Tetrahedron, ELE_TAG_Truss)
from ..utils import check_file


[docs]class GetFEMdata: """ Get the data in the openseespy model domain. Parameters ---------- results_dir: str, default="opstool_output" The dir that results saved. """ def __init__(self, results_dir: str = "opstool_output"): self.out_dir = results_dir if not os.path.exists(self.out_dir): os.makedirs(self.out_dir) self.model_info = dict() self.get_model_data_finished = False # Initialize cell connection data self.cells = dict() # Initialize eigenvalue data self.eigen = None # Analysis step model update data self.model_info_steps = dict() # Ele connection update data self.cells_steps = dict() # Update node response data self.node_resp_names = ("disp", "vel", "accel") self.node_resp_steps = dict() self.step_node_track = 0 self.beam_infos = dict() self.beam_resp_names = ['localForces'] # 'basicDeformations' self.beam_resp_step = dict() # ["N_1", "Vy_1", "Vz_1", "T_1", "My_1", "Mz_1", # "N_2", "Vy_2", "Vz_2", "T_2", "My_2", "Mz_2"] # ["eps", "thetaZ_1", "thetaZ_2", "thetaY_1", "thetaY_2", "thetaX"] self.step_beam_track = 0 # On/Off and Tracking for Model Updates self.model_update = False # self.reset_model_state() # self.reset_eigen_state() self.reset_steps_state() # fiber section data self.fiber_sec_tags = None self.fiber_sec_data = dict() self.fiber_sec_step_data = dict() self.step_fiber_track = 0
[docs] def reset_model_state(self): """Reset the state of results extract of model data.""" for name in self.model_info.keys(): self.model_info[name] = None for name in self.cells.keys(): self.cells[name] = None
[docs] def reset_eigen_state(self): """Reset the state of results extract of eigen data.""" self.eigen = dict() for name in self.eigen.keys(): self.eigen[name] = None
def _reset_model_step(self): for name in self.model_info.keys(): self.model_info_steps[name] = [] for name in self.cells.keys(): self.cells_steps[name] = [] self.model_info_steps['step_track'] = 0 self.cells_steps['step_track'] = 0 def _reset_node_resp(self): self.step_node_track = 0 for name in self.node_resp_names: self.node_resp_steps[name] = [] def _reset_beam_step(self): self.step_beam_track = 0 for name in self.beam_infos.keys(): self.beam_infos[name] = None for name in self.beam_resp_names: self.beam_resp_step[name] = [] def _reset_fiber_step(self): self.step_fiber_track = 0 self.fiber_sec_step_data = dict()
[docs] def reset_steps_state(self): """Reset the state of results extract in analysis step. .. important:: As the data is saved in the loop analysis using the list append method, it is important to clear the data from previous analysis case before each analysis loop. """ self._reset_model_step() self._reset_node_resp() self._reset_beam_step() self._reset_fiber_step()
# Truss Element Analysis Step Response Data # Beam Element Analysis Step Response Data
[docs] def get_model_data(self, save_file: Union[str, bool] = "ModelData.hdf5"): """Get data from the current model domain. The data will saved to file ``results_dir`` + ``save_file``. Parameters ----------- save_file: str, default="ModelData.hdf5" The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. """ if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) # -------------------------------- node_tags = ops.getNodeTags() # node_tags.sort() num_node = len(node_tags) # Get all the ele tags ele_tags = ops.getEleTags() # ele_tags.sort() num_ele = len(ele_tags) # Dict of node coordinates node_coords = np.zeros((num_node, 3)) node_index = dict() # key: nodeTag, value: index in Node_Coords model_dims = [] for i, Tag in enumerate(node_tags): coord = ops.nodeCoord(Tag) model_dim = len(coord) if model_dim == 1: coord.extend([0, 0]) elif model_dim == 2: coord.extend([0]) model_dims.append(model_dim) node_coords[i] = coord node_index[Tag] = i points = node_coords fixed_nodes = ops.getFixedNodes() fixed_dofs = [] for tag in fixed_nodes: fixeddofs = ops.getFixedDOFs(tag) fixities = [0] * 6 for dof in fixeddofs: fixities[dof - 1] = -1 fixed_dofs.append(fixities) fixed_dofs = np.array(fixed_dofs) # lines and faces # How the ele is connected,node number n-node tag 1-node tag 2-...-node tag n # ----------------- truss_cells = [] truss_cells_tags = [] # ----------------- link_cells = [] link_cells_tags = [] link_midpoints = [] link_xlocal = [] link_ylocal = [] link_zlocal = [] # ------------------ beam_cells = [] beam_cells_tags = [] beam_midpoints = [] beam_xlocal = [] beam_ylocal = [] beam_zlocal = [] # ----------------------- other_line_cells = [] other_line_cells_tags = [] all_lines_cells = [] all_lines_cells_tags = [] # -------------------- plane_cells = [] plane_cells_tags = [] # ------------------------ tetrahedron_cells = [] tetrahedron_cells_tags = [] # ----------------------------- brick_cells = [] brick_cells_tags = [] # ----------------------------- all_faces_cells = [] all_faces_cells_tags = [] # ------------------------------ ele_midpoints = [] # the coordinates of the ele's midpoint for i, ele in enumerate(ele_tags): ele_nodes = ops.eleNodes(ele) # Determine the element type based on the number of element nodes if len(ele_nodes) == 2: node_i, node_j = ele_nodes idx_i, idx_j = node_index[node_i], node_index[node_j] all_lines_cells.extend([2, idx_i, idx_j]) all_lines_cells_tags.append(ele) if ops.getEleClassTags(ele)[0] in ELE_TAG_Truss: truss_cells.extend([2, idx_i, idx_j]) truss_cells_tags.append(ele) elif ops.getEleClassTags(ele)[0] in ELE_TAG_Link: link_cells.extend([2, idx_i, idx_j]) link_cells_tags.append(ele) link_midpoints.append((node_coords[idx_i] + node_coords[idx_j]) / 2) xlocal = ops.eleResponse(ele, "xlocal") ylocal = ops.eleResponse(ele, "ylocal") zlocal = ops.eleResponse(ele, "zlocal") link_xlocal.append(np.array(xlocal) / np.linalg.norm(xlocal)) link_ylocal.append(np.array(ylocal) / np.linalg.norm(ylocal)) link_zlocal.append(np.array(zlocal) / np.linalg.norm(zlocal)) elif ops.getEleClassTags(ele)[0] in ELE_TAG_Beam: beam_cells.extend([2, idx_i, idx_j]) beam_cells_tags.append(ele) beam_midpoints.append((node_coords[idx_i] + node_coords[idx_j]) / 2) xlocal = ops.eleResponse(ele, "xlocal") ylocal = ops.eleResponse(ele, "ylocal") zlocal = ops.eleResponse(ele, "zlocal") beam_xlocal.append(np.array(xlocal) / np.linalg.norm(xlocal)) beam_ylocal.append(np.array(ylocal) / np.linalg.norm(ylocal)) beam_zlocal.append(np.array(zlocal) / np.linalg.norm(zlocal)) else: other_line_cells.extend([2, idx_i, idx_j]) other_line_cells_tags.append(ele) ele_midpoints.append((node_coords[idx_i] + node_coords[idx_j]) / 2) elif len(ele_nodes) == 3 or len(ele_nodes) == 6: if len(ele_nodes) == 3: node_i, node_j, node_k = ops.eleNodes(ele) else: node_i, node_j, node_k = ops.eleNodes(ele)[1], ops.eleNodes(ele)[3], ops.eleNodes(ele)[5] idx_i, idx_j, idx_k = ( node_index[node_i], node_index[node_j], node_index[node_k], ) all_faces_cells.extend([3, idx_i, idx_j, idx_k]) all_faces_cells_tags.append(ele) plane_cells.extend([3, idx_i, idx_j, idx_k]) plane_cells_tags.append(ele) ele_midpoints.append( (node_coords[idx_i] + node_coords[idx_j] + node_coords[idx_k]) / 3 ) elif len(ele_nodes) == 4 or len(ele_nodes) == 9: if len(ele_nodes) == 4: node_i, node_j, node_k, node_l = ops.eleNodes(ele) else: node_i, node_j, node_k, node_l = ops.eleNodes(ele)[0:4] idx_i, idx_j = node_index[node_i], node_index[node_j] idx_k, idx_l = node_index[node_k], node_index[node_l] if ops.getEleClassTags(ele)[0] in ELE_TAG_Tetrahedron: # tetrahedron tetrahedron_cells.extend([3, idx_i, idx_j, idx_k]) tetrahedron_cells.extend([3, idx_i, idx_j, idx_l]) tetrahedron_cells.extend([3, idx_i, idx_k, idx_l]) tetrahedron_cells.extend([3, idx_j, idx_k, idx_l]) tetrahedron_cells_tags.append(ele) all_faces_cells.extend([3, idx_i, idx_j, idx_k]) all_faces_cells.extend([3, idx_i, idx_j, idx_l]) all_faces_cells.extend([3, idx_i, idx_k, idx_l]) all_faces_cells.extend([3, idx_j, idx_k, idx_l]) all_faces_cells_tags.append(ele) else: plane_cells.extend([4, idx_i, idx_j, idx_k, idx_l]) plane_cells_tags.append(ele) all_faces_cells.extend([4, idx_i, idx_j, idx_k, idx_l]) all_faces_cells_tags.append(ele) ele_midpoints.append(np.mean(node_coords[[idx_i, idx_j, idx_k, idx_l]], axis=0)) elif len(ele_nodes) == 8 or len(ele_nodes) == 20: eleNodes = ops.eleNodes(ele)[0:8] tag_list = [node_index[node_] for node_ in eleNodes] temp_points = np.array([node_coords[i] for i in tag_list]) idxxx = np.argsort(temp_points[:, -1]) temp_points = temp_points[idxxx] tag_list = np.array(tag_list)[idxxx] temp_points = [tuple(i) for i in temp_points] tag_list = list(tag_list) tag_counter1 = counter_clockwise(temp_points[:4], tag_list[:4]) tag_counter2 = counter_clockwise(temp_points[4:], tag_list[4:]) tag_counts = tag_counter1 + tag_counter2 idx1, idx2, idx3, idx4, idx5, idx6, idx7, idx8 = tag_counts brick_cells.extend([4, idx1, idx4, idx3, idx2]) brick_cells.extend([4, idx5, idx6, idx7, idx8]) brick_cells.extend([4, idx1, idx5, idx8, idx4]) brick_cells.extend([4, idx2, idx3, idx7, idx6]) brick_cells.extend([4, idx1, idx2, idx6, idx5]) brick_cells.extend([4, idx3, idx4, idx8, idx7]) brick_cells_tags.append(ele) all_faces_cells.extend([4, idx1, idx4, idx3, idx2]) all_faces_cells.extend([4, idx5, idx6, idx7, idx8]) all_faces_cells.extend([4, idx1, idx5, idx8, idx4]) all_faces_cells.extend([4, idx2, idx3, idx7, idx6]) all_faces_cells.extend([4, idx1, idx2, idx6, idx5]) all_faces_cells.extend([4, idx3, idx4, idx8, idx7]) all_faces_cells_tags.append(ele) idxs1_8 = [idx1, idx2, idx3, idx4, idx5, idx6, idx7, idx8] ele_midpoints.append(np.mean(node_coords[idxs1_8], axis=0)) ele_midpoints = np.array(ele_midpoints) beam_midpoints = np.array(beam_midpoints) beam_xlocal = np.array(beam_xlocal) beam_ylocal = np.array(beam_ylocal) beam_zlocal = np.array(beam_zlocal) link_midpoints = np.array(link_midpoints) link_xlocal = np.array(link_xlocal) link_ylocal = np.array(link_ylocal) link_zlocal = np.array(link_zlocal) # Automatically determine the coordinate axis boundary # according to the model node coordinates min_node = np.min(points, axis=0) max_node = np.max(points, axis=0) space = (max_node - min_node) / 10 min_node = min_node - 2 * space max_node = max_node + 2 * space bounds = [ min_node[0], max_node[0], min_node[1], max_node[1], min_node[2], max_node[2], ] max_bound = np.max(max_node - min_node) # FEM data model_info = dict() model_info["coord_no_deform"] = points model_info["coord_ele_midpoints"] = ele_midpoints model_info["bound"] = bounds model_info["max_bound"] = max_bound model_info["num_node"] = num_node model_info["num_ele"] = num_ele model_info["NodeTags"] = node_tags model_info["FixNodeTags"] = fixed_nodes model_info["FixNodeDofs"] = fixed_dofs model_info["EleTags"] = ele_tags model_info["model_dims"] = model_dims model_info["coord_ele_midpoints"] = ele_midpoints model_info["beam_midpoints"] = beam_midpoints model_info["beam_xlocal"] = beam_xlocal model_info["beam_ylocal"] = beam_ylocal model_info["beam_zlocal"] = beam_zlocal model_info["link_midpoints"] = link_midpoints model_info["link_xlocal"] = link_xlocal model_info["link_ylocal"] = link_ylocal model_info["link_zlocal"] = link_zlocal cells = dict() cells["all_lines"] = all_lines_cells cells['all_lines_tags'] = all_lines_cells_tags cells["all_faces"] = all_faces_cells cells["all_faces_tags"] = all_faces_cells_tags cells["plane"] = plane_cells cells["plane_tags"] = plane_cells_tags cells["tetrahedron"] = tetrahedron_cells cells["tetrahedron_tags"] = tetrahedron_cells_tags cells["brick"] = brick_cells cells["brick_tags"] = brick_cells_tags cells["truss"] = truss_cells cells["truss_tags"] = truss_cells_tags cells["link"] = link_cells cells["link_tags"] = link_cells_tags cells["beam"] = beam_cells cells["beam_tags"] = beam_cells_tags cells["other_line"] = other_line_cells cells["other_line_tags"] = other_line_cells_tags for key, value in cells.items(): cells[key] = np.array(value) self.model_info.update(model_info) self.cells.update(cells) self.get_model_data_finished = True # if save_file: # output_filename = self.out_dir + '/ModelData' # with shelve.open(output_filename) as db: # db["ModelInfo"] = self.model_info # db["Cell"] = self.cells # print(f"Model data saved in {output_filename}!") if save_file: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: grp1 = f.create_group("ModelInfo") for name, value in self.model_info.items(): grp1.create_dataset(name, data=value) grp2 = f.create_group("Cell") for name, value in self.cells.items(): grp2.create_dataset(name, data=value) print(f"Model data saved in {output_filename} !")
[docs] def get_eigen_data( self, mode_tag: int = 1, solver: str = "-genBandArpack", save_file: str = 'EigenData.hdf5', ): """Get eigenvalue Analysis Data. The data will saved to file ``results_dir`` + ``save_file``. Parameters ---------- mode_tag: int mode tag. solver: str, default '-genBandArpack' type of solver, optional '-genBandArpack', '-fullGenLapack', see https://openseespydoc.readthedocs.io/en/latest/src/eigen.html. save_file: str, default='EigenData.hdf5' The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. Returns ------- None """ # ---------------------------------- if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) self.get_model_data(save_file=False) self.reset_eigen_state() # ---------------------------------- ops.wipeAnalysis() if mode_tag == 1: eigen_values = ops.eigen(solver, 2)[:1] else: eigen_values = ops.eigen(solver, mode_tag) omega = np.sqrt(eigen_values) f = omega / (2 * np.pi) self.eigen["f"] = f eigenvectors = [] for mode_tag in range(1, mode_tag + 1): # ------------------------------------------ eigen_vector = np.zeros((self.model_info["num_node"], 3)) for i, Tag in enumerate(self.model_info["NodeTags"]): coord = ops.nodeCoord(Tag) eigen = ops.nodeEigenvector(Tag, mode_tag) if len(coord) == 1: coord.extend([0, 0]) eigen.extend([0, 0]) elif len(coord) == 2: coord.extend([0]) if len(eigen) == 3 or len(eigen) == 2: eigen = eigen[:2] eigen.extend([0]) elif len(eigen) == 1: eigen.extend([0, 0]) else: eigen = eigen[:3] eigen_vector[i] = np.array(eigen) eigenvectors.append(eigen_vector) self.eigen["eigenvector"] = eigenvectors self.eigen.update(self.model_info) self.eigen.update(self.cells) # ---------------------------------------------------------------- # output_filename = self.out_dir + '/EigenData' # with shelve.open(output_filename) as db: # db["EigenInfo"] = self.eigen if save_file: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: grp = f.create_group("EigenInfo") for name, value in self.eigen.items(): grp.create_dataset(name, data=value) print(f"Eigen data saved in {output_filename} !")
[docs] def get_node_resp_step(self, num_steps: int = 100000000000, total_time: float = 100000000000, stop_cond: bool = False, save_file: str = "NodeRespStepData-1.hdf5", model_update: bool = False): """Get the node response data step by step. .. note:: You need to call this function at each analysis step in OpenSees. The advantage is that you can modify the iterative algorithm at each analysis step to facilitate convergence. Parameters ----------------- num_steps: int, default=100000000000 Total number of steps, set to determine when to save data. total_time: float, default=100000000000 Total analysis time, set to determine when to save data. You can specify one of the parameters *num_steps* and `total_time`. If both are used, it depends on which one arrives first. stop_cond: bool, default = False Condition used to determine when data is saved if ``num_steps`` and ``total_time`` unavailable. For example, stop_cond = ops.nodeDisp(nodeTag, 1) >= 0.1, i.e., once the displacement of node with tag nodeTag and dof 1 is greater than 0.1, the loop is terminated to save the data. save_file: str, default='NodeRespStepData-1.hdf5' The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. You need to specify different suffixes to distinguish between the different analysis cases. Such as "NodeRespStepData-1.hdf5", "NodeRespStepData-2.hdf5", etc. model_update: bool, default False whether to update the model domain data at each analysis step, this will be useful if model data has changed. For example, some elements and nodes were removed. Returns ------- None """ if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) if model_update: self.get_model_data(save_file=False) else: if not self.get_model_data_finished: self.get_model_data() num_node = self.model_info["num_node"] # num_ele = self.num_ele node_tags = self.model_info["NodeTags"] # EleTags = self.EleTags # Used to store the response data of each node at each time step, # the index is time step, node, coordinate dimension node_disp = np.zeros((num_node, 3)) node_vel = np.zeros((num_node, 3)) node_accel = np.zeros((num_node, 3)) # Used to store the deformed coordinate data of each node at each time step, # the index is time step, node, coordinate dimension node_deform_coord = np.zeros((num_node, 3)) for i, Tag in enumerate(node_tags): coord = ops.nodeCoord(Tag) disp = ops.nodeDisp(Tag) vel = ops.nodeVel(Tag) accel = ops.nodeAccel(Tag) if len(coord) == 1: coord.extend([0, 0]) disp.extend([0, 0]) vel.extend([0, 0]) accel.extend([0, 0]) elif len(coord) == 2: if len(disp) in [2, 3]: coord.extend([0]) disp = disp[:2] disp.extend([0]) vel = vel[:2] vel.extend([0]) accel = accel[:2] accel.extend([0]) else: coord.extend([0]) disp = disp[:2] disp.extend([0, 0]) vel = vel[:2] vel.extend([0, 0]) accel = accel[:2] accel.extend([0, 0]) else: disp = disp[:3] # ignore the rotation vel = vel[:3] accel = accel[:3] node_disp[i] = disp node_vel[i] = vel node_accel[i] = accel node_deform_coord[i] = [disp[ii] + coord[ii] for ii in range(3)] self.node_resp_steps["disp"].append(node_disp) self.node_resp_steps["vel"].append(node_vel) self.node_resp_steps["accel"].append(node_accel) if model_update: if self.step_node_track == self.model_info_steps['step_track']: for name in self.model_info.keys(): self.model_info_steps[name].append(self.model_info[name]) self.model_info_steps['step_track'] += 1 if self.step_node_track == self.cells_steps['step_track']: for name in self.cells.keys(): self.cells_steps[name].append(self.cells[name]) self.cells_steps['step_track'] += 1 else: if self.step_node_track == 0: self.model_info_steps.update(self.model_info) self.cells_steps.update(self.cells) # -------------------------------- self.model_update = model_update self.step_node_track += 1 # -------------------------------- if save_file: if self.step_node_track >= num_steps or ops.getTime() >= total_time or stop_cond: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: n = len(self.node_resp_steps['disp']) f.create_dataset("Nsteps", data=n) grp1 = f.create_group("ModelInfoSteps") grp2 = f.create_group("CellSteps") grp3 = f.create_group("NodeRespSteps") for name, value in self.model_info_steps.items(): if name not in ['step_track']: if model_update: subgrp = grp1.create_group(name) for i in range(n): subgrp.create_dataset(f"step{i + 1}", data=value[i]) else: grp1.create_dataset(name, data=value) for name, value in self.cells_steps.items(): if name not in ['step_track']: if model_update: subgrp = grp2.create_group(name) for i in range(n): subgrp.create_dataset(f"step{i + 1}", data=value[i]) else: grp2.create_dataset(name, data=value) for name, value in self.node_resp_steps.items(): subgrp = grp3.create_group(name) for i in range(n): subgrp.create_dataset(f"step{i + 1}", data=value[i]) print(f"Node response data saved in {output_filename}!")
[docs] def get_frame_resp_step(self, num_steps: int = 100000000000, total_time: float = 100000000000, stop_cond: bool = False, save_file: str = "BeamRespStepData-1.hdf5" ): """Get the response data step by step. .. note:: You need to call this function at each analysis step in OpenSees. The advantage is that you can modify the iterative algorithm at each analysis step to facilitate convergence. Parameters ---------- num_steps: int, default=100000000000 Total number of steps, set to determine when to save data. total_time: float, default=100000000000 Total analysis time, set to determine when to save data. You can specify one of the parameters *num_steps* and `total_time`. If both are used, it depends on which one arrives first. stop_cond: bool, default = False Condition used to determine when data is saved if ``num_steps`` and ``total_time`` unavailable. For example, stop_cond = ops.nodeDisp(nodeTag, 1) >= 0.1, i.e., once the displacement of node with tag nodeTag and dof 1 is greater than 0.1, the loop is terminated to save the data. save_file: str, default='BeamRespStepData-1.hdf5' The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. You need to specify different suffixes to distinguish between the different analysis cases. Such as "BeamRespStepData-1.hdf5", "BeamRespStepData-2.hdf5", etc. Returns ------- None """ if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) ele_tags = ops.getEleTags() ele_tags.sort() beam_tags = [] beam_node_tags = [] beam_node_map = dict() for i, eletag in enumerate(ele_tags): if ops.getEleClassTags(eletag)[0] in ELE_TAG_Beam: beam_tags.append(eletag) ele_nodes = ops.eleNodes(eletag) if ele_nodes[0] not in beam_node_tags: beam_node_tags.append(ele_nodes[0]) if ele_nodes[1] not in beam_node_tags: beam_node_tags.append(ele_nodes[1]) beam_node_map[eletag] = ele_nodes beam_node_coords = [] node_coord_map = dict() for i, nodetag in enumerate(beam_node_tags): coord = ops.nodeCoord(nodetag) model_dim = len(coord) if model_dim == 1: coord.extend([0, 0]) elif model_dim == 2: coord.extend([0]) beam_node_coords.append(coord) node_coord_map[nodetag] = i beam_node_coords = np.array(beam_node_coords) beam_cells = [] xlocals = [] ylocals = [] zlocals = [] for i, eletag in enumerate(beam_tags): node1, node2 = beam_node_map[eletag] idx_i, idx_j = node_coord_map[node1], node_coord_map[node2] beam_cells.append([2, idx_i, idx_j]) xlocal = ops.eleResponse(eletag, "xlocal") ylocal = ops.eleResponse(eletag, "ylocal") zlocal = ops.eleResponse(eletag, "zlocal") xlocals.append(np.array(xlocal) / np.linalg.norm(xlocal)) ylocals.append(np.array(ylocal) / np.linalg.norm(ylocal)) zlocals.append(np.array(zlocal) / np.linalg.norm(zlocal)) xlocals = np.array(xlocals) ylocals = np.array(ylocals) zlocals = np.array(zlocals) beam_cells = np.array(beam_cells) bounds = np.array(ops.nodeBounds()) self.beam_infos['beam_tags'] = beam_tags self.beam_infos['beam_node_coords'] = beam_node_coords self.beam_infos['beam_cells'] = beam_cells self.beam_infos['xlocal'] = xlocals self.beam_infos['ylocal'] = ylocals self.beam_infos['zlocal'] = zlocals self.beam_infos['bounds'] = bounds beam_resp_steps = [] for eletag in beam_tags: local_forces = ops.eleResponse(eletag, "localForce") if len(local_forces) == 6: local_forces = [local_forces[0], local_forces[1], 0, 0, 0, local_forces[2], local_forces[3], local_forces[4], 0, 0, 0, local_forces[5]] # for ii in range(6): # local_forces[ii] = -local_forces[ii] beam_resp_steps.append(local_forces) beam_resp_steps = np.array(beam_resp_steps) self.beam_resp_step['localForces'].append(beam_resp_steps) # ---------------------------------------------------------------- self.step_beam_track += 1 # ------------------------------------------ if save_file: if self.step_beam_track >= num_steps or ops.getTime() >= total_time or stop_cond: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: n = len(self.beam_resp_step['localForces']) f.create_dataset("Nsteps", data=n) grp1 = f.create_group("BeamInfos") grp2 = f.create_group("BeamRespSteps") for name, value in self.beam_infos.items(): grp1.create_dataset(name, data=value) for name, value in self.beam_resp_step.items(): subgrp = grp2.create_group(name) for i in range(n): subgrp.create_dataset(f"step{i + 1}", data=value[i]) print(f"Frame elements response data saved in {output_filename}!")
[docs] def get_fiber_data(self, ele_sec: list[tuple[int, int]], save_file: str = 'FiberData.hdf5'): """Get data from the section assigned by parameter ele_sec. Parameters ---------- ele_sec: list[tuple[int, int]] A list or tuple composed of element tag and sectag. e.g., [(ele1, sec1), (ele2, sec2), ... , (elen, secn)], The section is attached to an element in the order from end i to end j of that element. save_file: str, default='FiberData.hdf5' The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. Returns ------- None """ if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) self.fiber_sec_tags = ele_sec for ele_sec_i in ele_sec: key = f"{ele_sec_i[0]}-{ele_sec_i[1]}" self.fiber_sec_data[key] = None # get data for ele_sec_i in self.fiber_sec_tags: ele_tag = ele_sec_i[0] sec_tag = ele_sec_i[1] key = f"{ele_sec_i[0]}-{ele_sec_i[1]}" fiber_data = _get_fiber_sec_data(ele_tag, sec_tag) self.fiber_sec_data[key] = fiber_data # --------------------------------------------- if save_file: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: for name, value in self.fiber_sec_data.items(): f.create_dataset(name, data=value) print(f"Fiber section data saved in {output_filename}!")
[docs] def get_fiber_resp_step(self, num_steps: int = 100000000000, total_time: float = 100000000000, stop_cond: bool = False, save_file: str = "FiberRespStepData-1.hdf5"): """Get analysis step data for fiber section. Parameters ---------- num_steps: int, default=100000000000 Total number of steps, set to determine when to save data. total_time: float, default=100000000000 Total analysis time, set to determine when to save data. You can specify one of the parameters *num_steps* and `total_time`. If both are used, it depends on which one arrives first. stop_cond: bool, default = False Condition used to determine when data is saved if ``num_steps`` and ``total_time`` unavailable. For example, stop_cond = ops.nodeDisp(nodeTag, 1) >= 0.1, i.e., once the displacement of node with tag nodeTag and dof 1 is greater than 0.1, the loop is terminated to save the data. save_file: str, default='FiberRespStepData-1.hdf5' The file name that data saved. If None of False, the data will not be saved. .. warning:: Be careful not to include any path, only filename, the file will be saved to the directory ``results_dir``. You need to specify different suffixes to distinguish between the different analysis cases. Such as "FiberRespStepData-1.hdf5", "FiberRespStepData-2.hdf5", etc. Returns ------- None """ if save_file: check_file(save_file, ['.hdf5', '.h5', '.he5']) if not self.fiber_sec_data: raise ValueError( "Run get_fiber_step_data must run get_fiber_data() in advance!" ) if self.step_fiber_track == 0: for ele_sec_i in self.fiber_sec_tags: key = f"{ele_sec_i[0]}-{ele_sec_i[1]}" self.fiber_sec_step_data[key] = [] for ele_sec_i in self.fiber_sec_tags: ele_tag = ele_sec_i[0] sec_tag = ele_sec_i[1] key = f"{ele_sec_i[0]}-{ele_sec_i[1]}" fiber_data = _get_fiber_sec_data(ele_tag, sec_tag) defo_fo = ops.eleResponse(ele_tag, "section", sec_tag, "forceAndDeformation") if len(defo_fo) == 6: defo_fo = [defo_fo[0], defo_fo[1], 0., defo_fo[2], defo_fo[3], defo_fo[4], 0., defo_fo[5]] sec_defo_fo = np.array([defo_fo] * fiber_data.shape[0], dtype=float) data = np.hstack([fiber_data, sec_defo_fo]) self.fiber_sec_step_data[key].append(data) # ------------------------ self.step_fiber_track += 1 # ------------------------ if save_file: if self.step_fiber_track >= num_steps or ops.getTime() >= total_time or stop_cond: output_filename = self.out_dir + '/' + save_file with h5py.File(output_filename, "w") as f: f.create_dataset("Nsteps", data=self.step_fiber_track) grp = f.create_group("FiberRespSteps") for name, value in self.fiber_sec_step_data.items(): subgrp = grp.create_group(name) for i in range(self.step_fiber_track): subgrp.create_dataset(f"step{i + 1}", data=value[i]) print(f"Fiber section responses data saved in {output_filename}!")
def _get_fiber_sec_data(ele_tag: int, sec_tag: int = 1) -> ArrayLike: """Get the fiber sec data for a beam element. Parameters ---------- ele_tag: int The element tag to which the section is to be displayed. sec_tag: int Which integration point section is displayed, tag from 1 from segment i to j. Returns ------- fiber_data: ArrayLike """ # Extract fiber data using eleResponse() command fiber_data = ops.eleResponse(ele_tag, "section", sec_tag, "fiberData2") if len(fiber_data) == 0: fiber_data = ops.eleResponse(ele_tag, "section", "fiberData2") # From column 1 to 6: "yCoord", "zCoord", "area", 'mat', "stress", "strain" fiber_data = np.array(fiber_data).reshape((-1, 6)) # 变形为6列数组 return fiber_data def sort_xy(x, y): """ Sort points counterclockwise """ x0 = np.mean(x) y0 = np.mean(y) r = np.sqrt((x - x0) ** 2 + (y - y0) ** 2) angles = np.where( (y - y0) >= 0, np.arccos((x - x0) / r), 4 * np.pi - np.arccos((x - x0) / r) ) mask = np.argsort(angles) x_max = np.max(x) if x[mask][0] != x_max: mask = np.roll(mask, 1) return mask def counter_clockwise(points, tag): """ Used to sort the points on a face counterclockwise """ x = np.array([point[0] for point in points]) y = np.array([point[1] for point in points]) z = np.array([point[2] for point in points]) if all(np.abs(x - x[0]) < 1e-6): # yz # def algo(point): # return (math.atan2(point[2] - z_center, point[1] - y_center) + 2 * math.pi) % (2*math.pi) # sorted_points = sorted(points,key = algo ) index = sort_xy(y, z) sorted_points = list(zip(x[index], y[index], z[index])) sorted_id = [points.index(i) for i in sorted_points] sorted_tag = [tag[i] for i in sorted_id] elif all(np.abs(y - y[0]) < 1e-6): # xz # def algo(point): # return (math.atan2(point[2] - z_center, point[0] - x_center) + 2 * math.pi) % (2*math.pi) # sorted_points = sorted(points,key = algo ) index = sort_xy(x, z) sorted_points = list(zip(x[index], y[index], z[index])) sorted_id = [points.index(i) for i in sorted_points] sorted_tag = [tag[i] for i in sorted_id] else: # def algo(point): # return (math.atan2(point[1] - y_center, point[0] - x_center) + 2 * math.pi) % (2*math.pi) # sorted_points = sorted(points,key = algo ) index = sort_xy(x, y) sorted_points = list(zip(x[index], y[index], z[index])) sorted_id = [points.index(i) for i in sorted_points] sorted_tag = [tag[i] for i in sorted_id] return sorted_tag def _lines_angle(v1, v2): # return np.arctan2(np.linalg.norm(np.cross(v1, v2)), np.dot(v1, v2)) x = np.array(v1) y = np.array(v2) l_x = np.sqrt(x.dot(x)) l_y = np.sqrt(y.dot(y)) cos_ = x.dot(y) / (l_x * l_y) angle_r = np.arccos(cos_) return angle_r