ETABS and SAP2000
This guide provides detailed instructions for setting up the VIKTOR worker with the CSI software suite, focusing specifically on ETABS and SAP2000. The steps outlined are also applicable to other CSI tools. It is designed to offer the necessary context and file templates to facilitate the integration process.
There are two ways to integrate with ETABS software from an app. You can call the ETABS API directly from your app with
vkt.etabs.connect(), or you can send a Python script to the worker with vkt.etabs.ETABSAnalysis. Both need a worker;
Choose your approach compares them.
The worker
A worker is a program that connects the VIKTOR platform to third-party software running outside the platform. You can install the worker on your local machine or a remote server, but the CSI software must be installed where the worker is located. Your VIKTOR app will handle the communication between the web app and the worker as shown in the following diagram.

Here is what happens during the integration:
- The user enters input parameters in the VIKTOR UI.
- The
app.pyin the VIKTOR app sends a task to the worker - The worker (running on your local machine or a virtual machine) executes the task by using the CSI API.
- The worker returns the result of the calculation to your VIKTOR app.
- VIKTOR UI displays the result of the calculation.
The worker drives the real desktop application, so the machine it runs on needs a logged-in, interactive Windows session (a service running in Session 0 cannot start ETABS).
Choose your approach
vkt.etabs.connect() | vkt.etabs.ETABSAnalysis / vkt.sap.SAP2000Analysis | |
|---|---|---|
| Worker integration | etabsconnect | etabs / sap2000 |
| Where the API calls live | in your app | in a Python script that is sent to the worker |
Python + comtypes on the worker machine | not needed | required |
| Software | ETABS | ETABS / SAP2000 |
| SDK version | viktor >= 14.31.0 | viktor >= v14.17.0 |
vkt.etabs.connect() is the prefered approach for any integrations with ETABS, since you don't need any additional configuration on the worker side.
Integrations with SAP2000 should use vkt.sap.SAP2000Analysis().
ETABS
This is a BETA feature and requires SDK version >= 14.31.0.
vkt.etabs.connect() opens a live session with ETABS on a connected worker and returns
the model object itself: sap is the CSI SapModel, and every call on it is forwarded to that running ETABS
instance and executed there. Use it as a context manager — the session (and the ETABS instance) exists only inside
the with block:
import viktor as vkt
class Controller(vkt.Controller):
...
# A method inside the Controller opens the session and drives ETABS.
def run_etabs(self, params, **kwargs):
with vkt.etabs.connect(timeout=60) as sap:
ret = sap.InitializeNewModel(vkt.etabs.eUnits.kN_m_C) # a call returns the status code
[beam_name, ret] = sap.FrameObj.AddByCoord(0, 0, 0, 6, 0, 0, "", "Default", "Beam", "Global")
[pt_i, pt_j, ret] = sap.FrameObj.GetPoints(beam_name, "", "") # ...or out-params, then status
ret = sap.File.Save("model.edb") # use a relative filename, not an absolute path
Every member of the CSI API is reachable on sap. A call returns the API
status code (0 is success), or a list of the method's output parameters followed by that status code.
Please consider the following:
- Every call is a round trip to the worker, so prefer Open API methods that act on many objects at once over
long per-element loops.
timeoutbounds a single call, not the session. - File arguments must be relative filenames. Each session gets its own working directory on the worker, which is removed when the session closes; absolute paths are refused.
- The current version of
vkt.etabs.connect()doesn't support returning models created using the worker. Read the results you need through the CSI API (sap.Results...) while the session is open. - In the current state, each session starts its own ETABS instance; you cannot attach to an ETABS instance that is already running on the worker machine.
Add integration to app config
To make the worker integration available through the interface, add the following to your viktor.config.toml:
worker_integrations = [
"etabsconnect",
]
Install the worker
This worker calls the ETABS API directly, so it needs no Python environment on the worker machine.
Follow these steps to install the worker:
- Development
- Published App
Personal workers are installed and managed with VIKTOR Desktop:
-
Download and install VIKTOR Desktop and log in with your VIKTOR account, if you haven't done so already
-
In VIKTOR Desktop, click "Add" and select ETABS

-
Start the worker. You can view its logs inside VIKTOR Desktop, and the editor shows when your worker is online
Personal workers that were installed with the previous per-worker installer keep running, but new personal workers can only be added through VIKTOR Desktop: the per-worker installer download and connection-key flow are no longer available for personal use.
You need to be an environment administrator in order to install a worker for a published app.
-
Navigate to the "Integrations" tab in the Administrator panel
-
Click "Add integration"
-
Follow the steps provided in the modal

3.1. Select ETABS
3.2. Select the workspace(s) the integration should be available to
3.3. Download the worker .msi (Microsoft Installer) and run it on the machine of choice
3.4. Copy the generated connection key and paste it when the installer asks for it. In the browser, you can now click Finish and continue in the installer.
Connection KeyThe generated connection key should be copied immediately as VIKTOR will not preserve this data for security reasons.
-
Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut.
Testing
vkt.etabs.connect needs to be mocked within the context of (automated)
testing. The vkt.testing module provides the
mock_ETABSConnection decorator, which maps each Open API path to the
result it should return:
import unittest
import viktor as vkt
from app.my_entity_type.controller import MyEntityTypeController
class TestMyEntityTypeController(unittest.TestCase):
@vkt.testing.mock_ETABSConnection(results={
'FrameObj.AddByCoord': ['B1', 0], # <OAPI path>: [*output_params, status]
'FrameObj.GetPoints': ['P1', 'P2', 0],
})
def test_analysis(self):
MyEntityTypeController().analysis()
ETABS (Legacy) and SAP2000
Your app sends a Python script to the worker, which runs it against the CSI software through comtypes. This is
the only option for SAP2000, and remains supported for existing ETABS apps.
Add integration to app config
To make the worker integration available through the interface, add the following to your viktor.config.toml:
worker_integrations = [
"etabs",
"sap2000",
]
Install the worker
This worker runs your Python script, so its setup includes selecting the Python environment it should use.
For SAP2000, follow the same steps, but select SAP2000 instead of ETABS (Legacy).
Follow these steps to install the worker:
- Development
- Published App
Personal workers are installed and managed with VIKTOR Desktop:
-
Download and install VIKTOR Desktop and log in with your VIKTOR account, if you haven't done so already
-
In VIKTOR Desktop, click "Add" and select ETABS (Legacy)

