diff --git a/README.md b/README.md
index a6d5b6d..e426ee4 100644
--- a/README.md
+++ b/README.md
@@ -30,13 +30,30 @@
- [2.1. Prerequisites](#21-prerequisites)
- [2.2. Installation](#22-installation)
- [2.2.1. Production](#221-production)
- - [2.2.1.1. One line command](#2211-one-line-command)
- - [2.2.1.2. Install directly from repo](#2212-install-directly-from-repo)
- - [2.2.1.3. Install from Pypi release](#2213-install-from-pypi-release)
+ - [2.2.1.1. Install directly from repo](#2211-install-directly-from-repo)
+ - [2.2.1.2. Install from Pypi release](#2212-install-from-pypi-release)
- [2.2.2. Development](#222-development)
- [3. Usage](#3-usage)
- [3.1. GUI](#31-gui)
- [3.2. Layout Documentation](#32-layout-documentation)
+ - [Layout Map](#layout-map)
+ - [Initialize](#initialize)
+ - [Parent Level](#parent-level)
+ - [Sub-Modules](#sub-modules)
+ - [Model](#model)
+ - [Element](#element)
+ - [Point](#point)
+ - [Frame](#frame)
+ - [Database](#database)
+ - [Select](#select)
+ - [Loads](#loads)
+ - [Load Patterns](#load-patterns)
+ - [Load Cases](#load-cases)
+ - [Modal](#modal)
+ - [Analyze](#analyze)
+ - [Results](#results)
+ - [Material](#material)
+ - [Rebar](#rebar)
- [4. Roadmap](#4-roadmap)
- [5. License](#5-license)
- [6. Contact](#6-contact)
@@ -59,21 +76,7 @@
#### 2.2.1. Production
-##### 2.2.1.1. One line command
-
-1. Press `Win` + `R` to open the Run console
-2. Type "cmd" and press enter
-3. Type the following and press `Enter`
-
- ```cmd
- curl -sSL https://links.struct.work/SAP2000 > %USERPROFILE%\Desktop\install.bat
-
- ```
-
-4. You should now have a `install.bat` file in your desktop
-5. Move this file to your desired installtion directory and run to install the `AK_SAP` module
-
-##### 2.2.1.2. Install directly from repo
+##### 2.2.1.1. Install directly from repo
Clone repo and Install with flit
@@ -95,7 +98,7 @@ pip install flit
flit install --deps production --extras gui
```
-##### 2.2.1.3. Install from Pypi release
+##### 2.2.1.2. Install from Pypi release
```bash
pip install ak_sap
@@ -114,6 +117,15 @@ pip install flit
flit install --pth-file
```
+Updating Docs:
+
+- Update the [Usage.ipynb](./documentation/Usage.ipynb).
+- Open `cmd.exe` to run
+
+ ```bash
+ update-doc
+ ```
+
## 3. Usage
@@ -149,21 +161,389 @@ The repo has an optional streamlit GUI for the wrapper. Checkout [`GUI.md`](/doc
### 3.2. Layout Documentation
-To see module level usage, check out the [`Layout.md`](/documentation/Layout.md) or [`Usage.ipynb`](/documentation/Usage.ipynb)
+
+#### Layout Map
+
+![MindMap](assets/mindmap.svg)
+
+#### Initialize
+
+Usage Examples:
+
+```python
+from ak_sap import debug, Sap2000Wrapper
+debug(status=False)
+
+#Initialize
+sap = Sap2000Wrapper(attach_to_exist=True) #Attach to existing opened model
+sap = Sap2000Wrapper(attach_to_exist=False) #Create new blank model from latest SAP2000
+## Create blank model from a custom version of SAP2000
+sap = Sap2000Wrapper(attach_to_exist=False, program_path=r'Path\to\SAP2000.exe')
+```
+
+#### Parent Level
+
+Usage Examples:
+
+```python
+sap.hide() #Hide the SAP2000 window
+sap.unhide() #Unhides SAP2000 window
+sap.ishidden #Check if window is hidden
+sap.version #Returns SAP2000 version number
+sap.api_version #Returns Sap0API version number
+sap.exit(save=False) #Exit the application
+
+sap.save(r'\Path\to\save\file.sdb')
+```
+
+#### Sub-Modules
+##### Model
+
+Collection of methods and attributes that control changes to the model as a whole
+
+Usage Examples:
+
+```python
+sap.Model.units #Returns current model units
+sap.Model.units_database #Returns Internal Database units
+sap.Model.set_units(value='N_m_C') #Changes the present units of model
+
+sap.Model.merge_tol #retrieves the value of the program auto merge tolerance
+sap.Model.set_merge_tol(0.05) #sets the program auto merge tolerance
+
+sap.Model.filepath #Returns filepath of current file
+
+sap.Model.is_locked #Returns if the model is locked
+sap.Model.lock() #Locks the model
+sap.Model.unlock() #Unlocks the model
+
+sap.Model.project_info #Returns a dict of Project Info
+##Set project info, use `.project_info` to see available keys
+sap.Model.set_project_info({'Design Code': 'BCBC 2018'})
+
+sap.Model.logs #Retrieve user comments and logs
+sap.Model.set_logs('Add this comment') #Adds user comments/logs
+```
+
+##### Element
+
+Collection of methods and attributes that apply changes to elements in the model
+
+Usage Examples:
+
+```python
+object = sap.Object
+object.move_selected(dx=0.5, dy=0, dz=1.0) #Move selected object
+object.copy(dx=0.5, dy=0, dz=0, num=10)#copy selected object
+
+#Mirror and create object
+from ak_sap import Coord
+pt1 = Coord(x=10, y=20, z=0)
+p2 = Coord(x=10, y=30, z=0)
+object.mirror(plane='Z', coord1=pt1, coord2=pt2) #Mirror replicate selected obj.
+```
+
+###### Point
+
+Manipulate Point Elements
+
+Usage Examples:
+
+```python
+points = sap.Object.Point
+len(points) #list number of points in model
+points.add_by_coord((1,2,3)) #Add point to model
+points.is_selected(name='1') #Check if point is selected
+points.selected() #Yields selected points
+points.all() #Lists all defined points
+points.rename(old_name='1', new_name='1_1') #Rename point
+points.check_obj_legal(name='1') #Asserts point's existance
+points.delete(name='1') #Delete point
+
+#Manipilate
+points.deselect_all() #Deselect all points
+points.select(name='1') #Select a single point
+points.align(axis='Z', ordinate = 100) #Align selected points
+points.deselect(name='1') #Deselect a single point
+
+# Extrude point to frame
+points.extrude(
+ point_name='3',
+ property_name='FSec1',
+ dx=0, dy=144, dz=0,
+ num_frames=3
+)
+points.merge(tolerance=2) #Merge points that are within tol
+points.change_coord(name='1', x=0, y=0, z=0)#Change point coordinate
+```
+
+###### Frame
+
+Manipulate Frame Elements
+
+Usage Examples:
+
+```python
+frames = sap.Object.Frame
+len(frames) #list number of frames in model
+frames.is_selected(name='1') #Check if frame is selected
+frames.selected() #Yields selected frames
+frames.all() #Lists all defined frames
+frames.rename(old_name='1', new_name='1_1') #Rename frame
+frames.check_obj_legal(name='1') #Asserts frame's existance
+frames.get_section(name='1') #Get the assigned Section name
+frames.get_points(name='1') #Get points connected to frame
+
+#Manipulation
+frames.delete(name='1') #Delete frame
+frames.divide_by_distance(name='1',
+ dist=0.5,Iend=True) #Divide frame by distance
+frames.divide_by_intersection(name='2') #Divide at selected intersections
+frames.divide_by_ratio(name='3',ratio=0.3)#Divide at selected ratio
+frames.join('2','3') #Join Colinear frames
+frames.change_points(name='1', point1='1', point2='3') #Change connected points of frame
+
+# Extrude frames to area
+frames.extrude(
+ frame_name='8',
+ property_name='Default',
+ dx=0, dy=144, dz=0,
+ num_areas=3,
+ del_frame=True
+)
+
+# Get frame properties
+frames.Prop.rename(old_name="FSEC1", new_name="MySection") #Rename frame property
+frames.Prop.total() #Total # of defined frame properties
+```
+
+##### Database
+
+Control the database values
+
+Usage Examples:
+
+```python
+tables = sap.Table
+tables.list_available() #Lists available database tables
+tables.list_all() #Lists all database tables
+tables.get_table_fields('Analysis Options') #Get table Field Info
+tables.get(TableKey='Load Case Definitions', dataframe=False) #Get Table data in `list[dict]` format
+df = tables.get('Material Properties 01 - General') #Get Table data in pandas dataframe
+
+# Update Table
+df.iloc[0,0] = 'New Value'
+tables.update(TableKey='Material Properties 01 - General', data=df, apply=True)
+```
+
+##### Select
+
+Usage Examples:
+
+```python
+select = sap.Select
+
+select.all() #Select all objects
+select.clear() #Deselect all objects
+
+select.constraint(name='Diaph1') #Select points in constraint
+select.constraint(name='Diaph1', reverse=True) #Deselect points in constraint
+
+select.invert() #Invert selections
+select.selected #Returns list of selected objects
+select.previous() #restores the previous selection
+
+#Selection based on plane
+select.in_plane(pointname='1', plane='XY') #Select in XY plane
+select.in_plane(pointname='2', plane='YZ', reverse=False) #Deselect
+
+#Select by property
+select.property(type='Area', name='ASEC1')
+select.property(type='Cable', name='CAB1', reverse=True)
+select.property(type='Frame', name='FSEC1')
+select.property(type='Link', name='GAP1', reverse=True)
+select.property(type='Material', name='A992Fy50')
+select.property(type='Solid', name='SOLID1', reverse=True)
+select.property(type='Tendon', name='TEN1')
+```
+
+##### Loads
+
+Control the definition and assignments of loads.
+###### Load Patterns
+
+Usage Examples:
+
+```python
+pattern = sap.Load.Pattern
+len(pattern) # List the number of load patterns defined
+pattern.list_all() #List defined load patterns
+pattern.rename('Dead', 'Live') #Rename previously defined pattern
+pattern.delete(name='Dead') #Delete a load pattern
+
+pattern.get_selfwt_multiplier('DEAD') #Get defined self weight multiplier
+pattern.set_selfwt_multiplier('DEAD', 1.15) #Set self weight multiplier
+
+pattern.get_loadtype('DEAD') #Get the defined load type
+pattern.set_loadtype('DEAD', pattern_type='LIVE') #Set the defined load type
+
+#Add a Live load case with name "Custom Live", a 1.15x self weight multiplier and also generate an accompanying load case
+pattern.add(name='Custom Live', pattern_type='LIVE',
+ selfwt_multiplier=1.15, add_case=True)
+```
+
+###### Load Cases
+
+Usage Examples:
+
+```python
+cases = sap.Load.Case
+len(cases) #returns total # of defined cases
+cases.total(casetype='MODAL') #Get # of modal load cases
+cases.list_all() #List all load cases
+cases.rename('DEAD','WATER') #Rename existing load case
+cases.case_info(name='DEAD') #Get the Case type information
+cases.set_type(name='DEAD', casetype='LINEAR_STATIC') #Change the case type of existing load case
+```
+
+###### Modal
+
+`sap.Load.Modal`
+####### Eigen
+
+Usage Examples:
+
+```python
+eigen = sap.Load.Modal.Eigen
+eigen.set_case(case_name="LCASE1") #Set a Eigen Modal case
+
+eigen.set_initial_case(case_name='LCASE1', initial_case='DEAD') #Set initial stiffness case
+eigen.get_initial_case(case_name="LCASE1") #Get the Initial Case
+
+eigen.get_loads(case_name='LCASE1') #Get the load data
+
+#Set Eigen parameters
+eigen.set_parameters(
+ case_name='LCASE1',
+ EigenShiftFreq=0.05, #cyc/s
+ EigenCutOff=0.0001, #cyc/s
+ EigenTolerance=0.00000001,
+ AllowAutoFreqShift=True
+)
+eigen.get_parameters(case_name='LCASE1') #Get Parameters
+
+eigen.set_number_modes(case_name='LCASE1', max=10, min=5) #set number of modes
+eigen.get_number_modes(case_name='LCASE1') #get number of modes
+```
+
+####### Ritz
+
+Usage Examples:
+
+```python
+ritz = sap.Load.Modal.Ritz
+ritz.set_case(case_name="LCASE1") #Set a Eigen Modal case
+
+ritz.set_initial_case(case_name='LCASE1', initial_case='DEAD') #Set initial stiffness case
+ritz.get_initial_case(case_name="LCASE1") #Get the Initial Case
+
+ritz.get_loads(case_name='LCASE1') #Get the load data
+
+ritz.set_number_modes(case_name='LCASE1', max=10, min=5) #set number of modes
+ritz.get_number_modes(case_name='LCASE1') #get number of modes
+```
+
+##### Analyze
+
+Usage Examples:
+
+```python
+analyze = sap.Analyze
+analyze.create_model() #Create analysis model
+analyze.run() #Runs the analysis
+analyze.case_status() #retrieves the status for all load cases.
+analyze.get_run_flag() #retrieves the run flags for all cases
+analyze.set_run_flag(case='MODAL', status=True) # Set case to run
+analyze.get_solver() #Get solver info
+
+#Set solver options
+analyze.set_solver(
+ SolverType='Standard',
+ SolverProcessType='Auto',
+ NumberParallelRuns=0,
+ StiffCase=''
+)
+```
+
+##### Results
+
+Manipulate Results from SAP2000
+
+Usage Examples:
+
+```python
+results = sap.Results
+
+setup = sap.Results.Setup
+setup.clear_casecombo() #Deselect all Case&Combo for results
+setup.select_case(casename='DEAD') #sets an load case selected for output flag.
+setup.is_selected_case(casename='DEAD') #checks if an load case is selected for output.
+setup.select_combo(comboname='DEAD') #sets an load combo selected for output flag.
+setup.is_selected_combo(comboname='COMB1') #checks if an load combo is selected for output.
+setup.set_rxn_loc_get(x=0.5, y=0.5, z=5) #sets coordinates of the locn at which the base reactions are reported.
+setup.base_rxn_loc_get() #retrieves coordinates of the locn at which the base reactions are reported.
+
+results.joint_reactions(jointname='1') #Get Joint reactions as list of dict
+results.joint_displacements(jointname='1') #Get Joint displacements as list of dict
+results.joint_accelerations(jointname='1') #Get joint accelerations
+results.joint_velocities(jointname='1') #Get joint velocities
+
+results.delete('MODAL') #Delete results of `MODAL` case
+results.delete('All') #Delete results of all cases
+```
+
+##### Material
+
+Usage Examples:
+
+```python
+material = sap.Material
+material.rename(old="4000Psi", new="MatConc") #Rename existing material
+material.total() #Total # of defined material properties
+material.delete(name='4000Psi') #Delete existing material property
+material.list_all() #List all defined Material Properties
+material.get_props(name='4000Psi') #Returns basic material property data
+material.add(name='Steel', material_type='Steel') #Initialze Material Property
+material.set_isotropic(name='Steel', E=29500, poisson=0.25, thermal_coeff=6e-06) #Set isotropic material properties
+material.set_density(name='Steel', mass_per_vol=0.00029) #set density
+```
+
+###### Rebar
+
+Usage Examples:
+
+```python
+rebar = sap.Material.Rebar
+rebar.rename(old='R1', new='MyRebar') #Rename rebar
+rebar.total() #Total # of defined rebar properties
+rebar.delete(name='R1') #Delete existing rebar property
+rebar.list_all() #List all defined rebar Properties
+rebar.set_prop(name='MyRebar2', area=1.05, dia=1.0) #Define a rebar property
+rebar.get_prop(name='MyRebar2') #Get rebar property
+```
+
+
## 4. Roadmap
-![Roadmap/Checklist](/documentation/assets/mindmap.png)
-
-- [ ] Generate Load Patterns
-- [ ] Generate Load Cases
+- [x] Generate Load Patterns
+- [x] Generate Load Cases
- [ ] Apply Loads
- [ ] Points
- [ ] Area
- [ ] Line
-- [ ] Export joint reactions to Hilti-Profis file
-- [ ] Export Frame/Wall sections to S-Concrete
+- [x] Export joint reactions to Hilti-Profis file
## 5. License
diff --git a/documentation/Layout.md b/documentation/Layout.md
index 07f1d27..88e4339 100644
--- a/documentation/Layout.md
+++ b/documentation/Layout.md
@@ -9,6 +9,7 @@
- [Point](#point)
- [Frame](#frame)
- [Database](#database)
+ - [Select](#select)
- [Loads](#loads)
- [Load Patterns](#load-patterns)
- [Load Cases](#load-cases)
@@ -49,6 +50,7 @@ sap.unhide() #Unhides SAP2000 window
sap.ishidden #Check if window is hidden
sap.version #Returns SAP2000 version number
sap.api_version #Returns Sap0API version number
+sap.exit(save=False) #Exit the application
sap.save(r'\Path\to\save\file.sdb')
```
@@ -123,6 +125,13 @@ points.select(name='1') #Select a single point
points.align(axis='Z', ordinate = 100) #Align selected points
points.deselect(name='1') #Deselect a single point
+# Extrude point to frame
+points.extrude(
+ point_name='3',
+ property_name='FSec1',
+ dx=0, dy=144, dz=0,
+ num_frames=3
+)
points.merge(tolerance=2) #Merge points that are within tol
points.change_coord(name='1', x=0, y=0, z=0)#Change point coordinate
```
@@ -153,6 +162,15 @@ frames.divide_by_ratio(name='3',ratio=0.3)#Divide at selected ratio
frames.join('2','3') #Join Colinear frames
frames.change_points(name='1', point1='1', point2='3') #Change connected points of frame
+# Extrude frames to area
+frames.extrude(
+ frame_name='8',
+ property_name='Default',
+ dx=0, dy=144, dz=0,
+ num_areas=3,
+ del_frame=True
+)
+
# Get frame properties
frames.Prop.rename(old_name="FSEC1", new_name="MySection") #Rename frame property
frames.Prop.total() #Total # of defined frame properties
@@ -178,12 +196,16 @@ tables.update(TableKey='Material Properties 01 - General', data=df, apply=True)
```
## Select
-elect = sap.Select
-select.all() #Select all objects
-select.clear() #Deselect all objects
+Usage Examples:
-select.constraint(name='Diaph1')#Select points in constraint
+```python
+select = sap.Select
+
+select.all() #Select all objects
+select.clear() #Deselect all objects
+
+select.constraint(name='Diaph1') #Select points in constraint
select.constraint(name='Diaph1', reverse=True) #Deselect points in constraint
select.invert() #Invert selections
@@ -191,7 +213,7 @@ select.selected #Returns list of selected objects
select.previous() #restores the previous selection
#Selection based on plane
-select.in_plane(pointname='1', plane='XY') #Select in XY plane
+select.in_plane(pointname='1', plane='XY') #Select in XY plane
select.in_plane(pointname='2', plane='YZ', reverse=False) #Deselect
#Select by property
@@ -202,6 +224,8 @@ select.property(type='Link', name='GAP1', reverse=True)
select.property(type='Material', name='A992Fy50')
select.property(type='Solid', name='SOLID1', reverse=True)
select.property(type='Tendon', name='TEN1')
+```
+
## Loads
Control the definition and assignments of loads.
@@ -297,7 +321,7 @@ analyze = sap.Analyze
analyze.create_model() #Create analysis model
analyze.run() #Runs the analysis
analyze.case_status() #retrieves the status for all load cases.
-analyze.get_run_status() #retrieves the run flags for all cases
+analyze.get_run_flag() #retrieves the run flags for all cases
analyze.set_run_flag(case='MODAL', status=True) # Set case to run
analyze.get_solver() #Get solver info
diff --git a/documentation/Usage.ipynb b/documentation/Usage.ipynb
index 06af808..c489dd4 100644
--- a/documentation/Usage.ipynb
+++ b/documentation/Usage.ipynb
@@ -41,6 +41,7 @@
"sap.ishidden #Check if window is hidden\n",
"sap.version #Returns SAP2000 version number\n",
"sap.api_version #Returns Sap0API version number\n",
+ "sap.exit(save=False) #Exit the application\n",
"\n",
"sap.save(r'\\Path\\to\\save\\file.sdb')"
]
@@ -145,6 +146,13 @@
"points.align(axis='Z', ordinate = 100) #Align selected points\n",
"points.deselect(name='1') #Deselect a single point\n",
"\n",
+ "# Extrude point to frame\n",
+ "points.extrude(\n",
+ " point_name='3',\n",
+ " property_name='FSec1',\n",
+ " dx=0, dy=144, dz=0,\n",
+ " num_frames=3\n",
+ ")\n",
"points.merge(tolerance=2) #Merge points that are within tol\n",
"points.change_coord(name='1', x=0, y=0, z=0)#Change point coordinate"
]
@@ -183,6 +191,15 @@
"frames.join('2','3') #Join Colinear frames\n",
"frames.change_points(name='1', point1='1', point2='3') #Change connected points of frame\n",
"\n",
+ "# Extrude frames to area\n",
+ "frames.extrude(\n",
+ " frame_name='8',\n",
+ " property_name='Default',\n",
+ " dx=0, dy=144, dz=0,\n",
+ " num_areas=3,\n",
+ " del_frame=True\n",
+ ")\n",
+ "\n",
"# Get frame properties\n",
"frames.Prop.rename(old_name=\"FSEC1\", new_name=\"MySection\") #Rename frame property\n",
"frames.Prop.total() #Total # of defined frame properties"
@@ -223,15 +240,21 @@
]
},
{
- "cell_type": "markdown",
- "metadata": {},
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "outputs": [],
"source": [
"select = sap.Select\n",
"\n",
- "select.all() #Select all objects\n",
- "select.clear() #Deselect all objects\n",
+ "select.all() #Select all objects\n",
+ "select.clear() #Deselect all objects\n",
"\n",
- "select.constraint(name='Diaph1')#Select points in constraint\n",
+ "select.constraint(name='Diaph1') #Select points in constraint\n",
"select.constraint(name='Diaph1', reverse=True) #Deselect points in constraint\n",
"\n",
"select.invert() #Invert selections\n",
@@ -239,7 +262,7 @@
"select.previous() #restores the previous selection\n",
"\n",
"#Selection based on plane\n",
- "select.in_plane(pointname='1', plane='XY') #Select in XY plane\n",
+ "select.in_plane(pointname='1', plane='XY') #Select in XY plane\n",
"select.in_plane(pointname='2', plane='YZ', reverse=False) #Deselect\n",
"\n",
"#Select by property\n",
@@ -399,7 +422,7 @@
"analyze.create_model() #Create analysis model\n",
"analyze.run() #Runs the analysis\n",
"analyze.case_status() #retrieves the status for all load cases.\n",
- "analyze.get_run_status() #retrieves the run flags for all cases\n",
+ "analyze.get_run_flag() #retrieves the run flags for all cases\n",
"analyze.set_run_flag(case='MODAL', status=True) # Set case to run\n",
"analyze.get_solver() #Get solver info\n",
"\n",
diff --git a/documentation/Usage/GUI.md b/documentation/Usage/GUI.md
index f851480..0065a1a 100644
--- a/documentation/Usage/GUI.md
+++ b/documentation/Usage/GUI.md
@@ -20,20 +20,19 @@ The package not comes pre-compiled with the streamlit package.
- Install dependencies
```bash
- pip install flit && flit install
+ pip install flit && flit install --extras gui
```
- Launch the app run
```bash
- python -m streamlit run Start_Here.py
+ gui
```
- Alternatively, In windows launch by executing the script
```cmd
- cd scripts
- run.bat
+ python -m streamlit run Start_Here.py
```
- Open up the SAP2000 model of your choice and click `Attach to Model`
diff --git a/documentation/assets/mindmap.svg b/documentation/assets/mindmap.svg
index 5ce8e9c..bf61cb9 100644
--- a/documentation/assets/mindmap.svg
+++ b/documentation/assets/mindmap.svg
@@ -1 +1,2 @@
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 31ed417..b864c5c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,9 +13,7 @@ dynamic = ["version", "description"]
dependencies = [
"comtypes==1.2.0",
"forallpeople==2.6.7",
- "pandas==2.1.3",
- "rich==13.7.0",
- "typer[all]==0.9.0"
+ "pandas==2.1.3"
]
[project.optional-dependencies]
@@ -32,6 +30,11 @@ gui = [
"hilti_profis==0.0.3"
]
+cli = [
+ "rich==13.7.0",
+ "typer[all]==0.9.0"
+]
+
test = [
"pytest==7.4.3"
]
@@ -40,4 +43,5 @@ test = [
Home = "https://github.com/rpakishore/ak_sap"
[project.scripts]
-app="ak_sap.gui.cli_app:app"
\ No newline at end of file
+gui="ak_sap.gui.gui_app:app"
+update-doc="ak_sap.cli.update_doc:app"
\ No newline at end of file
diff --git a/src/ak_sap/Analyze/main.py b/src/ak_sap/Analyze/main.py
index f63179e..0e0a30b 100644
--- a/src/ak_sap/Analyze/main.py
+++ b/src/ak_sap/Analyze/main.py
@@ -29,7 +29,7 @@ def case_status(self) -> dict:
Returns:
list[dict]: Cases and their current status.
"""
- return case_status(ret=self.__Analyze.GetCaseStatus()), 0
+ return case_status(ret=self.__Analyze.GetCaseStatus()), 0 # type: ignore
@smooth_sap_do
def get_run_flag(self) -> dict:
@@ -38,7 +38,7 @@ def get_run_flag(self) -> dict:
Returns:
dict: Loadcases and their run flags
"""
- return get_run_flag(ret=self.__Analyze.GetRunCaseFlag()), 0
+ return get_run_flag(ret=self.__Analyze.GetRunCaseFlag()), 0 # type: ignore
@smooth_sap_do
def set_run_flag(self, case: str, status: bool):
@@ -57,7 +57,7 @@ def get_solver(self) -> dict:
Returns:
dict: Solver Info
"""
- return get_solver(ret = self.__Analyze.GetSolverOption_3()), 0
+ return get_solver(ret = self.__Analyze.GetSolverOption_3()), 0 # type: ignore
@smooth_sap_do
def set_solver(self,
diff --git a/src/ak_sap/Loads/Modal/Eigen/main.py b/src/ak_sap/Loads/Modal/Eigen/main.py
index 75a615a..084ed81 100644
--- a/src/ak_sap/Loads/Modal/Eigen/main.py
+++ b/src/ak_sap/Loads/Modal/Eigen/main.py
@@ -4,6 +4,7 @@
class Eigen(MasterClass):
def __init__(self, mySapObject) -> None:
super().__init__(mySapObject=mySapObject)
+ assert self.SapModel is not None
self.ModalEigen = self.SapModel.LoadCases.ModalEigen
def __str__(self) -> str:
diff --git a/src/ak_sap/Loads/Modal/Ritz/main.py b/src/ak_sap/Loads/Modal/Ritz/main.py
index 06ed4ad..473eef3 100644
--- a/src/ak_sap/Loads/Modal/Ritz/main.py
+++ b/src/ak_sap/Loads/Modal/Ritz/main.py
@@ -4,6 +4,7 @@
class Ritz(MasterClass):
def __init__(self, mySapObject) -> None:
super().__init__(mySapObject=mySapObject)
+ assert self.SapModel is not None
self.ModalRitz = self.SapModel.LoadCases.ModalRitz
def __str__(self) -> str:
diff --git a/src/ak_sap/Object/frame.py b/src/ak_sap/Object/frame.py
index f9cdee3..4421913 100644
--- a/src/ak_sap/Object/frame.py
+++ b/src/ak_sap/Object/frame.py
@@ -7,19 +7,22 @@ def __init__(self, mySapObject) -> None:
super().__init__(mySapObject=mySapObject, ElemObj=mySapObject.SapModel.FrameObj)
self.__EditFrame = mySapObject.SapModel.EditFrame
+ self.__EditGeneral = mySapObject.SapModel.EditGeneral
+ self.__FrameObj = mySapObject.SapModel.FrameObj
+
self.Prop = Prop(mySapObject=mySapObject)
@smooth_sap_do
def get_section(self, name: str) -> str:
self.check_obj_legal(name=name)
- _ret = self.ElemObj.GetSection(name)
+ _ret = self.__FrameObj.GetSection(name)
return (_ret[0], _ret[-1]) # type: ignore
@smooth_sap_do
def get_points(self, name: str) -> tuple[str]:
"""retrieves the names of the point objects at each end of a specified frame object."""
#self.check_obj_legal(name=name)
- return self.ElemObj.GetPoints(name)
+ return self.__FrameObj.GetPoints(name)
@smooth_sap_do
def divide_by_distance(self, name: str, dist: float, Iend: bool=True) -> tuple[str]:
@@ -77,6 +80,24 @@ def change_points(self, name: str, point1: str, point2: str) -> bool:
"""
return self.__EditFrame.ChangeConnectivity(name, point1, point2)
+ @smooth_sap_do
+ def extrude(self, frame_name: str, dx: float, dy: float, dz: float, num_areas: int, property_name: str|None = None, del_frame: bool=False) -> list[str]:
+ """Creates new area objects by linearly extruding a specified frame obj.
+
+ Args:
+ frame_name (str): Name of existing frame to extrude
+ dx (float): x offset.
+ dy (float): y offset.
+ dz (float): z offset.
+ num_areas (int): number of area objects to create
+ property_name (str | None, optional): Name of a defined area section property to be used for the new obj. Defaults to None.
+ del_frame(bool, optional): If this item is True, the straight frame object indicated by the Name item is deleted after the extrusion is complete. Defaults to False.
+
+ Returns:
+ list[str]: array of the name of each area object created
+ """
+ return self.__EditGeneral.ExtrudeFrameToAreaLinear(frame_name, property_name, dx, dy, dz, num_areas, del_frame)
+
class Prop:
def __init__(self, mySapObject) -> None:
self.__mySapObject=mySapObject.SapModel
diff --git a/src/ak_sap/Object/obj.py b/src/ak_sap/Object/obj.py
index a61b9c1..7208bc8 100644
--- a/src/ak_sap/Object/obj.py
+++ b/src/ak_sap/Object/obj.py
@@ -21,7 +21,7 @@ def move_selected(self, dx: float, dy: float, dz: float) -> bool:
dy (float): y offsets
dz (float): z offsets
"""
- self.__EditGeneral.Move(dx, dy, dz)
+ return self.__EditGeneral.Move(dx, dy, dz)
@smooth_sap_do
def copy(self, dx: float, dy: float, dz: float, num: int) -> tuple:
diff --git a/src/ak_sap/Object/point.py b/src/ak_sap/Object/point.py
index 1ed1ca6..0bcaac7 100644
--- a/src/ak_sap/Object/point.py
+++ b/src/ak_sap/Object/point.py
@@ -9,6 +9,7 @@ def __init__(self, mySapObject) -> None:
super().__init__(mySapObject=mySapObject, ElemObj=mySapObject.SapModel.PointObj)
self.__EditPoint = mySapObject.SapModel.EditPoint
self.__PointObj = mySapObject.SapModel.PointObj
+ self.__EditGeneral = mySapObject.SapModel.EditGeneral
@smooth_sap_do
def add_by_coord(self, point: tuple[float, float, float], name: str='', coord_sys: str = 'Global') -> str:
@@ -18,7 +19,7 @@ def add_by_coord(self, point: tuple[float, float, float], name: str='', coord_sy
name (str, optional): Custom name for point. Defaults to ''.
coord_sys (str, optional): Name of coordinate system. Defaults to 'Global'.
"""
- return self.ElemObj.AddCartesian(*point, '', name, coord_sys)
+ return self.__PointObj.AddCartesian(*point, '', name, coord_sys)
@smooth_sap_do
def align(self, axis: Literal['X', 'Y', 'Z'], ordinate: float) -> tuple:
@@ -73,4 +74,21 @@ def change_coord(self, name: str, x: float, y: float, z: float) -> bool:
Returns:
bool: Success
"""
- return self.__EditPoint.ChangeCoordinates_1(name, x, y, z)
\ No newline at end of file
+ return self.__EditPoint.ChangeCoordinates_1(name, x, y, z)
+
+ @smooth_sap_do
+ def extrude(self, point_name: str, dx: float, dy: float, dz: float, num_frames: int, property_name: str|None = None) -> list[str]:
+ """Creates new frame objects by linearly extruding a specified point obj. into frame objects.
+
+ Args:
+ point_name (str): Name of existing point to extrude
+ dx (float): x offset.
+ dy (float): y offset.
+ dz (float): z offset.
+ num_frames (int): number of frame objects to create
+ property_name (str | None, optional): Name of a defined frame section property to be used for the new frame obj. Defaults to None.
+
+ Returns:
+ list[str]: array of the name of each frame object created
+ """
+ return self.__EditGeneral.ExtrudePointToFrameLinear(point_name, property_name, dx, dy, dz, num_frames)
\ No newline at end of file
diff --git a/src/ak_sap/Results/main.py b/src/ak_sap/Results/main.py
index 52cc1d6..17ca04a 100644
--- a/src/ak_sap/Results/main.py
+++ b/src/ak_sap/Results/main.py
@@ -18,7 +18,7 @@ def delete(self, casename: str|Literal['All']) -> bool:
Args:
casename (str | Literal['All']): name of an existing load case that is to have its results deleted.
"""
- return self.mySapObject.SapModel.Analyze.DeleteResykts(casename, casename.casefold() == 'all')
+ return self.mySapObject.SapModel.Analyze.DeleteResykts(casename, casename.casefold() == 'all') # type: ignore
@smooth_sap_do
def joint_reactions(self, jointname:str) -> list[dict]:
@@ -27,7 +27,7 @@ def joint_reactions(self, jointname:str) -> list[dict]:
Args:
jointname (str): name of an existing point object
"""
- return joint_reactions_parse(ret=self.__Results.JointReact(jointname, 1)), 0
+ return joint_reactions_parse(ret=self.__Results.JointReact(jointname, 1)), 0 # type: ignore
@smooth_sap_do
@@ -37,7 +37,7 @@ def joint_displacements(self, jointname:str) -> list[dict]:
Args:
jointname (str): name of an existing point object
"""
- return joint_displacements_parse(ret=self.__Results.JointDispl(jointname, 1)), 0
+ return joint_displacements_parse(ret=self.__Results.JointDispl(jointname, 1)), 0 # type: ignore
@smooth_sap_do
def joint_accelerations(self, jointname:str) -> list[dict]:
@@ -46,7 +46,7 @@ def joint_accelerations(self, jointname:str) -> list[dict]:
Args:
jointname (str): name of an existing point object
"""
- return joint_displacements_parse(ret=self.__Results.JointAcc(jointname, 1)), 0
+ return joint_displacements_parse(ret=self.__Results.JointAcc(jointname, 1)), 0 # type: ignore
@smooth_sap_do
def joint_velocities(self, jointname:str, format: Literal['Pandas', 'List']= 'List') -> list[dict]:
@@ -55,7 +55,7 @@ def joint_velocities(self, jointname:str, format: Literal['Pandas', 'List']= 'Li
Args:
jointname (str): name of an existing point object
"""
- return joint_displacements_parse(ret=self.__Results.JointVel(jointname, 1)), 0
+ return joint_displacements_parse(ret=self.__Results.JointVel(jointname, 1)), 0 # type: ignore
def joint_displacements_parse(ret: list) -> list[dict]:
assert ret[-1] == 0
diff --git a/src/ak_sap/Select/main.py b/src/ak_sap/Select/main.py
index b44d586..2607af1 100644
--- a/src/ak_sap/Select/main.py
+++ b/src/ak_sap/Select/main.py
@@ -31,7 +31,7 @@ def constraint(self, name: str, reverse: bool=False) -> bool:
@property
def selected(self) -> list[dict]:
- return selected_parse(ret=self.__SelectObj.GetSelected()), 0
+ return selected_parse(ret=self.__SelectObj.GetSelected()), 0 # type: ignore
@smooth_sap_do
def in_plane(self, pointname: str, plane: Literal['XY', 'YZ', 'XZ'], reverse: bool=False) -> bool:
diff --git a/src/ak_sap/__init__.py b/src/ak_sap/__init__.py
index a68bdda..482e27b 100644
--- a/src/ak_sap/__init__.py
+++ b/src/ak_sap/__init__.py
@@ -1,12 +1,10 @@
"Python wrapper for SAP2000 API"
-__version__ = "0.0.2"
+__version__ = "0.0.3"
from ak_sap.utils.logger import log
from ak_sap.wrapper import Sap2000Wrapper
from ak_sap.misc import Coord
-#log = Log()
-
def debug(status=False):
"""Import this in a new module and enable debug to use debug
example:
diff --git a/src/ak_sap/gui/cli_app.py b/src/ak_sap/cli/cli_app.py
similarity index 89%
rename from src/ak_sap/gui/cli_app.py
rename to src/ak_sap/cli/cli_app.py
index 39edc0c..fa6e771 100644
--- a/src/ak_sap/gui/cli_app.py
+++ b/src/ak_sap/cli/cli_app.py
@@ -13,5 +13,4 @@ def template_fn(template_str: str, template_bool: bool = False):
"""This is a sample function to be executed through the cli app
"""
log.info('Called the `template_fn` function')
- ic(template_bool)
- ic(template_str)
\ No newline at end of file
+ print('CLI app will be launched')
\ No newline at end of file
diff --git a/src/ak_sap/cli/update_doc.py b/src/ak_sap/cli/update_doc.py
new file mode 100644
index 0000000..22ec8c2
--- /dev/null
+++ b/src/ak_sap/cli/update_doc.py
@@ -0,0 +1,47 @@
+import json
+import typer
+
+from pathlib import Path
+from typing import Optional
+
+from ..utils import log
+
+app = typer.Typer()
+
+@app.command()
+def template_fn():
+ """This is a sample function to be executed through the cli app
+ """
+ log.info('Called the `template_fn` function')
+ doc_path: Path = Path(__file__).parent.parent.parent.parent / 'documentation'
+
+ replace_keyword = '# Initialize'
+
+ layout = doc_path / 'Layout.md'
+ usage = doc_path / 'Usage.ipynb'
+
+ assert layout.is_file()
+ assert usage.is_file()
+
+ print('Layout docs found. Updating...', end='')
+
+ with open(usage, 'r') as f:
+ data = json.load(f)
+
+ with open(layout, 'r') as f:
+ contents = f.read().splitlines()
+ contents = contents[:contents.index(replace_keyword)]
+
+ for cell in data['cells']:
+ if cell.get('cell_type') == 'markdown':
+ contents.append(''.join(cell.get('source'))[1:])
+ elif cell.get('cell_type') == 'code':
+ _contents = "\nUsage Examples:\n\n```python\n"
+ _contents += ''.join(cell.get('source'))
+ _contents += '\n```\n'
+ contents.append(_contents)
+
+ with open(layout, 'w') as f:
+ f.write('\n'.join(contents))
+
+ print('Done.')
\ No newline at end of file
diff --git a/src/ak_sap/gui/gui_app.py b/src/ak_sap/gui/gui_app.py
new file mode 100644
index 0000000..546f547
--- /dev/null
+++ b/src/ak_sap/gui/gui_app.py
@@ -0,0 +1,12 @@
+import typer
+
+from pathlib import Path
+import subprocess
+import sys
+
+app = typer.Typer()
+
+@app.command()
+def launch():
+ streamlit_filepath: Path = Path(__file__).parent.parent.parent.parent / 'Start_Here.py'
+ subprocess.run([f"{sys.executable}","-m", "streamlit", "run", str(streamlit_filepath)])
\ No newline at end of file
diff --git a/src/ak_sap/misc/coordinates.py b/src/ak_sap/misc/coordinates.py
index 62c275b..9174b32 100644
--- a/src/ak_sap/misc/coordinates.py
+++ b/src/ak_sap/misc/coordinates.py
@@ -6,5 +6,5 @@ class Coord:
y: float
z: float
- def as_tuple(self) -> tuple[float]:
+ def as_tuple(self) -> tuple[float, float, float]:
return (self.x, self.y, self.z)
\ No newline at end of file
diff --git a/src/ak_sap/utils/logger.py b/src/ak_sap/utils/logger.py
index 5f55e65..c245a75 100644
--- a/src/ak_sap/utils/logger.py
+++ b/src/ak_sap/utils/logger.py
@@ -30,14 +30,14 @@ def info(self, msg):
def warning(self, msg):
try:
- suffix = f'Warning in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: '
+ suffix = f'Warning in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: ' # type: ignore
except Exception:
suffix = f'Warning in {Path(inspect.stack()[1].filename).name}: '
self.logger.warning(suffix + msg)
def error(self, msg):
try:
- suffix = f'Error in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: '
+ suffix = f'Error in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: ' # type: ignore
except Exception:
suffix = f'Error in {Path(inspect.stack()[1].filename).name}: '
self.logger.error(suffix + str(msg))
@@ -45,7 +45,7 @@ def error(self, msg):
def critical(self, msg):
try:
- suffix = f'Critical in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: '
+ suffix = f'Critical in {Path(inspect.stack()[1].filename).name} -> {inspect.currentframe().f_back.f_code.co_name}: ' # type: ignore
except Exception:
suffix = f'Error in {Path(inspect.stack()[1].filename).name}: '
self.logger.critical(suffix + str(msg))
diff --git a/src/ak_sap/wrapper.py b/src/ak_sap/wrapper.py
index a9175c5..737055f 100644
--- a/src/ak_sap/wrapper.py
+++ b/src/ak_sap/wrapper.py
@@ -43,9 +43,8 @@ def __repr__(self) -> str:
def __del__(self) -> None:
try:
# assert self.mySapObject.ApplicationExit(False) == 0
- # self.SapModel = None
- # self.mySapObject = None
- pass
+ self.SapModel = None
+ self.mySapObject = None
except Exception as e:
log.error(e.__str__())
@@ -99,6 +98,9 @@ def ishidden(self) -> bool:
@property
def version(self) -> str:
return self.SapModel.GetVersion()[0]
+
+ def exit(self, save: bool=False):
+ self.mySapObject.ApplicationExit(False)
def model(attach_to_instance: bool, program_path: str|Path|None = None):
"""Returns SapObject.