-
Select the Python environment of your choice by setting the path to its
python.exeas the executable path. This can be your system Python, or the python.exe in a dedicated virtual environmenttipYour default Python environment can usually be found in
C:\Users\Username\AppData\Local\Programs\Python\Python31X\python.exeIf you cannot find it, try running the following command in your terminal
where python -
Start the worker. You can view its logs inside VIKTOR Desktop, and the editor shows when your worker is online
Personal workers that were installed with the previous per-worker installer keep running, but new personal workers can only be added through VIKTOR Desktop: the per-worker installer download and connection-key flow are no longer available for personal use.
You need to be an environment administrator in order to install a worker for a published app.
-
Navigate to the "Integrations" tab in the Administrator panel
-
Click "Add integration"
-
Follow the steps provided in the modal

3.1. Select ETABS (Legacy)
3.2. Select the workspace(s) the integration should be available to
3.3. Download the worker .msi (Microsoft Installer) and run it on the machine of choice
3.4. Copy the generated connection key and paste it when the installer asks for it. In the browser, you can now click Finish and continue in the installer.
Connection KeyThe generated connection key should be copied immediately as VIKTOR will not preserve this data for security reasons.
-
In the installer wizard, select the Python executable of your choice, this can be your system Python, or the python.exe in a dedicated virtual environment
tipYour default Python environment can usually be found in
C:\Users\<Username>\AppData\Local\Programs\Python\Python31X\python.exe.If you cannot find it, try running
where pythonin your terminal. -
Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut.
Install Python dependencies
The etabs and sap2000 workers control the CSI software through a Python environment where pywin32 and comtypes need to be installed. This environment can be on
your local Windows machine or a remote server where the CSI software is installed with a valid license.
- Install the necessary libraries (
pywin32andcomtypes) usingpipin the python environment selected during worker setup (in VIKTOR Desktop, the Python environment is the one whosepython.exeyou set as the executable path):
pip install pywin32 comtypes
App code
The following directory structure can be used as a template when working with the ETABS and SAP2000 API:
my-etabs-app/
├── app.py
├── run_etabs_model.py
├── inputs.json
This is the role of each file:
-
The
app.pycontains the logic of your VIKTOR app. It will use theinputs.jsonfile as input for the worker and reads theoutput.jsongenerated by the worker. -
The worker executes the
run_etabs_model.pyusing the Python environment defined during worker installation (also defined in theconfig.yaml). This file will generateoutput.jsonwhich is send back to the VIKTOR app.
You can use the following app.py template to set up the communication with your worker:
# app.py
import viktor as vkt
from pathlib import Path
class Parametrization(vkt.Parametrization):
...
class Controller(vkt.Controller):
...
# A function inside the Controller creates the `inputs.json`.
def run_etabs(self, params, **kwargs):
script = vkt.File.from_path(Path(__file__).parent / "run_etabs_model.py")
files = [("inputs.json", vkt.File.from_path(Path(__file__).parent / "inputs.json"))]
analysis = vkt.etabs.ETABSAnalysis(
script=script, files=files, output_filenames=["output.json"]
)
analysis.execute(timeout=300)
output_file = analysis.get_output_file("output.json")
The following template can be used to define the content of your run_etabs_model.py to communicate with the worker and your VIKTOR app:
# run_etabs_model.py
import json
from pathlib import Path
def create_etabs_model():
'''
1. Your code reads the inputs.json file and
uses the content for structural analysis in ETABS.
'''
input_json = Path.cwd() / "inputs.json"
with open(input_json) as jsonfile:
data = json.load(jsonfile)
'''
2. Add your logic here for the analysis
using the ETABS API.
'''
'''
3. Store the results of your analysis
in the output.json file to be sent to
your VIKTOR app.
'''
output = Path.cwd() / "output.json"
with open(output, "w") as jsonfile:
json.dump(outputs, jsonfile)
create_etabs_model()
You can check the following tutorial to see the worker in action!
Testing
ETABSAnalysis.execute needs to be mocked within
the context of (automated) testing.
The viktor.testing module provides the mock_ETABSAnalysis
decorator that facilitate mocking of workers:
import unittest
import viktor as vkt
from viktor.testing import mock_ETABSAnalysis
from app.my_entity_type.controller import MyEntityTypeController
class TestMyEntityTypeController(unittest.TestCase):
@mock_ETABSAnalysis(get_output_file={
'result.xml': vkt.File.from_path('test_file.xml'), # <name>: <File>
'result.json': vkt.File.from_path('test_file.json'),
...
})
def test_analysis(self):
MyEntityTypeController().analysis()
For the decorator's input parameters the following holds:
- If a Sequence type is provided, the next entry is returned for each corresponding method call. When a call is performed on a depleted iterable, an Exception is raised.
- If a single object is provided, the object is returned each time the corresponding method is called (endlessly).
- If None is provided (default), a default File/BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly).