# VIKTOR Documentation - [VIKTOR Documentation](/index.md) ## search - [Search the documentation](/search.md) ## docs ### api API - [API](/docs/api.md): API #### rest REST API - [REST API](/docs/api/rest.md): REST API ##### jobs-delete Cancel the job by its id. This endpoint can be used to cancel a running app job. - [Cancel Job by Id](/docs/api/rest/jobs-delete.md): Cancel the job by its id. This endpoint can be used to cancel a running app job. ##### jobs-read Get the job by its id. This endpoint can be used to check on the status and contents of a job. Jobs can have - [Get Job by Id](/docs/api/rest/jobs-read.md): Get the job by its id. This endpoint can be used to check on the status and contents of a job. Jobs can have ##### statistics-details-audit-events Retrieve or export audit events within a specified time window. - [Get Audit Events within a Time Window](/docs/api/rest/statistics-details-audit-events.md): Retrieve or export audit events within a specified time window. ##### statistics-details-daily-developer-logins Retrieve or export daily developer logins within a specified time window. - [Get Daily Developer Logins within a Time Window](/docs/api/rest/statistics-details-daily-developer-logins.md): Retrieve or export daily developer logins within a specified time window. ##### statistics-details-daily-user-logins Retrieve or export daily user login details within a time window. - [Get Daily User Logins within a Time Window](/docs/api/rest/statistics-details-daily-user-logins.md): Retrieve or export daily user login details within a time window. ##### statistics-details-monthly-active-developers Retrieve or export monthly active developers within a specified time window. - [Get Monthly Active Developers within a Time Window](/docs/api/rest/statistics-details-monthly-active-developers.md): Retrieve or export monthly active developers within a specified time window. ##### statistics-details-monthly-active-users Retrieve or export monthly active users within a specified time window. - [Get Monthly Active Users within a Time Window](/docs/api/rest/statistics-details-monthly-active-users.md): Retrieve or export monthly active users within a specified time window. ##### statistics-list Returns the environment activity data as grouped by statistics scope (users, developers or workspaces). - [Get Environment Activity Data](/docs/api/rest/statistics-list.md): Returns the environment activity data as grouped by statistics scope (users, developers or workspaces). ##### viktor-api - [VIKTOR API](/docs/api/rest/viktor-api.md) ##### workspaces-activate Activate the workspace. This sends a signal to scale up the app version runners, making sure that there is an app replica available to process jobs. - [Activate the Workspace](/docs/api/rest/workspaces-activate.md): Activate the workspace. This sends a signal to scale up the app version runners, making sure that there is an app replica available to process jobs. ##### workspaces-app-version-settings Returns the workspace app version settings. - [Get Workspace Settings](/docs/api/rest/workspaces-app-version-settings.md): Returns the workspace app version settings. ##### workspaces-assets Download an asset from workspace context, such as an image in the parametrization. - [Download Workspace Asset](/docs/api/rest/workspaces-assets.md): Download an asset from workspace context, such as an image in the parametrization. ##### workspaces-entities-create Create an entity. - [Create Entity](/docs/api/rest/workspaces-entities-create.md): Create an entity. ##### workspaces-entities-delete Delete and entity by its id. - [Delete Entity by Id](/docs/api/rest/workspaces-entities-delete.md): Delete and entity by its id. ##### workspaces-entities-download Returns the download URL for the content of a file entity (only for file entity types). - [Get download url for content of file entity.](/docs/api/rest/workspaces-entities-download.md): Returns the download URL for the content of a file entity (only for file entity types). ##### workspaces-entities-entities-create Create a child entity. - [Create a Child Entity](/docs/api/rest/workspaces-entities-entities-create.md): Create a child entity. ##### workspaces-entities-entities-read Get all child entities of an entity by parent entity id. - [Get all Child Entities](/docs/api/rest/workspaces-entities-entities-read.md): Get all child entities of an entity by parent entity id. ##### workspaces-entities-jobs Creates a Job. For the simplest computation flow, set `poll_result=false` or do not include it in the payload. - [Create a Job](/docs/api/rest/workspaces-entities-jobs.md): Creates a Job. For the simplest computation flow, set `poll_result=false` or do not include it in the payload. ##### workspaces-entities-list Get all entities. - [Get all Entities](/docs/api/rest/workspaces-entities-list.md): Get all entities. ##### workspaces-entities-messages Fetch system and user messages within an editor session. User should have at least `READ` permission on the entity to fetch messages. - [Get Editor Session Messages](/docs/api/rest/workspaces-entities-messages.md): Fetch system and user messages within an editor session. User should have at least `READ` permission on the entity to fetch messages. ##### workspaces-entities-parametrization Blocking endpoint to get parametrization as resolved by the app. - [Send Parametrization Job](/docs/api/rest/workspaces-entities-parametrization.md): Blocking endpoint to get parametrization as resolved by the app. ##### workspaces-entities-parent Get the parent entity. - [Get Parent of an Entity](/docs/api/rest/workspaces-entities-parent.md): Get the parent entity. ##### workspaces-entities-permission-groups Get all permission groups of an entity by entity id. - [Get all Permission Groups of an Entity](/docs/api/rest/workspaces-entities-permission-groups.md): Get all permission groups of an entity by entity id. ##### workspaces-entities-read Get a single entity by its id. - [Get Entity by Id](/docs/api/rest/workspaces-entities-read.md): Get a single entity by its id. ##### workspaces-entities-session Create an editor session for the corresponding entity. - [Create a new Editor Session](/docs/api/rest/workspaces-entities-session.md): Create an editor session for the corresponding entity. ##### workspaces-entities-siblings Get siblings of an entity by its id. - [Get Siblings of an Entity](/docs/api/rest/workspaces-entities-siblings.md): Get siblings of an entity by its id. ##### workspaces-entities-update Update entity by its id. - [Update Entity by Id](/docs/api/rest/workspaces-entities-update.md): Update entity by its id. ##### workspaces-entity-types-entities-read Get all entities of an entity type. - [Get All Entities of an Entity Type](/docs/api/rest/workspaces-entity-types-entities-read.md): Get all entities of an entity type. ##### workspaces-entity-types-entity-types Get all child entity types of an entity type. - [Get all Child Entity Types of an Entity Type](/docs/api/rest/workspaces-entity-types-entity-types.md): Get all child entity types of an entity type. ##### workspaces-entity-types-list Get all entity types. - [Get all Entity Types](/docs/api/rest/workspaces-entity-types-list.md): Get all entity types. ##### workspaces-entity-types-read Get an entity type by its id. - [Get Entity Type by Id](/docs/api/rest/workspaces-entity-types-read.md): Get an entity type by its id. ##### workspaces-entity-types-upload Upload an entity of the corresponding file entity type. - [Upload an Entity of File Entity Type](/docs/api/rest/workspaces-entity-types-upload.md): Upload an entity of the corresponding file entity type. ##### workspaces-files-create Create a new file object in the scope of an entity or session. Subsequently, the `temp_upload_url` and `temp_upload_data` from the response need to be used to upload the file itself. - [Create File](/docs/api/rest/workspaces-files-create.md): Create a new file object in the scope of an entity or session. Subsequently, the `temp_upload_url` and `temp_upload_data` from the response need to be used to upload the file itself. ##### workspaces-files-delete Delete a file by its id. - [Delete File by Id](/docs/api/rest/workspaces-files-delete.md): Delete a file by its id. ##### workspaces-files-download Download a file by its id. - [Download File by Id](/docs/api/rest/workspaces-files-download.md): Download a file by its id. ##### workspaces-files-list List all files in the scope. - [List All Files](/docs/api/rest/workspaces-files-list.md): List all files in the scope. ##### workspaces-files-read Get a file by its id. - [Get File by Id](/docs/api/rest/workspaces-files-read.md): Get a file by its id. ##### workspaces-files-uploaded Viktor collects the metadata of a file and makes it available for usage in file field when this signal is called by the client. - [Send Uploaded Signal for a File by Id](/docs/api/rest/workspaces-files-uploaded.md): Viktor collects the metadata of a file and makes it available for usage in file field when this signal is called by the client. ##### workspaces-groups-list Returns current user's groups or all groups if the user is admin. - [Get All Workspace Groups](/docs/api/rest/workspaces-groups-list.md): Returns current user's groups or all groups if the user is admin. ##### workspaces-groups-permissions Returns the permissions assigned to a group, including permitted actions per permission object. **ONLY FOR ADMINS** - [Get Group Permissions by Id](/docs/api/rest/workspaces-groups-permissions.md): Returns the permissions assigned to a group, including permitted actions per permission object. **ONLY FOR ADMINS** ##### workspaces-groups-read Returns a single group if the current user belongs to the group or is an administrator. - [Get Workspace User Group by Id](/docs/api/rest/workspaces-groups-read.md): Returns a single group if the current user belongs to the group or is an administrator. ##### workspaces-list List the workspaces for the current user, depending on user role and access. - [Get All Workspaces](/docs/api/rest/workspaces-list.md): List the workspaces for the current user, depending on user role and access. ##### workspaces-read Returns a single workspace by id. - [Get Workspace by Id](/docs/api/rest/workspaces-read.md): Returns a single workspace by id. ##### workspaces-users-current Returns the logged-in user's workspace specific fields. - [Get Current User in the Workspace](/docs/api/rest/workspaces-users-current.md): Returns the logged-in user's workspace specific fields. ##### workspaces-users-export Returns a CSV-file export of all Users in the workspace. Excludes Organization Admins. - [Export Workspace Users](/docs/api/rest/workspaces-users-export.md): Returns a CSV-file export of all Users in the workspace. Excludes Organization Admins. ##### workspaces-users-list Lists all the users that have access to the workspace. - [List Users in the Workspace](/docs/api/rest/workspaces-users-list.md): Lists all the users that have access to the workspace. #### sdk API - [SDK API](/docs/api/sdk.md): API ##### handling-entity-data Read, create and modify entity data using the SDK API - [Handling entity data](/docs/api/sdk/handling-entity-data.md): Read, create and modify entity data using the SDK API ##### running-entity-computation Run an entity computation using the SDK API - [Running an entity computation](/docs/api/sdk/running-entity-computation.md): Run an entity computation using the SDK API ### app-builder Create apps in minutes using our AI-assisted app builder - [App Builder [BETA]](/docs/app-builder.md): Create apps in minutes using our AI-assisted app builder ### create-apps Learn how to create apps through tutorials, how-to guides and examples - [Develop apps](/docs/create-apps.md): Learn how to create apps through tutorials, how-to guides and examples #### automated-testing Continuous testing using automated tests - [Automated testing](/docs/create-apps/automated-testing.md): Continuous testing using automated tests ##### mocking How to use Mocking in tests - [Mocking](/docs/create-apps/automated-testing/mocking.md): How to use Mocking in tests #### development-tools-and-tips ##### ci Setting up CI/CD for automated testing/deploying of your VIKTOR app on the remote Git repository - [Continuous Integration/Deployment](/docs/create-apps/development-tools-and-tips/ci.md): Setting up CI/CD for automated testing/deploying of your VIKTOR app on the remote Git repository ##### environment-variables Configuring app secrets through custom environment variables - [Environment variables](/docs/create-apps/development-tools-and-tips/environment-variables.md): Configuring app secrets through custom environment variables ##### ide Configuring your favorite code editor for writing apps with VIKTOR - [Code editor](/docs/create-apps/development-tools-and-tips/ide.md): Configuring your favorite code editor for writing apps with VIKTOR ##### interactive-debugging Setting up and using interactive debugging in your code editor - [Interactive debugging](/docs/create-apps/development-tools-and-tips/interactive-debugging.md): Setting up and using interactive debugging in your code editor ##### keep-a-changelog Tracking app changes and versions by keeping a changelog - [Keeping a changelog](/docs/create-apps/development-tools-and-tips/keep-a-changelog.md): Tracking app changes and versions by keeping a changelog ##### private-packages Use private packages in your published app - [Use private packages](/docs/create-apps/development-tools-and-tips/private-packages.md): Use private packages in your published app ##### system-dependencies Use system packages in your published app - [Use system dependencies](/docs/create-apps/development-tools-and-tips/system-dependencies.md): Use system packages in your published app ##### use-python-packages Add Python packages to requirements.txt - [Use Python packages](/docs/create-apps/development-tools-and-tips/use-python-packages.md): Add Python packages to requirements.txt #### documents-and-spreadsheets Documents & spreadsheets - [Documents & spreadsheets](/docs/create-apps/documents-and-spreadsheets.md): Documents & spreadsheets ##### converting-to-pdf Converting Word, Excel or SVG files to PDF - [Converting to PDF](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf.md): Converting Word, Excel or SVG files to PDF ##### merging-pdf-files Merging PDFs into a single file - [Merging PDF files](/docs/create-apps/documents-and-spreadsheets/merging-pdf-files.md): Merging PDFs into a single file ##### spreadsheet-calculator Performing a calculation using a spreadsheet without macros - [Spreadsheet calculator](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator.md): Performing a calculation using a spreadsheet without macros ##### spreadsheet-templater Filling a spreadsheet from a template - [Spreadsheet templater](/docs/create-apps/documents-and-spreadsheets/spreadsheet-templater.md): Filling a spreadsheet from a template ##### text-file-templater Generating a text-file by filling variables in a template - [Text-file templater](/docs/create-apps/documents-and-spreadsheets/text-file-templater.md): Generating a text-file by filling variables in a template ##### word-file-templater Filling a Word-file from a template - [Word-file templater](/docs/create-apps/documents-and-spreadsheets/word-file-templater.md): Filling a Word-file from a template #### inform-end-user ##### dashboard Show a welcome text on the dashboard - [Dashboard welcome text](/docs/create-apps/inform-end-user/dashboard.md): Show a welcome text on the dashboard ##### output-field Add an output field to the parametrization - [Output field](/docs/create-apps/inform-end-user/output-field.md): Add an output field to the parametrization ##### show-message Raising an error or showing a message to the user - [Show a message to the user](/docs/create-apps/inform-end-user/show-message.md): Raising an error or showing a message to the user ##### static-image Add static images to the parametrization - [Static image](/docs/create-apps/inform-end-user/static-image.md): Add static images to the parametrization ##### text-blocks Add static text blocks to the parametrization - [Text blocks](/docs/create-apps/inform-end-user/text-blocks.md): Add static text blocks to the parametrization ##### tooltips Tooltips - [Tooltips](/docs/create-apps/inform-end-user/tooltips.md): Tooltips #### layout-and-styling Layout & styling - [Layout & styling](/docs/create-apps/layout-and-styling.md): Layout & styling ##### adjust-parametrization-width Adjust the parametrization width - [Adjust the parametrization width](/docs/create-apps/layout-and-styling/adjust-parametrization-width.md): Adjust the parametrization width ##### dashboard Dashboard - [Dashboard](/docs/create-apps/layout-and-styling/dashboard.md): Dashboard ##### entity-navigation Navigation inside a workspace - [Navigation inside a workspace](/docs/create-apps/layout-and-styling/entity-navigation.md): Navigation inside a workspace ##### manual-line-break Add a manual line break between fields in the parametrization - [Manual line break](/docs/create-apps/layout-and-styling/manual-line-break.md): Add a manual line break between fields in the parametrization ##### pages Organizing the editor using pages - [Creating pages](/docs/create-apps/layout-and-styling/pages.md): Organizing the editor using pages ##### steps Dictate a workflow in the editor using steps - [Creating steps](/docs/create-apps/layout-and-styling/steps.md): Dictate a workflow in the editor using steps ##### style-text Style text using Markdown - [Style / format text using Markdown](/docs/create-apps/layout-and-styling/style-text.md): Style text using Markdown ##### tabs-and-sections Organizing the editor using tabs & sections - [Creating tabs & sections](/docs/create-apps/layout-and-styling/tabs-and-sections.md): Organizing the editor using tabs & sections #### managing-files How to use the correct method for your file - [Managing files](/docs/create-apps/managing-files.md): How to use the correct method for your file ##### downloading-files Handling downloading of files by the user - [Downloading files](/docs/create-apps/managing-files/downloading-files.md): Handling downloading of files by the user ##### modify-files How to use the correct method for your file - [Modifying files](/docs/create-apps/managing-files/modify-files.md): How to use the correct method for your file ##### uploading-files Handling uploading of files by the user - [Uploading files](/docs/create-apps/managing-files/uploading-files.md): Handling uploading of files by the user #### other-topics ##### date-dependent-params Using date-dependent params - [Using date-dependent params](/docs/create-apps/other-topics/date-dependent-params.md): Using date-dependent params ##### processing-gef-files Using off-the-shelve geotechnical functions from the viktor.geo module - [Processing GEF files](/docs/create-apps/other-topics/processing-gef-files.md): Using off-the-shelve geotechnical functions from the viktor.geo module ##### share-using-api Share data between entities using the API - [Share data between entities using the API](/docs/create-apps/other-topics/share-using-api.md): Share data between entities using the API #### references ##### cli Using VIKTOR's command-line interface - [Command-line interface (CLI)](/docs/create-apps/references/cli.md): Using VIKTOR's command-line interface - [Changelog](/docs/create-apps/references/cli/changelog.md): All notable changes to the VIKTOR CLI will be documented in this file. ##### sdk SDK reference - [SDK](/docs/create-apps/references/sdk.md): SDK reference ##### viktor-config-toml Setting high level app specifications using the viktor.config.toml file - [viktor.config.toml](/docs/create-apps/references/viktor-config-toml.md): Setting high level app specifications using the viktor.config.toml file #### results-and-visualizations Show results and create visualizations - [Results & visualizations](/docs/create-apps/results-and-visualizations.md): Show results and create visualizations ##### data-and-tables Present data and tables in a view - [Show data & tables](/docs/create-apps/results-and-visualizations/data-and-tables.md): Present data and tables in a view ##### hide-view Hide a view depending on other fields - [Hide a view](/docs/create-apps/results-and-visualizations/hide-view.md): Hide a view depending on other fields ##### html Show HTML (web) content in a view - [Show HTML](/docs/create-apps/results-and-visualizations/html.md): Show HTML (web) content in a view ##### images Show an image in a view - [Show an image](/docs/create-apps/results-and-visualizations/images.md): Show an image in a view ##### map Displaying features on a map - [Display a map](/docs/create-apps/results-and-visualizations/map.md): Displaying features on a map ##### optimization-routine Perform an optimization routine using the OptimizationButton - [Perform an optimization routine](/docs/create-apps/results-and-visualizations/optimization-routine.md): Perform an optimization routine using the OptimizationButton ##### plots-charts-graphs Show plots, charts & graphs in a view - [Show plots, charts & graphs](/docs/create-apps/results-and-visualizations/plots-charts-graphs.md): Show plots, charts & graphs in a view ##### report Display a report in a view - [Display a report](/docs/create-apps/results-and-visualizations/report.md): Display a report in a view ##### show-summary Summarizing an entity - [Show a summary](/docs/create-apps/results-and-visualizations/show-summary.md): Summarizing an entity ##### storing-results Storing results - [Storing results](/docs/create-apps/results-and-visualizations/storing-results.md): Storing results ##### threed-model Show a geometric 3D model in a view - [Show a 3D model](/docs/create-apps/results-and-visualizations/threed-model.md): Show a geometric 3D model in a view #### software-integrations VIKTOR's integrations with 3rd party software - [Software integrations](/docs/create-apps/software-integrations.md): VIKTOR's integrations with 3rd party software ##### autodesk-platform-services Connecting to Autodesk Platform Services using OAuth 2.0 - [Autodesk Platform Services](/docs/create-apps/software-integrations/autodesk-platform-services.md): Connecting to Autodesk Platform Services using OAuth 2.0 ##### axisvm Creating and running an AxisVM model - [AxisVM](/docs/create-apps/software-integrations/axisvm.md): Creating and running an AxisVM model ##### databricks Connecting to databricks - [Databricks](/docs/create-apps/software-integrations/databricks.md): Connecting to databricks ##### dfoundations Creating and running a D-Foundations model - [D-Foundations](/docs/create-apps/software-integrations/dfoundations.md): Creating and running a D-Foundations model ##### dgeostability Running a D-Geo Stability model - [D-Geo Stability](/docs/create-apps/software-integrations/dgeostability.md): Running a D-Geo Stability model ##### dsettlement Creating and running a D-Settlement model - [D-Settlement](/docs/create-apps/software-integrations/dsettlement.md): Creating and running a D-Settlement model ##### dsheetpiling Running a D-Sheet Piling model - [D-Sheet Piling](/docs/create-apps/software-integrations/dsheetpiling.md): Running a D-Sheet Piling model ##### dstability Running a D-Stability model - [D-Stability](/docs/create-apps/software-integrations/dstability.md): Running a D-Stability model ##### dynamo-nodes Integrate using VIKTOR nodes in Dynamo - [Dynamo Nodes [BETA]](/docs/create-apps/software-integrations/dynamo-nodes.md): Integrate using VIKTOR nodes in Dynamo ##### dynamo Integrate with Dynamo Sandbox - [Dynamo Sandbox](/docs/create-apps/software-integrations/dynamo.md): Integrate with Dynamo Sandbox ##### etabs-and-sap2000 This guide provides the necessary context and file templates to facilitate the integration process of ETABS and SAP2000. - [ETABS and SAP2000](/docs/create-apps/software-integrations/etabs-and-sap2000.md): This guide provides the necessary context and file templates to facilitate the integration process of ETABS and SAP2000. ##### excel Running an Excel-sheet with macros - [Excel](/docs/create-apps/software-integrations/excel.md): Running an Excel-sheet with macros ##### generic Running a Generic integration - [Other Software](/docs/create-apps/software-integrations/generic.md): Running a Generic integration ##### geolib Using the GEOLIB package and running a model - [GEOLIB](/docs/create-apps/software-integrations/geolib.md): Using the GEOLIB package and running a model ##### grlweap Running a GRLWEAP model - [GRLWEAP](/docs/create-apps/software-integrations/grlweap.md): Running a GRLWEAP model ##### idea Creating and running a IDEA StatiCa Concrete model - [IDEA StatiCa Concrete](/docs/create-apps/software-integrations/idea.md): Creating and running a IDEA StatiCa Concrete model ##### matlab Running a Matlab integration - [Matlab](/docs/create-apps/software-integrations/matlab.md): Running a Matlab integration ##### plaxis Using the PLAXIS package and running a model - [PLAXIS](/docs/create-apps/software-integrations/plaxis.md): Using the PLAXIS package and running a model ##### revit Running an Autodesk Revit integration - [Autodesk Revit](/docs/create-apps/software-integrations/revit.md): Running an Autodesk Revit integration ##### rfem Running an RFEM model - [RFEM 5](/docs/create-apps/software-integrations/rfem.md): Running an RFEM model ##### rhino-grasshopper Running a Rhino / Grasshopper integration - [Rhino / Grasshopper](/docs/create-apps/software-integrations/rhino-grasshopper.md): Running a Rhino / Grasshopper integration ##### robot Running an Autodesk Robot Structural Analysis model - [Robot Structural Analysis](/docs/create-apps/software-integrations/robot.md): Running an Autodesk Robot Structural Analysis model ##### scia Creating and running a SCIA Engineer model - [SCIA Engineer](/docs/create-apps/software-integrations/scia.md): Creating and running a SCIA Engineer model ##### staadpro Creating and running a Bentley STAAD.Pro integration - [STAAD.Pro](/docs/create-apps/software-integrations/staadpro.md): Creating and running a Bentley STAAD.Pro integration ##### tekla Running a Tekla Structures integration - [Tekla Structures](/docs/create-apps/software-integrations/tekla.md): Running a Tekla Structures integration #### user-input User input, fields and buttons - [User input, fields and buttons](/docs/create-apps/user-input.md): User input, fields and buttons ##### action-buttons Adding buttons to enable user actions - [Action buttons](/docs/create-apps/user-input/action-buttons.md): Adding buttons to enable user actions ##### entity-selection Selecting entities made easy with these fields - [Entity selection](/docs/create-apps/user-input/entity-selection.md): Selecting entities made easy with these fields ##### geometry-selection Let the user select geometry objects from a geometry model - [Geometry selection](/docs/create-apps/user-input/geometry-selection.md): Let the user select geometry objects from a geometry model ##### hide-field Hide a field depending on other fields - [Hide a field](/docs/create-apps/user-input/hide-field.md): Hide a field depending on other fields ##### input-validation Validate user input and provide helpful guidance - [Input validation](/docs/create-apps/user-input/input-validation.md): Validate user input and provide helpful guidance ##### llm-chat Enable the potential of LLM in your app - [LLM Chat](/docs/create-apps/user-input/llm-chat.md): Enable the potential of LLM in your app ##### map-features Let the user draw geo-objects on a map - [Map features](/docs/create-apps/user-input/map-features.md): Let the user draw geo-objects on a map ##### numeric-input Adding number fields - [Numeric input](/docs/create-apps/user-input/numeric-input.md): Adding number fields ##### options-and-selections Adding options & selection fields - [Options & selections](/docs/create-apps/user-input/options-and-selections.md): Adding options & selection fields ##### other-fields DateField, toggle, and more... - [Other fields](/docs/create-apps/user-input/other-fields.md): DateField, toggle, and more... ##### read-only-fields Provide additional context using non-editable fields - [Read-only fields](/docs/create-apps/user-input/read-only-fields.md): Provide additional context using non-editable fields ##### set-params-using-button Setting params with a button - [Set params using a button](/docs/create-apps/user-input/set-params-using-button.md): Setting params with a button ##### tables-and-arrays Group input fields using tables & arrays - [Tables & arrays](/docs/create-apps/user-input/tables-and-arrays.md): Group input fields using tables & arrays ##### textual-input Adding text fields - [Textual input](/docs/create-apps/user-input/textual-input.md): Adding text fields ##### upload-files Upload file(s) using a field - [Upload files](/docs/create-apps/user-input/upload-files.md): Upload file(s) using a field ### faq Find answers to some common problems - [Frequently Asked Questions](/docs/faq.md): Find answers to some common problems ### getting-started Get started with VIKTOR - [Get started with VIKTOR](/docs/getting-started.md): Get started with VIKTOR #### fundamentals Explanations of fundamental VIKTOR concepts - [Fundamentals](/docs/getting-started/fundamentals.md): Explanations of fundamental VIKTOR concepts ##### app-types Discover different types of apps - [App types](/docs/getting-started/fundamentals/app-types.md): Discover different types of apps ##### basic-app-structure Define a controller and parametrization in app.py - [Basic app structure](/docs/getting-started/fundamentals/basic-app-structure.md): Define a controller and parametrization in app.py ##### call-flow Understanding VIKTOR's app code execution flow - [App code execution flow](/docs/getting-started/fundamentals/call-flow.md): Understanding VIKTOR's app code execution flow ##### entities-and-entity-types Understanding the differences between an entity and an entity type - [Entity vs. entity type](/docs/getting-started/fundamentals/entities-and-entity-types.md): Understanding the differences between an entity and an entity type #### installation Install VIKTOR and activate your account - [Install VIKTOR](/docs/getting-started/installation.md): Install VIKTOR and activate your account ##### cloud-based-development Installing VIKTOR using a cloud-based development environment - [Cloud-based development](/docs/getting-started/installation/cloud-based-development.md): Installing VIKTOR using a cloud-based development environment ##### installation-using-docker Installing VIKTOR using the Docker isolation mode - [Install VIKTOR with Docker](/docs/getting-started/installation/installation-using-docker.md): Installing VIKTOR using the Docker isolation mode ##### local-development-venv Install VIKTOR and activate your account - [Install VIKTOR](/docs/getting-started/installation/local-development-venv.md): Install VIKTOR and activate your account ##### restart-install-workflow How to install restart the installation workflow when installing existing account on new device VIKTOR - [Restart installation](/docs/getting-started/installation/restart-install-workflow.md): How to install restart the installation workflow when installing existing account on new device VIKTOR #### starter-guide Create your first VIKTOR app by following step-by-step instructions - [Starter guide](/docs/getting-started/starter-guide.md): Create your first VIKTOR app by following step-by-step instructions #### whats-next Learn more about VIKTOR or start developing your own app - [What's next?](/docs/getting-started/whats-next.md): Learn more about VIKTOR or start developing your own app ### manage-apps Learn more about how to manage your apps - [Manage apps](/docs/manage-apps.md): Learn more about how to manage your apps #### access-management How to configure access and roles within VIKTOR - [Access Management](/docs/manage-apps/access-management.md): How to configure access and roles within VIKTOR #### activity-dashboard Get insights into activity within your organization - [Activity Dashboard](/docs/manage-apps/activity-dashboard.md): Get insights into activity within your organization #### enterprise-it Using VIKTOR within an enterprise IT environment - [Enterprise IT](/docs/manage-apps/enterprise-it.md): Using VIKTOR within an enterprise IT environment #### organization-setting Organization wide settings on the platform - [Organization Settings](/docs/manage-apps/organization-setting.md): Organization wide settings on the platform #### regional-hosting Storing data in your desired region - [Regional hosting](/docs/manage-apps/regional-hosting.md): Storing data in your desired region #### single-sign-on Setting up single sign-on for (the users of) your VIKTOR app - [Single Sign On (SSO)](/docs/manage-apps/single-sign-on.md): Setting up single sign-on for (the users of) your VIKTOR app #### software-integrations Installing and operating external integrations - [Software integrations](/docs/manage-apps/software-integrations.md): Installing and operating external integrations #### workspaces-and-apps Setting up and customizing workspaces and apps - [Workspaces and apps](/docs/manage-apps/workspaces-and-apps.md): Setting up and customizing workspaces and apps ### publish-apps Publish your VIKTOR app - [Publishing an app](/docs/publish-apps.md): Publish your VIKTOR app #### backward-compatibility Making sure an update of your app does not break compatibility - [Backward compatibility](/docs/publish-apps/backward-compatibility.md): Making sure an update of your app does not break compatibility #### continuous-deployment Setting up automated deployment of your VIKTOR app on the remote Git repository - [Continuous Deployment (CD)](/docs/publish-apps/continuous-deployment.md): Setting up automated deployment of your VIKTOR app on the remote Git repository #### limits Understanding the limits applied on production environments - [Platform limits](/docs/publish-apps/limits.md): Understanding the limits applied on production environments #### upgrade-viktor-version Upgrade the VIKTOR SDK version in requirements.txt - [Upgrade VIKTOR version](/docs/publish-apps/upgrade-viktor-version.md): Upgrade the VIKTOR SDK version in requirements.txt ### tutorials Use one of our Tutorials to improve your skills - [Tutorials](/docs/tutorials.md): Use one of our Tutorials to improve your skills #### app-type-editor Learn how to create an editor-type app - [Creating an editor-type app](/docs/tutorials/app-type-editor.md): Learn how to create an editor-type app #### app-type-simple Learn how to create a simple-type app - [Creating a simple-type app](/docs/tutorials/app-type-simple.md): Learn how to create a simple-type app #### app-type-tree Learn how to create an app implementing a more complex entity type hierarchy - [Creating a tree-type app](/docs/tutorials/app-type-tree.md): Learn how to create an app implementing a more complex entity type hierarchy #### automatic-reporting Follow along and learn how to automatically generate a report in a VIKTOR app - [Tutorial - Automatic reporting](/docs/tutorials/automatic-reporting.md): Follow along and learn how to automatically generate a report in a VIKTOR app #### basic-3d-model This tutorial shows an example of how to visualize 3D models in a VIKTOR application. - [Tutorial - Create an interactive 3D building](/docs/tutorials/basic-3d-model.md): This tutorial shows an example of how to visualize 3D models in a VIKTOR application. #### etabs-getting-started Follow along and learn how to automatically Post-Processing ETABS Data with Plotly and Pandas in a VIKTOR app. - [Your first ETABS app](/docs/tutorials/etabs-getting-started.md): Follow along and learn how to automatically Post-Processing ETABS Data with Plotly and Pandas in a VIKTOR app. #### integrate-dynamo This tutorial shows an example of how to parametrically influence Dynamo models in a VIKTOR app - [Tutorial - Integrate Dynamo](/docs/tutorials/integrate-dynamo.md): This tutorial shows an example of how to parametrically influence Dynamo models in a VIKTOR app #### integrate-etabs-sap2000 This tutorial provides an example of generating and visualizing a 3D structure in ETABS and SAP2000, integrated within a VIKTOR app. - [Tutorial - Integrate ETABS and SAP2000](/docs/tutorials/integrate-etabs-sap2000.md): This tutorial provides an example of generating and visualizing a 3D structure in ETABS and SAP2000, integrated within a VIKTOR app. #### integrate-grasshopper This tutorial shows an example of how to parametrically integrate Rhino/Grasshopper models in a VIKTOR app - [Tutorial - Integrate Rhino/Grasshopper](/docs/tutorials/integrate-grasshopper.md): This tutorial shows an example of how to parametrically integrate Rhino/Grasshopper models in a VIKTOR app #### integrate-scia Learn how to create and run a SCIA model within a VIKTOR app - [Tutorial - Creating and analyzing a SCIA model](/docs/tutorials/integrate-scia.md): Learn how to create and run a SCIA model within a VIKTOR app #### integrate-staadpro This tutorial shows an example of how to parametrically integrate STAAD pro workflows in a VIKTOR app - [Tutorial - Integrate STAAD.Pro](/docs/tutorials/integrate-staadpro.md): This tutorial shows an example of how to parametrically integrate STAAD pro workflows in a VIKTOR app #### interactive-maps This tutorial shows an example of how to visualize data an on interactive map using VIKTOR - [Tutorial - Create an interactive map](/docs/tutorials/interactive-maps.md): This tutorial shows an example of how to visualize data an on interactive map using VIKTOR #### intermediate-3d-model This tutorial shows an example of how to generate and visualise 3D models in a VIKTOR app - [Tutorial - 3D models](/docs/tutorials/intermediate-3d-model.md): This tutorial shows an example of how to generate and visualise 3D models in a VIKTOR app #### plots-and-data Follow along and learn how to visualise and summarise data using Plotly and Pandas. - [Tutorial - Data Analysis with Plotly and Pandas](/docs/tutorials/plots-and-data.md): Follow along and learn how to visualise and summarise data using Plotly and Pandas. #### process-etabs-data Follow along and learn how to automatically Post-Processing ETABS Data with Plotly and Pandas in a VIKTOR app. - [Tutorial - Post-process ETABS data](/docs/tutorials/process-etabs-data.md): Follow along and learn how to automatically Post-Processing ETABS Data with Plotly and Pandas in a VIKTOR app. #### process-staad-data Follow along and learn how to automatically Post-Process STAAD.Pro Data with Pandas in a VIKTOR app. - [Tutorial - Post-process STAAD.Pro data](/docs/tutorials/process-staad-data.md): Follow along and learn how to automatically Post-Process STAAD.Pro Data with Pandas in a VIKTOR app. #### python-script-to-app Follow along and learn how to convert your Python project to a VIKTOR app - [How to convert a Python Project to a VIKTOR app](/docs/tutorials/python-script-to-app.md): Follow along and learn how to convert your Python project to a VIKTOR app #### spreadsheet-calculator Follow along and learn how to automatically generate an Excel spreadsheet in a VIKTOR app which will present the results of a simple beam analysis - [Tutorial - Spreadsheet Calculator](/docs/tutorials/spreadsheet-calculator.md): Follow along and learn how to automatically generate an Excel spreadsheet in a VIKTOR app which will present the results of a simple beam analysis #### visual-builder This tutorial shows how to use the Visual Builder. - [Tutorial - Using the Visual Builder](/docs/tutorials/visual-builder.md): This tutorial shows how to use the Visual Builder. ### use-apps How to use VIKTOR apps - [Use apps](/docs/use-apps.md): How to use VIKTOR apps #### integrate-app Integrate your VIKTOR app in other software using the API - [Integrate your app in other software](/docs/use-apps/integrate-app.md): Integrate your VIKTOR app in other software using the API ### welcome VIKTOR is a platform for creating powerful and user-friendly web apps, all with pure Python! Create apps to automate - [VIKTOR documentation](/docs/welcome.md): VIKTOR is a platform for creating powerful and user-friendly web apps, all with pure Python! Create apps to automate ### whats-new Find the latest updates and features here! - [What's new - July](/docs/whats-new.md): Find the latest updates and features here! #### all-updates If you missed any updates, you can find them here! - [All updates](/docs/whats-new/all-updates.md): If you missed any updates, you can find them here! #### changelog-cli If you missed any updates, you can find them here! - [Changelog](/docs/whats-new/changelog-cli.md): If you missed any updates, you can find them here! #### changelog-sdk If you missed any updates, you can find them here! - [Changelog](/docs/whats-new/changelog-sdk.md): If you missed any updates, you can find them here! ## sdk ### 13 #### api VIKTOR SDK API reference - [SDK Reference](/sdk/13/api.md): VIKTOR SDK API reference ##### api-v1 viktor.api_v1 - [viktor.api_v1](/sdk/13/api/api-v1.md): viktor.api_v1 ##### core viktor.core - [viktor.core](/sdk/13/api/core.md): viktor.core ##### errors viktor.errors - [viktor.errors](/sdk/13/api/errors.md): viktor.errors ##### external - [viktor.external.axisvm](/sdk/13/api/external/axisvm.md): viktor.external.axisvm - [viktor.external.dfoundations](/sdk/13/api/external/dfoundations.md): viktor.external.dfoundations - [viktor.external.dgeostability](/sdk/13/api/external/dgeostability.md): viktor.external.dgeostability - [viktor.external.dsettlement](/sdk/13/api/external/dsettlement.md): viktor.external.dsettlement - [viktor.external.dsheetpiling](/sdk/13/api/external/dsheetpiling.md): viktor.external.dsheetpiling - [viktor.external.dstability](/sdk/13/api/external/dstability.md): viktor.external.dstability - [viktor.external.dynamo](/sdk/13/api/external/dynamo.md): viktor.external.dynamo - [viktor.external.etabs](/sdk/13/api/external/etabs.md): viktor.external.etabs - [viktor.external.excel](/sdk/13/api/external/excel.md): viktor.external.excel - [viktor.external.external_program](/sdk/13/api/external/external-program.md): viktor.external.external_program - [viktor.external.generic](/sdk/13/api/external/generic.md): viktor.external.generic - [viktor.external.grasshopper](/sdk/13/api/external/grasshopper.md): viktor.external.grasshopper - [viktor.external.grlweap](/sdk/13/api/external/grlweap.md): viktor.external.grlweap - [viktor.external.idea](/sdk/13/api/external/idea.md): viktor.external.idea - [viktor.external.matlab](/sdk/13/api/external/matlab.md): viktor.external.matlab - [viktor.external.plaxis](/sdk/13/api/external/plaxis.md): viktor.external.plaxis - [viktor.external.python](/sdk/13/api/external/python.md): viktor.external.python - [viktor.external.revit](/sdk/13/api/external/revit.md): viktor.external.revit - [viktor.external.rfem](/sdk/13/api/external/rfem.md): viktor.external.rfem - [viktor.external.robot](/sdk/13/api/external/robot.md): viktor.external.robot - [viktor.external.sap2000](/sdk/13/api/external/sap2000.md): viktor.external.sap2000 - [viktor.external.scia](/sdk/13/api/external/scia.md): viktor.external.scia - [viktor.external.spreadsheet](/sdk/13/api/external/spreadsheet.md): viktor.external.spreadsheet - [viktor.external.tekla](/sdk/13/api/external/tekla.md): viktor.external.tekla - [viktor.external.word](/sdk/13/api/external/word.md): viktor.external.word ##### geo viktor.geo - [viktor.geo](/sdk/13/api/geo.md): viktor.geo ##### geometry viktor.geometry - [viktor.geometry](/sdk/13/api/geometry.md): viktor.geometry ##### parametrization viktor.parametrization - [viktor.parametrization](/sdk/13/api/parametrization.md): viktor.parametrization ##### result viktor.result - [viktor.result](/sdk/13/api/result.md): viktor.result ##### testing viktor.testing - [viktor.testing](/sdk/13/api/testing.md): viktor.testing ##### utils viktor.utils - [viktor.utils](/sdk/13/api/utils.md): viktor.utils ##### views viktor.views - [viktor.views](/sdk/13/api/views.md): viktor.views #### changelog SDK version history - [Changelog](/sdk/13/changelog.md): SDK version history #### upgrades SDK deprecations with upgrade steps and planned removal - [Upgrades](/sdk/13/upgrades.md): SDK deprecations with upgrade steps and planned removal #### v13-to-v14 Guide on how to migrate from VIKTOR SDK v13 to v14 - [Migrate (v13 to v14)](/sdk/13/v13-to-v14.md): Guide on how to migrate from VIKTOR SDK v13 to v14 ### api VIKTOR SDK API reference - [SDK Reference](/sdk/api.md): VIKTOR SDK API reference #### api-v1 viktor.api_v1 - [viktor.api_v1](/sdk/api/api-v1.md): viktor.api_v1 #### core viktor.core - [viktor.core](/sdk/api/core.md): viktor.core #### errors viktor.errors - [viktor.errors](/sdk/api/errors.md): viktor.errors #### external ##### axisvm viktor.external.axisvm - [viktor.external.axisvm](/sdk/api/external/axisvm.md): viktor.external.axisvm ##### dfoundations viktor.external.dfoundations - [viktor.external.dfoundations](/sdk/api/external/dfoundations.md): viktor.external.dfoundations ##### dgeostability viktor.external.dgeostability - [viktor.external.dgeostability](/sdk/api/external/dgeostability.md): viktor.external.dgeostability ##### dsettlement viktor.external.dsettlement - [viktor.external.dsettlement](/sdk/api/external/dsettlement.md): viktor.external.dsettlement ##### dsheetpiling viktor.external.dsheetpiling - [viktor.external.dsheetpiling](/sdk/api/external/dsheetpiling.md): viktor.external.dsheetpiling ##### dstability viktor.external.dstability - [viktor.external.dstability](/sdk/api/external/dstability.md): viktor.external.dstability ##### dynamo viktor.external.dynamo - [viktor.external.dynamo](/sdk/api/external/dynamo.md): viktor.external.dynamo ##### etabs viktor.external.etabs - [viktor.external.etabs](/sdk/api/external/etabs.md): viktor.external.etabs ##### excel viktor.external.excel - [viktor.external.excel](/sdk/api/external/excel.md): viktor.external.excel ##### external-program viktor.external.external_program - [viktor.external.external_program](/sdk/api/external/external-program.md): viktor.external.external_program ##### generic viktor.external.generic - [viktor.external.generic](/sdk/api/external/generic.md): viktor.external.generic ##### grasshopper viktor.external.grasshopper - [viktor.external.grasshopper](/sdk/api/external/grasshopper.md): viktor.external.grasshopper ##### grlweap viktor.external.grlweap - [viktor.external.grlweap](/sdk/api/external/grlweap.md): viktor.external.grlweap ##### idea viktor.external.idea - [viktor.external.idea](/sdk/api/external/idea.md): viktor.external.idea ##### matlab viktor.external.matlab - [viktor.external.matlab](/sdk/api/external/matlab.md): viktor.external.matlab ##### plaxis viktor.external.plaxis - [viktor.external.plaxis](/sdk/api/external/plaxis.md): viktor.external.plaxis ##### python viktor.external.python - [viktor.external.python](/sdk/api/external/python.md): viktor.external.python ##### revit viktor.external.revit - [viktor.external.revit](/sdk/api/external/revit.md): viktor.external.revit ##### rfem viktor.external.rfem - [viktor.external.rfem](/sdk/api/external/rfem.md): viktor.external.rfem ##### robot viktor.external.robot - [viktor.external.robot](/sdk/api/external/robot.md): viktor.external.robot ##### sap2000 viktor.external.sap2000 - [viktor.external.sap2000](/sdk/api/external/sap2000.md): viktor.external.sap2000 ##### scia viktor.external.scia - [viktor.external.scia](/sdk/api/external/scia.md): viktor.external.scia ##### spreadsheet viktor.external.spreadsheet - [viktor.external.spreadsheet](/sdk/api/external/spreadsheet.md): viktor.external.spreadsheet ##### tekla viktor.external.tekla - [viktor.external.tekla](/sdk/api/external/tekla.md): viktor.external.tekla ##### word viktor.external.word - [viktor.external.word](/sdk/api/external/word.md): viktor.external.word #### geo viktor.geo - [viktor.geo](/sdk/api/geo.md): viktor.geo #### geometry viktor.geometry - [viktor.geometry](/sdk/api/geometry.md): viktor.geometry #### parametrization viktor.parametrization - [viktor.parametrization](/sdk/api/parametrization.md): viktor.parametrization #### result viktor.result - [viktor.result](/sdk/api/result.md): viktor.result #### testing viktor.testing - [viktor.testing](/sdk/api/testing.md): viktor.testing #### utils viktor.utils - [viktor.utils](/sdk/api/utils.md): viktor.utils #### views viktor.views - [viktor.views](/sdk/api/views.md): viktor.views ### changelog SDK version history - [Changelog](/sdk/changelog.md): SDK version history ### upgrades SDK deprecations with upgrade steps and planned removal - [Deprecations & Upgrades](/sdk/upgrades.md): SDK deprecations with upgrade steps and planned removal ### v13-to-v14 Guide on how to migrate from VIKTOR SDK v13 to v14 - [Migrate (v13 to v14)](/sdk/v13-to-v14.md): Guide on how to migrate from VIKTOR SDK v13 to v14 --- # Full Documentation Content [Skip to main content](#__docusaurus_skipToContent_fallback) [![VIKTOR Logo](/img/viktor-logo-light.svg)![VIKTOR Logo](/img/viktor-logo-dark.svg)](/index.md) [****](/index.md)[Documentation](/docs/welcome/.md) [14](/sdk/api/.md) * [14](/sdk/api/.md) * [13](/sdk/13/api/.md) [Apps Gallery ](https://www.viktor.ai/apps-gallery) [Community Forum ](https://community.viktor.ai/) Search # Search the documentation [![VIKTOR Logo](/img/viktor-logo-light.svg)![VIKTOR Logo](/img/viktor-logo-dark.svg)](https://viktor.ai/) [Home](/index.md)[Community](https://community.viktor.ai/)[Contact Us](https://www.viktor.ai/contact/) [VIKTOR on LinkedIn](https://www.linkedin.com/company/viktor-ai "VIKTOR on LinkedIn")[VIKTOR on Twitter](https://twitter.com/ViktorAi "VIKTOR on Twitter")[VIKTOR on Instagram](https://www.instagram.com/workatviktor/ "VIKTOR on Instagram")[VIKTOR on YouTube](https://www.youtube.com/c/VIKTOR-platform "VIKTOR on YouTube") Copyright © 2025 VIKTOR. --- # API Welcome to the VIKTOR API documentation. ## What is an API?[​](/docs/api/.md#what-is-an-api "Direct link to What is an API?") An API, or Application Programming Interface, acts as a communication gateway between different software applications. It defines the rules and tools for building software and allows developers to access the functionality of a system, service, or platform. In simpler terms, an API enables interaction and data exchange between software components. ## When to Use?[​](/docs/api/.md#when-to-use "Direct link to When to Use?") The API provides a standardized interface to access specific features of the VIKTOR platform. Our API can be used to extract or modify data from your environment, integrate apps into your own software and workflows or automate tasks. When accessing the VIKTOR in the browser, using the API is not required as the functionality is directly available through the user interface. If you want to exchange data with the VIKTOR platform by means of code you can use the API. ## REST API vs SDK[​](/docs/api/.md#rest-api-vs-sdk "Direct link to REST API vs SDK") VIKTOR provides both a low-level **REST API** and an API module as part of the **SDK**. The [REST API](/docs/api/rest/.md) is the foundation for interaction and data exchange with the VIKTOR platform. Developers can use it to access app or organizational resources through HTTP requests. The REST API is programming-language agnostic and can be accessed by all popular programming languages such as Python, Javascript, Go(lang), Ruby, C#, etc. The VIKTOR [SDK API](/docs/api/sdk/.md) is built on top of the REST API and provides access to many of the relevant requests through an even developer-friendlier Python interface. The SDK API takes care of more complicated parts such as 'pagination', 'filtering by reference', and 'object serialization'. **We therefore strongly recommend using the SDK API wherever possible**. ![](/assets/images/rest_api_vs_sdk_api-d3413d315a965b66bce16982cb842375.png) ## Personal Access Token[​](/docs/api/.md#personal-access-token "Direct link to Personal Access Token") When using the [SDK API](/docs/api/sdk/.md) from within the context of a workspace, authentication is done automatically with the token of the current user performing the API call, which is valid within the workspace. When the SDK API is used [cross-workspace](/docs/api/sdk/.md#cross-workspace) or [from an external script](/docs/api/sdk/.md#from-an-external-script), or when using the [REST API](/docs/api/rest/.md) a *Personal Access Token* needs to be used for proper authentication. Your Personal Access Token is a personal unique token, that can be used to securely access the API without needing a username and password. The token looks something like: `vktrpat_●●●●●●●●●●●●●●_●●●●●●●●●●●●●●●●●●●●●●●●●●` and you can obtain it [through your profile settings page](/docs/faq/.md#account). By authenticating using a Personal Access Token, you obtain the same rights as the user that holds the token. Storing your Personal Access Token Your Personal Access Token can be used to **access or alter your sensitive data**. You should therefore make sure to **securely store it** and never store it directly in source-code or other plain text formats. Consider using [Environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md). * SDK * REST 1. Set your Personal Access Token as an environment variable. 2. Create an `API` instance with your token to perform API requests. ``` import viktor as vkt import os api = vkt.api_v1.API(token=os.environ["TOKEN"], ...) ... workspace = api.get_workspace(3) entity = workspace.get_entity(1) ``` 1. Set your Personal Access Token as an environment variable. 2. Use your token in the `Authorization` header to perform API requests. ``` import requests import os # Replace 'my_environment' with your actual environment e.g. 'cloud' or 'cloud.us1' if you are in a region other than Frankfurt environment = 'my_environment' # To never expose your token in code, set your actual token as an environment variable or use `input()` and paste the token in the terminal token = os.environ["my_token"] # Must be set as environment variable # Sending a GET request with Bearer token to obtain the list of workspaces in your VIKTOR environment response = requests.get( url=f"https://{environment}.viktor.ai/api/workspaces/", headers={'Authorization': f'Bearer {token}'} ) response.raise_for_status() # Print the response print(response.json()) ``` --- # REST API The REST API is the **foundation** for interaction and data exchange with the VIKTOR platform. Developers can use it to access app or organizational resources through HTTP requests. The REST API is programming-language agnostic and can be accessed by all popular programming languages such as Python, Javascript, Go(lang), Ruby, C#, etc. ## Authentication[​](/docs/api/rest/.md#authentication "Direct link to Authentication") REST API calls can be authenticated by using your [Personal Access Token](/docs/api/.md#personal-access-token) in the `Authorization` header: ``` import requests import os # Replace 'my_environment' with your actual environment e.g. 'cloud' or 'cloud.us1' if you are in a region other than Frankfurt environment = 'my_environment' # To never expose your token in code, set your actual token as an environment variable or use `input()` and paste the token in the terminal token = os.environ["my_token"] # Must be set as environment variable # Sending a GET request with Bearer token to obtain the list of workspaces in your VIKTOR environment response = requests.get( url=f"https://{environment}.viktor.ai/api/workspaces/", headers={'Authorization': f'Bearer {token}'} ) response.raise_for_status() # Print the response print(response.json()) ``` ## Pagination[​](/docs/api/rest/.md#pagination "Direct link to Pagination") When working with large sets of data, efficient handling is crucial. Our API supports pagination, allowing you to retrieve data in manageable chunks. Understand the pagination parameters and techniques to navigate through paginated results effectively, ensuring optimal performance and resource utilization in your applications. To paginate your results with the VIKTOR API you can add to your request the query params `limit` and `offset`. * `limit` is required and is used to specify the number of results you want to retrieve. Note that the results returned might be fewer than requested, depending on the max allowed page size of the resource you are trying to access. * `offset` is optionally used to specify the position of the first result you will receive in the total number of results. If not specified, it defaults to 0, the first result. Note that if the endpoint allows sorting of the results, the `offset` specifies the position relative to the requested sorting. For example, if the total number of results is 10 and you want to retrieve them in pages of 5, you can get all the results by sending the 2 requests below: * `?limit=5&offset=0` * `?limit=5&offset=5` In the paginated response you will receive two keys: * `count` will return an integer with the number of total results * `results` with return a list of objects of the requested resource Exceptions The above structure is our go-to way for paginating results, but make sure to check the endpoint specific descriptions for potential exceptions. ## How to Use?[​](/docs/api/rest/.md#how-to-use "Direct link to How to Use?") For detailed API specifications and endpoints please refer to individual reference pages in the upcoming sections. --- # Cancel Job by Id ``` DELETE /api/jobs/:id/ ``` Cancel the job by its id. This endpoint can be used to cancel a running app job. ## Request[​](/docs/api/rest/jobs-delete/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this app job. ## Responses[​](/docs/api/rest/jobs-delete/.md#responses "Direct link to Responses") * 204 * 401 * 403 Job cancelled. No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Job Owner* **Descriptions:** `Is Job Owner` : Checks whether job is created by the requesting user. Loading... --- # Get Job by Id ``` GET /api/jobs/:id/ ``` Get the job by its id. This endpoint can be used to check on the status and contents of a job. Jobs can have the following status: * running (the `message` data will be filled in) * failed (the `error` data will be filled in) * success (the `result` data will be filled in) * cancelled ## Request[​](/docs/api/rest/jobs-read/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this app job. ## Responses[​](/docs/api/rest/jobs-read/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **uid** integerrequired The id of the job. **kind** stringrequired **Possible values:** `non-empty` The kind of the job. Can be one of: 'result', 'result\_pointer' **status** stringrequired **Possible values:** \[`success`, `cancelled`, `failed`, `running`] The status of the job. Can be one of: \['success', 'cancelled', 'failed', 'running'] **completed\_at** date-timenullablerequired The completed time of the job. **error**object Information related to a failed job. **type** string **Possible values:** \[`error_code`, `error_user`, `error_timeout`] The type of error, can be one of: \['error\_code', 'error\_user', 'error\_timeout'] **message** stringnullable The error message. **invalid\_fields** objectnullable Any fields that are invalid. **result**object Information related to a successful job. **web** object Result for WebView. **ifc** object Result for IFCView. **pdf** object Result for PDFView. **geojson** object Result for MapView. **data** object Result for DataView. **image** object Result for ImageView. **plotly** object Result for PlotlyView. **geometry** object Result for GeometryView. **download** object Result for DownloadButton. **optimization** object Result for OptimizationButton. **set\_params** object Result for SetParamsButton. **message**object Information related to a running job. **message\_type** string **Possible values:** \[`progress`, `info`, `warning`, `success`] **message** stringnullable The message for the user **timestamp\_epoch** numbernullable The timestamp when the message was edit, can be null. **percentage** numbernullable Percentage, between 0 and 100, can be null. ``` { "uid": 0, "kind": "string", "status": "success", "completed_at": "2024-06-11T11:45:44.579Z", "error": { "type": "error_code", "message": "string", "invalid_fields": {} }, "result": { "web": {}, "ifc": {}, "pdf": {}, "geojson": {}, "data": {}, "image": {}, "plotly": {}, "geometry": {}, "download": {}, "optimization": {}, "set_params": {} }, "message": { "message_type": "progress", "message": "string", "timestamp_epoch": 0, "percentage": 0 } } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Job Owner* **Descriptions:** `Is Job Owner` : Checks whether job is created by the requesting user. Loading... --- # Get Audit Events within a Time Window ``` GET /api/statistics/details/audit_events/ ``` Retrieve or export audit events within a specified time window. ## Request[​](/docs/api/rest/statistics-details-audit-events/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **start\_date** date-timerequired Start of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **end\_date** date-timerequired End of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **user** integer\[] (optional) Filter by user id(s) **export** string **Possible values:** \[`csv`] Export the results in provided format. Supported formats are: csv **event\_type** stringrequired **Possible values:** \[`ENTITY.COPY_RECURSIVE`, `ENTITY.REVISE`, `USER.LOGIN_FAIL`, `USER.DEV_PAIRING_RETRIEVE`, `WORKSPACE.CREATE`, `USER.DEV_PAIRING_VERIFY`, `WORKSPACE.ARCHIVE`, `APP.UPDATE_VARIABLES`, `APP.PUBLISH_FAIL`, `WORKSPACE.ENTER`, `APP.CREATE`, `WORKSPACE.CHANGE_VISIBILITY`, `WORKSPACE.DELETE_USERS`, `EDITOR.EXIT`, `ORG.INVITE_USERS`, `EDITOR.ENTER`, `USER.LOCK`, `USER.CLI_DOWNLOAD`, `WORKSPACE.INVITE_USERS`, `USER.LOGOUT`, `APP.UNARCHIVE`, `ENTITY.RENAME`, `EDITOR.COMPUTE`, `WORKSPACE.UNARCHIVE`, `ENTITY.SAVE`, `ENTITY.COPY`, `APP.UPDATE`, `ENTITY.DELETE`, `APP.PUBLISH`, `APP.ARCHIVE`, `USER.DEV_PAIRING_ACTIVATE`, `USER.SUBMIT_SUPPORT_TICKET`, `ORG.DELETE_USERS`, `ENTITY.CREATE`, `USER.LOGIN`] Type of the event. Supported types are: ENTITY.COPY\_RECURSIVE, ENTITY.REVISE, USER.LOGIN\_FAIL, USER.DEV\_PAIRING\_RETRIEVE, WORKSPACE.CREATE, USER.DEV\_PAIRING\_VERIFY, WORKSPACE.ARCHIVE, APP.UPDATE\_VARIABLES, APP.PUBLISH\_FAIL, WORKSPACE.ENTER, APP.CREATE, WORKSPACE.CHANGE\_VISIBILITY, WORKSPACE.DELETE\_USERS, EDITOR.EXIT, ORG.INVITE\_USERS, EDITOR.ENTER, USER.LOCK, USER.CLI\_DOWNLOAD, WORKSPACE.INVITE\_USERS, USER.LOGOUT, APP.UNARCHIVE, ENTITY.RENAME, EDITOR.COMPUTE, WORKSPACE.UNARCHIVE, ENTITY.SAVE, ENTITY.COPY, APP.UPDATE, ENTITY.DELETE, APP.PUBLISH, APP.ARCHIVE, USER.DEV\_PAIRING\_ACTIVATE, USER.SUBMIT\_SUPPORT\_TICKET, ORG.DELETE\_USERS, ENTITY.CREATE, USER.LOGIN **app** integer\[] (optional) Filter by app(s) **workspace** integer\[] (optional) Filter by workspace(s) ## Responses[​](/docs/api/rest/statistics-details-audit-events/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **row\_id** string Unique row id **context** object Event context **event\_type** string **Possible values:** `non-empty` **timestamp** date-time **user** object User details ] ``` { "count": 0, "results": [ { "row_id": "string", "context": {}, "event_type": "string", "timestamp": "2024-06-11T11:45:44.586Z", "user": {} } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get Daily Developer Logins within a Time Window ``` GET /api/statistics/details/daily_developer_logins/ ``` Retrieve or export daily developer logins within a specified time window. ## Request[​](/docs/api/rest/statistics-details-daily-developer-logins/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **start\_date** date-timerequired Start of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **end\_date** date-timerequired End of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **user** integer\[] (optional) Filter by user id(s) **export** string **Possible values:** \[`csv`] Export the results in provided format. Supported formats are: csv ## Responses[​](/docs/api/rest/statistics-details-daily-developer-logins/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **row\_id** stringrequired **Possible values:** `non-empty` Unique row id **user** object User details **date** date-timerequired Date of the login event in format 'YYYY-MM-DDThh:mm:ss.sZ' **workspace** object Workspace details ] ``` { "count": 0, "results": [ { "row_id": "string", "user": {}, "date": "2024-06-11T11:45:44.587Z", "workspace": {} } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get Daily User Logins within a Time Window ``` GET /api/statistics/details/daily_user_logins/ ``` Retrieve or export daily user login details within a time window. ## Request[​](/docs/api/rest/statistics-details-daily-user-logins/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **start\_date** date-timerequired Start of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **end\_date** date-timerequired End of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **user** integer\[] (optional) Filter by user id(s) **export** string **Possible values:** \[`csv`] Export the results in provided format. Supported formats are: csv **workspace** integer\[] (optional) Filter by workspace(s) ## Responses[​](/docs/api/rest/statistics-details-daily-user-logins/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **row\_id** stringrequired **Possible values:** `non-empty` Unique row id **user** object User details **date** date-timerequired Date of the login event in format 'YYYY-MM-DDThh:mm:ss.sZ' **workspace** object Workspace details ] ``` { "count": 0, "results": [ { "row_id": "string", "user": {}, "date": "2024-06-11T11:45:44.587Z", "workspace": {} } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get Monthly Active Developers within a Time Window ``` GET /api/statistics/details/monthly_active_developers/ ``` Retrieve or export monthly active developers within a specified time window. ## Request[​](/docs/api/rest/statistics-details-monthly-active-developers/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **start\_date** date-timerequired Start of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **end\_date** date-timerequired End of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **user** integer\[] (optional) Filter by user id(s) **export** string **Possible values:** \[`csv`] Export the results in provided format. Supported formats are: csv ## Responses[​](/docs/api/rest/statistics-details-monthly-active-developers/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **row\_id** stringrequired **Possible values:** `non-empty` Unique row id **user** object User details **date** date-timerequired First date of activity in a month in format 'YYYY-MM-DDThh:mm:ss.sZ' ] ``` { "count": 0, "results": [ { "row_id": "string", "user": {}, "date": "2024-06-11T11:45:44.589Z" } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get Monthly Active Users within a Time Window ``` GET /api/statistics/details/monthly_active_users/ ``` Retrieve or export monthly active users within a specified time window. ## Request[​](/docs/api/rest/statistics-details-monthly-active-users/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **start\_date** date-timerequired Start of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **end\_date** date-timerequired End of date range in format 'YYYY-MM-DDThh:mm:ss.sZ' **user** integer\[] (optional) Filter by user id(s) **export** string **Possible values:** \[`csv`] Export the results in provided format. Supported formats are: csv ## Responses[​](/docs/api/rest/statistics-details-monthly-active-users/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **row\_id** stringrequired **Possible values:** `non-empty` Unique row id **user** object User details **date** date-timerequired First date of activity in a month in format 'YYYY-MM-DDThh:mm:ss.sZ' ] ``` { "count": 0, "results": [ { "row_id": "string", "user": {}, "date": "2024-06-11T11:45:44.590Z" } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get Environment Activity Data ``` GET /api/statistics/ ``` Returns the environment activity data as grouped by statistics scope (users, developers or workspaces). On successful response you will see the subset of the response structure based on the scope (users, developers or workspaces). ## Request[​](/docs/api/rest/statistics-list/.md#request "Direct link to Request") ### Query Parameters * **stats\_type** stringrequired **Possible values:** \[`users`, `developers`, `workspaces`] Choose 'users', 'developers' or 'workspaces'. **start** date-timerequired Start date of date range. **end** date-timerequired End date of date range. **org\_domain** string **Possible values:** `non-empty` Specify a specific Organization domain. ## Responses[​](/docs/api/rest/statistics-list/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **developers**objectrequired **total\_developers**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. **day** integerrequired **Possible values:** `>= 1` Day of the month. ] * **monthly\_active\_developers**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. ] * **daily\_active\_developers**objectrequired **per\_day**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. **day** integerrequired **Possible values:** `>= 1` Day of the month. ] * **per\_week**object\[]required Array \[ * **year** integerrequired Year value. **count** integerrequired Count value. **week** integerrequired **Possible values:** `>= 1` Week of the year. ] * **per\_month**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. ] * **users**objectrequired **total\_users**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. **day** integerrequired **Possible values:** `>= 1` Day of the month. ] * **monthly\_active\_users**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. ] * **daily\_active\_users**objectrequired **per\_day**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. **day** integerrequired **Possible values:** `>= 1` Day of the month. ] * **per\_week**object\[]required Array \[ * **year** integerrequired Year value. **count** integerrequired Count value. **week** integerrequired **Possible values:** `>= 1` Week of the year. ] * **per\_month**object\[]required Array \[ * **year** integerrequired Year value. **month** integerrequired **Possible values:** `>= 1` and `<= 12` Month number of the year. **count** integerrequired Count value. ] **workspaces**objectrequired **total\_users** objectrequired Total users in dynamic response with structure of `[{"year": , "month": , "day": , : ...}]` **monthly\_active\_users** objectrequired Monthly active users in dynamic response with structure of `[{"year": , "month": , : ...}]` **daily\_active\_users** objectrequired Daily active users in dynamic response with structure of `{"per_month": [{"year": , "month": , : ...}]}` ``` { "developers": { "total_developers": [ { "year": 0, "month": 0, "count": 0, "day": 0 } ], "monthly_active_developers": [ { "year": 0, "month": 0, "count": 0 } ], "daily_active_developers": { "per_day": [ { "year": 0, "month": 0, "count": 0, "day": 0 } ], "per_week": [ { "year": 0, "count": 0, "week": 0 } ], "per_month": [ { "year": 0, "month": 0, "count": 0 } ] } }, "users": { "total_users": [ { "year": 0, "month": 0, "count": 0, "day": 0 } ], "monthly_active_users": [ { "year": 0, "month": 0, "count": 0 } ], "daily_active_users": { "per_day": [ { "year": 0, "month": 0, "count": 0, "day": 0 } ], "per_week": [ { "year": 0, "count": 0, "week": 0 } ], "per_month": [ { "year": 0, "month": 0, "count": 0 } ] } }, "workspaces": { "total_users": {}, "monthly_active_users": {}, "daily_active_users": {} } } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Not App* **AND** *Is Authenticated*) **Descriptions:** `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Loading... --- Version: v1 # VIKTOR API ## Authentication * API Key: Bearer\_Auth Enter your bearer token in the format 'Bearer TOKEN'. | Security Scheme Type: | apiKey | | ---------------------- | ------------- | | Header parameter name: | Authorization | --- # Activate the Workspace ``` POST /api/workspaces/:id/activate/ ``` Activate the workspace. This sends a signal to scale up the app version runners, making sure that there is an app replica available to process jobs. ## Request[​](/docs/api/rest/workspaces-activate/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this workspace. ## Responses[​](/docs/api/rest/workspaces-activate/.md#responses "Direct link to Responses") * 204 * 401 * 403 * 429 Success No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Permission* **AND** *Workspace Is Not Dev* **AND** *Workspace Is Not Public* **Descriptions:** `Workspace Is Not Public` : Checks whether the requested workspace object is not a public workspace. `Workspace Is Not Dev` : Checks whether the requested workspace object is not a development workspace. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. `Workspace Permission` : Checks whether the user has permission to the workspace object. Total computation time limit is exceeded Loading... --- # Get Workspace Settings ``` GET /api/workspaces/:id/settings/ ``` Returns the workspace app version settings. ## Request[​](/docs/api/rest/workspaces-app-version-settings/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this workspace. ## Responses[​](/docs/api/rest/workspaces-app-version-settings/.md#responses "Direct link to Responses") * 200 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **uses\_privileged\_api** booleanrequired Specifies whether the app version makes use of the PrivilegedAPI to bypass user management restrictions. **welcome\_text** string Welcome text to be displayed on the workspace dashboard. **sdk\_version**objectrequired Specifies the VIKTOR SDK version with which the app version was built. **complete** string **Possible values:** `non-empty` The complete version of the SDK. **major** integer The major version of the SDK. **minor** integer The minor version of the SDK. **patch** integer The patch version of the SDK. **pre** string **Possible values:** `non-empty` Specifies the pre-release version name. In case of stable release, this value is null. **app\_type** string Shows the application type. It can be one of tree,simple,editor ``` { "uses_privileged_api": true, "welcome_text": "string", "sdk_version": { "complete": "string", "major": 0, "minor": 0, "patch": 0, "pre": "string" }, "app_type": "string" } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Permission* **Descriptions:** `Workspace Permission` : Checks whether the user has permission to the workspace object. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Workspace does not exist. Loading... --- # Download Workspace Asset ``` GET /api/workspaces/:id/assets/ ``` Download an asset from workspace context, such as an image in the parametrization. ## Request[​](/docs/api/rest/workspaces-assets/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this workspace. ### Query Parameters * **path** stringrequired **Possible values:** `non-empty` and `<= 2048 characters` Full path of the asset file. ## Responses[​](/docs/api/rest/workspaces-assets/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **temp\_download\_url** string **Possible values:** `non-empty` Temporary download url. ``` { "temp_download_url": "string" } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Permission* **Descriptions:** `Workspace Permission` : Checks whether the user has permission to the workspace object. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Workspace is not found. Loading... --- # Create Entity ``` POST /api/workspaces/:workspace_id/entities/ ``` Create an entity. ## Request[​](/docs/api/rest/workspaces-entities-create/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired - application/json ### Body**required** * **properties** objectnullablerequired **groups** integer\[] **entity\_type** integerrequired **name** string **Possible values:** `non-empty` and `<= 128 characters` **filename** string **Possible values:** `non-empty` and `<= 128 characters` ## Responses[​](/docs/api/rest/workspaces-entities-create/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Simple App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. `Is Simple App Workspace Context` : Workspace should have a `simple` app. Loading... --- # Delete Entity by Id ``` DELETE /api/workspaces/:workspace_id/entities/:id/ ``` Delete and entity by its id. ## Request[​](/docs/api/rest/workspaces-entities-delete/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ## Responses[​](/docs/api/rest/workspaces-entities-delete/.md#responses "Direct link to Responses") * 204 Loading... --- # Get download url for content of file entity. ``` GET /api/workspaces/:workspace_id/entities/:id/download/ ``` Returns the download URL for the content of a file entity (only for file entity types). ## Request[​](/docs/api/rest/workspaces-entities-download/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ## Responses[​](/docs/api/rest/workspaces-entities-download/.md#responses "Direct link to Responses") * 200 * 401 * 403 * 404 File stream with custom attachment No authentication found or authentication is not correct. Specified path is not allowed S3 NoSuchKey Error Loading... --- # Create a Child Entity ``` POST /api/workspaces/:workspace_id/entities/:id/entities/ ``` Create a child entity. Note: The paginated response is optional in this endpoint, when client provides `limit` and `offset` query parameters client gets paginated response. ## Request[​](/docs/api/rest/workspaces-entities-entities-create/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. - application/json ### Body**required** * **properties** objectnullablerequired **groups** integer\[] **entity\_type** integerrequired **name** string **Possible values:** `non-empty` and `<= 128 characters` **filename** string **Possible values:** `non-empty` and `<= 128 characters` ## Responses[​](/docs/api/rest/workspaces-entities-entities-create/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * Array \[ * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ] ``` [ { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ] ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Tree App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. `Is Tree App Workspace Context` : Workspace should have a `tree` app. Loading... --- # Get all Child Entities ``` GET /api/workspaces/:workspace_id/entities/:id/entities/ ``` Get all child entities of an entity by parent entity id. ## Request[​](/docs/api/rest/workspaces-entities-entities-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. **limit** integer **Possible values:** `>= 1` Number of results to return per page. **offset** integer The initial index from which to return the results. **entity\_type** string\[] **Possible values:** `non-empty` Allows filtering on id (int) or class\_name (string). **sort** string\[] **Possible values:** `non-empty` Allowed values: `name`, `updated_at`, `summary_updated_at` and/or `summary`. **name** string **Possible values:** `non-empty` **search** string **Possible values:** `non-empty` Allow for fuzzy name match. **only\_name** boolean **created\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **last\_updated\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **created\_at\_min** date-time Created after specified date (ISO format). **created\_at\_max** date-time Created before specified date (ISO format). **updated\_at\_min** date-time Updated after specified date (ISO format). **updated\_at\_max** date-time Updated before specified date (ISO format). **id** integer\[] Filter on specific entity id. ## Responses[​](/docs/api/rest/workspaces-entities-entities-read/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**objectrequired **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "count": 0, "results": { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Tree App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. `Is Tree App Workspace Context` : Workspace should have a `tree` app. Loading... --- # Create a Job ``` POST /api/workspaces/:workspace_id/entities/:id/jobs/ ``` Creates a Job. For the simplest computation flow, set `poll_result=false` or do not include it in the payload. This will ensure that the end-point always responds with: * 201: job is still running, start polling on the `/jobs/UID/` end-point, provided under "url" key. (see Jobs end-points) Setting `poll_result=true` is only useful for very quick jobs, since the BE polls checks internally for job completion for a short period before responding with either: * 200: job returned with full response. * 201: job is still running, start polling on the `/jobs/UID/` end-point, provided under "url" key. (see Jobs end-points) ## Request[​](/docs/api/rest/workspaces-entities-jobs/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. - application/json ### Body**required** * **poll\_result** boolean Let the endpoint temporarily poll for the result. **method\_name** string **Possible values:** `non-empty` Name to the method to run the App Job. **method\_type** string **Possible values:** `non-empty` Type to the method to run the App Job. **editor\_session** uuid UUID of the current editor session. This field is required when called under public endpoints. **params** objectnullable **Default value:** `[object Object]` (Optional) params as input for App Job. **events** string\[] **Default value:** \`\` (Optional) events as input for App Job. **timeout** integer **Possible values:** `>= 1` and `<= 86400` **Default value:** `86400` (Optional) max job duration as input for App Job. **arguments** objectnullable **Default value:** `[object Object]` (deprecated) replaced with `params`. **method** string **Possible values:** `non-empty` (deprecated) replaced with `method_name`. ## Responses[​](/docs/api/rest/workspaces-entities-jobs/.md#responses "Direct link to Responses") * 200 * 201 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **uid** integer The uid of the AppJob. **message** string **Possible values:** `non-empty` Progress message when app runner is still processing the job. **kind** string **Possible values:** `non-empty` The result payload kind. **status** string **Possible values:** `non-empty` Status of the AppJob. 'success' | 'error' | 'error\_user' | 'stopped' | 'message'. **error\_message** string **Possible values:** `non-empty` If error is raised, the error message returned. **error\_stack\_trace** object If error is raised, the stack trace is returned. **invalid\_fields** object Any invalid fields that were found during the Job. **content** object The actual result content. ``` { "uid": 0, "message": "string", "kind": "string", "status": "string", "error_message": "string", "error_stack_trace": {}, "invalid_fields": {}, "content": {} } ``` * application/json - Schema - Example (from schema) **Schema** * **uid** integer The uid of the AppJob. **url** urinullable **Possible values:** `non-empty` The URL to the location of the AppJob. ``` { "uid": 0, "url": "string" } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Get all Entities ``` GET /api/workspaces/:workspace_id/entities/ ``` Get all entities. ## Request[​](/docs/api/rest/workspaces-entities-list/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. **limit** integer **Possible values:** `>= 1` Number of results to return per page. **offset** integer The initial index from which to return the results. **entity\_type** string\[] **Possible values:** `non-empty` Allows filtering on id (int) or class\_name (string). **sort** string\[] **Possible values:** `non-empty` Allowed values: `name`, `updated_at`, `summary_updated_at` and/or `summary`. **name** string **Possible values:** `non-empty` **search** string **Possible values:** `non-empty` Allow for fuzzy name match. **only\_name** boolean **created\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **last\_updated\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **created\_at\_min** date-time Created after specified date (ISO format). **created\_at\_max** date-time Created before specified date (ISO format). **updated\_at\_min** date-time Updated after specified date (ISO format). **updated\_at\_max** date-time Updated before specified date (ISO format). **id** integer\[] Filter on specific entity id. ## Responses[​](/docs/api/rest/workspaces-entities-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ] ``` { "count": 0, "results": [ { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Get Editor Session Messages ``` GET /api/workspaces/:workspace_id/entities/:id/messages/ ``` Fetch system and user messages within an editor session. User should have at least `READ` permission on the entity to fetch messages. ## Request[​](/docs/api/rest/workspaces-entities-messages/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ### Query Parameters * **editor\_session** uuidrequired Session identifier (UUID) ## Responses[​](/docs/api/rest/workspaces-entities-messages/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * Array \[ * **job\_id** integer Id of the job. **created\_at** date-time Creation date of the job. **job\_label** stringnullable **Possible values:** `non-empty` Human readable label of the job. **job\_method\_type** string **Possible values:** `non-empty` Job method type. It can be one of: geometry, plotly, data, optimise-button, image\_and\_data, step-next, plotly\_and\_data, ifc\_and\_data, geojson, svg\_and\_data, svg, analyse-button, web\_and\_data, ifc, pdf, set-params-button, image, download-button, geojson\_and\_data, web, geometry\_and\_data. **completion\_type** string **Possible values:** `non-empty` Type of completion. It can be one of: result, stopped, expired, error, error\_user. **error\_reported** boolean Shows whether error is reported. Errors can be reported when job is finished with `ERROR` completion type. **error\_message** stringnullable **Possible values:** `non-empty` Error message of the job if finished with `ERROR_USER` completion type. **messages**object\[]required List of last messages. Array \[ * **message\_type** string **Possible values:** `non-empty` Type of the message. It can be one of success, info, warning, started, result, stopped, expired, error, error\_user **message** string **Possible values:** `non-empty` Message content. **timestamp** date-time Timestamp of the message. ] * ] ``` [ { "job_id": 0, "created_at": "2024-06-11T11:45:44.603Z", "job_label": "string", "job_method_type": "string", "completion_type": "string", "error_reported": true, "error_message": "string", "messages": [ { "message_type": "string", "message": "string", "timestamp": "2024-06-11T11:45:44.603Z" } ] } ] ``` No associated editor session found. No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Send Parametrization Job ``` POST /api/workspaces/:workspace_id/entities/:id/parametrization/ ``` Blocking endpoint to get parametrization as resolved by the app. ## Request[​](/docs/api/rest/workspaces-entities-parametrization/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. - application/json ### Body**required** * **editor\_session** uuid UUID of the current editor session. This field is required on public workspace parametrization endpoint. **params** objectnullable **Default value:** `[object Object]` (Optional) params as input for parametrization. ## Responses[​](/docs/api/rest/workspaces-entities-parametrization/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 * 504 - application/json * Schema * Example (from schema) **Schema** * **uid** integer The uid of the AppJob. **message** string **Possible values:** `non-empty` Progress message when app runner is still processing the job. **kind** string **Possible values:** `non-empty` The result payload kind. **status** string **Possible values:** `non-empty` Status of the AppJob. 'success' | 'error' | 'error\_user' | 'stopped' | 'message'. **error\_message** string **Possible values:** `non-empty` If error is raised, the error message returned. **error\_stack\_trace** object If error is raised, the stack trace is returned. **invalid\_fields** object Any invalid fields that were found during the Job. **content** object The actual result content. ``` { "uid": 0, "message": "string", "kind": "string", "status": "string", "error_message": "string", "error_stack_trace": {}, "invalid_fields": {}, "content": {} } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Job has timed out. Loading... --- # Get Parent of an Entity ``` GET /api/workspaces/:workspace_id/entities/:id/parent/ ``` Get the parent entity. ## Request[​](/docs/api/rest/workspaces-entities-parent/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. ## Responses[​](/docs/api/rest/workspaces-entities-parent/.md#responses "Direct link to Responses") * 200 * 204 * 400 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ``` Requested entity has no parent Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Tree App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. `Is Tree App Workspace Context` : Workspace should have a `tree` app. Requested entity not found Loading... --- # Get all Permission Groups of an Entity ``` GET /api/workspaces/:workspace_id/entities/:id/permission_groups/ ``` Get all permission groups of an entity by entity id. ## Request[​](/docs/api/rest/workspaces-entities-permission-groups/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ### Query Parameters * **entity\_type\_id** integerrequired Entity type id. ## Responses[​](/docs/api/rest/workspaces-entities-permission-groups/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **inherited** integer\[]required Inherited group ids for the user in the specified entity level **available** integer\[]required Available group ids for the user in the specified entity level ``` { "inherited": [ 0 ], "available": [ 0 ] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Not App* **AND** *Is Not Editor App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Is Not Editor App Workspace Context` : Not available for `editor` type apps. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Get Entity by Id ``` GET /api/workspaces/:workspace_id/entities/:id/ ``` Get a single entity by its id. ## Request[​](/docs/api/rest/workspaces-entities-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. ## Responses[​](/docs/api/rest/workspaces-entities-read/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Create a new Editor Session ``` POST /api/workspaces/:workspace_id/entities/:id/session/ ``` Create an editor session for the corresponding entity. ## Request[​](/docs/api/rest/workspaces-entities-session/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. ## Responses[​](/docs/api/rest/workspaces-entities-session/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **editor\_session** uuidrequired The uuid reserved for this Session. ``` { "editor_session": "3fa85f64-5717-4562-b3fc-2c963f66afa6" } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Get Siblings of an Entity ``` GET /api/workspaces/:workspace_id/entities/:id/siblings/ ``` Get siblings of an entity by its id. ## Request[​](/docs/api/rest/workspaces-entities-siblings/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. **limit** integer **Possible values:** `>= 1` Number of results to return per page. **offset** integer The initial index from which to return the results. **entity\_type** string\[] **Possible values:** `non-empty` Allows filtering on id (int) or class\_name (string). **sort** string\[] **Possible values:** `non-empty` Allowed values: `name`, `updated_at`, `summary_updated_at` and/or `summary`. **name** string **Possible values:** `non-empty` **search** string **Possible values:** `non-empty` Allow for fuzzy name match. **only\_name** boolean **created\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **last\_updated\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **created\_at\_min** date-time Created after specified date (ISO format). **created\_at\_max** date-time Created before specified date (ISO format). **updated\_at\_min** date-time Updated after specified date (ISO format). **updated\_at\_max** date-time Updated before specified date (ISO format). **id** integer\[] Filter on specific entity id. ## Responses[​](/docs/api/rest/workspaces-entities-siblings/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Not Editor App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Is Not Editor App Workspace Context` : Not available for `editor` type apps. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Update Entity by Id ``` PUT /api/workspaces/:workspace_id/entities/:id/ ``` Update entity by its id. ## Request[​](/docs/api/rest/workspaces-entities-update/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity. - application/json ### Body**required** * **name** stringrequired **Possible values:** `non-empty` Entity name. **properties** objectrequired Entity properties to be saved. **filename** stringrequired **Possible values:** `non-empty` File name of the entity if entity is a member of file entity type. **message** stringrequired **Possible values:** `non-empty` Revision message. ## Responses[​](/docs/api/rest/workspaces-entities-update/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ``` { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Get All Entities of an Entity Type ``` GET /api/workspaces/:workspace_id/entity_types/:id/entities/ ``` Get all entities of an entity type. ## Request[​](/docs/api/rest/workspaces-entity-types-entities-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **properties** boolean Whether or not to include entity.properties. **clean\_params** boolean Whether or not to clean the params before returning. **param\_types** boolean Whether or not to include entity.param\_types. **summary\_types** boolean Whether or not to include entity.summary\_types. **privileged** boolean Whether or not the request should be done with elevated access. **limit** integer **Possible values:** `>= 1` Number of results to return per page. **offset** integer The initial index from which to return the results. **entity\_type** string\[] **Possible values:** `non-empty` Allows filtering on id (int) or class\_name (string). **sort** string\[] **Possible values:** `non-empty` Allowed values: `name`, `updated_at`, `summary_updated_at` and/or `summary`. **name** string **Possible values:** `non-empty` **search** string **Possible values:** `non-empty` Allow for fuzzy name match. **only\_name** boolean **created\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **last\_updated\_by** integer\[] Specify one or more user ids. This field is not allowed on public workspace entities endpoint. **created\_at\_min** date-time Created after specified date (ISO format). **created\_at\_max** date-time Created before specified date (ISO format). **updated\_at\_min** date-time Updated after specified date (ISO format). **updated\_at\_max** date-time Updated before specified date (ISO format). **id** integer\[] Filter on specific entity id. ## Responses[​](/docs/api/rest/workspaces-entity-types-entities-read/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **id** integer **name** string **properties** object **summary\_status** string **summary** string **summary\_updated\_at** string **summary\_types** string **deleted** string **locked** boolean **locked\_by** object **entity\_type** integerrequired **entity\_type\_name** string **updated\_at** string **parent\_count** integer **actions** string **param\_types** string **created\_by** integer **created\_at** string **last\_updated\_by** integer **path** integer **show\_on\_dashboard** boolean ] ``` { "count": 0, "results": [ { "id": 0, "name": "string", "properties": {}, "summary_status": "string", "summary": "string", "summary_updated_at": "string", "summary_types": "string", "deleted": "string", "locked": true, "locked_by": {}, "entity_type": 0, "entity_type_name": "string", "updated_at": "string", "parent_count": 0, "actions": "string", "param_types": "string", "created_by": 0, "created_at": "string", "last_updated_by": 0, "path": 0, "show_on_dashboard": false } ] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Not Editor App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Is Not Editor App Workspace Context` : Not available for `editor` type apps. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Get all Child Entity Types of an Entity Type ``` GET /api/workspaces/:workspace_id/entity_types/:id/entity_types/ ``` Get all child entity types of an entity type. ## Request[​](/docs/api/rest/workspaces-entity-types-entity-types/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity type. ### Query Parameters * **limit** integer **Possible values:** `>= 1` Number of results to return per page. **offset** integer The initial index from which to return the results. ## Responses[​](/docs/api/rest/workspaces-entity-types-entity-types/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **id** integer **name** string **Possible values:** `non-empty` **class\_name** stringnullable **Possible values:** `non-empty` **preprocess\_method** stringnullable **Possible values:** `non-empty` **is\_file** boolean **has\_designer** boolean **show\_children\_as** string **Possible values:** `non-empty` **views** object\[] Views definition **summary** object\[] Summary definition **scope** string **Possible values:** `non-empty` and `<= 15 characters` **actions** string User permissions **child\_entity\_type\_ids** integer\[]required Ids of the child entity types **file\_constraints** object Specifies the maximum size and allowed file types **viktor\_store\_table\_option\_field\_value** boolean Migration flag: if true, the value of an option field within a table is stored instead of its label **viktor\_enforce\_field\_constraints** boolean Migration flag: if true, violated field constraints block actions until they are resolved **parametrization\_width** integernullable **views\_only** boolean Specifies whether entity type has only views (no parametrization) **show\_file\_manager** boolean **navigate\_to\_editor** boolean If true, users will navigate directly to the editor of the entity instead of the browse screen ] ``` { "count": 0, "results": [ { "id": 0, "name": "string", "class_name": "string", "preprocess_method": "string", "is_file": true, "has_designer": true, "show_children_as": "string", "views": [ {} ], "summary": [ {} ], "scope": "string", "actions": "string", "child_entity_type_ids": [ 0 ], "file_constraints": {}, "viktor_store_table_option_field_value": true, "viktor_enforce_field_constraints": true, "parametrization_width": 0, "views_only": true, "show_file_manager": true, "navigate_to_editor": true } ] } ``` Incorrect query params No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Tree App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Workspace Context Permission` : Workspace must be available to the User. `Is Tree App Workspace Context` : Workspace should have a `tree` app. Children not found or no permission Loading... --- # Get all Entity Types ``` GET /api/workspaces/:workspace_id/entity_types/ ``` Get all entity types. ## Request[​](/docs/api/rest/workspaces-entity-types-list/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. ## Responses[​](/docs/api/rest/workspaces-entity-types-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**object\[]required Array \[ * **id** integer **name** string **Possible values:** `non-empty` **class\_name** stringnullable **Possible values:** `non-empty` **preprocess\_method** stringnullable **Possible values:** `non-empty` **is\_file** boolean **has\_designer** boolean **show\_children\_as** string **Possible values:** `non-empty` **views** object\[] Views definition **summary** object\[] Summary definition **scope** string **Possible values:** `non-empty` and `<= 15 characters` **actions** string User permissions **child\_entity\_type\_ids** integer\[]required Ids of the child entity types **file\_constraints** object Specifies the maximum size and allowed file types **viktor\_store\_table\_option\_field\_value** boolean Migration flag: if true, the value of an option field within a table is stored instead of its label **viktor\_enforce\_field\_constraints** boolean Migration flag: if true, violated field constraints block actions until they are resolved **parametrization\_width** integernullable **views\_only** boolean Specifies whether entity type has only views (no parametrization) **show\_file\_manager** boolean **navigate\_to\_editor** boolean If true, users will navigate directly to the editor of the entity instead of the browse screen ] ``` { "count": 0, "results": [ { "id": 0, "name": "string", "class_name": "string", "preprocess_method": "string", "is_file": true, "has_designer": true, "show_children_as": "string", "views": [ {} ], "summary": [ {} ], "scope": "string", "actions": "string", "child_entity_type_ids": [ 0 ], "file_constraints": {}, "viktor_store_table_option_field_value": true, "viktor_enforce_field_constraints": true, "parametrization_width": 0, "views_only": true, "show_file_manager": true, "navigate_to_editor": true } ] } ``` Incorrect query params No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Get Entity Type by Id ``` GET /api/workspaces/:workspace_id/entity_types/:id/ ``` Get an entity type by its id. ## Request[​](/docs/api/rest/workspaces-entity-types-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity type. ## Responses[​](/docs/api/rest/workspaces-entity-types-read/.md#responses "Direct link to Responses") * 200 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **Possible values:** `non-empty` **class\_name** stringnullable **Possible values:** `non-empty` **preprocess\_method** stringnullable **Possible values:** `non-empty` **is\_file** boolean **has\_designer** boolean **show\_children\_as** string **Possible values:** `non-empty` **views** object\[] Views definition **summary** object\[] Summary definition **scope** string **Possible values:** `non-empty` and `<= 15 characters` **actions** string User permissions **child\_entity\_type\_ids** integer\[]required Ids of the child entity types **file\_constraints** object Specifies the maximum size and allowed file types **viktor\_store\_table\_option\_field\_value** boolean Migration flag: if true, the value of an option field within a table is stored instead of its label **viktor\_enforce\_field\_constraints** boolean Migration flag: if true, violated field constraints block actions until they are resolved **parametrization\_width** integernullable **views\_only** boolean Specifies whether entity type has only views (no parametrization) **show\_file\_manager** boolean **navigate\_to\_editor** boolean If true, users will navigate directly to the editor of the entity instead of the browse screen ``` { "id": 0, "name": "string", "class_name": "string", "preprocess_method": "string", "is_file": true, "has_designer": true, "show_children_as": "string", "views": [ {} ], "summary": [ {} ], "scope": "string", "actions": "string", "child_entity_type_ids": [ 0 ], "file_constraints": {}, "viktor_store_table_option_field_value": true, "viktor_enforce_field_constraints": true, "parametrization_width": 0, "views_only": true, "show_file_manager": true, "navigate_to_editor": true } ``` Loading... --- # Upload an Entity of File Entity Type ``` POST /api/workspaces/:workspace_id/entity_types/:id/upload/ ``` Upload an entity of the corresponding file entity type. ## Request[​](/docs/api/rest/workspaces-entity-types-upload/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this entity type. ## Responses[​](/docs/api/rest/workspaces-entity-types-upload/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 Upload URL. EntityType is not a file No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** (*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **AND** *Is Not Editor App Workspace Context* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Is Not Editor App Workspace Context` : Not available for `editor` type apps. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Create File ``` POST /api/workspaces/:workspace_id/files/ ``` Create a new file object in the scope of an entity or session. Subsequently, the `temp_upload_url` and `temp_upload_data` from the response need to be used to upload the file itself. ## Request[​](/docs/api/rest/workspaces-files-create/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired - application/json ### Body**required** * **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integer Id of entity which the file is bound. This field can be provided when in tree or simple app types only. **editor\_session** uuid Editor session to be scoped under. This field should be provided on editor app type only. **filename** stringrequired **Possible values:** `non-empty` and `<= 512 characters` Name of the file to be uploaded. ## Responses[​](/docs/api/rest/workspaces-files-create/.md#responses "Direct link to Responses") * 201 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integer Id of entity which the file is bound. This field can be provided when in tree or simple app types only. **editor\_session** uuid Editor session to be scoped under. This field should be provided on editor app type only. **filename** stringrequired **Possible values:** `non-empty` and `<= 512 characters` Name of the file to be uploaded. **created\_at** date-time Creation date and time of the file. **temp\_upload\_url** string **Possible values:** `non-empty` Temporary S3 upload url of the object. See :ref:`Using S3 Presigned Post Payloads ` for details. **temp\_upload\_data** object Temporary S3 upload fields which will be used when sending the object to S3 with **file**. See :ref:`Using S3 Presigned Post Payloads ` for details. ``` { "id": 0, "scope": "entity", "entity_id": 0, "editor_session": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "filename": "string", "created_at": "2024-06-11T11:45:44.613Z", "temp_upload_url": "string", "temp_upload_data": {} } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Delete File by Id ``` DELETE /api/workspaces/:workspace_id/files/:id/ ``` Delete a file by its id. ## Request[​](/docs/api/rest/workspaces-files-delete/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this field file. - application/json ### Body**required** * **editor\_session** uuid UUID of the editor session. This field is only required when used from public endpoints. ## Responses[​](/docs/api/rest/workspaces-files-delete/.md#responses "Direct link to Responses") * 204 * 401 * 403 Deleted successfully. No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Download File by Id ``` GET /api/workspaces/:workspace_id/files/:id/download/ ``` Download a file by its id. ## Request[​](/docs/api/rest/workspaces-files-download/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this field file. ### Query Parameters * **editor\_session** uuid UUID of the editor session. This field is only required when used from public endpoints. **redirect** boolean **Default value:** `true` Should the response be a redirect response to the file resource? This field is `true` on default. ## Responses[​](/docs/api/rest/workspaces-files-download/.md#responses "Direct link to Responses") * 200 * 302 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **temp\_download\_url** string **Possible values:** `non-empty` Temporary download url (if 'redirect=false'). ``` { "temp_download_url": "string" } ``` File stream redirection No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. File is not found Loading... --- # List All Files ``` GET /api/workspaces/:workspace_id/files/ ``` List all files in the scope. Files can have two different scopes, namely `entity` or `session`. When file is scoped under `entity`, it will be available under the file discovery modal of that specific entity. When file is scoped under `session`, it will only be available in the editor session lifetime and then destroyed. ## Request[​](/docs/api/rest/workspaces-files-list/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **pagination\_token** string Pagination token indicating the next cursor position **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integer Filter by scoped entity id. It is only applicable in simple and tree app types. **editor\_session** uuid Filter by scoped editor session. This field is required in editor-only app and not applicable in other types of apps. **id** integer\[] FieldFile id. This field accepts multiple. **file\_type** string\[] **Possible values:** `non-empty` and `<= 10 characters` Type of the file which starts with dot(.). This field accepts multiple. **file\_size\_max** integer Maximum file size in bytes.(including) **search** string **Possible values:** `non-empty` and `<= 512 characters` Search term of the filename including extension. ## Responses[​](/docs/api/rest/workspaces-files-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 - application/json * Schema * Example (from schema) **Schema** * **count** integer Count of all the objects in the result set. **next\_token** string Token for the results of the next page, to be sent as **pagination\_token** in the next request. **results**object\[]required Array \[ * **id** integer **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integerrequired Id of entity which the file is bound. **editor\_session** uuidrequired Editor session to be scoped under. This field should be provided on editor app type only. **filename** stringrequired **Possible values:** `non-empty` and `<= 512 characters` Name of the file to be uploaded. **file\_size** integerrequired Size of the file in bytes. **created\_at** date-timerequired Creation date and time of the file. **created\_by** integernullable ID of the user that created the file. ] ``` { "count": 0, "next_token": "string", "results": [ { "id": 0, "scope": "entity", "entity_id": 0, "editor_session": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "filename": "string", "file_size": 0, "created_at": "2024-06-11T11:45:44.612Z", "created_by": 0 } ] } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Loading... --- # Get File by Id ``` GET /api/workspaces/:workspace_id/files/:id/ ``` Get a file by its id. ## Request[​](/docs/api/rest/workspaces-files-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this field file. ### Query Parameters * **editor\_session** uuid UUID of the editor session. This field is only required when used from public endpoints. ## Responses[​](/docs/api/rest/workspaces-files-read/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integerrequired Id of entity which the file is bound. **editor\_session** uuidrequired Editor session to be scoped under. This field should be provided on editor app type only. **filename** stringrequired **Possible values:** `non-empty` and `<= 512 characters` Name of the file to be uploaded. **file\_size** integerrequired Size of the file in bytes. **created\_at** date-timerequired Creation date and time of the file. **created\_by** integernullable ID of the user that created the file. ``` { "id": 0, "scope": "entity", "entity_id": 0, "editor_session": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "filename": "string", "file_size": 0, "created_at": "2024-06-11T11:45:44.614Z", "created_by": 0 } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. Loading... --- # Send Uploaded Signal for a File by Id ``` POST /api/workspaces/:workspace_id/files/:id/uploaded/ ``` Viktor collects the metadata of a file and makes it available for usage in file field when this signal is called by the client. ## Request[​](/docs/api/rest/workspaces-files-uploaded/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this field file. - application/json ### Body**required** * **editor\_session** uuid UUID of the editor session. This field is only required when used from public endpoints. ## Responses[​](/docs/api/rest/workspaces-files-uploaded/.md#responses "Direct link to Responses") * 200 * 401 * 403 * 405 - application/json * Schema * Example (from schema) **Schema** * **id** integer **scope** stringrequired **Possible values:** \[`entity`, `session`] Scope of the file. Can be one of: entity, session. **entity\_id** integerrequired Id of entity which the file is bound. **editor\_session** uuidrequired Editor session to be scoped under. This field should be provided on editor app type only. **filename** stringrequired **Possible values:** `non-empty` and `<= 512 characters` Name of the file to be uploaded. **file\_size** integerrequired Size of the file in bytes. **created\_at** date-timerequired Creation date and time of the file. **created\_by** integernullable ID of the user that created the file. ``` { "id": 0, "scope": "entity", "entity_id": 0, "editor_session": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "filename": "string", "file_size": 0, "created_at": "2024-06-11T11:45:44.615Z", "created_by": 0 } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** ((*Is Authenticated Organization Admin* **OR** *Workspace Context Permission*) **OR** *Public Permission*) **AND** *Is Not App* **Descriptions:** `Is Authenticated Organization Admin` : User must be an Organization Admin. `Public Permission` : Checks corresponding workspace is public. `Workspace Context Permission` : Workspace must be available to the User. `Is Not App` : Client must not be a VIKTOR app. File is not uploaded yet. Loading... --- # Get All Workspace Groups ``` GET /api/workspaces/:workspace_id/groups/ ``` Returns current user's groups or all groups if the user is admin. ## Request[​](/docs/api/rest/workspaces-groups-list/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **sort** string **Possible values:** \[`name`, `name:asc`, `name:desc`] Sort by name, allowing for `:asc` and `:desc` suffixes. **search** string **Possible values:** `non-empty` Search within name and description ## Responses[​](/docs/api/rest/workspaces-groups-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 128 characters` **description** stringnullable **Possible values:** `<= 512 characters` **members** integer\[] **members\_only\_in\_this\_group** integer **is\_default** boolean ``` { "id": 0, "name": "string", "description": "string", "members": [ 0 ], "members_only_in_this_group": 0, "is_default": true } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** ((*Safe Permission* **AND** *Read Group Permission*) **OR** (*Workspace Context Permission* **AND** *Is Authenticated Workspace Admin*)) **AND** *Is Not Editor App Workspace Context* **Descriptions:** `Read Group Permission` : Permitted to read Group if member of Group. `Is Not Editor App Workspace Context` : Not available for `editor` type apps. `Workspace Context Permission` : Workspace must be available to the User. `Is Authenticated Workspace Admin` : Checks whether the user has admin rights to the workspace. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. `Safe Permission` : Permitted to perform Safe operations (read) Loading... --- # Get Group Permissions by Id ``` GET /api/workspaces/:workspace_id/groups/:id/permissions/ ``` Returns the permissions assigned to a group, including permitted actions per permission object. **ONLY FOR ADMINS** ## Request[​](/docs/api/rest/workspaces-groups-permissions/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this group. ### Query Parameters * **object\_type** string Filter response by `EntityType` or `Entity` ## Responses[​](/docs/api/rest/workspaces-groups-permissions/.md#responses "Direct link to Responses") * 200 - application/json * Schema * Example (from schema) **Schema** * Array \[ * **id** integer **workspace** integerrequired **group** integerrequired **object\_type** stringrequired **Possible values:** \[`EntityType`, `Entity`] `EntityType` or `Entity` **object\_instance**objectnullable **id** integerrequired `EntityType.id` or `Entity.id` **\** string **actions** stringrequired ] ``` [ { "id": 0, "workspace": 0, "group": 0, "object_type": "EntityType", "object_instance": { "id": 0, "": "string" }, "actions": "string" } ] ``` Loading... --- # Get Workspace User Group by Id ``` GET /api/workspaces/:workspace_id/groups/:id/ ``` Returns a single group if the current user belongs to the group or is an administrator. ## Request[​](/docs/api/rest/workspaces-groups-read/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired **id** integerrequired A unique integer value identifying this group. ## Responses[​](/docs/api/rest/workspaces-groups-read/.md#responses "Direct link to Responses") * 200 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 128 characters` **description** stringnullable **Possible values:** `<= 512 characters` **members** integer\[] **members\_only\_in\_this\_group** integer **is\_default** boolean ``` { "id": 0, "name": "string", "description": "string", "members": [ 0 ], "members_only_in_this_group": 0, "is_default": true } ``` Loading... --- # Get All Workspaces ``` GET /api/workspaces/ ``` List the workspaces for the current user, depending on user role and access. ## Request[​](/docs/api/rest/workspaces-list/.md#request "Direct link to Request") ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. **include\_development** boolean Set to True for gathering all individual development workspaces of users. Requires **org admin** permission. **include\_archived** boolean Whether or not to include archived workspaces. Requires **org admin** permission. **visibility** string\[] **Possible values:** \[`INTERNAL`, `PRIVATE`, `DEVELOPMENT`, `PUBLIC`] Filter on workspace visibility. Can be one of: INTERNAL, PRIVATE, DEVELOPMENT, PUBLIC. **app** integer\[] Filter on app ID. **label** integer\[] Filter on label ID. **sort** string **Possible values:** \[`name`, `name:asc`, `name:desc`, `created_at`, `created_at:asc`, `created_at:desc`, `views`, `views:asc`, `views:desc`] Sort by name | created\_at | views, allowing for `:asc` and `:desc` suffixes. **search** string **Possible values:** `non-empty` Allow for fuzzy name/description match. ## Responses[​](/docs/api/rest/workspaces-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired Count of all the objects in the result set. **results**objectrequired **count** integerrequired **next** urinullable **previous** urinullable **results**object\[]required Array \[ * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 128 characters` The name of the workspace. **slug** slug **Possible values:** `non-empty`, Value must match regular expression `^[-a-zA-Z0-9_]+$` The unique slug representation of the workspace if it is public. **description** string A description about the workspace and its usage. **created\_at** date-time The workspace creation date. The value is in ISO 8601 format. **updated\_at** date-time The date the workspace was last updated. The value is in ISO 8601 format. **visibility** stringrequired **Possible values:** \[`INTERNAL`, `PRIVATE`, `DEVELOPMENT`, `PUBLIC`] **app\_version**object **id** integer **tag** string **Possible values:** `non-empty` Unique version tag for the application. **is\_conflicted** boolean **status** string **Possible values:** \[`CREATED`, `UPLOADING`, `PACKING`, `CHECKING`, `PUBLISHING`, `PUBLISHED`, `ERROR`, `ERROR_WITH_ACTION_REQUIRED`] Status of the app version. It can be one of CREATED, UPLOADING, PACKING, CHECKING, PUBLISHING, PUBLISHED, ERROR, ERROR\_WITH\_ACTION\_REQUIRED **app\_type** string **Possible values:** \[`tree`, `simple`, `editor`] Shows the application type. It can be one of tree,simple,editor **sdk\_version** string **python\_version** string **Possible values:** `non-empty` Python version of the version. Supported versions are: 3.7, 3.8, 3.9, 3.10, 3.11 **connector\_version** string **Possible values:** `non-empty` Connector version. **created\_at** date-time App version creation date. The value is in ISO 8601 format. **created\_by\_type** stringrequired **Possible values:** \[`User`, `CI`] Type of the instance creating. It can be one of User, CI **created\_by\_instance** integerrequired Returns the creating instance id. **created\_by\_context** object **Default value:** `[object Object]` Context dictionary which is provided in publishing flow. It can be either user object(*id*, *name*, *first\_name*, *last\_name*, *email*) or CI object(*id*, *name*) **progress** string Progress steps of the app version statuses.This field returns list of dictionary having *name*, *detail*, *status*, *started\_at*, and *finished\_at*. It can be one of AWAITING, STARTED, FINISHED, FINISHED\_WITH\_WARNINGS, ERROR **app**object **id** integer **name** string **errors**object\[] Array \[ * **code** string **Possible values:** `non-empty` The error code. Check the codes reference for more information. **context** object Extra information related to the context of the error. Check the codes reference for more information. ] * **image** stringnullable **Possible values:** `non-empty` An image (b64 encoded, <1MB) visible on the workspace card. **is\_dev** boolean Returns whether the workspace is dev. **owner** integer Returns the owner id of a development workspace. This field is `null` when `is_dev` is false. **is\_initialized** boolean Returns whether the workspace is initialized with entity types. **is\_archived** boolean Returns whether the workspace is archived. **is\_active** boolean Shows whether runners are ready for jobs. **labels**object\[] Array \[ * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 30 characters` **description** string **Possible values:** `<= 100 characters` **color** stringrequired **Possible values:** `non-empty` and `<= 6 characters` **number\_of\_apps** integer **number\_of\_workspaces** integer ] * **default\_group** integer **nr\_views** integer The calculated total daily unique sessions in case of internal/private workspace, and the number of views (count editor sessions) in case of public workspace ] ``` { "count": 0, "results": { "count": 0, "next": "string", "previous": "string", "results": [ { "id": 0, "name": "string", "slug": "string", "description": "string", "created_at": "2024-06-11T11:45:44.592Z", "updated_at": "2024-06-11T11:45:44.592Z", "visibility": "INTERNAL", "app_version": { "id": 0, "tag": "string", "is_conflicted": true, "status": "CREATED", "app_type": "tree", "sdk_version": "string", "python_version": "string", "connector_version": "string", "created_at": "2024-06-11T11:45:44.592Z", "created_by_type": "User", "created_by_instance": 0, "created_by_context": {}, "progress": "string" }, "app": { "id": 0, "name": "string" }, "errors": [ { "code": "string", "context": {} } ], "image": "string", "is_dev": true, "owner": 0, "is_initialized": true, "is_archived": true, "is_active": true, "labels": [ { "id": 0, "name": "string", "description": "string", "color": "string", "number_of_apps": 0, "number_of_workspaces": 0 } ], "default_group": 0, "nr_views": 0 } ] } } ``` Validation error response. It produces a validation error schema like below. ``` { "field1": ["Validation error"], "non_field_errors": ["Sample non field validation error"] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **Descriptions:** `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Get Workspace by Id ``` GET /api/workspaces/:id/ ``` Returns a single workspace by id. ## Request[​](/docs/api/rest/workspaces-read/.md#request "Direct link to Request") ### Path Parameters * **id** integerrequired A unique integer value identifying this workspace. ## Responses[​](/docs/api/rest/workspaces-read/.md#responses "Direct link to Responses") * 200 * 401 * 403 * 404 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 128 characters` The name of the workspace. **slug** slug **Possible values:** `non-empty`, Value must match regular expression `^[-a-zA-Z0-9_]+$` The unique slug representation of the workspace if it is public. **description** string A description about the workspace and its usage. **created\_at** date-time The workspace creation date. The value is in ISO 8601 format. **updated\_at** date-time The date the workspace was last updated. The value is in ISO 8601 format. **visibility** stringrequired **Possible values:** \[`INTERNAL`, `PRIVATE`, `DEVELOPMENT`, `PUBLIC`] **app\_version**object **id** integer **tag** string **Possible values:** `non-empty` Unique version tag for the application. **is\_conflicted** boolean **status** string **Possible values:** \[`CREATED`, `UPLOADING`, `PACKING`, `CHECKING`, `PUBLISHING`, `PUBLISHED`, `ERROR`, `ERROR_WITH_ACTION_REQUIRED`] Status of the app version. It can be one of CREATED, UPLOADING, PACKING, CHECKING, PUBLISHING, PUBLISHED, ERROR, ERROR\_WITH\_ACTION\_REQUIRED **app\_type** string **Possible values:** \[`tree`, `simple`, `editor`] Shows the application type. It can be one of tree,simple,editor **sdk\_version** string **python\_version** string **Possible values:** `non-empty` Python version of the version. Supported versions are: 3.7, 3.8, 3.9, 3.10, 3.11 **connector\_version** string **Possible values:** `non-empty` Connector version. **created\_at** date-time App version creation date. The value is in ISO 8601 format. **created\_by\_type** stringrequired **Possible values:** \[`User`, `CI`] Type of the instance creating. It can be one of User, CI **created\_by\_instance** integerrequired Returns the creating instance id. **created\_by\_context** object **Default value:** `[object Object]` Context dictionary which is provided in publishing flow. It can be either user object(*id*, *name*, *first\_name*, *last\_name*, *email*) or CI object(*id*, *name*) **progress** string Progress steps of the app version statuses.This field returns list of dictionary having *name*, *detail*, *status*, *started\_at*, and *finished\_at*. It can be one of AWAITING, STARTED, FINISHED, FINISHED\_WITH\_WARNINGS, ERROR **app**object **id** integer **name** string **errors**object\[] Array \[ * **code** string **Possible values:** `non-empty` The error code. Check the codes reference for more information. **context** object Extra information related to the context of the error. Check the codes reference for more information. ] * **image** stringnullable **Possible values:** `non-empty` An image (b64 encoded, <1MB) visible on the workspace card. **is\_dev** boolean Returns whether the workspace is dev. **owner** integer Returns the owner id of a development workspace. This field is `null` when `is_dev` is false. **is\_initialized** boolean Returns whether the workspace is initialized with entity types. **is\_archived** boolean Returns whether the workspace is archived. **is\_active** boolean Shows whether runners are ready for jobs. **labels**object\[] Array \[ * **id** integer **name** stringrequired **Possible values:** `non-empty` and `<= 30 characters` **description** string **Possible values:** `<= 100 characters` **color** stringrequired **Possible values:** `non-empty` and `<= 6 characters` **number\_of\_apps** integer **number\_of\_workspaces** integer ] **default\_group** integer **nr\_views** integer The calculated total daily unique sessions in case of internal/private workspace, and the number of views (count editor sessions) in case of public workspace ``` { "id": 0, "name": "string", "slug": "string", "description": "string", "created_at": "2024-06-11T11:45:44.593Z", "updated_at": "2024-06-11T11:45:44.593Z", "visibility": "INTERNAL", "app_version": { "id": 0, "tag": "string", "is_conflicted": true, "status": "CREATED", "app_type": "tree", "sdk_version": "string", "python_version": "string", "connector_version": "string", "created_at": "2024-06-11T11:45:44.593Z", "created_by_type": "User", "created_by_instance": 0, "created_by_context": {}, "progress": "string" }, "app": { "id": 0, "name": "string" }, "errors": [ { "code": "string", "context": {} } ], "image": "string", "is_dev": true, "owner": 0, "is_initialized": true, "is_archived": true, "is_active": true, "labels": [ { "id": 0, "name": "string", "description": "string", "color": "string", "number_of_apps": 0, "number_of_workspaces": 0 } ], "default_group": 0, "nr_views": 0 } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Permission* **Descriptions:** `Workspace Permission` : Checks whether the user has permission to the workspace object. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Workspace does not exist. Loading... --- # Get Current User in the Workspace ``` GET /api/workspaces/:workspace_id/users/current/ ``` Returns the logged-in user's workspace specific fields. ## Request[​](/docs/api/rest/workspaces-users-current/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. ## Responses[​](/docs/api/rest/workspaces-users-current/.md#responses "Direct link to Responses") * 200 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **count** integerrequired **next** urinullable **previous** urinullable **results**object\[]required Array \[ * **id** integer **name** string **first\_name** string **Possible values:** `non-empty` **last\_name** string **Possible values:** `non-empty` **username** string **Possible values:** `non-empty` Required. 150 characters or fewer. Letters, digits and @/./+/-/\_ only. **email** email **Possible values:** `non-empty` **job\_title** stringnullable **Possible values:** `non-empty` **last\_login** date-time The last time the user logged into the environment. The value is in ISO 8601 format. **previous\_login** date-time The second last time the user logged into the environment. The value is in ISO 8601 format. **is\_ws\_deletable** boolean Specifies whether a user can be removed from the workspace. **access\_groups** integer\[] The user groups to which the user is a member of inside the workspace. **is\_ws\_admin** boolean Specifies whether the user is a workspace admin. **is\_env\_admin** boolean Specifies whether the user is an organization admin. Defaults to `false`. **last\_workspace\_visit** date-time The last time the user visited the workspace (and ran a Job). The value is in ISO 8601 format. ] ``` { "count": 0, "next": "string", "previous": "string", "results": [ { "id": 0, "name": "string", "first_name": "string", "last_name": "string", "username": "string", "email": "user@example.com", "job_title": "string", "last_login": "2024-06-11T11:45:44.618Z", "previous_login": "2024-06-11T11:45:44.618Z", "is_ws_deletable": true, "access_groups": [ 0 ], "is_ws_admin": true, "is_env_admin": true, "last_workspace_visit": "2024-06-11T11:45:44.618Z" } ] } ``` No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Context Permission* **Descriptions:** `Workspace Context Permission` : Workspace must be available to the User. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # Export Workspace Users ``` GET /api/workspaces/:workspace_id/users/export/ ``` Returns a CSV-file export of all Users in the workspace. Excludes Organization Admins. ## Request[​](/docs/api/rest/workspaces-users-export/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. ## Responses[​](/docs/api/rest/workspaces-users-export/.md#responses "Direct link to Responses") * 200 * 401 * 403 Exported CSV-file No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated Workspace Admin* **Descriptions:** `Is Authenticated Workspace Admin` : Checks whether the user has admin rights to the workspace. Loading... --- # List Users in the Workspace ``` GET /api/workspaces/:workspace_id/users/ ``` Lists all the users that have access to the workspace. In case of non-admin users, only members of the same user groups are returned. ## Request[​](/docs/api/rest/workspaces-users-list/.md#request "Direct link to Request") ### Path Parameters * **workspace\_id** stringrequired ### Query Parameters * **limit** integer Number of results to return per page. **offset** integer The initial index from which to return the results. ## Responses[​](/docs/api/rest/workspaces-users-list/.md#responses "Direct link to Responses") * 200 * 400 * 401 * 403 - application/json * Schema * Example (from schema) **Schema** * **id** integer **name** string **first\_name** string **Possible values:** `non-empty` **last\_name** string **Possible values:** `non-empty` **username** string **Possible values:** `non-empty` Required. 150 characters or fewer. Letters, digits and @/./+/-/\_ only. **email** email **Possible values:** `non-empty` **job\_title** stringnullable **Possible values:** `non-empty` **last\_login** date-time The last time the user logged into the environment. The value is in ISO 8601 format. **previous\_login** date-time The second last time the user logged into the environment. The value is in ISO 8601 format. **is\_ws\_deletable** boolean Specifies whether a user can be removed from the workspace. **access\_groups** integer\[] The user groups to which the user is a member of inside the workspace. **is\_ws\_admin** boolean Specifies whether the user is a workspace admin. **is\_env\_admin** boolean Specifies whether the user is an organization admin. Defaults to `false`. **last\_workspace\_visit** date-time The last time the user visited the workspace (and ran a Job). The value is in ISO 8601 format. ``` { "id": 0, "name": "string", "first_name": "string", "last_name": "string", "username": "string", "email": "user@example.com", "job_title": "string", "last_login": "2024-06-11T11:45:44.617Z", "previous_login": "2024-06-11T11:45:44.617Z", "is_ws_deletable": true, "access_groups": [ 0 ], "is_ws_admin": true, "is_env_admin": true, "last_workspace_visit": "2024-06-11T11:45:44.617Z" } ``` Incorrect query params No authentication found or authentication is not correct. Specified path is not allowed **Permission evaluation:** *Is Authenticated* **AND** *Is Not App* **AND** *Workspace Context Permission* **Descriptions:** `Workspace Context Permission` : Workspace must be available to the User. `Is Authenticated` : Allows access only to authenticated users. `Is Not App` : Client must not be a VIKTOR app. Loading... --- # SDK API The VIKTOR SDK API can be accessed using the [api\_v1](/sdk/api/api-v1/.md) module and is built on top of the REST API. It provides access to many of the relevant requests through an even developer-friendlier Python interface and takes care of more complicated parts such as 'pagination', 'filtering by reference', and 'object serialization'. **We therefore strongly recommend using the SDK API wherever possible**. The following resources are available in the SDK API: * `Workspaces` * `Entity types` * `Entities` * `Revisions` * `Current user` It is possible to use the SDK API in 3 scenarios: * [Within a workspace](/docs/api/sdk/.md#within-a-workspace) (nothing needed) * [Cross-workspace](/docs/api/sdk/.md#cross-workspace) (token needed) * [From an external script](/docs/api/sdk/.md#from-an-external-script) (token and environment needed). ![](/assets/images/api_scenarios-d845a8b3505423b1bea850afff871f66.png) ## Within a workspace[​](/docs/api/sdk/.md#within-a-workspace "Direct link to Within a workspace") If you want to use the SDK API module **from within the context of a workspace**, it is as simple as instantiating the `API` class using VIKTOR's [api\_v1](/sdk/api/api-v1/.md) module: ``` import viktor as vkt api = vkt.api_v1.API() ... entity = api.get_entity(1) # the current workspace is automatically selected ``` ### Current workspace and entity[​](/docs/api/sdk/.md#current-workspace-and-entity "Direct link to Current workspace and entity") The `workspace_id` of the **current** workspace, and `entity_id` and `entity_name` of the **current** entity are sent along within all view-methods and callback-functions. The `workspace_id` / `entity_id` can be used to construct the current workspace/entity object, from which you can, for example, navigate to relatives within a view-method: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Data") def calculate_view(self, params, entity_id, entity_name, workspace_id, **kwargs): current_entity = vkt.api_v1.API().get_entity(entity_id) parent = current_entity.parent() parent_params = parent.last_saved_params # do something with parent_params return vkt.DataResult(...) ``` Or a callback-function in the parametrization: ``` import viktor as vkt def get_options(params, entity_id, entity_name, workspace_id, **kwargs): current_entity = vkt.api_v1.API().get_entity(entity_id) parent = current_entity.parent() parent_params = parent.last_saved_params # do something with parent_params return [...] class Parametrization(vkt.Parametrization): field = vkt.OptionField(..., options=get_options) ``` ### Performance[​](/docs/api/sdk/.md#performance "Direct link to Performance") Within a single job (see [app code execution flow](/docs/getting-started/fundamentals/call-flow/.md) for the possible triggers of a job) the results of API calls are temporarily stored (memoized). This means that multiple calls to the same entity only require a single request in the background. This is particularly handy for option functions: ``` import viktor as vkt def get_options1_from_parent(params, entity_id, workspace_id, **kwargs): parent = vkt.api_v1.API().get_entity(entity_id).parent() parent_params = parent.last_saved_params # get options1 from parent_params ... def get_options2_from_parent(params, entity_id, workspace_id, **kwargs): parent = vkt.api_v1.API().get_entity(entity_id).parent() parent_params = parent.last_saved_params # get options2 from parent_params ... class Parametrization(vkt.Parametrization): option1 = vkt.OptionField('Option 1', options=get_options1_from_parent) option2 = vkt.OptionField('Option 2', options=get_options2_from_parent) ``` ### Bypassing user access restrictions[​](/docs/api/sdk/.md#bypassing-user-access-restrictions "Direct link to Bypassing user access restrictions") caution If not used properly, (confidential) information which SHOULD NOT be accessible to a user may leak (e.g. by including confidential data in a view, the data is visible to users with access to that view). Please consider the following when using this flag: * Make sure the app's admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. Some applications have user restrictions that limit access to certain entities or entity types. For example, if a user does not have permission to read some entity data, the code will also **NOT** be able to reach this data through an API call when run by the same user. In some cases it is desirable to restrict user access to a certain entity but have access within the code nonetheless. An example is the case of a global settings entity that consists of confidential pricing data, which should be inaccessible for users but accessible for the code to calculate costs. For these cases a `privileged` flag can be used: 1. Configure `viktor.config.toml` to make use of the privileged api. This serves as an additional layer of security/awareness. ``` enable_privileged_api = true ``` 2. Use the `privileged` flag on the relevant API call. ``` settings_entity = api.get_root_entities(entity_type_names=['Settings'], privileged=True)[0] ``` ## Cross-workspace[​](/docs/api/sdk/.md#cross-workspace "Direct link to Cross-workspace") If you want to use the SDK API module from one workspace to access data from a different workspace, you can instantiate the `API` class using VIKTOR's [api\_v1](/sdk/api/api-v1/.md) module and include your [Personal Access Token](/docs/api/.md#personal-access-token): ``` import viktor as vkt import os api = vkt.api_v1.API(token=os.environ["TOKEN"]) ... workspace = api.get_workspace(4) entity = workspace.get_entity(1) ``` ## From an external script[​](/docs/api/sdk/.md#from-an-external-script "Direct link to From an external script") If you want to use the SDK API from an external python script (e.g. Jupyter Notebook), make sure to first install the VIKTOR SDK using pip: ``` pip install viktor ``` In your python script, you can now instantiate the `API` class using VIKTOR's [api\_v1](/sdk/api/api-v1/.md) module. You will need to provide some additional authentication-related information: * Your VIKTOR environment url (the location where your data is stored, e.g. `cloud.viktor.ai` or `company.us1.viktor.ai`) * Your [Personal Access Token](/docs/api/.md#personal-access-token) ``` import viktor as vkt import os api = vkt.api_v1.API(token=os.environ["TOKEN"], environment="cloud.us1.viktor.ai") ... workspace = api.get_workspace(3) entity = workspace.get_entity(1) ``` --- # Handling entity data The SDK API can be used to read, create and modify entity data. ## Navigating entities[​](/docs/api/sdk/handling-entity-data/.md#navigating-entities "Direct link to Navigating entities") The starting point for navigating entities is an [`Entity`](/sdk/api/api-v1/.md#_Entity) (or [`EntityList`](/sdk/api/api-v1/.md#_EntityList)) object. An `Entity` object can be obtained in one of the following ways: * By means of an `entity_id`: ``` entity = api.get_workspace(workspace_id).get_entity(entity_id) entity = api.get_entity_children(entity_id) entity = api.get_entity_siblings(entity_id) entity = api.get_entity_parent(entity_id) ``` * By entity type: ``` entities = api.get_workspace(workspace_id).get_entities_by_type('MyType') ``` * Start from the root entities: ``` entities = api.get_workspace(workspace_id).get_root_entities() ``` * An `Entity` object that is returned from an [entity field](/docs/create-apps/user-input/entity-selection/.md#entity-object): ``` entity = params.entity_field ``` tip When using the API to obtain entity data from the **current** workspace from within an app, you can drop the workspace part and the current workspace will automatically be selected. For example: ``` entity = api.get_entity(entity_id) # only works if entity with this id is in the current workspace ``` Having an `Entity` object, navigating to relatives is easy, by making use of the below methods: ``` entity.parent() entity.children() entity.siblings() ``` It's also possible to chain these methods, to navigate even further: ``` grand_parent = entity.parent().parent() ``` Or filter on entity type: ``` gef_children = entity.children(entity_type_names=['GEF']) ``` ### Exclude params[​](/docs/api/sdk/handling-entity-data/.md#exclude-params "Direct link to Exclude params") By default, the `params` of an entity are obtained along with the entity, in all of the above mentioned API calls. In case only the id, name or type of an `Entity` is desired, the performance of the call can be improved by setting the `include_params` flag to `False`. This will exclude the params from being sent during the call: ``` gef_children = entity.children(entity_type_names=['GEF'], include_params=False) ``` ## Obtaining entity data[​](/docs/api/sdk/handling-entity-data/.md#obtaining-entity-data "Direct link to Obtaining entity data") Historical revisions of an entity can be obtained by: ``` revisions = api.get_entity_revisions(entity_id) ``` ``` revisions = entity.get_revisions() ``` The params from a certain `Revision` can be obtained by: ``` revision = revisions[0] # e.g. first revision params = revision.params ``` Often, you only need the last saved params/summary of an entity. This can be obtained by directly reading the corresponding property on the `Entity` object: ``` params = entity.last_saved_params summary = entity.last_saved_summary ``` ### File-type entity[​](/docs/api/sdk/handling-entity-data/.md#file-type-entity "Direct link to File-type entity") In case the entity is of file-type, the underlying `File` can be obtained by: ``` revisions = api.get_entity_file(entity_id) ``` ``` revisions = entity.get_file() ``` ## Modifying entity data[​](/docs/api/sdk/handling-entity-data/.md#modifying-entity-data "Direct link to Modifying entity data") The API supports the following methods to create/modify entity data: ``` api.rename_entity(entity_id, new_name) api.delete_entity(entity_id) api.set_entity_params(entity_id, new_params) api.create_child_entity(parent_entity_id, entity_type_name, new_entity_name) ``` And corresponding methods on the `Entity` object: ``` entity.rename(new_name) entity.delete() entity.set_entity_params(new_params) entity.create_child(entity_type_name, new_entity_name) ``` ## List-object[​](/docs/api/sdk/handling-entity-data/.md#list-object "Direct link to List-object") Some methods return a series of objects in a **list-object**, instead of an actual list of instances (e.g. `EntityList`, instead of `List[Entity]`). This has been done for performance reasons and has little effect on handling, as most normal list operations are still allowed: ``` children = entity.children() # children is of type `EntityList` len(children) # ok children[0] # positive indexing: ok children[-1] # negative indexing: ok for child in children: # iterating: ok # do something with child ``` note Slicing of a list-object (e.g. `children[0:5]`) is **not** supported. --- # Running an entity computation New in v14.12.0 Besides handling entity data, the SDK API can be used to run a computation on an entity. This can be used to, for example, utilize the entity as a calculation tool in other apps by remotely running the logic on the entity's Controller. ``` api.entity_compute(workspace_id=1, entity_id=2, method_name="my_calculation", params={...}) ``` ``` workspace = api.get_workspace(1) workspace.entity_compute(entity_id=2, method_name="my_calculation", params={...}) ``` ``` entity = api.get_entity(2) entity.compute(method_name="my_calculation", params={...}) ``` note * Not all methods on an entity can be called over the API. Currently, only [view methods](/docs/create-apps/results-and-visualizations/.md) and [button methods](/docs/create-apps/user-input/action-buttons/.md) are supported * It is not possible to use `compute` on an entity within your own development workspace (it will return a TimeoutError) ## Example[​](/docs/api/sdk/running-entity-computation/.md#example "Direct link to Example") The example below shows how to replicate a geometry-view from another entity (from another workspace) in the current entity, without copying any logic. For more information on how to set up the API for cross-workspace access, see [here](/docs/api/sdk/.md#cross-workspace). ``` import viktor as vkt import os class Controller(vkt.Controller): @vkt.GeometryView("Geometry", duration_guess=5) def geometry_view_from_other_entity(self, params, **kwargs): api = vkt.api_v1.API(token=os.environ["TOKEN"]) entity = api.get_entity(other_entity_id, workspace_id=other_workspace_id) result = entity.compute("geometry_view", params=entity.last_saved_params) return vkt.GeometryResult(**result['geometry']) ``` --- # App Builder \[BETA] BETA FEATURE The App Builder is a beta feature and because of this it is not completely stable yet. This means we might make changes to the App Builder without prior notice. The App Builder has not been rolled out to all environments. Contact us if you would like to use it. ## What is the App Builder?[​](/docs/app-builder/.md#what-is-the-app-builder "Direct link to What is the App Builder?") The App Builder is your AI-powered coding assistant, designed to help you create VIKTOR apps quickly, all from your browser. It features a browser-based chat interface and a development environment. This eliminates the need for any local software installation, allowing you to go from an idea to a working app in seconds with our AI assistant as your pair-programmer! The AI assistant updates your app based on your prompts, but you can also make manual changes directly in the code editor. A real-time preview of your app is available, allowing you to see changes instantly. Once you're satisfied with your app, you can deploy it to your environment with a single click! ## Using the App Builder[​](/docs/app-builder/.md#using-the-app-builder "Direct link to Using the App Builder") You can create new apps using the App Builder directly from the Develop page in the VIKTOR environment. 1. Start by entering a prompt. Describe the kind of app you want to build, specifying the desired inputs, visualization, and logic. ![](/assets/images/app-builder-1-af3882a4ad56555030f9d3384bf6807b.png) 2. Upon sending your prompt, you will enter the App Builder, and our AI assistant will begin generating your app. 3. Once the AI assistant finishes generating the app code, it will provide an explanation of the actions performed on the left side of the screen. On the right, you will see a preview of your app. You can interact with the app in Preview mode to test its functionality. To view the underlying Python code, simply switch to Code mode. 4. Now, you can iteratively improve your app. This can be done by asking follow-up questions to VIKTOR's AI assistant. The assistant will then update the app and show you the results. Alternatively, you can modify the Python code yourself by switching from preview to code mode. Simply adjust any code in the editor, and after saving your changes, the preview will reload to show the updated app. 5. To inspect what changes have been made to your app, click the 'Show changes' button. This will open a comparison of the current and previous revisions. If you are not happy with how the assistant has changed your app, you can revert these changes by clicking the 'Undo' button. ![](data:image/png;base64,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) 6. Each change made to your app, whether by you or the AI assistant, is automatically saved as a revision. This allows you to restore earlier versions of your app. To find a revision, scroll up in your chat history. You can restore that revision directly by clicking the 'Restore' button. You may first want to see what the revision looked like by clicking the 'Show revision' button, which will load the revision for your inspection before restoring. ![](/assets/images/app-builder-revisions-70a479f34dcf7ca1127ea759eecfb3e6.png) 7. Once you are satisfied with your app and wish to make it available within your environment, press the 'Publish' button in the top-right corner. After the publishing process is completed, you can add the app to a project to start using it. 8. As mentioned in step 6, every change you make to your app within the App Builder is saved as a revision, so you can exit the App Builder without losing your progress. You can find your apps on both the Develop page and in the App Store under My apps. Click the Develop button to re-enter the App Builder and continue enhancing your app! ![](/assets/images/app-builder-app-card-45bf790cc1e7a7021849bda95293bb9c.png) ### File support[​](/docs/app-builder/.md#file-support "Direct link to File support") The App Builder allows you to upload a file to provide additional context for the AI assistant. This is especially useful when your app idea is based on existing data, documentation, or visuals. The assistant will automatically use the uploaded file to better understand your request and generate more relevant code. In the current version, only one file can be uploaded per conversation, but it will remain available throughout the entire conversation even if you leave and return to the App Builder later. Supported file types: * Documents: .pdf, .csv, .doc, .docx, .xls, .xlsx, .html, .txt, .md (Max size: 4.5 MB) * Images: .png, .jpg, .jpeg, .gif, .webp (Max size: 3.75 MB, max resolution: 8000 × 8000 px) Below you can find a few supported use cases for the file upload functionality: * Uploading a CSV or Excel file to build an app that processes and visualizes the data. (note: you will need to upload the file in the resulting app to check the functionality though) * Uploading a PDF report or specification document to extract relevant parameters or logic. * Uploading an image or schematic to guide the app's UI or calculations. Once uploaded, the file is automatically available to the assistant and does not need to be referenced again manually, although doing so could improve accuracy. #### Best practices[​](/docs/app-builder/.md#best-practices "Direct link to Best practices") * Be specific about what the assistant should do with the file. For example: “Extract all material parameters from the uploaded PDF and use them to populate the form.” * Mention the file or filename in your prompt. For example: “Use the uploaded Excel file to create an app that plots the temperature over time.” * The App builder will examine the file to extract relevant information. If the app builder struggles you can help by providing additional context. For example: “The CSV has three columns: time, pressure, and velocity.” ## The underlying Large Language Model[​](/docs/app-builder/.md#the-underlying-large-language-model "Direct link to The underlying Large Language Model") The App Builder uses Anthropic's [Claude 4 Sonnet](https://www.anthropic.com/news/claude-4) and [Claude 3.5 Sonnet](https://www.anthropic.com/news/claude-3-5-sonnet) through [AWS Bedrock](https://aws.amazon.com/bedrock/) to generate VIKTOR code based on your prompts. Please refer to our [AI addendum](https://www.viktor.ai/ai-specific-addendum) for more information on how AI features are integrated into the VIKTOR platform. ## Limitations[​](/docs/app-builder/.md#limitations "Direct link to Limitations") The App Builder is a beta feature and is currently under development. This means that not all features supported in local development are available here. When you encounter one of these limitations, we currently advise you to copy the app code and continue developing locally. The installation and activation flow for local development can be found under the 'Level up' section on the Develop page. ### App types[​](/docs/app-builder/.md#app-types "Direct link to App types") The current version of the App Builder only supports creating Editor apps. For more information on the different app types, please refer to [App types](/docs/getting-started/fundamentals/app-types/.md) in the Getting Started section of the documentation. ### Python version[​](/docs/app-builder/.md#python-version "Direct link to Python version") The App Builder runtime uses Python 3.12. It is currently not possible to change to a different Python (minor) version. ### Supported packages[​](/docs/app-builder/.md#supported-packages "Direct link to Supported packages") The App Builder runs on Python 3.12 and currently supports a fixed set of libraries that you can use in your apps. In the current version of the App Builder, it is not possible to install additional packages. Below you can find the full list of supported packages: ``` aiohttp==3.12.14 altair==5.5.0 anthropic==0.58.2 beautifulsoup4==4.13.4 blue-prints==0.4.1 bokeh==3.7.3 cadquery==2.3.0 cadquery-ocp==7.8.1.1.post1 chardet==5.2.0 ezdxf==1.4.2 fiona==1.10.1 folium==0.20.0 geopandas==1.1.1 geopy==2.4.1 google-genai==1.26.0 ifcopenshell==0.8.3.post1 jinja2==3.1.6 kaleido==0.2.1 lxml==5.4.0 matplotlib==3.10.3 networkx==3.5 numpy==2.3.1 openai==1.97.0 opencv-python==4.11.0.86 openpyxl==3.1.5 openseespy==3.7.1.2 pandas==2.3.1 pdfplumber==0.11.7 pillow==11.3.0 pint==0.24.4 plotly==6.2.0 polars==1.31.0 pymupdf==1.26.3 pypdf==5.8.0 python-docx==1.2.0 python-pptx==1.0.2 reportlab==4.4.3 requests==2.32.4 scikit-learn==1.7.1 scipy==1.16.0 seaborn==0.13.2 shapely==2.1.1 statsmodels==0.14.5 sympy==1.14.0 trimesh==4.7.1 urllib3==2.5.0 viktor==14.24.0 xarray==2025.7.1 yfinance==0.2.65 ``` ### Multiple file support[​](/docs/app-builder/.md#multiple-file-support "Direct link to Multiple file support") The current version of the App Builder does not support using multiple files to structure your app code. You must write all app code in a single `app.py` file. The same applies to using additional files next to your Python code for storing constants or other data. ### Software integrations / workers[​](/docs/app-builder/.md#software-integrations--workers "Direct link to Software integrations / workers") The VIKTOR platform supports integrating with local desktop software using a [worker](/docs/create-apps/software-integrations/.md). The current version of the App Builder is not optimized to generate the required app code for these integrations. Additionally, you need to install a worker and connect it to your app manually. Therefore, we currently advise developing apps with integrations locally rather than using the App Builder. ### Collaboration[​](/docs/app-builder/.md#collaboration "Direct link to Collaboration") The App Builder does not currently support real-time collaboration. While it is possible to assign multiple maintainers to apps created with the App Builder, the App Builder's context and code are bound to an individual user. This means that a colleague will not be able to see your conversation history or code within your App Builder environment. ### Regional hosting[​](/docs/app-builder/.md#regional-hosting "Direct link to Regional hosting") VIKTOR supports [regional hosting](/docs/manage-apps/regional-hosting/.md), meaning apps are synced across multiple geographic regions. Apps created with the App Builder are also synced across regions. However, the content (chat history and app revisions) of the associated App Builder environment is not synced across regions. ### Print statements[​](/docs/app-builder/.md#print-statements "Direct link to Print statements") While you can use a print-statement in your app code the output will not be shown in the console. ### Environment variables and secrets[​](/docs/app-builder/.md#environment-variables-and-secrets "Direct link to Environment variables and secrets") Environment variables are fully supported in the App Builder. You can configure environment variables for your App Builder apps using the same process as for published apps: 1. Navigate to the 'Apps' page in your VIKTOR environment and find your App Builder app, then click 'Details'. Alternatively, you can access the app details by clicking the dropdown next to the 'Publish' button within the App Builder. 2. Select the 'Variables' tab to create, update or remove environment variables. 3. Environment variables set here are automatically available within the App Builder environment during development. Environment variables can be accessed in your app code using the standard Python `os` module: ``` import os my_variable = os.getenv("MY_ENV_VAR") ``` For more detailed information on configuring and using environment variables, see the [Environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md) documentation. ## Writing effective prompts[​](/docs/app-builder/.md#writing-effective-prompts "Direct link to Writing effective prompts") The AI in the VIKTOR App Builder helps you transform ideas into working applications quickly. To get the most out of it, it’s crucial to learn how to write effective prompts. Think of prompting as providing clear, concise instructions to a highly capable assistant. The better your instructions, the better the result. ### Core prompting principles[​](/docs/app-builder/.md#core-prompting-principles "Direct link to Core prompting principles") 1. **Structured input and output**
Clearly state what inputs you’re providing and what outputs you expect, whether they are text, code, plots, tables, or 3D models. 2. **Clarity and specificity**
Provide enough context for the AI to understand the scope and capabilities. Describe exactly what calculations, formulas, or visualizations you need. 3. **Task decomposition**
Break complex tasks into smaller, manageable steps. For instance, first prompt for the UI, then the logic, and finally the visualization. These principles are also covered in our blog:
[Mastering LLMs: Essential Prompting Techniques for AEC Professionals](https://www.viktor.ai/blog/194/mastering-ll-ms-essential-prompting-techniques-for-aec-professionals) ### Tips for better prompts[​](/docs/app-builder/.md#tips-for-better-prompts "Direct link to Tips for better prompts") Start with the goal: > I want an app that calculates pressure loss in a pipe based on user input. Mention input/output: > Inputs: diameter, flow rate, pipe length. Output: pressure loss in bar, shown as a table and line plot. Use engineering terms: > Use the Darcy‑Weisbach equation to calculate pressure loss. Break it down into steps: > First, generate the form UI. Then, write the calculation logic. Finally, render results. Guide the view/output: > Show pressure loss as a line plot versus pipe length, and include a summary table. Additionally, you can add some examples of inputs/outputs and expected behavior. This will allow the AI assistant to understand your intentions. ## Troubleshooting and debugging[​](/docs/app-builder/.md#troubleshooting-and-debugging "Direct link to Troubleshooting and debugging") LLMs make mistakes, therefore, you might encounter issues or unexpected behavior. Here's how to approach troubleshooting and debugging your app within the App Builder. ### Understanding error messages[​](/docs/app-builder/.md#understanding-error-messages "Direct link to Understanding error messages") When an error occurs, the App Builder will display an error message. When you switch to Code mode an error console will be shown with a Python traceback. ![](/assets/images/app-builder-error-aef62f26d2a3542353cb29e298eed7f5.png) This traceback is crucial for identifying the problem: * Location: Look for file names (e.g. app.py) and line numbers. This tells you exactly where the error occurred in your code. * Error Type: The error type (e.g. Attribute, TypeError, ValueError) indicates the kind of problem. * Attribute: Usually means you're trying to use a variable or function that hasn't been defined. * TypeError: Occurs when an operation is performed on an object of an inappropriate type (e.g. trying to add a string and a number). * ValueError: Indicates that an operation received an argument that has the right type but an inappropriate value. * Description: Read the accompanying description carefully. It often provides specific details about why the error occurred. More information on Python Tracebacks can be found in [this Real Python](https://realpython.com/python-traceback/) article. You can ask the AI assistant to fix the error for you by clicking the 'Fix with VIKTOR.AI' button. The AI assistant can also help explain why the error occurred. ### Debugging your Python code[​](/docs/app-builder/.md#debugging-your-python-code "Direct link to Debugging your Python code") * Check Input Values: Verify that the inputs provided in the UI are what your code expects. Sometimes, a simple typo in the input can lead to unexpected results. * Inspect Intermediate Calculations: For complex calculations, break it down in smaller steps and visualize each sub-result. This helps pinpoint exactly where the calculation goes wrong. ### When the App Builder gets stuck or generates unexpected code[​](/docs/app-builder/.md#when-the-app-builder-gets-stuck-or-generates-unexpected-code "Direct link to When the App Builder gets stuck or generates unexpected code") Sometimes the App Builder might struggle with a complex prompt, produce irrelevant code, or seem 'stuck' in a loop. Here's how to help it: 1. Simplify Your Prompt: If your initial prompt was very broad or complex, try breaking it down into smaller, more specific steps (as outlined in 'Task Decomposition') * Instead of: 'Create an app that calculates structural integrity and plots the results in 3D, allowing for material changes and load variations.' * Try: 'First, create a form with inputs for material properties (e.g., Young's Modulus, Poisson's Ratio) and dimensions. Next, add a view for a simple stress calculation based on these inputs.' 2. Provide More Context: If the AI is missing information, provide it explicitly. This is especially true when trying to use uploaded files in your app. * If the AI struggles with a CSV: 'The CSV file has three columns: Time (s), Force (kN), Displacement (mm).' 3. Rephrase or Reset: If the AI's response is consistently off-topic, try rephrasing your prompt with different keywords or a different approach. If it seems truly stuck, you can try reverting to an earlier revision of your app and trying a different prompting strategy. 4. Make Manual Edits: For small, specific issues, it might be faster and more efficient to switch to Code mode and fix the Python code yourself rather than trying to prompt the AI to fix it. By following these troubleshooting and debugging steps, you can more effectively develop and refine your VIKTOR apps using the App Builder. --- # Develop apps This is your go-to place when you are developing. It includes how-to guides, tutorials and examples, and it gives you an overview of all available features. ## Developer dashboard[​](/docs/create-apps/.md#developer-dashboard "Direct link to Developer dashboard") When you log in as a developer you land on the 'Develop' page. Here you will find a few things: * A step-by-step process to install VIKTOR, learn the basics of the framework, create your first app and publish it to make it available to others. * An overview of the latest apps you created * A personalized showcase, containing app templates, to help you find inspiration for your next developments. ![Developer dashboard](/assets/images/development-dashboard-9bcb2ddc645069125813bcf5984070aa.png) ## App store[​](/docs/create-apps/.md#app-store "Direct link to App store") The App store is where you will find all apps that have been created by you and other developers in your organization. All apps that are maintained by you can be found by selecting the 'My apps' tab. ![App store](/assets/images/app-store-my-apps-62b6b156c90342943dd79f0f6b854485.png) ## Development workspace[​](/docs/create-apps/.md#development-workspace "Direct link to Development workspace") All new developments start by creating an app in VIKTOR. You can do this by clicking the 'Create app' button on the Develop page or in the App store., You can choose three different starting points: * Create an app from scratch * Choose 'Create and close' if you already have your own app code that you want to link to an app in VIKTOR * Choose 'Create and setup' if you want to use the 'quickstart' command to download an empty app on your computer * Create an app from an existing excel spreadsheet * Create an app from one of the many templates in our library ![App Creation options](/assets/images/create-new-app-options-f8f047dbe5e44922a98535bbd4aff234.png) tip If you are quite new to programming, we recommend starting from a spreadsheet or a template. Each app has its own Development workspace that you can use to see what your app looks like and try out the functionalities. You can enter the development workspace in two different ways: 1. By clicking the 'Develop' button on the app card. The 3 latest apps you created are shown on the 'Develop' page. Alternatively, you can find all your apps by visiting the App store and selecting 'My apps'. ![](/img/docs/development-workspace-app-card.png) 2. By following the URL that is shown in the terminal when your app code connects to the VIKTOR platform. This is a direct link to the corresponding development workspace. ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` --- # Automated testing Writing tests is an essential part of application development. Whether the application is intended for self-use only or for distribution, it is important to test that all functionalities work as expected. The more thorough your application is tested, the more robust it will be and code changes can be made with more confidence. An application can be tested by manually clicking through the different entities and checking all functionalities for different scenarios. This, however, takes a lot of time and can easily be replaced by writing a few **automated** tests. Automated testing will prevent you from spending a lot of time trying to find and fix bugs in the application later on. There is a lot of documentation available on writing tests. The following webpages provide info on good practices for writing automated tests in Python: * * ## Testing frameworks[​](/docs/create-apps/automated-testing/.md#testing-frameworks "Direct link to Testing frameworks") Python has its own builtin library available for writing automated tests: [unittest](https://docs.python.org/3/library/unittest.html). The CLI [`test`](/docs/create-apps/references/cli/.md#test) and [`ci-test`](/docs/create-apps/references/cli/.md#ci-test) commands works with the unittest library out-of-the-box. Other testing frameworks There are other third-party Python libraries for testing, such as `pytest`, `nose2`, or `robotframework`, but currently only `unittest` is directly supported by the CLI. ## Testing as part of the development lifecycle[​](/docs/create-apps/automated-testing/.md#testing-as-part-of-the-development-lifecycle "Direct link to Testing as part of the development lifecycle") It is good practice to not only write a few tests for your application here and there, but make testing an integral part of your Software Development Life Cycle (SDLC). This allows you to worry less about you or your colleague introducing new bugs, so that you can focus more on developing interesting and impactful additions to your app. A good way to make testing an integral part of your development lifecycle, is through Continuous Integration (CI). Please refer to our [CI/CD guide](/docs/create-apps/development-tools-and-tips/ci/.md) to set this up. ## Writing tests[​](/docs/create-apps/automated-testing/.md#writing-tests "Direct link to Writing tests") When writing automated tests, two main types of tests can be considered: **unit** and **integration** tests. In short, a unit test is the test of a single specific module or function and shows that the individual parts are working correctly. An integration test is a test of an overall system of multiple modules or functions, and shows that the interfaces between the modules are working correctly. A unit test verifies that a certain input results in the expected output (for all cases of interest), but does not detect integration errors or other application-wide issues. On the other hand, an integration test may detect errors when functions or modules are incorrectly integrated but usually doesn't check intermediate results and specific cases. Integration tests tend to be much more complex than unit tests and often requires more [mocking](/docs/create-apps/automated-testing/mocking/.md) of certain parts of your application. In the context of a VIKTOR app you could consider asserting that a view method returns the expected result with an integration test. We have introduced functionality to make this easy to implement, see [mocking view functions](/docs/create-apps/automated-testing/mocking/.md#mocking-view-functions) for an example implementation. A generic example of a unittest is shown below. In this example, a particular function is imported from the app code and tested using the unittest framework. It tests whether the function provides the correct output for a valid input, and it tests whether a correct error is raised when the input is incorrect. ``` import unittest from app.function_library.weight_functions import calculate_weight class TestWeightFunctions(unittest.TestCase): def test_calculate_weight_returns_correct_value(self): # Arrange volume = 10 density = 100 expected_weight = 1000 # Act weight = calculate_weight(volume, density) # Assert self.assertEqual(weight, expected_weight) def test_calculate_weight_raises_TypeError_with_incorrect_input(self): # Arrange volume = 10 density = 'one hundred' # Act & Assert with self.assertRaises(TypeError): weight = calculate_weight(volume, density) ``` ## Folder structure[​](/docs/create-apps/automated-testing/.md#folder-structure "Direct link to Folder structure") Whether you are writing unit tests or integration tests, it is good-practice to separate the test code from the application code. We advise using the general folder structure described below. note the CLI [test](/docs/create-apps/references/cli/.md#test) and [`ci-test`](/docs/create-apps/references/cli/.md#ci-test) commands require all tests to reside in a folder named "tests". ``` my-app ├── app.py ├── tests │ ├── test_app.py <- you are free to split this file up into separate files within the tests folder │ └── __init__.py └── ... ``` Or for larger apps: ``` my-app ├── app │ ├── entity_type_1 │ │ ├── controller.py │ │ └── parametrization.py │ ├── entity_type_2 │ │ ├── controller.py │ │ └── parametrization.py │ ├── function_library │ │ └── weight_functions.py │ └── __init__.py ├── tests │ ├── entity_type_1 │ │ ├── test_controller.py │ │ └── __init__.py │ ├── entity_type_2 │ │ ├── test_controller.py │ │ └── __init__.py │ ├── function_library │ │ ├── test_weight_functions.py │ │ └── __init__.py │ └── __init__.py └── ... ``` caution Always make sure that each folder in the 'tests' directory contains an `__init__.py` and that the Python files start with `test_.py`! --- # Mocking Mocking is (temporary) replacing parts of your to-be-tested application with 'fake' objects within the scope of the test, so that you have full control over input and output within a certain test function. Python’s `unittest` library has built-in functionalities for mocking: Learn more? The topic of 'mocking in Python' is extensively covered on the website: When writing tests for your VIKTOR application, it is likely that you will **need** to mock certain VIKTOR functions. For example, `API` calls in your app encountered within a test will return a "OSError: Job token is not set" error, as the token is not available outside the app context. The [`viktor.testing`](/sdk/api/testing/.md) module provides various mock-objects to simplify the process of mocking certain VIKTOR objects. VIKTOR components that require mocking: * [`API` calls](/docs/create-apps/automated-testing/mocking/.md#mocking-api) * [Functions decorated with `@ParamsFromFile`](/docs/create-apps/automated-testing/mocking/.md#mocking-paramsfromfile) * [View functions (e.g. functions decorated with `@GeometryView`)](/docs/create-apps/automated-testing/mocking/.md#mocking-view-functions) * [Functions that call external worker](/docs/create-apps/automated-testing/mocking/.md#mocking-functions-that-call-external-worker) * [Functions that call external servers](/docs/create-apps/automated-testing/mocking/.md#mocking-functions-that-call-external-servers) ## Mocking `API`[​](/docs/create-apps/automated-testing/mocking/.md#mocking-api "Direct link to mocking-api") API calls need to be mocked within the context of (automated) testing. There are two approaches you could take to achieve this: 1. By [using the `mock_API`](/docs/create-apps/automated-testing/mocking/.md#testing-by-using-mock_api) decorator 2. By [isolating API actions](/docs/create-apps/automated-testing/mocking/.md#testing-by-isolating-api-actions) in separate methods ### Testing by using `mock_API`[​](/docs/create-apps/automated-testing/mocking/.md#testing-by-using-mock_api "Direct link to testing-by-using-mock_api") New in v13.3.0 ``` import unittest from viktor.testing import mock_API from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_API() def test_function(self): MyEntityTypeController().function(...) ``` For each method that is called on the `API` class, the decorator will return mock objects: * `MockedEntity` representing [`Entity`](/sdk/api/api-v1/.md#_Entity) (e.g. when calling `API.get_entity()`) * `MockedEntityList` representing [`EntityList`](/sdk/api/api-v1/.md#_EntityList) (e.g. when calling `API.get_root_entities()`) * `MockedEntityRevision` representing [`EntityRevision`](/sdk/api/api-v1/.md#_EntityRevision) (e.g. when calling `API.get_entity_revisions()`) * `MockedEntityType` representing [`EntityType`](/sdk/api/api-v1/.md#_EntityType) (e.g. when calling `Entity.entity_type`) * `MockedUser` representing [`User`](/sdk/api/api-v1/.md#_User) (e.g. when calling `API.get_current_user()`) Each of these mock objects supports the properties and methods of their represented objects, for example, `MockedEntity.last_saved_params` mimics `Entity.last_saved_params`. Assume the `function()` of the example above performs an API call to retrieve the child entities to count the number of red, green, and blue entities: ``` import viktor as vkt class MyEntityTypeController(vkt.Controller): ... def function(self, entity_id): red, green, blue = 0, 0, 0 children = vkt.api_v1.API().get_entity_children(entity_id) for child in children: if child.last_saved_params.color == 'red': red += 1 if child.last_saved_params.color == 'green': green += 1 if child.last_saved_params.color == 'blue': blue += 1 return red, green, blue ``` By default, the [`mock_API`](/sdk/api/testing/.md#_mock_API) decorator returns a zero-length `MockedEntityList` when `get_entity_children()` is called. This means that, in the example above, `function` will return (0, 0, 0). However, the decorator allows you to specify the outcome of each individual method such that we can actually test what would happen if a VIKTOR workspace consists of specific entities. For example, let's pass the entities that `get_entity_children()` in the example above should return, by providing a sequence of `MockedEntity` objects in the decorator: ``` import unittest from viktor.testing import mock_API, MockedEntity from app.my_entity_type.controller import MyEntityTypeController CHILD_ENTITIES = [ MockedEntity(params={'color': 'red'}), MockedEntity(params={'color': 'green'}), MockedEntity(params={'color': 'green'}), MockedEntity(params={'color': 'blue'}), ] class TestMyEntityTypeController(unittest.TestCase): @mock_API(get_entity_children=CHILD_ENTITIES) def test_function(self): red, green, blue = MyEntityTypeController().function(...) self.assertEqual(red, 1) self.assertEqual(green, 2) self.assertEqual(blue, 1) ``` Instead of the default zero-length `MockedEntityList`, the decorator is now instructed to return the provided entities. Note that in this example the params are passed to `MockedEntity`, but you can define much more (e.g. parent / children / siblings etc.). ### Testing by isolating API actions[​](/docs/create-apps/automated-testing/mocking/.md#testing-by-isolating-api-actions "Direct link to Testing by isolating API actions") Structuring the controller in such a way that each API action is isolated in a separate method makes it easier to maintain, debug, and reuse your code. Assume a controller that looks like this: ``` import viktor as vkt class MyEntityTypeController(vkt.Controller): def get_child_params(self, entity_id): # perform API actions return child_params def get_parent_params(self, entity_id): # perform API actions return parent_params @vkt.GeometryView("3D model", x_axis_to_right=True) def visualize(self, params, entity_id, **kwargs): parent_params = self.get_parent_params(entity_id) child_params = self.get_child_params(entity_id) visualization = self.create_visualisation(parent_params, child_params) return vkt.GeometryResult(visualization) def download_file(self, params, entity_id, **kwargs): parent_params = self.get_parent_params(entity_id) download_content = self.generate_download_result(parent_params) return vkt.DownloadResult(download_content) ``` If the `visualize` and `download_file` methods are now to be tested, we can make use of unittests `mock.patch.object` decorator in combination with `mock.MagicMock` to control the return value: ``` import unittest from unittest import mock from app.my_entity_type.controller import MyEntityTypeController # params dictionaries ENTITY_PARAMS = ... PARENT_PARAMS = ... CHILD_PARAMS = ... class TestMyEntityTypeController(unittest.TestCase): @mock.patch.object(MyEntityTypeController, 'get_child_params', mock.MagicMock(return_value=CHILD_PARAMS)) @mock.patch.object(MyEntityTypeController, 'get_parent_params', mock.MagicMock(return_value=PARENT_PARAMS)) def test_visualise(self): MyEntityTypeController().visualize(params=ENTITY_PARAMS) @mock.patch.object(MyEntityTypeController, 'get_child_params', mock.MagicMock(return_value=CHILD_PARAMS)) def test_generate_download_content(self): MyEntityTypeController().generate_download_content(params=ENTITY_PARAMS) ``` ## Mocking deserialized params[​](/docs/create-apps/automated-testing/mocking/.md#mocking-deserialized-params "Direct link to Mocking deserialized params") The VIKTOR platform deserializes the raw params, such that they will enter the app code in their intuitive format. For example, an `EntityOptionField` will return an `Entity` object in the params instead of an entity\_id. However, when you are using raw params in your tests (e.g. a JSON file), you will need to deserialize the params yourself. This is necessary when any of the following fields is used in the parametrization of the corresponding entity type: * `DateField` * `EntityOptionField` * `ChildEntityOptionField` * `SiblingEntityOptionField` * `EntityMultiSelectField` * `ChildEntityMultiSelectField` * `SiblingEntityMultiSelectField` * `GeoPointField` * `GeoPolylineField` * `GeoPolygonField` * `FileField` * `MultiFileField` For example, when the parametrization consists of a `NumberField`, `ChildEntityOptionField`, and a `FileField`, the raw params could look like: ``` params = { 'number': 1, 'entity': 2, # corresponds to entity id 'file': 3, # corresponds to file resource id } ``` Let's assume `function()` to perform an API call to * retrieve the `last_saved_params` of the selected child entity * retrieve the content of the selected file ``` ... class MyEntityTypeController(vkt.Controller): ... def function(self, params): child_params = params.entity.last_saved_params file = params.file.file ... ``` The raw integers of `params_dict` should be converted to their corresponding mock objects (i.e. deserialized), in order for `function()` to succeed. There are two ways to achieve this: 1. By defining a dictionary consisting of the mock objects manually ``` from viktor import File from viktor.testing import MockedEntity, MockedFileResource params = { 'number': 1, 'entity': MockedEntity(name="My Entity"), 'file': MockedFileResource(file=File.from_data("content"), filename="file.txt"), } ``` 2. By using the [`mock_params`](/sdk/api/testing/.md#_mock_params) function, providing a JSON file consisting of the raw params along with the parametrization and (optionally) mocked resources ``` from viktor import File from viktor.testing import MockedEntity, MockedFileResource, mock_params params = mock_params( params=File.from_path("path to JSON file"), parametrization=MyEntityTypeController.parametrization, entities={2: MockedEntity(name="My Entity")}, file_resources={3: MockedFileResource(file=File.from_data("content"), filename="file.txt")}, ) ``` The `function()` can then be tested by providing the deserialized params: ``` ... class TestMyEntityTypeController(unittest.TestCase): def test_function(self): MyEntityTypeController().function(params=params) ``` ## Mocking `ParamsFromFile`[​](/docs/create-apps/automated-testing/mocking/.md#mocking-paramsfromfile "Direct link to mocking-paramsfromfile") A file-type entity implements the `@ParamsFromFile` decorator on one of its controller methods. In order to test this method, the `ParamsFromFile` decorator (object) needs to be mocked (`ParamsFromFile` performs `API` calls internally). The `viktor.testing` module provides the [`mock_ParamsFromFile`](/sdk/api/testing/.md#_mock_ParamsFromFile) decorator to simplify this mocking: ``` import unittest from viktor.testing import mock_ParamsFromFile from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_ParamsFromFile(MyEntityTypeController) def test_process_file(self): file = File.from_data("abc") returned_dict = MyEntityTypeController().process_file(file) self.assertDictEqual(returned_dict, {...}) ``` ## Mocking View functions[​](/docs/create-apps/automated-testing/mocking/.md#mocking-view-functions "Direct link to Mocking View functions") New in v13.3.0 `mock_View` decorator for easier testing of view methods [View](/docs/create-apps/results-and-visualizations/.md) functions can be tested by mocking the decorator using [`mock_View`](/sdk/api/testing/.md#_mock_View): ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_my_view(self): params = ... result = MyEntityTypeController().my_view(params=params) self.assertEqual(result, ...) ``` Please see each individual view guide for a specific example. ## Mocking functions that call external worker[​](/docs/create-apps/automated-testing/mocking/.md#mocking-functions-that-call-external-worker "Direct link to Mocking functions that call external worker") When calling the `execute()` method on a class that inherits from [`ExternalProgram`](/sdk/api/external/external-program/.md#_ExternalProgram), a job is sent to an external [worker](/docs/create-apps/software-integrations/.md#worker). These function calls need to be mocked within the context of (automated) testing. Currently, the `viktor.testing` module provides the following decorators that facilitate mocking of workers: * [`mock_AxisVMAnalysis`](/sdk/api/testing/.md#_mock_AxisVMAnalysis) (>= v13.5.0) * [`mock_DFoundationsAnalysis`](/sdk/api/testing/.md#_mock_DFoundationsAnalysis) (>= v13.5.0) * [`mock_DGeoStabilityAnalysis`](/sdk/api/testing/.md#_mock_DGeoStabilityAnalysis) (>= v13.5.0) * [`mock_DSettlementAnalysis`](/sdk/api/testing/.md#_mock_DSettlementAnalysis) (>= v13.5.0) * [`mock_DSheetPilingAnalysis`](/sdk/api/testing/.md#_mock_DSheetPilingAnalysis) (>= v13.5.0) * [`mock_DStabilityAnalysis`](/sdk/api/testing/.md#_mock_DStabilityAnalysis) (>= v13.5.0) * [`mock_Excel`](/sdk/api/testing/.md#_mock_Excel) (>= v13.5.0) * [`mock_GenericAnalysis`](/sdk/api/testing/.md#_mock_GenericAnalysis) (>= v13.5.0) * [`mock_GRLWeapAnalysis`](/sdk/api/testing/.md#_mock_GRLWeapAnalysis) (>= v13.5.0) * [`mock_IdeaRcsAnalysis`](/sdk/api/testing/.md#_mock_IdeaRcsAnalysis) (>= v13.5.0) * [`mock_RFEMAnalysis`](/sdk/api/testing/.md#_mock_RFEMAnalysis) (>= v13.5.0) * [`mock_RobotAnalysis`](/sdk/api/testing/.md#_mock_RobotAnalysis) (>= v13.5.0) * [`mock_SciaAnalysis`](/sdk/api/testing/.md#_mock_SciaAnalysis) (>= v13.3.0) ## Mocking functions that call external servers[​](/docs/create-apps/automated-testing/mocking/.md#mocking-functions-that-call-external-servers "Direct link to Mocking functions that call external servers") There are various functions within the VIKTOR library that make use of (internal) services that are being processed on external servers. These external server calls cannot be performed outside the app-context and therefore these function calls need to be mocked within the context of (automated) testing. The complete list of all functions that call external servers (hence require mocking): * `viktor.external.dfoundations.BearingPilesModel.generate_input_file` * `viktor.external.dfoundations.TensionPilesModel.generate_input_file` * `viktor.external.dsettlement.Model1D.generate_input_file` * `viktor.external.dsettlement.Model2D.generate_input_file` * `viktor.external.idea_rcs.Model.generate_xml_input` * `viktor.external.idea_rcs.OpenModel.generate_xml_input` * `viktor.external.scia.Model.generate_xml_input` * `viktor.external.spreadsheet.SpreadsheetCalculation.evaluate` * `viktor.external.spreadsheet.SpreadsheetTemplate.render` * `viktor.external.spreadsheet.render_spreadsheet` * `viktor.external.word.WordFileTemplate.render` * `viktor.external.word.render_word_file` * `viktor.geo.GEFData.classify` * `viktor.geo.GEFFile.parse` * `viktor.utils.convert_excel_to_pdf` * `viktor.utils.convert_svg_to_pdf` * `viktor.utils.convert_word_to_pdf` * `viktor.utils.merge_pdf_files` * `viktor.utils.render_jinja_template` --- # Continuous Integration/Deployment This guide explains the necessary steps for continuous integration on your viktor application and provides some example files for frequently used CI/CD platforms. See [this article](https://realpython.com/python-continuous-integration/) for an introduction on the concepts of continuous integration if you're unfamiliar with the topic. ## Setting up the environment[​](/docs/create-apps/development-tools-and-tips/ci/.md#setting-up-the-environment "Direct link to Setting up the environment") First you need to make sure that your CI environment is the same as the environment in which your app will run. This means: * Linux machine * Matching Python version * Environment variables `VIKTOR_DEV` and `VIKTOR_TOKEN` should be set. Contact VIKTOR to receive CI-credentials (**don't use your personal developer credentials!**). * Environment variable `VIKTOR_ENV` should be set with the environment you are publishing to (e.g. `{company}.viktor.ai`). ## Continuous Integration[​](/docs/create-apps/development-tools-and-tips/ci/.md#continuous-integration "Direct link to Continuous Integration") 1. Download the CLI, which will be used to perform CI commands: ``` curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli ``` 2. Install the app and its dependencies: ``` ./viktor-cli ci-install ``` Make sure you only use `ci-install` in the CI job and `install` during local development: * The `ci-install` command is an alias for a very involved `pip install` command, which would otherwise pollute your local Python environment. * The `install` command does not work in your CI environment 3. Perform all tests (found in the 'tests' directory): ``` ./viktor-cli ci-test ``` ## Continuous Deployment[​](/docs/create-apps/development-tools-and-tips/ci/.md#continuous-deployment "Direct link to Continuous Deployment") note Currently, publishing is supported for the following CI/CD platforms: * Azure Pipelines * GitHub Actions * GitLab CI/CD The CLI can be used to automate the publishing of apps in CI pipelines with the [`ci-publish`](/docs/create-apps/references/cli/.md#ci-publish) command. We recommended creating a Git tag to reference specific versions of the app code you are publishing on the platform. It is possible to conditionally trigger pipelines / workflows only when a tag is created. ``` ./viktor-cli ci-publish ``` The CLI determines which CI/CD platform is used based on platform-specific environment variables. Subsequently, all information required to publish your app is collected by the CLI and used to create a publication context. This context is stored together with the app version for later reference. The variables used to determine the publication context are shown in the table below. | | Azure Pipelines | GitHub Actions | GitLab CI/CD | | ----------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------- | -------------------- | | User name | `Build.RequestedFor` | `GITHUB_ACTOR` | `GITLAB_USER_NAME` | | User email | `Build.RequestedForEmail` | n.a. | `GITLAB_USER_EMAIL` | | Commit hash | `Build.SourceVersion` | `GITHUB_SHA` | `CI_COMMIT_SHA` | | Branch or tag ref | `Build.SourceBranchName` | `GITHUB_REF_NAME` | `CI_COMMIT_REF_NAME` | | Pipeline URL | `System.TeamFoundationCollectionUri`, `System.TeamProject`, `Build.BuildId`\* | `GITHUB_SERVER_URL`, `GITHUB_REPOSITORY`, `GITHUB_RUN_ID`\* | `CI_PIPELINE_URL` | | Tag | `Build.SourceBranchName` | `GITHUB_REF_NAME` | `CI_COMMIT_TAG` | \* These variables are combined into a URL to the pipeline / workflow that triggered the ci-publish command. ## Example CI/CD files[​](/docs/create-apps/development-tools-and-tips/ci/.md#example-cicd-files "Direct link to Example CI/CD files") Below are examples of configuration files for frequently used CI/CD platforms. In the examples below you should replace NAME with the name of the app as it is registered on the platform. * Azure Pipelines * GitHub Actions * GitLab CI/CD * CircleCI * TravisCI note Be sure to set the variables `VIKTOR_DEV`, `VIKTOR_TOKEN` and `VIKTOR_ENV` within a [variable group](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops\&tabs=classic#create-a-variable-group) with name (e.g. "VIKTOR"). ``` variables: - group: VIKTOR # variable group within DevOps library containing the variables VIKTOR_DEV VIKTOR_TOKEN & VIKTOR_ENV jobs: - job: test container: python:3.13-bookworm steps: - bash: curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli - bash: ./viktor-cli ci-install - bash: ./viktor-cli ci-test - job: publish container: python:3.13-bookworm condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/')) # only run for a tag and when previous job completed successfully steps: - bash: curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli - bash: ./viktor-cli ci-publish NAME # replace NAME with the actual name of the app ``` note Be sure to set the variables `VIKTOR_DEV`, `VIKTOR_TOKEN` and `VIKTOR_ENV` by creating [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets). ``` name: viktor-test-publish on: push env: VIKTOR_DEV: ${{ secrets.VIKTOR_DEV }} VIKTOR_TOKEN: ${{ secrets.VIKTOR_TOKEN }} VIKTOR_ENV: ${{ secrets.VIKTOR_ENV }} jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: 3.13 - run: curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli - run: ./viktor-cli ci-install - run: ./viktor-cli ci-test publish: runs-on: ubuntu-latest needs: test # start when job 'test' is finished if: ${{ success() && startsWith(github.ref, 'refs/tags/') }} # only run for a tag and when previous job completed successfully steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: 3.13 - run: curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli - run: ./viktor-cli ci-publish NAME # replace NAME with the actual name of the app ``` note Be sure to set the variables `VIKTOR_DEV`, `VIKTOR_TOKEN` and `VIKTOR_ENV` to the [project's settings](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project). ``` stages: - test - publish image: python:3.13-bookworm test: stage: test script: # download CLI - curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli # install app and dependencies - ./viktor-cli ci-install # perform tests - ./viktor-cli ci-test publish: stage: publish script: # download CLI - curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli # publish the app - ./viktor-cli ci-publish NAME # replace NAME with the actual name of the app only: - tags when: manual ``` caution Publishing of viktor apps using `ci-publish` is currently not supported for CircleCI ``` version: 2 jobs: test: docker: - image: python:3.13-bookworm steps: - checkout # download CLI - run: curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli # install app and dependencies - run: ./viktor-cli ci-install # perform tests - run: ./viktor-cli ci-test ``` caution Publishing of viktor apps using `ci-publish` is currently not supported for TravisCI ``` language: python python: - "3.13" script: # download CLI - curl -Lo viktor-cli 'https://developers.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' && chmod +x viktor-cli # install app and dependencies - ./viktor-cli ci-install # perform tests - ./viktor-cli ci-test ``` --- # Environment variables Environment variables can be used for data that you don't want to store in plain text in your app. For example, when connecting to external APIs it is recommended to not use credentials in your app code directly, but pass them to the code as environment variables. This guide covers how to set environment variables for local development, App Builder apps, and published apps. This section ends with a short guide on how to access these environment variables in your app code. ## Defining environment variables for local development[​](/docs/create-apps/development-tools-and-tips/environment-variables/.md#defining-environment-variables-for-local-development "Direct link to Defining environment variables for local development") Environment variables can be set with the CLI for your local development environment. You can set environment variables with the `--env`, `-e` flag when running the `install`, `start` and `run` commands. For example, the environment variable with key `FOO` and corresponding value `bar` can be used as follows: ``` viktor-cli start --env FOO=bar ``` The CLI will connect the local app code to your VIKTOR environment as usual, but with the addition that the environment variable has been set on the running Python process. ## Defining environment variables for app builder and published apps[​](/docs/create-apps/development-tools-and-tips/environment-variables/.md#defining-environment-variables-for-app-builder-and-published-apps "Direct link to Defining environment variables for app builder and published apps") Maintainers and environment administrators can create, update or remove environment variables for both App Builder and published apps. Environment variables can be set from the 'Apps' menu. Environment variables are encrypted at rest in your organization's database using an AES encryption algorithm. For app builder apps, environment variables set on the app details page are automatically available within the app builder environment during development. Follow the steps below to create, update or remove environment variables: 1. Navigate to the 'Apps' page in your VIKTOR environment and find the app you want to set environment variables for and click 'Details'. 2. Select the 'Variables' tab to create, update or remove environment variables. ![app variables page](/assets/images/app_details_variables-d64e0def95e4d027d3ba9c6a408080b1.png) 3. New variables can be added with the 'Add Variable' button on the top right. It is possible to mark a variable as secret. By doing so, it is not possible to inspect the value of the variable at a later moment. Once created a secret variable can only be deleted. Regular variables can be inspected and modified after creation. ![app variables page](/assets/images/create_new_variable-b07783371c1411778556891b60692220.png) Variables in the publishing process If an environment variable is used in the app publication process, for example for authenticating with a [private Python package index](/docs/create-apps/development-tools-and-tips/private-packages/.md), please make sure to add the variable before publishing the app. Reserved Variables Environment variables that start with `VIKTOR_` (with the exception of `VIKTOR_APP_SECRET`) are reserved for internal use by VIKTOR and cannot be set by the user. ## Accessing environment variables in your app code[​](/docs/create-apps/development-tools-and-tips/environment-variables/.md#accessing-environment-variables-in-your-app-code "Direct link to Accessing environment variables in your app code") Environment variables can be accessed in your app code by using the built-in [`os`](https://docs.python.org/3/library/os.html) module. Consider the example mentioned earlier `FOO=bar`. After creating this variable on the 'Variables' tab it can be accessed using `os.environ` or `os.getenv()`. For example, the code below will assign the value `bar` to the variable `my_var` by retrieving the environment variable `FOO`. ``` import os my_var = os.getenv("FOO") ``` --- # Code editor This guide covers setting up your code editor for developing VIKTOR apps. Below instructions assume the app resides in a folder called 'my-app-folder'. ## Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/ide/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") * PyCharm * VS Code - Virtual environment - Docker Open the 'my-app-folder' directory. PyCharm will take this directory as the root directory from which imports are resolved. If you have not installed your app yet PyCharm will ask you to configure a virtual environment. You can click 'Cancel' as the CLI will create a virtual environment when you use the install command. If there is a 'requirements.txt' file you can run `viktor-cli install` to create a virtual environment and install the app's dependencies. Subsequently, open the settings to select a Python interpreter: ``` File > Settings > Project: {Project Name} > Python interpreter > Wheel icon > Add... ``` The virtual environment created by the CLI will be selected as the default existing environment. You can click 'OK', 'Apply' and 'OK' again to select the Python intepreter. Now you are ready to start development in PyCharm! note Using a WSL2 based interpreter in PyCharm is only available in PyCharm Professional Open the 'my-app-folder' directory. PyCharm will take this directory as the root directory from which imports are resolved. This works fine for the app specific code, but it cannot find the VIKTOR SDK code (and of all other dependencies). To solve this, add the 'pip-cache' folder as content root: ``` File > Settings > Project: {Project Name} > Project Structure > Add Content Root ``` Directory which should be added, in which `HOME` has to be replaced with `%USERPROFILE%` (usually `C:\Users\`) in case of Windows, or `$HOME` (usually `/home/`) in case of Linux: ``` HOME └── .viktor └── viktor-installs └── my-app-folder-specific └── pip-cache ``` note Since the folder to be added is within a hidden folder ('.viktor'), it must be made visible by clicking the "Show Hidden Files and Directories" button in the "Select Content Root Directory" window. * Virtual environment * Docker Make sure to install the "python" extension: ``` View > Extensions > Search for "python" by Microsoft ``` Open the 'my-app-folder' directory. If a virtual environment folder is already present you are ready to start developing your app. Otherwise, install your app with `viktor-cli install`. When the virtual environment is created Visual Studio Code detects the virtual environment and will ask you to select it for the workspace folder, click 'Yes'. Now you are ready to start development in Visual Studio Code! Make sure to install the "python" extension: ``` View > Extensions > Search for "python" by Microsoft ``` Within the app directory, add another directory named `.vscode` and add a file named `settings.json` ``` my-app-folder └── .vscode └── settings.json ``` On Windows add the following content to settings.json (replace `` with the value of the `%USERPROFILE%` environment variable (e.g. `C:/Users/`) and `` with the name of the app folder): ``` { "python.autoComplete.extraPaths": [ "/.viktor/viktor-installs/-specific/pip-cache" ], "python.analysis.extraPaths": [ "/.viktor/viktor-installs/-specific/pip-cache" ], } ``` On WSL2/Linux add the following content (replace `` with the name of the app folder): ``` { "python.autoComplete.extraPaths": [ "${env:HOME}/.viktor/viktor-installs/-specific/pip-cache" ], "python.analysis.extraPaths": [ "${env:HOME}/.viktor/viktor-installs/-specific/pip-cache" ], } ``` ## Automatically start your app[​](/docs/create-apps/development-tools-and-tips/ide/.md#automatically-start-your-app "Direct link to Automatically start your app") By means of startup tasks, you are able to automatically start the application as soon as you open the project in your code editor. note The startup tasks assume the application is installed correctly. * PyCharm * VS Code Within the app directory, add the following files: ``` my-app-folder └── .idea ├── runConfigurations │ └── VIKTOR.xml └── startup.xml ``` with the following contents: my-app-folder/.idea/runConfigurations/VIKTOR.xml ``` ``` my-app-folder/.idea/startup.xml ``` ``` Within the app directory, add another directory named `.vscode` and add a file named `tasks.json`: ``` my-app-folder └── .vscode └── tasks.json ``` with the following content: my-app-folder/.vscode/tasks.json ``` { "version": "2.0.0", "tasks": [ { "label": "VIKTOR", "type": "shell", "command": "viktor-cli start", "runOptions": { "runOn": "folderOpen" } } ] } ``` Now re-open your project to check that the app starts in the terminal of the code editor. --- # Interactive debugging The goal of this page is to set up your code editor in such a way, that you will be able to start VIKTOR in debugging mode from your code editor, set breakpoints and inspect the values of variables in your code editor. Depending on your code editor, operating system and virtualization mode the instructions are different. We provide instructions for the following platforms, code editors and virtualization modes: Operating system: * Windows * Linux * [Cloud-based development](/docs/getting-started/installation/cloud-based-development/.md) Code editor: * PyCharm * VS Code Virtualization mode: * Venv * Docker ## Configure the code editor[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-code-editor "Direct link to Configure the code editor") info Before configuring the code editor for debugging, make sure you have installed your application by using `viktor-cli install`. The steps for configuring your editor depend on your operating system, VIKTOR isolation mode and editor. Below instructions assume the app resides in a folder called 'my-app-folder'. First, select your code editor and operating system: * Windows * Linux * Cloud-based development - PyCharm - VS Code * Virtual environment * Docker (Hyper-V) * Docker (WSL) #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") In the bottom right, add a Python interpreter by clicking the `Python 3.X` (or ``) button, followed by `add interpreter`. ![](/assets/images/debug_pycharm_add_interpreter_button-dc45e19af2ec27e709d820eb28013327.png) Then select "existing environment", usually this is selected automatically. Then select the Python interpreter `\venv\Scripts\python.exe` folder if it is not already selected. Click "ok" to save the settings. ![Add existing environment](/assets/images/debug_pycharm_add_interpreter_modal-2ed2cf3a2d2abed0715c574ee55d979a.png) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Next, in the top menu, click `Run > Edit configurations`. A modal will appear where you can create new debug configurations. Then follow these steps: 1. Click the `+` in the top-left and from the dropdown select `Python` to create a new debug configuration 2. Change `Script path` to `Module name` 3. Type `viktor_debugging` in the field for the module name 4. Select the Python interpreter you just configured 5. Change the working directory to the project directory. 6. (optionally) give the configuration a name, such as *"VIKTOR Debug"* 7. Click `OK` to save the debug configuration ![](/assets/images/debug_pycharm_configuration-791984eb109a82c2575ee9c4b777d1fb.png) PyCharm should now be configured for debugging. #### Set up unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-unit-tests "Direct link to Set up unit tests") Go to `Settings (Ctrl + Alt + S) > Tools > Python Integrated Tools`. Then under the header *"Testing"* change the *Default test runner* to `Unittests` (not PyTest nor Autodetect) and hit *"OK"* to save the changes. caution Debugging in a Docker container using PyCharm is only possible with the PyCharm Professional edition. #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") `Bottom right > add interpreter > Docker` * Server: `Docker` * image name: `python:3.13-bookworm` (change the number if you use a different Python version) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Within the app directory, go to the `.idea` add another directory named `runConfigurations` and add a file named `VIKTOR_Debug.xml`: ``` my-app-folder └── .idea └── runConfigurations └── VIKTOR_Debug.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example), this can be found on the highlighted line. my-app-folder/.idea/runConfigurations/VIKTOR\_Debug.xml ``` ``` PyCharm should now be configured for debugging. #### Set up unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-unit-tests "Direct link to Set up unit tests") Configure using *Unittests* (not PyTest nor Autodetect) in `Settings (Ctrl + Alt + S) > Tools > Python Integrated Tools > Testing > Default test runner` Within the app directory, go to the `.idea` add another directory named `runConfigurations` and create a file `_template__of_Unittests.xml`: ``` my-app-folder └── .idea └── runConfigurations ├── VIKTOR_Debug.xml └── _template__of_Unittests.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example), this can be found on the highlighted line. my-app-folder/.idea/runConfigurations/\_template\_\_of\_Unittests.xml ``` ``` info Restart PyCharm to make sure the configuration is loaded properly. caution Debugging in a Docker container using PyCharm is only possible with the PyCharm Professional edition. #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") `Bottom right > add interpreter > Docker` * Server: `Docker` * image name: `python:3.13-bookworm` (change the number if you use a different Python version) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Within the app directory, go to the `.idea` add another directory named `runConfigurations` and add a file named `VIKTOR_Debug.xml`: ``` my-app-folder └── .idea └── runConfigurations └── VIKTOR_Debug.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example) and replace `` with the Windows path to the WSL user home directory (will look something like `//wsl$/Ubuntu/home/`). Both can be found on the highlighted line. my-app-folder/.idea/runConfigurations/VIKTOR\_Debug.xml ``` ``` PyCharm should now be configured for debugging. #### Set up unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-unit-tests "Direct link to Set up unit tests") Configure using *Unittests* (not PyTest nor Autodetect) in `Settings (Ctrl + Alt + S) > Tools > Python Integrated Tools > Testing > Default test runner` Within the app directory, go to the `.idea` add another directory named `runConfigurations` and create a file `_template__of_Unittests.xml`: ``` my-app-folder └── .idea └── runConfigurations ├── VIKTOR_Debug.xml └── _template__of_Unittests.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example) and replace `` with the Windows path to the WSL user home directory (could be something like `/Ubuntu/home/username`). Both can be found on the highlighted line. my-app-folder/.idea/runConfigurations/\_template\_\_of\_Unittests.xml ``` ``` info Restart PyCharm to make sure the configuration is loaded properly. * Virtual environment * Docker (Hyper-V) * Docker (WSL) #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") Install the Python extension for VS Code (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python`) Open the command pallette (`Ctrl + Shift + P`), and search for `Python: Select Interpreter`. Then select `Python .\venv\Scripts\python.exe`. #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") In the top menu, click `Run > Add configuration...`. Select 1. `Python` 2. `Module` 3. Enter `viktor_debugging` Now a `launch.json` file should be created containing the following: (if you like, you can change the name to `VIKTOR Debug`) my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "python", "request": "launch", "module": "viktor_debugging", "justMyCode": true } ] } ``` VS Code should now be configured for debugging. #### Unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#unit-tests "Direct link to Unit tests") Configure using unittest: Open command pallette: `Ctrl + Shift + P`, and search for `Python: Configure Tests`. Then select 1. `unittest` to configure the test runner 2. `tests` to configure what folder the tests can be found 3. `test*.py` to so that all files starting with "test" are selected #### Install extensions[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#install-extensions "Direct link to Install extensions") Install the Python and Docker extensions for VS Code (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python` and `ms-azuretools.vscode-docker`) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Within the app directory, add another directory named `.vscode` and add a two files named `launch.json` and `tasks.json`: ``` my-app-folder └── .vscode ├── launch.json └── tasks.json ``` Inside the `launch.json` file, add the following content: my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: debug", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}","remoteRoot": "/usr/src/app" } ], "projectType": "general", } }, { "name": "Unittest", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: test", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}","remoteRoot": "/usr/src/app" } ], "projectType": "general", } } ] } ``` And inside the `tasks.json` add the following content. If you use a python version different from 3.13, change the number on the highlighted lines: my-app-folder/.vscode/tasks.json ``` { "version": "2.0.0", "tasks": [ { "label": "docker-run: debug", "type": "docker-run", "python": { "module": "viktor_debugging" }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${env:USERPROFILE}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${env:USERPROFILE}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } }, { "label": "docker-run: test", "type": "docker-run", "python": { "module": "unittest", "args": ["discover", "-s", "tests", "-v"] }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${env:USERPROFILE}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${env:USERPROFILE}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } } ] } ``` VS Code should now be configured for debugging and testing. #### Install extensions[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#install-extensions "Direct link to Install extensions") Install the "Remote - WSL", "Python" and "Docker" extensions for VS Code (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-vscode-remote.remote-wsl`, `ms-python.python` and `ms-azuretools.vscode-docker`). Next, click the green "Remote window" button in the bottom left corner of the window (see image below) and click "New WSL Window" to connect VS Code to a WSL development environment. This may take a while. Once connected, you should see "WSL: Ubuntu" in the bottom left corner. ![](data:image/png;base64,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) Then, in the WSL Development environment, you should again install the "Python" and "Docker" extensions for VS Code (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python` and `ms-azuretools.vscode-docker`, or you can use the "Install in WSL: Ubuntu" button, see screenshot). ![](/assets/images/debug_vscode_install_in_wsl-8b310aa097571378dbcb6bcb8002f7b8.png) To check the extensions are installed in WSL, you may need to expand the "WSL: Ubuntu" section. ![](/assets/images/debug_vscode_extensions_are_installed-dad063a4ece0900bb7fe620dcdfaca11.png) Then open your project by chosing from the top menu: `File > Open Folder` and select the project. Do not use the recently opened links, as they will open the project ouside of the WSL development environment. Lastly, in a WSL terminal, run `sudo apt install python-is-python3` to make sure that the Python debugger of VS Code can find the correct python version in the WSL environment. #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Within the app directory, add another directory named `.vscode` and add a two files named `launch.json` and `tasks.json`: ``` my-app-folder └── .vscode ├── launch.json └── tasks.json ``` Inside the `launch.json` file, add the following content: my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: debug", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}","remoteRoot": "/usr/src/app" } ], "projectType": "general", } }, { "name": "Unittest", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: test", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}","remoteRoot": "/usr/src/app" } ], "projectType": "general", } } ] } ``` And inside the `tasks.json` add the following content. If you use a python version different from 3.13, change the number on the highlighted lines: my-app-folder/.vscode/tasks.json ``` { "version": "2.0.0", "tasks": [ { "label": "docker-run: debug", "type": "docker-run", "python": { "module": "viktor_debugging" }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${userHome}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${userHome}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } }, { "label": "docker-run: test", "type": "docker-run", "python": { "module": "unittest", "args": ["discover", "-s", "tests", "-v"] }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${userHome}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${userHome}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } } ] } ``` VS Code should now be configured for debugging and testing. * PyCharm * VS Code - Virtual environment - Docker #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") In the bottom right, add a Python interpreter by clicking the `Python 3.X` (or ``) button, followed by `add interpreter`. ![](/assets/images/debug_pycharm_add_interpreter_button-dc45e19af2ec27e709d820eb28013327.png) In the bottom right, add a Python interpreter by clicking the `Python 3.X` (or ``) button, followed by `add interpreter`. Then select "existing environment", usually this is selected automatically. Then select the Python interpreter in `/venv/bin/python` folder if it is not already selected. Click "ok" to save the settings. ![Add existing environment](/assets/images/debug_pycharm_add_interpreter_modal_linux-28419dd64703d442192d872c35e45451.png) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Next, in the top menu, click `Run > Edit configurations`. A modal will appear where you can create new debug configurations. Then follow these steps: 1. Click the `+` in the top-left and from the dropdown select `Python` to create a new debug configuration 2. Change `Script path` to `Module name` 3. Type `viktor_debugging` in the field for the module name 4. Select the Python interpreter you just configured 5. Change the working directory to the project directory. 6. (optionally) give the configuration a name, such as *"VIKTOR Debug"* 7. Click `ok` to save the debug configuration ![](/assets/images/debug_pycharm_configuration_linux-bf005f4dda274d64b75958dbfd957dd8.png) PyCharm should now be configured for debugging. #### Unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#unit-tests "Direct link to Unit tests") Go to `Settings (Ctrl + Alt + S) > Tools > Python Integrated Tools`. Then under the header *"Testing"* change the *Default test runner* to `Unittests` (not PyTest nor Autodetect) and hit *"OK"* to save the changes. caution Debugging in a Docker container using PyCharm is only possible with the PyCharm Professional edition. #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") `Bottom right > add interpreter > Docker` * Server: `Docker` (unix sock) * image name: `python:3.13-bookworm` (change the number if you use a different Python version) #### Debug configuration[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#debug-configuration "Direct link to Debug configuration") Within the app directory, add another directory named `.run` and add a file named `debug.run.xml`: ``` my-app-folder └── .run └── debug.run.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example), this can be found on the highlighted line. my-app-folder/.run/debug.run.xml ``` ``` PyCharm should now be configured for debugging, to start debugging. #### Unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#unit-tests "Direct link to Unit tests") Configure using *Unittests* (not PyTest nor Autodetect) in `Settings (ctrl + alt + s) > Tools > Python Integrated Tools > Testing > Default test runner` And create a `Template Python tests.run.xml` ``` my-app-folder └── .run ├── debug.run.xml └── Template Python tests.run.xml ``` Inside this file, add the XML provided in the snippet below. Make sure to replace `` with the directory name of your app folder (e.g. `my-app-folder` in the example), this can be found on the highlighted line. my-app-folder/.run/Template Python tests.run.xml ``` ``` info Restart PyCharm to make sure the configuration is loaded properly. * Virtual environment * Docker #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") Install the "Python" extension (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python`) Open command pallette: `Ctrl + Shift + P`, and search for `Python: Select Interpreter`. Then select `Python ('venv': venv) ./venv/bin/python`. #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") In the top menu, click `Run > Add configuration...`. Select 1. `Python` 2. `Module` 3. Enter `viktor_debugging` Now a `launch.json` file should be created containing the following: (if you like, you can change the name to `VIKTOR Debug`) my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "python", "request": "launch", "module": "viktor_debugging", "justMyCode": true } ] } ``` The code editor should now be configured for debugging. #### Unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#unit-tests "Direct link to Unit tests") Configure using unittest: Open command pallette: `Ctrl + Shift + P`, and search for `Python: Configure Tests`. Then select 1. `unittest` to configure the test runner 2. `tests` to configure what folder the tests can be found 3. `test*.py` to so that all files starting with "test" are selected #### Install extensions[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#install-extensions "Direct link to Install extensions") Install the Python and Docker extensions for VS Code (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python` and `ms-azuretools.vscode-docker`) #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") Within the app directory, add another directory named `.vscode` and add a two files named `launch.json` and `tasks.json`: ``` my-app-folder └── .vscode ├── launch.json └── tasks.json ``` Inside the `launch.json` file, add the following content: my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: debug", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "/usr/src/app" } ], "projectType": "general", } }, { "name": "Unittest", "type": "docker", "request": "launch", "preLaunchTask": "docker-run: test", "python": { "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "/usr/src/app" } ], "projectType": "general", } } ] } ``` And inside the `tasks.json` add the following content: If you use a python version different from 3.13, change the number on the highlighted lines. my-app-folder/.vscode/tasks.json ``` { "version": "2.0.0", "tasks": [ { "label": "docker-run: debug", "type": "docker-run", "python": { "module": "viktor_debugging" }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${env:HOME}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${env:HOME}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } }, { "label": "docker-run: test", "type": "docker-run", "python": { "module": "unittest", "args": ["discover", "-s", "tests", "-v"] }, "dockerRun": { "network": "host", "containerName": "viktor-container", "image": "python:3.13-bookworm", "remove": true, "env": { "PYTHONPATH": "/usr/src/app:/usr/src/packages", "PYTHONUNBUGGERED": "1", "PYTHONDONTWRITEBYTECODE": "1" }, "customOptions": "-w /usr/src/app", "volumes": [ {"containerPath": "/usr/src/app", "localPath": "${workspaceFolder}"}, {"containerPath": "/root/.viktor", "localPath": "${env:HOME}/.viktor"}, {"containerPath": "/usr/src/packages", "localPath": "${env:HOME}/.viktor/viktor-installs/${workspaceFolderBasename}-specific/pip-cache"} ] } } ] } ``` VS Code should now be configured for debugging and running unit tests. #### Configure the Python interpreter[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#configure-the-python-interpreter "Direct link to Configure the Python interpreter") Install the "Python" extension (in extensions menu (`Ctrl+Shift+X`) you can search for `ms-python.python`) Open command pallette: `Ctrl + Shift + P`, and search for `Python: Select Interpreter`. Then select `Python ('venv': venv) ./venv/bin/python`. #### Set up debugging[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#set-up-debugging "Direct link to Set up debugging") In the top menu, click `Run > Add configuration...`. Select 1. `Python` 2. `Module` 3. Enter `viktor_debugging` Now a `launch.json` file should be created containing the following: (if you like, you can change the name to `VIKTOR Debug`) my-app-folder/.vscode/launch.json ``` { "version": "0.2.0", "configurations": [ { "name": "VIKTOR Debug", "type": "python", "request": "launch", "module": "viktor_debugging", "justMyCode": true } ] } ``` The code editor should now be configured for debugging. #### Unit tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#unit-tests "Direct link to Unit tests") Configure using unittest: Open command pallette: `Ctrl + Shift + P`, and search for `Python: Configure Tests`. Then select 1. `unittest` to configure the test runner 2. `tests` to configure what folder the tests can be found 3. `test*.py` to so that all files starting with "test" are selected ## Start the debugger[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#start-the-debugger "Direct link to Start the debugger") Before starting a debugging session, make sure that you are **not running** the app using the viktor-cli (close the connection using `Ctrl+C`). To start the debugging session, use: * **PyCharm:** In the top menu, click `Run > Debug... (Alt+Shift+F9)` and select the debug configuration we just made. If it is already selected you can also use `Run > Debug (VIKTOR Debug) (Shift+F9)`. * **Visual Studio Code:** In the top menu, click `Run > Start debugging... (F5)`. caution Auto-reload is not possible in debug mode. Code changes only take effect after restarting the debugging session. (pycharm: `Ctrl+F5`, vscode: `Ctrl+Shift+F5`) ## Setting breakpoints[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#setting-breakpoints "Direct link to Setting breakpoints") When the debugger is started, a terminal should appear at the bottom of your editor window, in which your app is started. You should be able to go to your personal dev url in a browser and use the app. You can set breakpoints in the code, and inspect the parameters at these points. You can read more about setting breakpoints, stepping through code and reading variables in the documentation of the specific editors: | PyCharm | VS Code | | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | [Set breakpoints in PyCharm](https://www.jetbrains.com/help/pycharm/using-breakpoints.html#set-breakpoints) | [Set breakpoints in VS Code](https://code.visualstudio.com/docs/editor/debugging#_breakpoints) | | [Stepping through code in PyCharm](https://www.jetbrains.com/help/pycharm/stepping-through-the-program.html) | [Stepping through code in VS Code](https://code.visualstudio.com/docs/editor/debugging#_debug-actions) | | [Reading variables in PyCharm](https://www.jetbrains.com/help/pycharm/examining-suspended-program.html#variables) | [Reading variables in VS Code](https://code.visualstudio.com/docs/editor/debugging#_data-inspection) | When writing a Python script, normally you will hit the breakpoints when you start the script. In a VIKTOR application however, the breakpoints will only be hit when the function is [triggered](/docs/getting-started/fundamentals/call-flow/.md#triggering-actions) by the user. For example, the code in a view function runs when the view is opened in the web browser. Note that when debugging quick views or callback functions that are used for the parametrization, the editor will not respond when the call (including debugging time) takes longer than about 10 seconds. tip When debugging views, you can (temporarily) set the `duration_guess` to some high number to require manual triggering of the computation, leading to a nicer debug experience. This will also allow you to see the updated results in the web browser once the call is finished. ## Debugging tests[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#debugging-tests "Direct link to Debugging tests") We assume your tests are located in the "tests" folder. ### PyCharm[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#pycharm "Direct link to PyCharm") In the project explorer, right-click a test file or test directory and then *Debug "Python tests in test..."*. Alternatively, you can debug individual tests (or test classes) by opening a test file and clicking the play button in the gutter and then selecting *Debug "Python tests in test..."*. ![](/assets/images/debug_test_pycharm-252b85582a3330605391060ba730d080.png) ### Visual Studio Code - venv[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#visual-studio-code---venv "Direct link to Visual Studio Code - venv") In the left panel, choose tests (the Erlenmeyer flask icon). You should see your tests listed there. In this panel you can hover a test file and click the run or debug icon. Alternatively, you can debug individual tests by going to your test file and right-clicking the icon in the gutter next to the test function and selecting "Debug test". ![](/assets/images/debug_test_vscode-3f964f0be2ffbb0edb550b0dcf5e5211.png) ### Visual Studio Code - Docker[​](/docs/create-apps/development-tools-and-tips/interactive-debugging/.md#visual-studio-code---docker "Direct link to Visual Studio Code - Docker") In the left menu, go to the debug panel (`Ctrl+Shift+D`) and at the top choose *"Unittest"*. Click on the green arrow next to it to debug the unit tests. This runs all unit tests. --- # Keeping a changelog It is advised to keep a list of all notable changes that have been made in the source code of an application. By doing so, current and future contributors have a concise and clear overview of what has changed between different versions of the app. The changelog is usually named `CHANGELOG.md` and written in [markdown](https://www.markdownguide.org/basic-syntax/) format. It should be easily accessible, therefore ideally be placed on the top level of the source code repository: ``` my-app ├── app ├── ... ├── CHANGELOG.md ``` ## Example changelog[​](/docs/create-apps/development-tools-and-tips/keep-a-changelog/.md#example-changelog "Direct link to Example changelog") These are a couple of guidelines to keep in mind: * Add a small text on top to mention the type of versioning that is used (e.g. semantic) * Order the changelog entries chronologically with the latest changes on top * Group entries per type of change: * `Added`: new features * `Changed`: changes in existing features * `Removed`: removed features * `Fixed`: bug fixes * Add a date with each new version An example is provided below, which can also be used as template for your applications: ``` # Changelog All notable changes to this project will be documented in this file. Semantic versioning is used to denote different versions of this project. ## [Unreleased] - YYYY-MM-DD ### Added - EntityTypeA: Report download ### Changed ### Removed ### Fixed - EntityTypeB: Aspect ratio in SVG visualization ## [v0.1.0] - 2021-01-19 ### Added - Setup entity type structure with EntityTypeA and EntityTypeB - EntityTypeA: MapView visualization - EntityTypeB: SVG visualization ``` ## Semantic versioning[​](/docs/create-apps/development-tools-and-tips/keep-a-changelog/.md#semantic-versioning "Direct link to Semantic versioning") Semantic versioning is commonly used to denote the different versions of an application. The convention that is used for the version number has format v**X**.**Y**.**Z** where: * **X** is the major: increments when a backwards incompatible change is introduced. * **Y** is the minor: increments when a new functionality is added, without breaking compatibility with older versions. * **Z** is the patch: increments when the code can drop-in-replace the previous code, or when documentation is added/changed. ## Referencing to issue number[​](/docs/create-apps/development-tools-and-tips/keep-a-changelog/.md#referencing-to-issue-number "Direct link to Referencing to issue number") In case you develop and maintain your application code in a source-code hosting facility which has a ticketing system (e.g. GitHub, GitLab, BitBucket etc.), the changelog will often also be visible in the interface. It is possible to refer to a specific ticket (issue number), which is very helpful to easily trace back to the historic moment of a specific change. For example, in GitLab you can refer to the issue number using a "#" symbol: ``` - (#123) EntityTypeA: MapView visualization ``` --- # Use private packages Packages that are publicly available on [PyPI](https://pypi.org/) can be specified in your app's `requirements.txt` file to become available in your app as dependency, as shown [here](/docs/create-apps/development-tools-and-tips/use-python-packages/.md). But sometimes you might want to add a package that is only available privately (e.g. code stored on a centralized repository within the company to be reused in multiple apps). There are different options to make such a package available in a (published) app, without the need to copy the code manually into your app folder: * [Git submodule](/docs/create-apps/development-tools-and-tips/private-packages/.md#git-submodule) * [Git repository](/docs/create-apps/development-tools-and-tips/private-packages/.md#install-from-a-git-repository) * [Private PyPI](/docs/create-apps/development-tools-and-tips/private-packages/.md#publish-your-package-on-a-private-pypi) ## Git submodule[​](/docs/create-apps/development-tools-and-tips/private-packages/.md#git-submodule "Direct link to Git submodule") The easiest way to add an app-dependency is to copy the package code (as a sub-folder) into your app folder. A disadvantage of this approach is that if the package is maintained in a separate repository, the copied code needs to be manually updated to receive the latest additions or bugfixes. This problem can be resolved by adding the dependency as a Git *submodule* to your app. Obviously, this requires your app code itself to be a Git repository. Add an existing Git repository as a submodule to your app by: ``` git submodule add https://my-package-repository-url app/submodules/my-package ``` note All code, including the submodules, must reside (in a sub-folder) within the 'app' folder to be available in production. This will copy the repository's content in a sub-folder `submodules/my-package/` within your app folder, and creates a `.gitmodules` file in your project folder that stores the mapping between the package URL and local path. Updating your app including all submodules can be done with: ``` git pull --recurse-submodules ``` Cloning a project including all submodules to your local hard disk can be done by: ``` git clone --recurse-submodules https://my-project-repository-url ``` All ins and outs of using Git submodules can be found on the [Git website](https://git-scm.com/book/en/v2/Git-Tools-Submodules). ## Install from a Git repository[​](/docs/create-apps/development-tools-and-tips/private-packages/.md#install-from-a-git-repository "Direct link to Install from a Git repository") Alternatively, it is possible to install a Python package directly from a (private) Git repository host. For example, it is possible to install `my-package` that is hosted on the URL `https://github.com/my-user-account/my-package` by adding the line below to `requirements.txt`. Additionally, you can install a specific branch or tag by appending an `@` followed by the reference to the url, for example `@v1.2.3`. ``` my-package@git+https://${MY_USER}:${MY_PASSWORD}@github.com/my-user-account/my-package ``` caution For security reasons, we advise against hard-coding the authentication credentials in `requirements.txt`, prefer to use [environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md) instead. ## Publish your package on a private PyPI[​](/docs/create-apps/development-tools-and-tips/private-packages/.md#publish-your-package-on-a-private-pypi "Direct link to Publish your package on a private PyPI") Another way to make a private package available in an app is to publish it on a private PyPI. This way the code is not copied in your app, but handled as any other package dependency. Moreover, access can even be restricted by means of authentication credentials. Examples of platforms that allow for hosting your own packages, are: * GitLab - [Package Registry](https://docs.gitlab.com/ee/user/packages/pypi_repository/) * Microsoft Azure - [Azure Artifacts](https://learn.microsoft.com/en-us/azure/devops/pipelines/artifacts/pypi) Instructions on how to host your private package on each platform can be found in the corresponding links. The hosted package can then be added in your app's `requirements.txt` file, as follows: ``` --extra-index-url https://my-private-package-index-url my-private-package ``` If the private package index is protected by means of authentication credentials, this can be passed using [environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md): ``` --extra-index-url https://${MY_USER}:${MY_PASSWORD}@my-private-package-index-url my-private-package ``` caution For security reasons, we advise against hard-coding the authentication credentials in `requirements.txt`, prefer to use [environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md) instead. --- # Use system dependencies In some cases your application uses Python packages that depend on one or multiple packages that cannot be installed using `pip`. These system packages need to be installed with the package manager of the operating system. For example [`vtk`](https://pypi.org/project/vtk/) could be used for processing of images. When you try to publish an app, you may receive the following error: ``` ImportError: libGL.so.1: cannot open shared object file: No such file or directory ``` Above error happens because `vtk` is using an OpenGL-based program in the background which requires libGL. To annotate that such system dependencies should be installed when the application is being published, you can specify `packages` in your app's [viktor.config.toml file](/docs/create-apps/references/viktor-config-toml/.md#packages): ``` packages = ["libgl1"] ``` The provided packages should be [apt-get compatible](https://linux.die.net/man/8/apt-get) as published VIKTOR apps run on Linux. ## Common system packages[​](/docs/create-apps/development-tools-and-tips/system-dependencies/.md#common-system-packages "Direct link to Common system packages") The table below provides common use cases for Python package with their required system packages. | Python package | System package(s) | Use case | | ---------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------ | | [ffmpeg-python](https://pypi.org/project/python-ffmpeg/) | ffmpeg | Video file processing | | [opencv-python](https://pypi.org/project/opencv-python/) | python3-opencv | Image processing | | [pdf2docx](https://pypi.org/project/pdf2docx/) | libgl1 | PDF file processing | | [pyenchant](https://pypi.org/project/pyenchant/) | python3-enchant | Spelling check and correction suggestions | | [pyomo](https://pypi.org/project/pyomo/) (GLPK solver) | libglpk-dev, glpk-utils | Formulating, solving, and analyzing optimization models | | [pytesseract](https://pypi.org/project/pytesseract/) | tesseract-ocr | Image processing | | [python-poppler](https://pypi.org/project/python-poppler/) | poppler-utils, libpoppler-cpp-dev | PDF file processing | | [pyvista](https://pypi.org/project/pyvista/) | libgl1 | High-level API for Visualization Toolkit (VTK) | | [vtk](https://pypi.org/project/vtk/) | libgl1 | Image processing | | [locale](https://docs.python.org/3/library/locale.html) | locales-all | Support localization with locales that are not included by default | Help us improve Do you have a use case which is not listed in the table above? Please contact `support@viktor.ai` or post a message on the [Community Forum](https://community.viktor.ai/) and help us improve this overview! --- # Use Python packages App dependencies can be specified in your app's `requirements.txt` file. Besides the VIKTOR SDK version, this can include any Python package to be used in the app: ``` viktor==X.X.X drawSVG==1.3.1 ``` ## Pinning version number and version clashes[​](/docs/create-apps/development-tools-and-tips/use-python-packages/.md#pinning-version-number-and-version-clashes "Direct link to Pinning version number and version clashes") Both the VIKTOR SDK and drawSVG package have an explicit version number defined (pinned version numbers). This is done to ensure that your app always uses the same version. If the package maintainers release a new version overnight, this does not break your app when re-installing. By pinning the versions, you decide when to upgrade to a newer version and this enables reading the CHANGELOG which might contain necessary actions for upgrading. It is possible that you are using a package which is also used by the VIKTOR SDK. The SDK defines a range of allowed versions. If the app specifies a version outside this range, an error will be logged: ``` ERROR: viktor X.X.X has requirement numpy>=1.15.3, but you'll have numpy 1.15.0 which is incompatible. ``` This might also happen when you don't have a pinned version number and the latest version has not yet been added to the SDK range. caution External packages that are internally used in the SDK are available in your app (e.g. `munch`), even when you don't add them to your app's `requirements.txt`. Nevertheless, **you are highly encouraged to explicitly define them in your app requirements**, as deletion of dependencies within the SDK will be done without prior notice and therefore may break your app! caution Some package licenses do not allow for commercial use, or requires you to open-source your implementation. Make sure the package licensing permits, before using it in your app. ## Use private packages[​](/docs/create-apps/development-tools-and-tips/use-python-packages/.md#use-private-packages "Direct link to Use private packages") Instructions on how to use private packages in your app can be found [here](/docs/create-apps/development-tools-and-tips/private-packages/.md). ## Use system packages[​](/docs/create-apps/development-tools-and-tips/use-python-packages/.md#use-system-packages "Direct link to Use system packages") Instructions on how to use system packages in your app can be found [here](/docs/create-apps/development-tools-and-tips/system-dependencies/.md). --- # Documents & spreadsheets VIKTOR offers several services that can be used to for example convert a file's extension (e.g. Word to PDF), or to dynamically fill a file where the content depends on other factors. caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ## Document conversion / merging[​](/docs/create-apps/documents-and-spreadsheets/.md#document-conversion--merging "Direct link to Document conversion / merging") The following methods can be used to [convert a file to PDF](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md): * Word to PDF ([`convert_word_to_pdf()`](/sdk/api/utils/.md#_convert_word_to_pdf)). * Excel to PDF ([`convert_excel_to_pdf()`](/sdk/api/utils/.md#_convert_excel_to_pdf)). * SVG to PDF ([`convert_svg_to_pdf()`](/sdk/api/utils/.md#_convert_svg_to_pdf)). Multiple PDF documents can easily be [merged into a single document](/docs/create-apps/documents-and-spreadsheets/merging-pdf-files/.md) using [`merge_pdf_files()`](/sdk/api/utils/.md#_merge_pdf_files). ## Templating[​](/docs/create-apps/documents-and-spreadsheets/.md#templating "Direct link to Templating") Dynamically filling a document can be achieved by using one of the available templaters: * [Word](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md) ([`render_word_file()`](/sdk/api/external/word/.md#_render_word_file)). * [Spreadsheet](/docs/create-apps/documents-and-spreadsheets/spreadsheet-templater/.md) ([`render_spreadsheet()`](/sdk/api/external/spreadsheet/.md#_render_spreadsheet)). * [Jinja](/docs/create-apps/documents-and-spreadsheets/text-file-templater/.md) ([`render_jinja_template()`](/sdk/api/utils/.md#_render_jinja_template)). Furthermore, a spreadsheet can be used as [calculator](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md). --- # Converting to PDF caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. Various formats can be converted to PDF using VIKTOR's built-in services. Converters for the following file types are currently supported: * [Word](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#word-to-pdf) * [Excel](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#excel-to-pdf) * [SVG](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#svg-to-pdf) ## Word to PDF[​](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#word-to-pdf "Direct link to Word to PDF") A Word file can be converted to PDF using the [`convert_word_to_pdf`](/sdk/api/utils/.md#_convert_word_to_pdf) function: ``` from pathlib import Path import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.docx") with file1.open_binary() as f1: pdf = vkt.convert_word_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.docx", "rb") as f1: pdf = vkt.convert_word_to_pdf(f1) ``` ## Excel to PDF[​](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#excel-to-pdf "Direct link to Excel to PDF") An Excel file can be converted to PDF using the [`convert_excel_to_pdf`](/sdk/api/utils/.md#_convert_excel_to_pdf) function: ``` from pathlib import Path import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.xlsx") with file1.open_binary() as f1: pdf = vkt.convert_excel_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.xlsx", "rb") as f1: pdf = vkt.convert_excel_to_pdf(f1) ``` ## SVG to PDF[​](/docs/create-apps/documents-and-spreadsheets/converting-to-pdf/.md#svg-to-pdf "Direct link to SVG to PDF") An SVG image file can be converted to PDF using the [`convert_svg_to_pdf`](/sdk/api/utils/.md#_convert_svg_to_pdf) function: ``` from pathlib import Path import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.svg") with file1.open_binary() as f1: pdf = vkt.convert_svg_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.svg", "rb") as f1: pdf = vkt.convert_svg_to_pdf(f1) ``` --- # Merging PDF files caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. Merging PDF files can be done using the [`merge_pdf_files`](/sdk/api/utils/.md#_merge_pdf_files) function: ``` from pathlib import Path import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "pdf1.pdf") file2 = vkt.File.from_path(Path(__file__).parent / "pdf2.pdf") with file1.open_binary() as f1, file2.open_binary() as f2: merged_pdf = vkt.merge_pdf_files(f1, f2) # using built-in `open()` with open(Path(__file__).parent / "pdf1.pdf", "rb") as f1, open(Path(__file__).parent / "pdf2.pdf", "rb") as f2: merged_pdf = vkt.merge_pdf_files(f1, f2) ``` --- # Spreadsheet calculator tip This guide is an informative piece to help you if you have questions about the Spreadsheet calculation functionality. If you would like a more instructive lesson, take a look at the [Spreadsheet calculator tutorial](/docs/tutorials/spreadsheet-calculator/.md) we have available. caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The [`SpreadsheetCalculation`](/sdk/api/external/spreadsheet/.md#_SpreadsheetCalculation) object can be used to utilize a spreadsheet **without macros** as an external calculator. If you want to use an Excel sheet **with macros** as a calculation tool, you can use VIKTOR's [Excel integration](/docs/create-apps/software-integrations/excel/.md). ## Calculation sheet set-up[​](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md#calculation-sheet-set-up "Direct link to Calculation sheet set-up") 1. Add two sheets inside the Excel calculation document named "viktor-input-sheet" and "viktor-output-sheet". caution Note that these names must match in order for VIKTOR to find the correct sheet! 2. In the input and output sheets specify the following four columns: * A1 = Parameters, * B1 = Unit, * C1 = Comment, * D1 = Values 3. In "viktor-input-sheet": add input identifiers in the "Parameters" column and optionally specify default values in the "Values" column ![](/assets/images/evaluate-spreadsheet-input-429d897bc162c0f247a83a9c2748e8b4.png) *viktor-input-sheet example* 4. Link to these values as a source for the calculation in the calculation sheet 5. In "viktor-output-sheet": add output identifiers in the "Parameters" column ![](/assets/images/evaluate-spreadsheet-output-393652ff75e083c9131a57af0d09c661.png) *viktor-output-sheet example* 6. In "viktor-output-sheet": point to the relevant cell(s) in the calculation sheet ![](/assets/images/evaluate-spreadsheet-calculation-61c33d3ed2c8de632d68a98661f1b375.png) *calculation sheet example* ## Implementation in app[​](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md#implementation-in-app "Direct link to Implementation in app") 7. Import `SpreadsheetCalculation` and `SpreadsheetCalculationInput` from the `viktor.external` package 8. Evaluate the spreadsheet and obtain a SpreadsheetResult with a dictionary of the `output_key` parameters with corresponding values ``` import viktor as vkt def calculation_result(a, b): input_list = [ vkt.spreadsheet.SpreadsheetCalculationInput('input_key1', a), vkt.spreadsheet.SpreadsheetCalculationInput('input_key2', b) ] spreadsheet = vkt.File.from_path('calculation_sheet.xlsx') sheet = vkt.spreadsheet.SpreadsheetCalculation(spreadsheet, input_list) result = sheet.evaluate() return result.values calculation_values = calculation_result(3, 6) print(calculation_values['output_key1']) ``` ## Using lists as input or output[​](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md#using-lists-as-input-or-output "Direct link to Using lists as input or output") To pass a list of values as **input** for the calculation spreadsheet, one can pass a (e.g. semicolon) separated string ("value1;value2;value3;...") using `SpreadsheetCalculationInput` and write code logic in the spreadsheet to 'parse' and use the values. It is also possible to store a range of cells to a list as output. Simply link the cells in the columns behind "Values" to the desired cells using an **array formula**. ![](/assets/images/evaluate-spreadsheet-output-list-6029e441a03fa4b92b5c1b3aa8d44293.png) *output list example* In the example `output_list1` and `output_list2` will return the same range of results. caution Currently a list can have a maximum of 47 values. A temporary workaround to make use of longer lists is by using a `TEXTJOIN` function in the calculation sheet. This function returns a joined string of the results separated by a user specified separator (e.g. ";"). In the client code, this list can then be converted back to a list of the results by using the `split()` function. --- # Spreadsheet templater caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. This guide will assume the template (represented by bytes) is available. Either named cells (cells which can be found using a certain key) or direct cells (cell which can be found by a direct address `{sheet, column, row}`) can be used to fill the template. An example implementation of how a spreadsheet template can be filled can be found below. ``` import viktor as vkt cells = [ vkt.spreadsheet.DirectInputCell('sheet1', 'A', 1, 5), vkt.spreadsheet.NamedInputCell('named_cell_1', 'text_to_be_placed'), ] template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.xlsx' with open(template_path, 'rb') as template: filled_spreadsheet = vkt.spreadsheet.render_spreadsheet(template, cells) ``` When large blocks of cells need to be filled, an [`InputCellRange`](/sdk/api/external/spreadsheet/.md#_InputCellRange) can be used. --- # Text-file templater caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. Templating can be a very powerful tool for creating input dependent content. Packages like [jinja2](https://jinja.palletsprojects.com/) greatly simplify the process of creating and rendering these templates: ``` >>> from jinja2 import Template >>> template = Template('Hello {{ name }}!') >>> template.render({'name': 'John Doe'}) 'Hello John Doe!' ``` It consists of two parts: * the template: `'Hello {{ name }}!'` * the context: `{'name': 'John Doe'}` In some situations, both the template and the context will be strictly controlled by the developer: the template is a file in the repository and the developer creates a dictionary with the context from his own code. In others, it might be beneficial to give the user more flexibility and let them create either the template or the context. An example use-case could be user defined reports in which the format varies a lot. Instead of figuring out all the logic, the user can create its own template. This increase in flexibility however comes with a significant security risk which should be addressed. ## Security risks[​](/docs/create-apps/documents-and-spreadsheets/text-file-templater/.md#security-risks "Direct link to Security risks") A templating engine combines the template with the context by defining a syntax. In the case of jinja2 this syntax is very extensive. It has for-loops, if-statements, variable assignment, to name a few. All these possibilities make it very versatile and easy to for instance dump complete Python objects into the template and handle complex relations. This however also makes it possible to execute random Python logic. In more generic terms: jinja2 is turing complete, meaning that it is possible to write a complete computer program by just using the template and the context. In the case of a developer controlled template and context, there is no problem: it is guaranteed that there will be no weird code injections taking place. This becomes problematic however when the template or the context is directly provided by the user or not strictly sanitized by the developer (e.g. inserting an input field directly into the template). We do not want the user to execute its own created scripts directly on the server as it can do all sorts of harm. ## `render_jinja_template`[​](/docs/create-apps/documents-and-spreadsheets/text-file-templater/.md#render_jinja_template "Direct link to render_jinja_template") Because of the possibility of code injection, it is necessary to run the rendering of the template in an isolated environment, often called a sandbox. Jinja2 provides such a sandbox in the library, but is has been circumvented a few times already. Instead, VIKTOR provides a [`render_jinja_template`](/sdk/api/utils/.md#_render_jinja_template) function which makes jinja templating easy and safe: ``` import viktor as vkt with open("path/to/template.jinja", 'rb') as template: result = vkt.render_jinja_template(template, {'name': 'John Doe'}) ``` This has the added benefit of not needing an extra dependency in your app. note This sandboxing has also been applied to the [Word-file templater](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md) --- # Word-file templater tip This guide is an informative piece to help you if you have questions about the Word-file templating functionality. If you would like a more instructive lesson, take a look at the [Reporting tutorial](/docs/tutorials/automatic-reporting/.md) we have available. caution Services need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The following steps are to be performed to implement a Word template. A more elaborate example of the individual components will be shown in the sections below. 1. Template a Word (.docx) file using the [jinja notation](https://jinja.palletsprojects.com/templates) (e.g. `{{ tag }`}) note The extension of the Word template should be of type .docx (not .doc). 2. Create a sequence of [`WordFileTag`](/sdk/api/external/word/.md#_WordFileTag) and/or [`WordFileImage`](/sdk/api/external/word/.md#_WordFileImage) objects 3. Execute [`render_word_file`](/sdk/api/external/word/.md#_render_word_file) with the word template from step 1 and the components from step 2 ## Example Word template[​](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#example-word-template "Direct link to Example Word template") The figure below shows an example of a quotation document, in which the contact details of the customer is filled in as well as listing the components that he or she has selected. ![](/assets/images/word-template-example-2dd703bdd53cfcadc1e50971efa97fd5.png) *Word template* Also note that styling as defined in the original .docx file will be inherited by the rendered document. For example, the 'date' tag is bold in the template, which results in a bold rendered date in the resulting file. ## `WordFileTag`[​](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#wordfiletag "Direct link to wordfiletag") In the application you need to refer to the created tags in the word file components. In case of textual data the [`WordFileTag`](/sdk/api/external/word/.md#_WordFileTag) can be used: ``` components = [] components.append(WordFileTag('client', params.client)) components.append(WordFileTag('date', datetime.datetime.today().strftime('%d-%m-%Y'))) ``` The `WordFileTag` values can also be of type `list` or `dict`, to make it possible to iterate within the template. In the example template above, the `products` is a list of dictionaries: ``` products = [ {'qty': 1, 'desc': 'Product A', 'price': 100, 'total': 150}, {'qty': 3, 'desc': 'Product B', 'price': 150, 'total': 450}, ... ] components.append(WordFileTag('products', products)) ``` Using the `{%tr for p in products %}` notation in the template allows for looping through the products, printing each product on a new line in the defined table. Please consult the [jinja](https://jinja.palletsprojects.com/) documentation for more detail on jinja templating. ## `WordFileImage`[​](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#wordfileimage "Direct link to wordfileimage") note SVG is not supported as image type. An image can be inserted using the [`WordFileImage`](/sdk/api/external/word/.md#_WordFileImage) object, which requires a binary image file handle. This can either be a static image (path), an uploaded image (file entity), or a dynamically created image of, for example, a result plot. ``` from pathlib import Path image_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'static_image.png' with open(image_path, 'rb') as image: word_file_image = WordFileImage(image, 'img_tag') components.append(word_file_image) ``` The *static\_image.png* in this case will be placed on the position of *image\_tag* in the Word template, in its original size. The image can be scaled by defining a width and/or height (pt). When only one is provided, the other is scaled. When both are provided, both are used and the original aspect ratio might be changed. ``` WordFileImage(img, 'img_tag', width=30) ``` ## `render_word_file`[​](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#render_word_file "Direct link to render_word_file") Now that all the Word file components are defined, the Word file can be rendered using [`render_word_file`](/sdk/api/external/word/.md#_render_word_file). The template can also be either a static file (path) or an uploaded file (file entity): ``` template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.docx' with open(template_path, 'rb') as template: word_file = render_word_file(template, components) ``` The document can then be passed to for example a [`DownloadResult`](/sdk/api/result/.md#_DownloadResult): ``` return DownloadResult(word_file, f'quotation_{params.quotation_id}.docx') ``` --- # Dashboard welcome text A custom welcome message that will be shown to the user upon entering the dashboard, can be set in the [viktor.config.toml](/docs/create-apps/references/viktor-config-toml/.md#welcome_text) file. --- # Output field note For larger sections of text in the parametrization, see [`Text`](/docs/create-apps/inform-end-user/text-blocks/.md) An [`OutputField`](/sdk/api/parametrization/.md#_OutputField) can be used to display a textual or numeric value to the user within a parametrization that cannot be modified by the user. The `value` must be set in the parametrization and can be a static value or obtained dynamically. ``` import viktor as vkt class Parametrization(vkt.Parametrization): output = vkt.OutputField('Output', value=3.1415) ``` note The value of the `OutputField` field is not included in the params. ## Dynamic value[​](/docs/create-apps/inform-end-user/output-field/.md#dynamic-value "Direct link to Dynamic value") ### Depending on another field[​](/docs/create-apps/inform-end-user/output-field/.md#depending-on-another-field "Direct link to Depending on another field") If the value depends on another field, the easiest solution is to use a `Lookup`: ``` import viktor as vkt class Parametrization(vkt.Parametrization): param_x = vkt.NumberField('X') output = vkt.OutputField('X (read only)', value=vkt.Lookup('param_x')) ``` ### Inside a DynamicArray[​](/docs/create-apps/inform-end-user/output-field/.md#inside-a-dynamicarray "Direct link to Inside a DynamicArray") If the value depends on the result of another field within a [`DynamicArray`](/docs/create-apps/user-input/tables-and-arrays/.md#dynamicarray), a `RowLookup`can be used. Using the `RowLookup`, the value of a field in a specific row can be made read-only: ``` import viktor as vkt class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.NumberField('X') array.output = vkt.OutputField('X (read only)', value=vkt.RowLookup('param_x')) ``` ### Using a function[​](/docs/create-apps/inform-end-user/output-field/.md#using-a-function "Direct link to Using a function") The most generic way to dynamically set the value is to use a **callback function**. Upon evaluation of the value, the platform passes the `params`, `entity_id`, `entity_name`, and `workspace_id` (>= v14.7.1) to the custom function: ``` import viktor as vkt def sum_x_y(params, **kwargs): return params.param_x + params.param_y class Parametrization(vkt.Parametrization): param_x = vkt.NumberField('X') param_y = vkt.NumberField('Y') output = vkt.OutputField('X + Y', value=sum_x_y) ``` If the `OutputField` is defined within a `DynamicArray`, make sure that the callback function returns a list of values, one for each row in the array. The length of this list must be equal to the number of rows in the array, otherwise (a warning is logged and) the field will be empty: ``` import viktor as vkt def sum_x_y(params, **kwargs): return [row.param_x + row.param_y for row in params.array] class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.NumberField('X') array.param_y = vkt.NumberField('Y') array.output = vkt.OutputField('X + Y', value=sum_x_y) ``` tip All individual `kwargs` can be added explicitly in the signature if needed: ``` def sum_x_y(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` When the value depends on data of another entity, the `entity_id` can be used to navigate and obtain data using the [SDK API](/docs/api/sdk/handling-entity-data/.md). --- # Show a message to the user This guide explains how to send a message to the VIKTOR interface to inform/warn users. It will cover aspects as in what scenarios such messages come in handy, what steps to take to achieve this, and examples are given. ## Job log[​](/docs/create-apps/inform-end-user/show-message/.md#job-log "Direct link to Job log") All messages (except for [progress messages](/docs/create-apps/inform-end-user/show-message/.md#progress-message)) are logged in the "Job log", which can be accessed from the editor toolbar: ![](data:image/png;base64,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) ## Interruptive (error) message[​](/docs/create-apps/inform-end-user/show-message/.md#interruptive-error-message "Direct link to Interruptive (error) message") New in v13.7.0 `UserException` is replaced by `UserError` which supports marking invalid fields in the interface. Sometimes it is desirable to inform the user about incorrect (or missing) input, and interrupt the job flow so that the user is forced to fix the problem before continuing. For example, when input is not (yet) defined but required at some point within the code, the user does not always know how to fix the problem, while the developer does. We can guide the user in the right direction by providing an error message in the interface, by raising a [`UserError`](/sdk/api/errors/.md#_UserError). ### Implementation[​](/docs/create-apps/inform-end-user/show-message/.md#implementation "Direct link to Implementation") 1. Identify at what point in the code an event may occur where the user should be informed and forced to fix 2. Catch this event (e.g. with if-else statements) 3. Raise a `UserError` with the desired message, along with fields that should be marked as invalid ``` import viktor as vkt def calculate_block_volume(params): width = params.width length = params.length height = params.height violations = [] if width is None: violations.append(vkt.InputViolation("Input 'width' cannot be empty!", fields=['width'])) if length is None: violations.append(vkt.InputViolation("Input 'length' cannot be empty!", fields=['length'])) if height is None: violations.append(vkt.InputViolation("Input 'height' cannot be empty!", fields=['height'])) if violations: raise vkt.UserError("Cannot calculate block volume", input_violations=violations) return width * length * height ``` tip For more information on input validation, please see [this guide](/docs/create-apps/user-input/input-validation/.md). ## Non-interruptive message[​](/docs/create-apps/inform-end-user/show-message/.md#non-interruptive-message "Direct link to Non-interruptive message") New in v14.0.0 `UserMessage` to show a (non-interruptive) message to the end-user. Sometimes it is desirable to show a message to the user without interrupting the running app job, such as an informative or warning message. This can be done by using the [`UserMessage`](/sdk/api/core/.md#_UserMessage). Three different types of messages can be sent with the `UserMessage`: a **warning**, an **info** and a **success** message, each of them having a slightly different look within the interface. ### Implementation[​](/docs/create-apps/inform-end-user/show-message/.md#implementation-1 "Direct link to Implementation") ``` import viktor as vkt def calculate(params): if not is_params_recommended(params): vkt.UserMessage.warning("The current set of params is not recommended") vkt.UserMessage.info("The calculation will be run with the following input: ...") result = run_calculation(...) vkt.UserMessage.success("Analysis successfully finished!") ... ``` ## Progress message[​](/docs/create-apps/inform-end-user/show-message/.md#progress-message "Direct link to Progress message") Sometimes it is useful to keep the user informed during a long-running job (e.g. processing of analysis, optimization or downloadable content when working with large files or complex calculations), by showing one or more [progress messages](/sdk/api/core/.md#_progress_message). ### Implementation[​](/docs/create-apps/inform-end-user/show-message/.md#implementation-2 "Direct link to Implementation") ``` import viktor as vkt def process_files(my_files): for file in my_files: vkt.progress_message(message=f'Processing {file}') ... # process file ``` The progress\_message also accepts a percentage. The platform will render the progress with your progress message and a progress bar showing the progress. ``` import viktor as vkt def process_files(my_files): n = len(my_files) for i, file in enumerate(my_files): vkt.progress_message(message=f'Processing {file}', percentage=(i/n)*100) ... # process file ``` note * Progress messages are only shown to the user during long-running jobs and don't show up during short-running jobs. * Progress messages are not logged in the [Job log](/docs/create-apps/inform-end-user/show-message/.md#job-log). ### Extending a previous message[​](/docs/create-apps/inform-end-user/show-message/.md#extending-a-previous-message "Direct link to Extending a previous message") Whenever a progress message is invoked, the progress window will be "refreshed" with the specified text (i.e. old messages will be dropped). In some cases this is not desired, and new messages should be "appended" to the already existing ones. This can be implemented by using line breaks within the message: ``` import viktor as vkt def process_files(my_files): n = len(my_files) for i, file in enumerate(my_files): p_message = f'Reading {file}' ... # read file vkt.progress_message(message=p_message) p_message += f'\n Processing {file}' ... # process file vkt.progress_message(message=p_message) p_message += f'\n Export result of {file}' ... # export results vkt.progress_message(message=p_message) ``` --- # Static image New in v14.3.0 A static image (JPEG / PNG) can be displayed in the parametrization of an editor to, for example, provide additional context to help users fill in certain input fields. ![](/assets/images/image-e9c9788520f58ca0c4de36eb0271c430.png) ## Minimal implementation[​](/docs/create-apps/inform-end-user/static-image/.md#minimal-implementation "Direct link to Minimal implementation") Assume a folder structure as shown below: ``` my-folder ├── app.py ├── assets │ └── viktor.png ├── requirements.txt └── viktor.config.toml ``` The image `viktor.png` can be displayed in the parametrization by referencing to it in the app code using an [`Image`](/sdk/api/parametrization/.md#_Image) field: ``` class Parametrization(vkt.Parametrization): img = vkt.Image(path="viktor.png") ``` The image `path` is relative with respect to the **assets\_path** which can be named arbitrarily and should be defined in the viktor.config.toml: ``` ... assets_path = "assets" ``` note Note that the assets directory does not support nesting of directories. Re-install your app You will need to re-install your app after removing the hashtag and adding the 'assets' directory. ## Image customization[​](/docs/create-apps/inform-end-user/static-image/.md#image-customization "Direct link to Image customization") You can tweak the visual by specifying one or multiple of the following attributes: * `align`: Alignment within the parametrization component ("left" | "center" | "right") * `caption`: A caption which is shown underneath the image * `flex`: Width of the image as percentage of the total parametrization width * `max_width`: A maximum width (pixels) can be set to make sure an image is not stretched beyond illegible boundaries ## Show/hide an image depending on user selection[​](/docs/create-apps/inform-end-user/static-image/.md#showhide-an-image-depending-on-user-selection "Direct link to Show/hide an image depending on user selection") There may be cases where the user needs to be informed differently depending on a previous choice. An `Image` cannot have a dynamic source, however it is possible to use its [visibility to show/hide](/docs/create-apps/user-input/hide-field/.md) a specific image. --- # Text blocks A [`Text`](/sdk/api/parametrization/.md#_Text) field that can be used to display a static text (max. 1800 characters) as follows: ``` class Parametrization(vkt.Parametrization): not_in_params = vkt.Text('My static text') ``` note The value of the `Text` field is not included in the params. The value of the `Text` fields can be [styled using Markdown](/docs/create-apps/layout-and-styling/style-text/.md): ![](/assets/images/formatting-text-52e47329c02925c8c5455788b9704af4.png) ``` import viktor as vkt class Parametrization(vkt.Parametrization): info1 = vkt.Text(""" Please select the wing model below ✈️ - 2D: Select 2D to model an **infinite wing** - 3D: Select 3D to model a *finite wing*, along with the aspect ratio 1. High AR for slender wings 2. Low AR for delta wings """) model = vkt.OptionField("Wing model", options=["2D", "3D"]) ar = vkt.NumberField("AR", variant="slider", min=1, max=30) info2 = vkt.Text(""" ### Block / in-line math #### Lift Coefficient $$ L = \\frac{1}{2} \\rho v^2 S C_L $$ where $\\rho = \\frac{m}{v}$. Read more about this equation on [this page](https://en.wikipedia.org/wiki/Lift_coefficient). ### Horizontal rules --- --- and another... --- # Heading level 1 ## Heading level 2 """) ``` --- # Tooltips Tooltips can be created by setting the `description` argument (max. 200 characters) on any of the [input fields](/docs/create-apps/user-input/.md), [tabs and sections](/docs/create-apps/layout-and-styling/tabs-and-sections/.md), [pages](/docs/create-apps/layout-and-styling/pages/.md), [steps](/docs/create-apps/layout-and-styling/steps/.md), or [views](/docs/create-apps/results-and-visualizations/.md) as follows: ``` class Parametrization(vkt.Parametrization): number = vkt.NumberField("My number", description="This text is shown in the field's tooltip") ``` ``` class Parametrization(vkt.Parametrization): tab = vkt.Tab("My tab", description="This text is shown in the tab's tooltip") tab.section = vkt.Section("My section", description="This text is shown in the section's tooltip") ``` ``` class Parametrization(vkt.Parametrization): page = vkt.Page("My page", description="This text is shown in the page's tooltip") ``` ``` class Parametrization(vkt.Parametrization): step = vkt.Step("My step", description="This text is shown in the step's tooltip") ``` ``` class Controller(vkt.Controller): ... @vkt.MapView("My map view", description="This text is shown in the view's tooltip") def my_map_view(self, params, **kwargs): ... ``` The value of `description` can be [styled using Markdown](/docs/create-apps/layout-and-styling/style-text/.md). --- # Layout & styling New in v14.2.0 Simplify [navigation inside the workspace](/docs/create-apps/layout-and-styling/entity-navigation/.md) by using a `ChildEntityManager` There are multiple ways to adjust the layout & styling of an entity's editor. * Divide the parametrization in [Tabs and Sections](/docs/create-apps/layout-and-styling/tabs-and-sections/.md), [Pages](/docs/create-apps/layout-and-styling/pages/.md), or [Steps](/docs/create-apps/layout-and-styling/steps/.md). * [Adjust the width](/docs/create-apps/layout-and-styling/adjust-parametrization-width/.md) of individual fields within the parametrization, a page or step, or the parametrization as a whole. * [Add manual line breaks](/docs/create-apps/layout-and-styling/manual-line-break/.md) between fields within a parametrization to obtain a cleaner looking parametrization. * [Style text](/docs/create-apps/layout-and-styling/style-text/.md) using Markdown. Furthermore you are able to tweak the: * [dashboard](/docs/create-apps/layout-and-styling/dashboard/.md) * [navigation inside the workspace](/docs/create-apps/layout-and-styling/entity-navigation/.md) ## Tabs & sections[​](/docs/create-apps/layout-and-styling/.md#tabs--sections "Direct link to Tabs & sections") ![](/img/docs/cards/tabs.svg) ## [Tab](/docs/create-apps/layout-and-styling/tabs-and-sections/.md) Represents a collapsible tab ![](/img/docs/cards/sections.svg) ## [Section](/docs/create-apps/layout-and-styling/tabs-and-sections/.md) Represents a collapsible section ## Pages & steps[​](/docs/create-apps/layout-and-styling/.md#pages--steps "Direct link to Pages & steps") ![](/img/docs/cards/pages.svg) ## [Page](/docs/create-apps/layout-and-styling/pages/.md) Can be used to construct a combination of inputs and outputs ![](/img/docs/cards/steps.svg) ## [Step](/docs/create-apps/layout-and-styling/steps/.md) Similar to Page, but dictates a page order ## Parametrization width[​](/docs/create-apps/layout-and-styling/.md#parametrization-width "Direct link to Parametrization width") ![](/img/docs/cards/parametrization_width.svg) ## [Parametrization width](/docs/create-apps/layout-and-styling/adjust-parametrization-width/.md) Adjust the default width of the parametrization ## Line break[​](/docs/create-apps/layout-and-styling/.md#line-break "Direct link to Line break") ![](/img/docs/cards/linebreak.svg) ## [Line break](/docs/create-apps/layout-and-styling/manual-line-break/.md) Force input fields to be placed on the next line --- # Adjust the parametrization width When a user enters an editor, the parametrization and views (if present) are shown with a default width ratio of 40% / 60%. For some entity types it may be desirable to adjust this ratio, for example when the input side needs to be a bit wider because of large tables. Or when the output side needs to be wider to put more emphasize on a view. ![](/assets/images/editor-parametrization-width-60-21cab3a32804495c0a6e4dddfe94dda8.png) To adjust the default width, the `width` argument can be set on your parametrization class. Its value is the percentage of the complete width of the editor (input + output) and should be an integer between 20 and 80: ``` class Controller(vkt.Controller): parametrization = Parametrization(width=60) ``` Note that besides this width, each field can have its own `flex` to adjust the width w\.r.t. the parametrization side. Defining both a `width` and a `flex` results in a multiplication of the two. As an example, the following combination results in a full-width field taking up 30% of the editor: ``` class Parametrization(vkt.Parametrization): number = vkt.NumberField("Number", flex=100) class Controller(vkt.Controller): parametrization = Parametrization(width=30) ``` ![](/assets/images/editor-parametrization-width-30-3d652744464045670a16e9d4b2ffd556.png) It may be possible that you will see no difference on certain screens between a width of, for example, 20 and 25. Depending on the screen resolution and pixel density, some widths can result in an input / output window which is too small to be readable. Therefore, a minimum width is implemented in the platform to prevent such behavior. ## Specific width per Page / Step[​](/docs/create-apps/layout-and-styling/adjust-parametrization-width/.md#specific-width-per-page--step "Direct link to Specific width per Page / Step") New in v14.7.0 In case your editor consists of Page or Step elements, separate widths can be provided if desired: * [Page](/docs/create-apps/layout-and-styling/pages/.md#adjust-the-parametrization-width) * [Step](/docs/create-apps/layout-and-styling/steps/.md#adjust-the-parametrization-width) --- # Dashboard The dashboard is an overview page with data on the current workspace, such as a [welcome text](/docs/create-apps/layout-and-styling/dashboard/.md#welcome-text), activity data, and quick links to [top-level entities](/docs/create-apps/layout-and-styling/dashboard/.md#top-level-entity-cards). This page explains the possibilities of tweaking the dashboard page. ![](/assets/images/dashboard-88175c1d986aa90421542fc225f3ecfd.png) tip For a [tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app), the dashboard is the start page by default. It is possible to use an [entity as start page](/docs/create-apps/layout-and-styling/entity-navigation/.md#entity-as-start-page) instead. ## Welcome text[​](/docs/create-apps/layout-and-styling/dashboard/.md#welcome-text "Direct link to Welcome text") The welcome text is shown on the top of the page and can be set in the [viktor.config.toml](/docs/create-apps/references/viktor-config-toml/.md#welcome_text) file. ## Top-level entity cards[​](/docs/create-apps/layout-and-styling/dashboard/.md#top-level-entity-cards "Direct link to Top-level entity cards") Just below the welcome text, cards are shown that link to entities on the highest level (top-level entities), to enable quick and easy access. By default, all top level entities are shown. The `show_on_dashboard` attribute can be set on one or more [initial entities](/docs/getting-started/fundamentals/app-types/.md#initial-entities) to only show a subset. --- # Navigation inside a workspace New in v14.2.0 This page describes ways to adjust the navigation flow, to improve user experience, within a [tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app). ## Entity as start page[​](/docs/create-apps/layout-and-styling/entity-navigation/.md#entity-as-start-page "Direct link to Entity as start page") By default, users start on the [dashboard](/docs/create-apps/layout-and-styling/dashboard/.md) when entering a workspace: ![](/assets/images/entity-navigation-dashboard-79d2c620e557712386f1dce43d5c325c.png) For some apps, users might have a better experience if they immediately land on some **entity**, instead of the dashboard, upon entering the workspace. This can be achieved by setting the `use_as_start_page` argument on one of the [initial entities](/docs/getting-started/fundamentals/app-types/.md#initial-entities): ``` import viktor as vkt initial_entities = [ vkt.InitialEntity("Top-level entity", use_as_start_page=True, ...), ... ] ``` note If redirection of the user to the assigned starting entity fails, he/she will be redirected to the dashboard instead. ## Manage child entities within editor[​](/docs/create-apps/layout-and-styling/entity-navigation/.md#manage-child-entities-within-editor "Direct link to Manage child entities within editor") By default, when a user then clicks on an entity in the side navigation menu ("My Folder" in the below example), he/she will be directed to the entity browser view: ![](/assets/images/entity-navigation-browser-37039f9ad1425d71c95720f7ecdebdf7.png) The entity browser view can, in some cases, be confusing, as the user is left with the choice: do I need to create a child entity or open the editor of the current entity? By implementing the [`ChildEntityManager`](/sdk/api/parametrization/.md#_ChildEntityManager), management of child entities (e.g. creation, deletion, navigation) is moved **within the editor of the parent entity**. By doing so, the browser view is automatically skipped, and users will directly enter the editor when navigating to the parent entity. This way a developer can guide the user better throughout the application: ``` import viktor as vkt class Parametrization(vkt.Parametrization): manager = vkt.ChildEntityManager('MyEntityType') ``` ![](/assets/images/entity-navigation-manager-be71f27d88033c317a0f678dcbcf19d7.png) --- # Manual line break A [`LineBreak`](/sdk/api/parametrization/.md#_LineBreak) can be used to force [input fields](/docs/create-apps/user-input/.md) to be placed on the next 'line' to obtain a cleaner looking parametrization within an editor. ``` import viktor as vkt class Parametrization(vkt.Parametrization): n1 = vkt.NumberField('N1') n2 = vkt.NumberField('N2') lb = vkt.LineBreak() # split the fields in 2 pairs n3 = vkt.NumberField('N3') n4 = vkt.NumberField('N4') ``` --- # Creating pages A [`Page`](/sdk/api/parametrization/.md#_Page) can be used to construct a combination of inputs (e.g. tabs / sections) and outputs (views). This grouping allows for specific views to become visible, depending on the page a user has selected. Assume an editor with a `GeometryView` and a `DataView`: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.GeometryView(...) def geometry_view(...): ... @vkt.DataView(...) def data_view(...): ... ``` Now we would like to have an editor with 2 pages. When a user is working on "Page 1", no views will be visible. When the user switches to "Page 2", a geometry view and a data view will become visible. A `Page` is defined in the parametrization similar to [tabs and sections](/docs/create-apps/layout-and-styling/tabs-and-sections/.md): ``` import viktor as vkt class Parametrization(vkt.Parametrization): page_1 = vkt.Page('Page 1 - without views') page_1.input_1 = vkt.TextField('This is a text field') page_1.input_2 = vkt.NumberField('This is a number field') page_2 = vkt.Page('Page 2 - with views', views=['geometry_view', 'data_view']) page_2.input_1 = vkt.TextField('This is a text field') page_2.input_2 = vkt.NumberField('This is a number field') ``` ![](/assets/images/editor-pages-without-views-fa73a44476562de7f1415671bd9864a3.png) *Page 1 with no views* When navigating to page 2, you will see that the two views will be present: ![](/assets/images/editor-pages-with-views-a80adf9b7210329d42299c9afc75eced.png) *Page 2 with a GeometryView and a DataView* All the layered structures of `Tab` / `Section` / fields can be encapsulated in a `Page`: ``` # fields directly as input fields on a page class Parametrization(vkt.Parametrization): page = vkt.Page(...) page.number = vkt.NumberField(...) ... # tabs on a page class Parametrization(vkt.Parametrization): page = vkt.Page(...) page.tab = vkt.Tab(...) ... # sections on a page class Parametrization(vkt.Parametrization): page = vkt.Page(...) page.section = vkt.Section(...) ... ``` ## Hide a Page[​](/docs/create-apps/layout-and-styling/pages/.md#hide-a-page "Direct link to Hide a Page") New in v14.7.0 Hiding a Page can be done in a similar way as [hiding a field](/docs/create-apps/user-input/hide-field/.md), by setting the `visible` argument: ``` vkt.Page("Page 2", visible=vkt.Lookup("page_1.param_x")) ``` or using a callback function: ``` vkt.Page("Page 2", visible=get_visible) ``` ## Adjust the parametrization width[​](/docs/create-apps/layout-and-styling/pages/.md#adjust-the-parametrization-width "Direct link to Adjust the parametrization width") New in v14.7.0 A separate parametrization width per Page can be defined by specifying the `width` argument: ``` import viktor as vkt class Parametrization(vkt.Parametrization): page_1 = vkt.Page("Page 1", width=30) ... page_2 = vkt.Page("Page 2", width=70) ... ``` When the `width` is defined both on the Parametrization class **and** a Page, the width of the Page will take precendence while the global width is used for pages that have not defined a specific width. For more detail on the global parametrization width and rules with respect to a field's `flex` argument, please refer to [this page](/docs/create-apps/layout-and-styling/adjust-parametrization-width/.md). --- # Creating steps Similar to a [`Page`](/docs/create-apps/layout-and-styling/pages/.md), grouping can be achieved by using the [`Step`](/sdk/api/parametrization/.md#_Step) class. Other than with pages, with steps the developer can dictate the order of pages to be visited: the user is not able to move freely between pages but moves to the next/previous step with a next/previous button. `Page` and `Step` cannot be combined within a single parametrization. A `Step` is defined in the parametrization similar to a `Page`. The labels of the next and previous buttons can be set per step: ``` import viktor as vkt class Parametrization(vkt.Parametrization): step_1 = vkt.Step('Step 1 - without views') step_1.input_1 = vkt.TextField('This is a text field') step_1.input_2 = vkt.NumberField('This is a number field') step_2 = vkt.Step('Step 2 - with views', views=['geometry_view', 'data_view']) step_2.input_1 = vkt.TextField('This is a text field') step_2.input_2 = vkt.NumberField('This is a number field') ``` ![](/assets/images/editor-steps-without-views-070ba83309146042cdc39f8f15588fd3.png) *Step 1 with no views* When navigating to step 2, you will see that the two views will be present: ![](/assets/images/editor-steps-with-views-d6d93863dcebca337434c25e18245c73.png) *Step 2 with a GeometryView and a DataView* ## Button labels[​](/docs/create-apps/layout-and-styling/steps/.md#button-labels "Direct link to Button labels") The labels of the previous and next buttons can be set per step: ``` vkt.Step('Step 2', previous_label='Go to step 1', next_label='Go to step 3') ``` ## Validation of user input[​](/docs/create-apps/layout-and-styling/steps/.md#validation-of-user-input "Direct link to Validation of user input") New in v13.7.0 When implementing the `on_next` argument, the corresponding function is called when a user clicks the 'next' button to move to the next step. This can be used to, for example, validate the input of the current active step. Please note that the validation function cannot take longer than 3 seconds! ``` import viktor as vkt def validate_step_1(params, **kwargs): if params.step_1.width > params.step_1.height: raise vkt.UserError("The design is not feasible") class Parametrization(vkt.Parametrization): step_1 = vkt.Step('Step 1', on_next=validate_step_1) step_1.width = vkt.NumberField('Width') step_1.height = vkt.NumberField('Height') ``` ![](data:image/png;base64,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) Generic constraints (e.g. `min` on a `NumberField`) are [automatically validated](/docs/create-apps/user-input/input-validation/.md#generic-field-constraints) by the platform. Additionally, fields can be [marked as invalid](/docs/create-apps/user-input/input-validation/.md#specific-input-validation). tip All individual `kwargs` can be added explicitly in the signature if needed: ``` def validate_step_1(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` ## Disabling a step[​](/docs/create-apps/layout-and-styling/steps/.md#disabling-a-step "Direct link to Disabling a step") New in v14.11.0 Disabling a Step can be done by setting the `enabled` argument, similar to [hiding a field](/docs/create-apps/user-input/hide-field/.md): * By using a BooleanField ``` vkt.Step("Step 2", enabled=vkt.Lookup("step_1.param_x")) ``` * By using a callback function ``` def get_enabled(params, **kwargs): return params.step_1.param_y > 5 vkt.Step("Step 2", enabled=get_enabled) ``` * Depending on other field(s) ``` _step_enabled = vkt.And( vkt.IsFalse(vkt.Lookup('step_1.param_x')), vkt.IsEqual(vkt.Lookup('step_1.param_y'), 5) ) step = vkt.Step("Step 2", enabled=_step_enabled) ``` When a step is disabled, it will be skipped when the user clicks the "next step" button. The step number will remain visible, as a visual cue that there is a skipped step. In some cases you may have steps that depend on user input. For example, "Step 2(a)" for calculations about a stone house, and "Step 2(b)" for calculations about a glass house. In such cases, we recommend to merge them into one step (e.g. "Calculations") and use [tab visibility](/docs/create-apps/layout-and-styling/tabs-and-sections/.md#hide-a-tab--section) to hide the tab/fields that you do not need, within the step. This will lead to a more consistent flow through the steps for the end user. ## Adjust the parametrization width[​](/docs/create-apps/layout-and-styling/steps/.md#adjust-the-parametrization-width "Direct link to Adjust the parametrization width") New in v14.7.0 A separate parametrization width per Step can be defined by specifying the `width` argument: ``` import viktor as vkt class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1", width=30) ... step_2 = vkt.Step("Step 2", width=70) ... ``` When the `width` is defined both on the Parametrization class **and** a Step, the width of the Step will take precendence while the global width is used for steps that have not defined a specific width. For more detail on the global parametrization width and rules with respect to a field's `flex` argument, please refer to [this page](/docs/create-apps/layout-and-styling/adjust-parametrization-width/.md). --- # Style / format text using Markdown In certain parts of the platform, user-defined text can be styled using Markdown, a simple and easy-to-use markup language. See the [basic Markdown syntax guide](https://www.markdownguide.org/basic-syntax/) or try the [10-minute interactive Markdown tutorial](https://commonmark.org/help/tutorial/) to learn more. ## Where styled text is supported[​](/docs/create-apps/layout-and-styling/style-text/.md#where-styled-text-is-supported "Direct link to Where styled text is supported") * [Parametrization field labels](/sdk/api/parametrization/.md#_Field), including `prefix` and `suffix`. (inline) * [Text](/sdk/api/parametrization/.md#_Text) (block) * All parametrization descriptions * [Field descriptions](/sdk/api/parametrization/.md#_Field) (block) * [Tab descriptions](/sdk/api/parametrization/.md#_Tab) (block) * [Section descriptions](/sdk/api/parametrization/.md#_Section) (block) * [Page descriptions](/sdk/api/parametrization/.md#_Page) (block) * All [View descriptions](/sdk/api/views/.md#_View) (block) * [DataItem](/sdk/api/views/.md#_DataItem) `explanation_label`, `prefix` and `suffix` (inline) * [SummaryItem](/sdk/api/views/.md#_SummaryItem) labels, including `prefix` and `suffix` (inline) * Descriptions of all types of [MapFeature](/sdk/api/views/.md#_MapFeature) (block) * [MapPoint](/sdk/api/views/.md#_MapPoint) * [MapLine](/sdk/api/views/.md#_MapLine) * [MapPolyline](/sdk/api/views/.md#_MapPolyline) * [MapPolygon](/sdk/api/views/.md#_MapPolygon) * [Welcome text](/docs/create-apps/inform-end-user/dashboard/.md) on the dashboard of a workspace ### Block vs inline text[​](/docs/create-apps/layout-and-styling/style-text/.md#block-vs-inline-text "Direct link to Block vs inline text") In certain places, styled text will be displayed *inline*. Inline text renders as a single line, hence newlines and horizontal rules are ignored, and lists are collapsed. Because text is rendered inline in field labels, [LaTeX text](/docs/create-apps/layout-and-styling/style-text/.md#rendering-math-symbols-with-latex) might not appear as intended. In these cases, it is recommended to move the LaTeX expression to the `description`. ### Use cases[​](/docs/create-apps/layout-and-styling/style-text/.md#use-cases "Direct link to Use cases") Here are some examples of how you can apply styled text: * Add an equation to a parametrization field description tooltip: ![](data:image/png;base64,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) * Add a subscript to a parametrization field label: ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASoAAABWCAYAAAB4rdshAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAudEVYdENyZWF0aW9uIFRpbWUARnJpIDE2IFNlcCAyMDIyIDA5OjM1OjMxIEFNIENFU1REuG0+AAAFAUlEQVR4nO3dy0tUfRzH8c843oY0Q01KMyMvedmoEVEbceEiaBGBhS2FNvkfuPI/aCXYpkW7IMGNihouJEjQdDGUlOMkjFoqEyrjoE3OaRGdh3nG51Jezrd6v3b+5oznezZvzjmecXyO4zgCAMMyvB4AAP4LoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgHqECYB6hAmAeoQJgXqbXA0hSNBrVkydP9OnTJ+3u7qq4uFh+v1+JREKZmZlqbGxUa2ur/H6/16MC8IDPcRzH6yG+e/TokaLRqLq7u9215eVl9fX1qb6+Xh0dHR5OB8ArZi79ksmkIpGIampqUtbLysqUk5OjYDDo0WQAvGYmVCsrK/r8+bOqqqpS1j9+/KitrS2VlpZ6NBkAr5kJ1fv37+Xz+VRdXe2ura6u6unTpyooKNCdO3c8nA6Al0zcTJekcDisnJwcPXv2TMlkUmtra4rH47p27ZpaWloUCAS8HhGAR0yEynEcLS4uqrGxUbdv35YkbWxs6OHDhyopKSFSwB/ORKjW1ta0vb2tiooKd+3UqVMqKirSxMSEmpubU7aPxWIaHR3V5OSkrl+/rqtXr2pzc1PPnz9XPB5XU1OT2traUt4TjUY1MjKijY0NPXjw4FiOC8DhMBGqcDgsSTp//ry7lkwmtb6+rsLCwrTt8/LyVFNTozdv3ujWrVuSpLNnz2p6eloNDQ1qbW1Ne8/4+LguXLigRCJxREcB4KiYuJkeDocVCARUXFzsrn348EG7u7s6ceLEP76nvLw8ZS0SiaiysnLf7UOhkBoaGtTS0nJ4gwM4Fp6HynEcLSwsqLy8XD6fz13PysqSJGVkfBtxeHhY6+vr7uuhUEhlZWXuz9vb24rH4zp37lzK79/c3NTAwIB2dnY0OTmp1dVV97W5uTkNDg5qdHRUw8PDR3J8AA7O39PT0+PVzh8/fqzBwUHFYjHFYjHNzs6qtrZWgUDAPZOan5/XwsKCSkpKVF9fL+lblIaGhpSfn69IJKL5+Xm9evVKJ0+e1OXLl1P2kZubq4yMDG1tbam9vV15eXmSpHfv3ml8fFz37t1TMpmU4zhpZ2gAbPD0HlVnZ+e/vt7W1pZ2U1z661GGu3fvup//6+/v3/d+lvTtkvDvEXrx4oWuXLkin8+X9jQ8AFs8v/T7GaFQSJcuXXIj5TiOXr9+rYsXL+67/dLSUlqoEomETp8+7f68uLh4ZPMCOBgTf/X7v758+aKxsTEFg0GdOXPGfZp9ampKsVhMwWBQpaWl7v2t75aWltKebL9x44amp6fdj+7U1dUd56EA+AGm/nvCYZuZmVF2drZevnyp+/fvez0OgJ/0S51R/ai3b99qb29PN2/e9HoUAAfwW59RAfg9/JI30wH8WQgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzCBUA8wgVAPMIFQDzPP2m5N7eXi93D+AQdHV1Hfk++KZkAOZx6QfAPEIFwDxCBcA8QgXAPEIFwDxCBcA8QgXAPEIFwDxCBcA8QgXAPEIFwDxCBcA8QgXAPEIFwDxCBcC8r0ODYakDJj+LAAAAAElFTkSuQmCC) * Add a unit suffix to a parametrization field label: ![](data:image/png;base64,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) * Refine an editor with clarifying, styled text and formulae: ![](/assets/images/formatting-text-52e47329c02925c8c5455788b9704af4.png) * Add a heading and a list to [MapPoint](/sdk/api/views/.md#_MapPoint) description: ![](/assets/images/formatting-map-popup-52fe14b36fa97017c4fac3ca14c9362d.png) * Style the welcome message in the dashboard: ![](/assets/images/formatting-welcome-text-6b965a61bd4526c48897e1f2973c8aff.png) ## Supported Markdown syntax[​](/docs/create-apps/layout-and-styling/style-text/.md#supported-markdown-syntax "Direct link to Supported Markdown syntax") All of [CommonMark](https://commonmark.org/help/) Markdown is supported except for images, which are ignored. Using HTML tags in Markdown-styled text is not supported, all HTML tags are automatically stripped for security reasons. Markdown links will always open in a new tab. ## Rendering math symbols with LaTeX[​](/docs/create-apps/layout-and-styling/style-text/.md#rendering-math-symbols-with-latex "Direct link to Rendering math symbols with LaTeX") Rendering math symbols is supported using LaTeX syntax. See [KaTeX Supported functions](https://katex.org/docs/supported.html) or [KaTeX Support Table](https://katex.org/docs/support_table.html) for all supported LaTeX functions. To render LaTeX inline, wrap a LaTeX expression in dollar signs. For example: ``` $x=\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$ ``` To render LaTeX as a block, wrap a LaTeX expression in double dollar signs and a newline: ``` $$ L = \\frac{1}{2} \\rho v^2 S C_L $$ ``` Block LaTeX text is centered by default. tip A nifty webapp to find the right LaTeX symbol by drawing is [Detexify: LaTeX handwritten symbol recognition](http://detexify.kirelabs.org/classify.html) ### Escape strings in Python[​](/docs/create-apps/layout-and-styling/style-text/.md#escape-strings-in-python "Direct link to Escape strings in Python") While writing LaTeX you may encounter the following warning on the command-line: ``` DeprecationWarning: invalid escape sequence \p ``` When certain characters (for example `\u`, `\f`, `\b`, `\r`, `\v`, `\x`) are preceded by a backslash they are viewed as 'escape sequences' by Python. To resolve this deprecation warning simply add another backslash in front of the LaTeX function to make the warning go away, for example `$\\xi = \\gamma \\times \\epsilon^3$`. ### My LaTeX equation is showing as plain text, what's wrong?[​](/docs/create-apps/layout-and-styling/style-text/.md#my-latex-equation-is-showing-as-plain-text-whats-wrong "Direct link to My LaTeX equation is showing as plain text, what's wrong?") 1. Check if your LaTeX expression is wrapped in dollar signs `$` 2. If it is colored red, the math expression is not valid KaTeX. Check your LaTeX functions and check if they are supported by [KaTeX](https://katex.org/docs/supported.html). Try entering it in [online KaTeX editor](https://katex.org/#demo) and see if it renders ok in there. 3. Check if there's an invalid escape sequence in your LaTeX expression ## Line breaks[​](/docs/create-apps/layout-and-styling/style-text/.md#line-breaks "Direct link to Line breaks") In block-styled (non-inline) text, line breaks can be defined in two ways: using the newline control character `\n` or using multiline strings. ### 1. Using the newline control character[​](/docs/create-apps/layout-and-styling/style-text/.md#1-using-the-newline-control-character "Direct link to 1. Using the newline control character") Use `\\\n` or `\n` preceded by two spaces to add a newline to a regular string: ``` description="This description \n is multiline" ``` ``` description="This description \\\n is multiline" ``` ![single newline](data:image/png;base64,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) ### 2. Using multiline strings[​](/docs/create-apps/layout-and-styling/style-text/.md#2-using-multiline-strings "Direct link to 2. Using multiline strings") Multiline strings are strings that are wrapped in three quotes (single or double): `"""a multiline string"""` or `'''a multiline string'''`. To add a newline in between lines, just add an empty line in between. ``` description="""This description is multiline""" ``` ![multi newline](data:image/png;base64,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) To make a single newline in a multiline string, add `\\` to the end of a line: ``` description="""This description \\ is multiline""" ``` Or use the newline control character with three backslashes or preceded by two spaces: ``` description="""This description \\\n is multiline""" ``` ``` description="""This description \n is multiline""" ``` ![single newline](data:image/png;base64,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) caution **Do not include indentation in multiline strings.** Be sure to remove indentation at the start of each line, **any line with indentation in a multiline string is ignored**. If you want to add indentation to a line you can do so by making it a blockquote by prefixing it with `>`. Alternately, you can add the special character ` ` at the start of line to add a space. ``` description="""Line 1 > Indented blockquote line    2 spaces indented line Space indented lines will be ignored Line 3""" ``` --- # Creating tabs & sections In some cases, the parametrization becomes quite big which requires a more structured layout. This can be achieved by making use of a [`Tab`](/sdk/api/parametrization/.md#_Tab) and [`Section`](/sdk/api/parametrization/.md#_Section), which represent a tab and collapsible section in the interface respectively. A 2-layered structure using `Tab` objects looks like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): tab_1 = vkt.Tab('Tab 1') tab_1.input_1 = vkt.TextField('This is a text field') tab_1.input_2 = vkt.NumberField('This is a number field') tab_2 = vkt.Tab('Tab 2') tab_2.input_1 = vkt.TextField('Text field in Tab 2') tab_2.input_2 = vkt.NumberField('Number field in Tab 2') ``` ![](/assets/images/editor-two-layered-tabs-c1e7f01a0cb38e9b8dc09d1a94cc6c3d.png) *Parametrization with tabs, no sections* Using `Section` objects results in the following: ``` import viktor as vkt class Parametrization(vkt.Parametrization): section_1 = vkt.Section('Section 1') section_1.input_1 = vkt.TextField('This is a text field') section_1.input_2 = vkt.NumberField('This is a number field') section_2 = vkt.Section('Section 2') section_2.input_1 = vkt.TextField('Text field in Section 2') section_2.input_2 = vkt.NumberField('Number field in Section 2') ``` ![](/assets/images/editor-two-layered-sections-2b17116cfe559fdd6036e6ad5705d110.png) *Parametrization with sections, no tabs* A parametrization with a maximum depth of 3 layers consists of `Tab`, `Section`, and `Field` objects: ``` import viktor as vkt class Parametrization(vkt.Parametrization): tab_1 = vkt.Tab('Tab 1') tab_1.section_1 = vkt.Section('Section 1') tab_1.section_1.input_1 = vkt.TextField('This is a text field') tab_1.section_1.input_2 = vkt.NumberField('This is a number field') tab_1.section_2 = vkt.Section('Section 2') ... tab_2 = vkt.Tab('Tab 2') ... ``` ![](/assets/images/editor-three-layered-a034d1717eac4f117e16564eec58ab2b.png) *Parametrization with sections and tabs* ## Hide a Tab / Section[​](/docs/create-apps/layout-and-styling/tabs-and-sections/.md#hide-a-tab--section "Direct link to Hide a Tab / Section") New in v14.7.0 Hiding a Tab or Section can be done in a similar way as [hiding a field](/docs/create-apps/user-input/hide-field/.md), by setting the `visible` argument: ``` vkt.Tab("Tab 2", visible=vkt.Lookup("tab_1.param_x")) ``` or using a callback function: ``` vkt.Tab("Tab 2", visible=get_visible) ``` ## Expand a Section[​](/docs/create-apps/layout-and-styling/tabs-and-sections/.md#expand-a-section "Direct link to Expand a Section") New in v14.21.0 As a developer, you can define which sections should be expanded and which should be collapsed (default) when a user enters the editor, by setting the `initially_expanded` parameter: ``` vkt.Section("Section", initially_expanded=True) ``` note If `initially_expanded` is not set on any section within a parametrization, the default behavior is triggered with the first section being expanded and the others collapsed. --- # Managing files When starting out coding with python, you could probably copy file paths from the File Explorer. However, when developing apps with VIKTOR, it's crucial to understand that these file paths don't function the same way as the apps are deployed on the cloud. VIKTOR apps are stateless, meaning they reset with each session, files uploaded (via a `FileField`) to the cloud are only available for that session. Any files that are part of the app (such as an excel sheet integration) will reset for the next session. Additionally, VIKTOR applications follow a standardized structure, making them easy to move, store, and deploy on the cloud, a concept known as "containerized" development. However, any additions to the application are uploaded separately and are not part of the standardized package. Therefore, it's essential to consider these factors when handling files on the VIKTOR platform. Understanding the file's intended actions are crucial for choosing the correct methods for file manipulation. ## File paths[​](/docs/create-apps/managing-files/.md#file-paths "Direct link to File paths") In most apps the code uses information from files on the hard drive. In order to access such files, a path must be provided. Python's built-in `pathlib` module can be used for this purpose. caution Never use a **static** path to access a file (e.g. '/home/users/foo/app/entity/file.txt', '../file.txt', or 'file.txt')! This might work fine when testing on your local machine, but will most likely crash when the app is published and runs on a server (different username, folder structure and operating system). Assume an application with the following structure of the `app` directory: ``` app ├── entity_type_a │ ├── __init__.py │ ├── controller.py │ └── parametrization.py ├── __init__.py └── file.txt ``` We can make use of `Path(__file__)` as a starting point, which points to the file in which the code is invoked. On this path object, we can easily navigate to the parent directory by calling `Path(__file__).parent`. In the structure above, getting the file `file.txt` in the controller of entity\_type\_a can thus be done by: ``` # entity_type_a/controller.py from pathlib import Path entity_folder_path = Path(__file__).parent # entity_type_a file_path = entity_folder_path.parent / 'file.txt' with file_path.open() as f: content = f.read() ``` This implementation allows your application/project/module to be portable. For example, the folder `entity_type_a` (and even `controller.py`!) can be renamed without breaking the link to `file.txt`, because the navigation is relative to the source file (`controller.py`). ## Large files, storage and memory issues[​](/docs/create-apps/managing-files/.md#large-files-storage-and-memory-issues "Direct link to Large files, storage and memory issues") For large files and calculations, it may be desirable to store some data in your application. VIKTOR offers a `storage` which can be used to store and retrieve files within an app workspace and the files will remain available. This can be very helpful in cases where (intermediate) results need to be shared between jobs. For more information on storage visit our [storing results page](/docs/create-apps/results-and-visualizations/storing-results/.md). For processing large files, it is suggested to look into working with [VIKTOR file objects in binary mode](/docs/create-apps/managing-files/modify-files/.md#using-a-viktor-file-object-in-binary-mode)). ## Production hosting and limits[​](/docs/create-apps/managing-files/.md#production-hosting-and-limits "Direct link to Production hosting and limits") When your application runs on production environments, a few things can be different than running it on development. Make sure you read up on [files persistence between jobs](/docs/getting-started/fundamentals/call-flow/.md#local-files-persistence-between-jobs) and [disk limits](/docs/publish-apps/limits/.md#disk-storage-limit-of-5-gb). --- # Downloading files A [download action](/docs/create-apps/user-input/action-buttons/.md#download-action) enables the user to download a file to hard disk upon clicking a button. In order to do so, the following steps need to be taken: 1. Add a [`DownloadButton`](/sdk/api/parametrization/.md#_DownloadButton) in the parametrization class of the corresponding entity type: ``` import viktor as vkt class Parametrization(vkt.Parametrization): download = vkt.DownloadButton('Download', method='download_file') ``` 2. Add the download method (in this case `download_file`) on the corresponding controller class of the entity type to link the `DownloadButton`, and return the file (content) as [`DownloadResult`](/sdk/api/result/.md#_DownloadResult): ``` import viktor as vkt class Controller(vkt.Controller): def download_file(self, params, **kwargs): return vkt.DownloadResult('file content', 'filename.txt') ``` ## Downloading a File object[​](/docs/create-apps/managing-files/downloading-files/.md#downloading-a-file-object "Direct link to Downloading a File object") `DownloadResult` directly accepts a `File` object as input. This type is often returned by VIKTOR functions such as utils' document conversions and external analyses. This allows for easy handling of result files: ``` import viktor as vkt class Controller(vkt.Controller): def download_spreadsheet(self, params, **kwargs): ... filled_spreadsheet = vkt.spreadsheet.render_spreadsheet(...) return vkt.DownloadResult(filled_spreadsheet, 'filled_spreadsheet.xlsx') def download_word_file(self, params, **kwargs): ... word_file = vkt.word.render_word_file(...) return vkt.DownloadResult(word_file, 'word_file.docx') def download_scia_result(self, params, **kwargs): ... result_file = scia_analysis.get_xml_output_file(as_file=True) return vkt.DownloadResult(result_file, 'scia_result.xml') ``` ## Downloading other file types[​](/docs/create-apps/managing-files/downloading-files/.md#downloading-other-file-types "Direct link to Downloading other file types") It is also possible to download any other type of document (e.g. `.txt`, `.xml`, `.json`, etc.). In these cases, the `DownloadResult` should be passed the file content as type `str` or `bytes`. Since VIKTOR does not offer specific template for these file types, you will have to write the logic that generates the desired file content yourself. ## Downloading multiple files[​](/docs/create-apps/managing-files/downloading-files/.md#downloading-multiple-files "Direct link to Downloading multiple files") Downloading multiple files in one go is easy when using the `zipped_files` argument in a `DownloadResult`. The files will be bundled in a zip-file with given `file_name`: ``` DownloadResult(zipped_files={'my_file_1.txt': my_file_1, 'my_file_2.txt': my_file_2}, file_name="my_file.zip") ``` Alternatively, you can use the [zipfile](https://docs.python.org/3/library/zipfile.html) module from Python's standard library to create your own zip-file manually: ``` import viktor as vkt import zipfile class Controller(vkt.Controller): def download_zip(self, params, **kwargs): ... file = vkt.File() with zipfile.ZipFile(file.source, 'w', zipfile.ZIP_DEFLATED) as z: z.writestr('my_file_1.txt', my_file_1_content) z.writestr('my_file_2.txt', my_file_2_content) return vkt.DownloadResult(file, file_name="my_file.zip") ``` --- # Modifying files ## Open, read, write and remove files[​](/docs/create-apps/managing-files/modify-files/.md#open-read-write--and-remove-files "Direct link to Open, read, write and remove files") In general python, the function you use to work in files most is `open()`. It takes two parameters as inputs; *filename* and *mode*. For the mode you have **four** options: **1. read a file ("r"):** This is the default value, it will open and read the file and returns an error if the file does not exist. **2. write to a file ("w"):** This opens a file for writing data to. If the file does not exist this will create one with the given filename. **3. create a file ("x"):** This will create a new file with the given filename. If a file with that name already exists then this will return an error. **4. append to a file ("a"):** This will open a file for appending data. If the file does not exist, it will make a file with the given filename. Each mode also lets you specify if you would like to handle the file as **text ("t")** or **binary ("b")**. (You can also open a file for **updating ("+")** which lets you read and write). All of the above can be applied in this example below. Note that in this example we are opening a text file to write to: ``` file_path = "path/to/text_file.txt" with open(file_path_, "wt") as file: # do something with the file ``` ## Using a VIKTOR file object in binary mode[​](/docs/create-apps/managing-files/modify-files/.md#using-a-viktor-file-object-in-binary-mode "Direct link to Using a VIKTOR file object in binary mode") One of the features of the VIKTOR platform is the VIKTOR `File` object. This file like object can be used for files and opens a door to file handling that you can apply. The important thing to understand is that this method will open and/or read the files in binary mode. As binary mode is consistent across packages, there is no extra encoding or decoding that you may encounter when dealing with non-text files. On that note, using a binary method you can open file formats that may get corrupted by a text mode. Another advantage of the binary mode is that it allows for efficient stream based processing. This allows for working with larger files without loading the entire contents into memory. The basic way to open a VIKTOR file object in binary mode is to use `open_binary()`. You may refer to the example below: ``` my_file = #path to a csv file as VIKTOR File object with my_file.open_binary() as fp: df.read_csv(fp) ``` If you would like to save a figure like those created by Matplotlib, you can also use `open_binary()`. ``` fig = Figure() ... my_svg = File() with my_svg.open_binary() as fp: fig.savefig(fp, "svg") ``` Be mindful of big files When using the method above, the entire file gets opened meaning large files will use a lot of memory. On these files it is better to use the previous method. In case you would like to extract data, you may use: ``` # binary mode some_bytes = my_file.getvalue_binary() #limited by memory # text mode (only for text-based data types) some_strings = my_other_file.getvalue() ``` In summary, using the VIKTOR file object is the most versatile way to handle your files. The code will only require up to 3 lines, it keeps the code clean and is compatible across platforms reliably. ## Using packages[​](/docs/create-apps/managing-files/modify-files/.md#using-packages "Direct link to Using packages") In some cases it is possible to use a package to read the content of a file. An easy example is turning a .csv document into a Pandas dataframe. Dataframes are a commonly used way to store structured data because they are easy to modify and analyse. See the package documentation to see the possibilities. --- # Uploading files There are two ways for the user to upload a file in the VIKTOR interface: 1. By defining a `FileField` in the parametrization, a user can upload a file through an upload modal and directly attach it to a specific field. This way, the developer can easily use the file (content) which will be present in the `params` of a job. This method is encouraged due to its simplicity and the possibility for users to stay within the current entity in which the `FileField` resides. 2. By creating a [file-like entity type](/docs/create-apps/managing-files/uploading-files/.md#upload-using-file-like-entity-type). When a user creates a new entity of this type, he or she will be prompted with an upload modal instead of just the entity name. This method is a bit more cumbersome for users, since it requires more actions (clicks) to be performed and navigation between entities. This method can be used to isolate a file with, for example, attached views. ## Upload using `FileField`[​](/docs/create-apps/managing-files/uploading-files/.md#upload-using-filefield "Direct link to upload-using-filefield") Adding a [`FileField`](/sdk/api/parametrization/.md#_FileField) (or [`MultiFileField`](/sdk/api/parametrization/.md#_MultiFileField)) is as easy as adding any other field: ``` import viktor as vkt class Parametrization(vkt.Parametrization): csv_file = vkt.FileField('CSV file') ``` These fields will be generated in the VIKTOR interface as dropdown fields, with the possibility to upload one or multiple files. When the user has made a selection, the file resource will be available in the `params` of every job as [`FileResource`](/sdk/api/api-v1/.md#_FileResource) object: In this example we use the `.file` property to get the file contents of the uploaded file as a VIKTOR `File` object. You can also use the `.filename` property to get the file name, these two properties make up a VIKTOR `File` object. After that you can use it as a regular `File` object in your app, for example by loading the csv in a pandas DataFrame and visualizing it in a `TableView`. ``` import viktor as vkt import pandas as pd class Parametrization(vkt.Parametrization): csv_file = vkt.FileField('CSV file') class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Table") def show_csv(self, params, **kwargs): csv_file = params.csv_file.file # Retrieve the File object from the FileResource with csv_file.open() as r: df = pd.read_csv(r) return vkt.TableResult(df) ``` tip `FileResource` objects originating from a `FileField` or `MultiFileField` are [memoizable](/docs/create-apps/results-and-visualizations/storing-results/.md#memoize) ### Temporary files[​](/docs/create-apps/managing-files/uploading-files/.md#temporary-files "Direct link to Temporary files") Although not recommended, it is possible to use temporary files. This module creates temporary files that get deleted after closing. You can use this as a temporary storage solution as the file is created securely and on completion is removed. For a `NamedTemporaryFile` the returned object is always a file-like object that can be used in a `with` statement, just like a normal file. ## Upload using file-like entity type[​](/docs/create-apps/managing-files/uploading-files/.md#upload-using-file-like-entity-type "Direct link to Upload using file-like entity type") In short, the following steps should be implemented. A more elaborate example is shown in the following sections. 1. Add a new entity type by defining a [controller](/docs/getting-started/fundamentals/basic-app-structure/.md#the-controller). 2. Implement a process method (can be named arbitrarily) on the controller class, decorated by [`ParamsFromFile`](/sdk/api/core/.md#_ParamsFromFile). ``` import viktor as vkt class Controller(vkt.Controller): @vkt.ParamsFromFile() def process_file(self, file: vkt.File, **kwargs): return {} # nothing to store ``` In the example above, the `process_file` method does not contain any logic. However, this method can also be used to parse certain information from the file, which can be stored in the parametrization of the entity. See the example below if this is desired. ### File processing[​](/docs/create-apps/managing-files/uploading-files/.md#file-processing "Direct link to File processing") caution Prevent storing the complete file content on the properties if the file is large, as this may cause speed and/or stability issues. The file content can be retrieved at all times using the API whenever necessary. The processed content can **only** be stored on fields that are defined in the entity's parametrization. These can be input fields (e.g. [`NumberField`](/sdk/api/parametrization/.md#_NumberField)), but also read-only ([`OutputField`](/sdk/api/parametrization/.md#_OutputField)) or even a [`HiddenField`](/sdk/api/parametrization/.md#_HiddenField). Let's assume the following parametrization and text file to be uploaded: ``` class Parametrization(vkt.Parametrization): number_of_entries = vkt.NumberField('Number of entries') project_name = vkt.TextField('Project') ``` ``` Project=Super nice project Entry1 Entry2 Entry3 ``` The decorated process method should return the data in a dictionary format. The structure of this dictionary should match with the structure of the parametrization fields: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.ParamsFromFile() def process_file(self, file: vkt.File, **kwargs): # viktor.core.File # app specific parse logic number_of_entries = 0 project_name = '' with file.open(encoding='utf-8') as f: for lineno, line in enumerate(f): if lineno == 0: _, project_name = line.split('=') elif line.startswith('Entry'): number_of_entries += 1 # linking the parsed output to the parametrization fields (names in database) return { 'number_of_entries': number_of_entries, 'project_name': project_name } ``` In case of a nested parametrization structure, the return value is a nested dictionary: ``` class Controller(vkt.Controller): @vkt.ParamsFromFile() def process_file(self, file: vkt.File, **kwargs): ... return { 'tab': { 'section' : { 'number_of_entries': number_of_entries, 'project_name': project_name } } } ``` tip The file entity can be retrieved and the file (content) can be extracted (from either the current entity or another) [using the API](/docs/api/sdk/.md). ## File restrictions[​](/docs/create-apps/managing-files/uploading-files/.md#file-restrictions "Direct link to File restrictions") A limit is set on the file size of an upload to protect the developer for potential memory issues and/or instability of the application when handled incorrectly. Sometimes however, it is required to deal with large files. In this case the limit can be increased using the `max_size` argument: ``` file = vkt.FileField('CPT file', max_size=100_000_000) # 100 MB ``` ``` @vkt.ParamsFromFile(max_size=100_000_000) # 100 MB ``` Keep in mind that reading the complete content of a large file in memory will lead to memory issues. We therefore recommend reading the file in chunks (see [`File`](/sdk/api/core/.md#_File)). Similarly, you are able to restrict the file type(s) that may be uploaded, by means of `file_types`: ``` file = vkt.FileField('CPT file', file_types=['.png', '.jpg', '.jpeg']) ``` ``` @vkt.ParamsFromFile(file_types=['.png', '.jpg', '.jpeg']) ``` ## Excel vs CSV[​](/docs/create-apps/managing-files/uploading-files/.md#excel-vs-csv "Direct link to Excel vs CSV") If you want to upload an Excel file, the preferred method is to convert it to a plain-text CSV (comma-separated values) format (extension ".csv"). Excel files (".xls", ".xlsx") are not plain-text and special characters are not always imported correctly. An additional advantage of a CSV file is that, being plain-text, they can be compared using version control software (e.g. Git). info A CSV file does not support 'sheets' as an Excel file does, meaning that a CSV file must be created for each sheet in a multi-sheet Excel file. --- # Using date-dependent params Projects that make use of a database with prices are often invoiced with prices that may change over the years. If such prices are changed and the project is re-opened, the latest revision of the price-database is used by default. However, this could influence resulting data (e.g. a quotation) of an old project that the user would like to review. In such cases it is very helpful to select or specify a date at which the database settings were applicable. Selecting a date can be implemented in different ways. Note that in case a [`DateField`](/sdk/api/parametrization/.md#_DateField) is used to pick a date you should account for possible UTC offsets. Assume a revision is created in Los Angeles at 17:00 local time (UTC-8), this will result in a UTC time stamp at 1:00 the **next day** so the latter date should be selected. The user does not know this will happen, so depending on the UTC zone of the user, the possible 1-day fluctuation should be taken into account. Steps: 1. From the backend API, call the revisions of the 'settings' entity (e.g. `API().get_entity_revisions(entity_id)`). 2. Get the dates of the revisions, stored under ['created\_date'](/sdk/api/api-v1/.md#_EntityRevision) property. 3. Get the user-specified date. 4. Since both dates are datetime objects, comparison can easily be done. 5. Filter the revision that was applicable at the user-specified date. The last step can vary depending on the way you would like to filter the revisions. For example if multiple revisions are created on the specified date, you can write an algorithm to select the correct revision of that day (e.g. the latest or first created). Make sure to notify the user whether the specified date is within the bounds of the possible revisions or not. --- # Processing GEF files Classes have been created to simplify usage of GEF files such as a data access class (`GEFData`) that includes visualization of GEF measurement data, or classification of soil layout. All classes and functions can be imported from the [`viktor.geo`](/sdk/api/geo/.md) module. For more detailed examples, please check the docstring of the functions. ## `GEFFile` class[​](/docs/create-apps/other-topics/processing-gef-files/.md#geffile-class "Direct link to geffile-class") The [`GEFFile`](/sdk/api/geo/.md#_GEFFile) object is used to parse the file content of GEF files and convert the data to dictionary or `GEFData` object. The data is split into 'measurement\_data' and 'headers' category. For 'measurement\_data' the compulsory fields are 'Rf', 'qc' and 'elevation'. These are automatically always returned and stored when parsing a GEF file. Additional columns can be requested from the controller by specifying them in the parse call using the keyword "additional\_columns". The height reference- and coordinate system are parsed from the gef file and return in the properties "height\_system" and "coordinate\_system". Any property relating with a reference relates to the height\_system value. In general the following definitions (taken from the norm) are used: * depth is always a positive number, denoting vertical distance from start of measurement to end * length is always a positive number, denoting distance measured along path of measurement * elevation is the vertical position of a measurement wrt to a reference datum. (so reference\_datum\_height - depth), can be partially positive and negative caution `GEFFile.parse` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ## `GEFData` class[​](/docs/create-apps/other-topics/processing-gef-files/.md#gefdata-class "Direct link to gefdata-class") [`GEFData`](/sdk/api/geo/.md#_GEFData) is a data class to simplify the usage of GEF data. A `GEFData` object can directly be initiated with the dictionary that is created by the `GEFFile` class. All keys from 'measurement\_data' and 'headers' are set as attributes of the `GEFData` object, and are therefore directly accessible. The measurement data can be used to determine the soil types with `classify(method: Type[ClassificationMethod], return_soil_layout_obj: bool = True)`. Currently, the [`RobertsonMethod`](/sdk/api/geo/.md#_RobertsonMethod) and [`TableMethod`](/sdk/api/geo/.md#_TableMethod) are supported for soil classification. The properties of all possible soil types need to be provided when calling the `classify` method in order to create a [`SoilLayout`](/sdk/api/geo/.md#_SoilLayout). caution `GEFData.classify` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ## GEF visualization[​](/docs/create-apps/other-topics/processing-gef-files/.md#gef-visualization "Direct link to GEF visualization") For easy visualization of GEF data, a helper function is created. A code example is provide below: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.ImageView("GEF plot", duration_guess=5) def visualize(self, params, **kwargs): gef_data = ... soil_layout_original = ... soil_layout_user = ... svg_image = vkt.geo.gef_visualization(self.gef_data, self.soil_layout_original, self.soil_layout_user, as_file=True) return vkt.ImageResult(svg_image) ``` If the standard helper function does not satisfy the requirements, it is possible to create your own matplotlib. `GEFData` has `get_resistance_visualization(axes: matplotlib.pyplot.Axes)` and `get_cone_visualization(axes: matplotlib.pyplot.Axes)` functions, while `SoilLayout` has `get_visualization(axes: matplotlib.pyplot.Axes)`. All functions require a matplotlib `Axes` object that are stateful, and therefore the visualization functions do not return. Example to use one of the visualization functions is shown below: ``` import viktor as vkt import matplotlib.pyplot as plt class Controller(vkt.Controller): @vkt.ImageView("GEF plot", duration_guess=5) def visualize(self, params, **kwargs): gef_data = ... # Create main figure fig = plt.figure(figsize=(8.27, 11.69)) # Define contour (rectangle) for cone visualization, and create Axes object that can be modified by functions rect_cone = [0.1, 0.1, 0.4, 0.9] # [left, bottom, width, height] cone_axes = plt.axes(rect_cone) # Modify created Axes objects gef_data.get_cone_visualization(cone_axes) # Convert to SVG for visualization svg_data = StringIO() fig.savefig(svg_data, format='svg', bbox_inches='tight', pad_inches=0.8) plt.close() return vkt.ImageResult(svg_data) ``` ## Soil structure[​](/docs/create-apps/other-topics/processing-gef-files/.md#soil-structure "Direct link to Soil structure") A general purpose soil structure has been introduced that is being used by the GEF parser, namely `Soil`, `SoilLayer` and `SoilLayout`. A `SoilLayout` is a collection of `SoilLayer` objects, which contain a `Soil`, top and bottom of layer as attributes. Extra properties can be added to the `Soil` class to provide more (geotechnical) information. Properties can be stored on `Soil` and `SoilLayer` object by calling `update_properties` and providing a dict with the relevant parameters. A `SoilLayout` can be manually created using the `__init__(self, soil_layers: List[SoilLayer])` function, but in order to simplify storage of the object in the database class methods have been created. To store the object in the database the function `serialize()` can be used. For re-initialization of `SoilLayout` the function `from_dict(cls, soil_layout_dict: Dict[str, List])` can be used. --- # Share data between entities using the API ## Sharing data between entities using the API[​](/docs/create-apps/other-topics/share-using-api/.md#sharing-data-between-entities-using-the-api "Direct link to Sharing data between entities using the API") tip If the selection of an entity needs to be done by the user, you can make use of the [entity selection fields](/docs/create-apps/user-input/entity-selection/.md) Sometimes information is needed from another entity. For example, when you want to show all the child locations on a `MapView`. Or when you require general settings, which are specified on the parent entity. Please refer to our [SDK API documentation](/docs/api/sdk/.md) for examples on how to set this up. caution Please keep in mind that API requests are relatively slow, so make sure you only execute them when necessary. --- # Command-line interface (CLI) The VIKTOR command-line interface (CLI) is used to interact with your application code (installing dependencies, starting the app, running tests). This guide covers the installation and available commands. ## Installation[​](/docs/create-apps/references/cli/.md#installation "Direct link to Installation") Apps on the VIKTOR platform can be developed on Windows and Linux operating systems. Please consult the [installation](/docs/getting-started/installation/.md) section for the differences between using the CLI with and without Docker, Hyper-V virtualization and WSL2. note If you are on Windows and want to use WSL2 you need to use the Linux version of the CLI. Choose the CLI for your specific operating system and installation method below: \[ ]I accept the [terms and conditions](https://www.viktor.ai/terms) and [privacy policy](https://www.viktor.ai/privacy).[Download for Windows (no WSL2)](<> "Accept the terms & conditions and privacy policy first")[Download for Linux (or WSL2)](<> "Accept the terms & conditions and privacy policy first") A token is required to use the CLI. This token is linked to the email address associated with your development account. Configuration of the CLI can be done using the [`configure`](/docs/create-apps/references/cli/.md#configure) command. You will be asked to supply the email address and token during the configuration process. This action only needs to be performed once. ## Commands[​](/docs/create-apps/references/cli/.md#commands "Direct link to Commands") ### activate[​](/docs/create-apps/references/cli/.md#activate "Direct link to activate") Activate your VIKTOR account on the given environment, to get started developing. ``` viktor-cli activate [flags] Flags: -h, --help help for activate ``` ### apps[​](/docs/create-apps/references/cli/.md#apps "Direct link to apps") List apps that are connected to your VIKTOR development account. ``` viktor-cli apps [flags] Flags: -h, --help help for apps ``` ### check-system[​](/docs/create-apps/references/cli/.md#check-system "Direct link to check-system") Check if software environment is ready for developing VIKTOR apps. The following checks are performed: default: * OS can access PyPI * OS can access VIKTOR domains * Python (64-bit) is installed and configured * VIKTOR credentials are valid using `--docker`: * Docker is running * Docker can use correct container * Docker has access to user directory * Docker can access PyPI * Docker can access VIKTOR domains * VIKTOR credentials are valid ``` viktor-cli check-system [flags] Flags: --docker Run system checks for docker isolation mode -h, --help help for check-system --verbose Perform checks with more verbose logging to provide additional information ``` ### ci-install[​](/docs/create-apps/references/cli/.md#ci-install "Direct link to ci-install") Install the required dependencies inside a continuous integration environment. ``` viktor-cli ci-install [flags] Flags: -h, --help help for ci-install ``` ### ci-publish[​](/docs/create-apps/references/cli/.md#ci-publish "Direct link to ci-publish") Publish the app from a continuous integration environment. The following CI/CD platforms are supported: * Azure DevOps * GitHub Actions * GitLab CI/CD ``` viktor-cli ci-publish [flags] Flags: -h, --help help for ci-publish --tag string Used to identify the version of the app on the platform. The tag may contain letters, numbers, dots and hyphens, max. 128 characters and should be unique. --use-filesystem Publish all files in current folder, as opposed to only files committed in git. ``` ### ci-test[​](/docs/create-apps/references/cli/.md#ci-test "Direct link to ci-test") Perform tests inside a continuous integration environment. The following command is executed: `python -m unittest discover -s tests`. ``` viktor-cli ci-test [flags] Flags: -h, --help help for ci-test ``` ### clean-start[​](/docs/create-apps/references/cli/.md#clean-start "Direct link to clean-start") Install and start your app in a clean development workspace. ``` viktor-cli clean-start [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") -h, --help help for clean-start ``` ### clear[​](/docs/create-apps/references/cli/.md#clear "Direct link to clear") Clear entities and entity types that are present in the database of your development workspace. ``` viktor-cli clear [flags] Flags: -h, --help help for clear --region us1 Specify the region in case of a multi-region organization if different than the default defined in the configuration file (e.g. us1) --registered-name string Registered name of the app (see 'viktor-cli apps') to connect to. When not defined, the 'registered_name' in the viktor.config.toml file be used. ``` ### configure delete-account[​](/docs/create-apps/references/cli/.md#configure-delete-account "Direct link to configure delete-account") Delete a specific configuration account. This will not delete your account from the environment it is registered on! ``` viktor-cli configure delete-account [flags] Flags: -h, --help help for delete-account ``` ### configure list-accounts[​](/docs/create-apps/references/cli/.md#configure-list-accounts "Direct link to configure list-accounts") Lists the configured accounts. These accounts are related to a specific VIKTOR development environment. ``` viktor-cli configure list-accounts [flags] Flags: -h, --help help for list-accounts ``` ### configure switch-account[​](/docs/create-apps/references/cli/.md#configure-switch-account "Direct link to configure switch-account") Switch to another configuration account, without needing to reconfigure the current active account. ``` viktor-cli configure switch-account [flags] Flags: -h, --help help for switch-account ``` ### configure[​](/docs/create-apps/references/cli/.md#configure "Direct link to configure") Configure your development account, consisting of: * environment * email address * token * isolation mode * Python path The following isolation modes can be selected: * `venv`: a Python virtual environment to manage dependencies * `docker`: code and dependency management using Docker containers A configuration file will be written to the '.viktor' folder in your user home directory. * Windows: this is the directory set in the USERPROFILE environment variable * Linux: this is the directory set in the HOME environment variable The 'configure' command configures the account that is currently active. Use the --name flag to configure a specific account. A new configuration account is created if it does not yet exist. ``` viktor-cli configure [flags] Flags: -h, --help help for configure --name string Configure a specific account ``` ### create-app[​](/docs/create-apps/references/cli/.md#create-app "Direct link to create-app") Create a new VIKTOR app with the given name within the current working directory using the latest SDK, as a starting point for development. If NAME is not provided, the app will be created directly inside the current working directory. ``` viktor-cli create-app [flags] Flags: --app-type string Type of app to be generated ['editor' | 'simple' | 'tree']. Mutually exclusive with --demo flag. (default "simple") --demo Generate a demo app, including examples and comments. -h, --help help for create-app ``` ### describe[​](/docs/create-apps/references/cli/.md#describe "Direct link to describe") Show latest published versions of an app by the given registered name. Shows the last 10 published app versions. ``` viktor-cli describe [flags] Flags: -h, --help help for describe ``` ### fix[​](/docs/create-apps/references/cli/.md#fix "Direct link to fix") Fix deprecations by modifying the app source code. A diff is shown with the proposed changes and a prompt to accept or reject. Multiple upgrades can be applied using the `--upgrade` flag: `viktor-cli fix -u 41 -u 43 -u 45`. All upgrades of the current SDK major version are applied when omitting the `--upgrade` flag. ``` viktor-cli fix [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") -a, --apply directly apply fix -h, --help help for fix -k, --keep-original keep original files (e.g. foo.py -> foo.py & foo.orig.py) -u, --upgrade 42 upgrade number (e.g. 42) ``` ### get-started[​](/docs/create-apps/references/cli/.md#get-started "Direct link to get-started") Get started developing with VIKTOR by activating your account on the given environment. ``` viktor-cli get-started [flags] Flags: -h, --help help for get-started ``` ### install[​](/docs/create-apps/references/cli/.md#install "Direct link to install") Install the app and its dependencies: * VIKTOR platform dependencies (e.g. 'viktor-connector') * app dependencies (e.g. 'viktor', 'numpy', etc.) The application should always be reinstalled when changes are made in the `requirements.txt` file. ``` viktor-cli install [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") --connector 5.2.0 (NOT recommended) Custom connector version (e.g. 5.2.0) (default "latest") --dns 1.1.1.1 Custom DNS servers (e.g. 1.1.1.1) (default []) -e, --env FOO=foo Additional environment variables (e.g. FOO=foo) (default []) -h, --help help for install --max-memory 500 (Docker only) Memory limit of the container in megabytes (e.g. 500) (default 500) --use-pip Use this flag to enable installation using 'pip' instead of the default 'uv' as package manager --use-truststore Use this flag to enable/disable installation of the app using the system truststore for HTTPS certificate verification instead of the bundled certifi certificates of pip (e.g. --use-truststore=false) (default true) ``` ### publish[​](/docs/create-apps/references/cli/.md#publish "Direct link to publish") Publish new versions of the application code to an app running in production. If you are ready to publish your app, please use the following flow: 1. Prepare your code for release. 2. Use the publish command. 3. Once you press enter you will see a spinner which you can use to monitor the publication. At this moment it not possible to cancel the process once you see the spinner. It is not a problem if you accidentally close the CLI at this point, publishing will continue in the background. During publication several checks will be performed. If any problems occur you will be presented with the reason for failure. 4. There might be a small delay between the 'publication successful' message from the CLI and the actual update of the app. If this is the case, just refresh your browser. 5. If you want to check out the latest tag and status you can use the `apps` or `describe` commands. ``` viktor-cli publish --registered-name [--use-filesystem] [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") -h, --help help for publish --registered-name string Registered name on the platform (see 'viktor-cli apps') to publish the app to. When not defined, the 'registered_name' in the viktor.config.toml file be used. --tag string Used to identify the version of the app on the platform. The tag may contain letters, numbers, dots and hyphens, max. 128 characters and should be unique. If the app directory is a git repository and its HEAD is on a tag it will default to this tag. --use-filesystem Publish all files in current folder, as opposed to only files committed in git. When using GitHub Codespaces this setting will always be true. ``` ### quickstart[​](/docs/create-apps/references/cli/.md#quickstart "Direct link to quickstart") Start developing from a sample app, or converted Excel file. ``` viktor-cli quickstart [flags] Flags: -h, --help help for quickstart ``` ### run[​](/docs/create-apps/references/cli/.md#run "Direct link to run") Run a given command in the container of the app. Use two dashes when using flags in your command, for example: `viktor-cli run -- ls -a` ``` viktor-cli run [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") --dns 1.1.1.1 (Docker only) Custom DNS servers (e.g. 1.1.1.1) (default []) --echo-command Only echo command, no execution -e, --env FOO=foo Additional environment variables (e.g. FOO=foo) (default []) -h, --help help for run --max-memory 500 (Docker only) Memory limit of the container in megabytes (e.g. 500) (default 500) --python 3.11 (Docker only) Python version used by the container (e.g. 3.11) (default "3.11") --region us1 Specify the region in case of a multi-region organization if different than the default defined in the configuration file (e.g. us1) -v, --volume {HOSTVOLUME}:{CONTAINERVOLUME} (Docker only) Additional volumes in container. Formatted as {HOSTVOLUME}:{CONTAINERVOLUME} (e.g. `/host/volume/path:/usr/src/docs` ``` ### start[​](/docs/create-apps/references/cli/.md#start "Direct link to start") Start the app, connect it to the platform and make it available in the browser for local development. The process can be stopped by pressing CTRL+C ``` viktor-cli start [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") --autoreload Deprecated: autoreload is enabled by default and can be disabled with the '--no-autoreload' flag --dns 1.1.1.1 (Docker only) Custom DNS servers (e.g. 1.1.1.1) (default []) --echo-command Only echo command, no execution -e, --env FOO=foo Additional environment variables (e.g. FOO=foo) (default []) -h, --help help for start --max-memory 500 (Docker only) Memory limit of the container in megabytes (e.g. 500) (default 500) --no-autoreload Do not automatically reload code upon file changes --region us1 Specify the region in case of a multi-region organization if different than the default defined in the configuration file (e.g. us1) --registered-name string Registered name of the app (see 'viktor-cli apps') to connect to. When not defined, the 'registered_name' in the viktor.config.toml file be used. --silence-warnings Silence all (deprecation) warnings on the command-line -v, --volume {HOSTVOLUME}:{CONTAINERVOLUME} (Docker only) Additional volumes in container. Formatted as {HOSTVOLUME}:{CONTAINERVOLUME} (e.g. `/host/volume/path:/usr/src/docs`) ``` ### test[​](/docs/create-apps/references/cli/.md#test "Direct link to test") Execute all unittests found inside the 'tests' directory, or in the 'path' provided. The following command is executed in case of a directory: `python -m unittest discover -s tests`, By providing the `--path` flag you can run specific tests (e.g. tests.test\_filename.TestClass.test\_function ``` viktor-cli test [flags] Flags: --app-dir string Path to the directory that contains the app code (default: current working directory). (default ".") --dns 1.1.1.1 (Docker only) Custom DNS servers (e.g. 1.1.1.1) (default []) --echo-command Only echo command, no execution -h, --help help for test --max-memory 500 (Docker only) Memory limit of the container in megabytes (e.g. 500) (default 500) --path string Dotted path to the component (directory, module, class, or method) that should be tested, e.g. 'tests.test_model.TestModel'. (default: discover in 'tests'). (default "tests") --region us1 Specify the region in case of a multi-region organization if different than the default defined in the configuration file (e.g. us1) ``` ### upgrade[​](/docs/create-apps/references/cli/.md#upgrade "Direct link to upgrade") Upgrade the CLI to the latest version. ``` viktor-cli upgrade [flags] Flags: -h, --help help for upgrade ``` ### version[​](/docs/create-apps/references/cli/.md#version "Direct link to version") Show the CLI version. ``` viktor-cli version [flags] Flags: -h, --help help for version ``` --- # Changelog All notable changes to the VIKTOR CLI will be documented in this file. *** ## v0.44.3 - 20/03/2025[​](/docs/create-apps/references/cli/changelog/.md#v0443---20032025 "Direct link to v0.44.3 - 20/03/2025") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed "Direct link to Fixed") * Prevent double reload on Windows by discarding file watch events for `__pycache__` directories *** ## v0.44.2 - 19/02/2025[​](/docs/create-apps/references/cli/changelog/.md#v0442---19022025 "Direct link to v0.44.2 - 19/02/2025") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed "Direct link to Changed") * Exit with proper code when error occurs during `ci-publish` *** ## v0.44.1 - 09/01/2025[​](/docs/create-apps/references/cli/changelog/.md#v0441---09012025 "Direct link to v0.44.1 - 09/01/2025") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-1 "Direct link to Changed") * Repeat tag and registered name before confirming publish ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-1 "Direct link to Fixed") * Do not trigger immediate reload when starting an app *** ## v0.44.0 - 19/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0440---19122024 "Direct link to v0.44.0 - 19/12/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added "Direct link to Added") * Attach digital signature to executable and installer *** ## v0.43.4 - 13/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0434---13122024 "Direct link to v0.43.4 - 13/12/2024") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-2 "Direct link to Fixed") * Set `UV_LINK_MODE=copy` to prevent installation errors when copying files inside virtual environment *** ## v0.43.3 - 10/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0433---10122024 "Direct link to v0.43.3 - 10/12/2024") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-3 "Direct link to Fixed") * Empty suggested app name when validation of registered name fails *** ## v0.43.2 - 09/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0432---09122024 "Direct link to v0.43.2 - 09/12/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-1 "Direct link to Added") * Add more information and options to 'invalid registered-name' prompt ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-4 "Direct link to Fixed") * Fix bug where registered-name would sometimes be treated as case-sensitive *** ## v0.43.1 - 02/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0431---02122024 "Direct link to v0.43.1 - 02/12/2024") *** ## v0.43.0 - 02/12/2024[​](/docs/create-apps/references/cli/changelog/.md#v0430---02122024 "Direct link to v0.43.0 - 02/12/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-2 "Direct link to Added") * Prompt to migrate development workspace when user maintains multiple apps * Add validation on provided registered-name, prompt to select if invalid ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-5 "Direct link to Fixed") * Fix error during publish when `assets_path` points to an empty directory *** ## v0.42.0 - 18/11/2024[​](/docs/create-apps/references/cli/changelog/.md#v0420---18112024 "Direct link to v0.42.0 - 18/11/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-3 "Direct link to Added") * Added `--use-pip` flag on the `install` command to switch to 'pip' as package manager (default is 'uv') ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-2 "Direct link to Changed") * The `install` command now uses 'uv' as package manager by default to improve performance ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-6 "Direct link to Fixed") * Fix setting incorrect UID / GID when running docker isolation on Windows *** ## v0.41.5 - 11/11/2024[​](/docs/create-apps/references/cli/changelog/.md#v0415---11112024 "Direct link to v0.41.5 - 11/11/2024") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-7 "Direct link to Fixed") * Fix quickstart command from unnecessarily prompting for `registered-name` *** ## v0.41.4 - 06/11/2024[​](/docs/create-apps/references/cli/changelog/.md#v0414---06112024 "Direct link to v0.41.4 - 06/11/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-4 "Direct link to Added") * Added `--registered-name` flag on the `clear` command ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-3 "Direct link to Changed") * Don't Prompt IDE when no IDEs are found on the machine of the user *** ## v0.41.3 - 04/11/2024[​](/docs/create-apps/references/cli/changelog/.md#v0413---04112024 "Direct link to v0.41.3 - 04/11/2024") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-8 "Direct link to Fixed") * Update false positive in `check-system` to properly handle new error format ## v0.41.2 - 29/10/2024[​](/docs/create-apps/references/cli/changelog/.md#v0412---29102024 "Direct link to v0.41.2 - 29/10/2024") *** ## v0.41.1 - 24/10/2024[​](/docs/create-apps/references/cli/changelog/.md#v0411---24102024 "Direct link to v0.41.1 - 24/10/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-4 "Direct link to Changed") * When running the `start`, `quickstart`, or `clean-start` commands the cli automatically updates to the latest version *** ## v0.41.0 - 24/10/2024[​](/docs/create-apps/references/cli/changelog/.md#v0410---24102024 "Direct link to v0.41.0 - 24/10/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-5 "Direct link to Added") * Support environment variable `VIKTOR_JS_SDK_PATH` used for WebView interaction * When running the `start` command the user is prompted to upgrade if a new cli version is available * Warn when starting an app that has no `registered_name` defined * Added `--registered-name` flag on the `start` command ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-5 "Direct link to Changed") * Removed environment variable `VIKTOR_SUBDOMAIN` which was incorrect and therefore has no use ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-9 "Direct link to Fixed") * Set ownership to HOME directory (docker isolation mode) to fix warnings regarding writing to cache (e.g. matplotlib, fontconfig etc.) *** ## v0.40.0 - 09/10/2024[​](/docs/create-apps/references/cli/changelog/.md#v0400---09102024 "Direct link to v0.40.0 - 09/10/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-6 "Direct link to Added") * Added marker for active account for account selection prompt * Support for Python 3.13 ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-6 "Direct link to Changed") * Automatically detect changes to `assets_path` when developing *** ## v0.39.0 - 05/09/2024[​](/docs/create-apps/references/cli/changelog/.md#v0390---05092024 "Direct link to v0.39.0 - 05/09/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-7 "Direct link to Added") * Added `hello-viktor` app to `quickstart` command * Added `activate` command * Added resources to the output table of the `apps` command ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-7 "Direct link to Changed") * Updated the embedded app templates to use a single viktor import * Updated style of the output table of the `apps` command *** ## v0.38.0 - 12/08/2024[​](/docs/create-apps/references/cli/changelog/.md#v0380---12082024 "Direct link to v0.38.0 - 12/08/2024") * Support blank apps in `quickstart` command *** ## v0.37.0 - 29/07/2024[​](/docs/create-apps/references/cli/changelog/.md#v0370---29072024 "Direct link to v0.37.0 - 29/07/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-8 "Direct link to Added") * Support Excel converter in `quickstart` command *** ## v0.36.2 - 24/07/2024[​](/docs/create-apps/references/cli/changelog/.md#v0362---24072024 "Direct link to v0.36.2 - 24/07/2024") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-10 "Direct link to Fixed") * Disable CGO *** ## v0.36.1 - 24/07/2024[​](/docs/create-apps/references/cli/changelog/.md#v0361---24072024 "Direct link to v0.36.1 - 24/07/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-8 "Direct link to Changed") * Updated golang to v1.22 and the dependencies to the latest versions ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-11 "Direct link to Fixed") * Remove venv when Python version check cannot be completed *** ## v0.36.0 - 25/06/2024[​](/docs/create-apps/references/cli/changelog/.md#v0360---25062024 "Direct link to v0.36.0 - 25/06/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-9 "Direct link to Added") * Added `quickstart` command to start developing from a sample app ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-12 "Direct link to Fixed") * Ignore nested `__pycache__` directories when gathering app files for publishing *** ## v0.35.0 - 29/04/2024[​](/docs/create-apps/references/cli/changelog/.md#v0350---29042024 "Direct link to v0.35.0 - 29/04/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-9 "Direct link to Changed") * Make `--tag` flag optional in `publish` command * Read `registered_name` from viktor.config.toml and make `--registered-name` flag optional in `publish` command ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-13 "Direct link to Fixed") * Fix URL to documentation in demo app *** ## v0.34.1 - 09/04/2024[​](/docs/create-apps/references/cli/changelog/.md#v0341---09042024 "Direct link to v0.34.1 - 09/04/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-10 "Direct link to Changed") * Removed installation of demo app from `get-started` command * When using `create-app` in GitHub Codespaces, the codespace Python version is set in viktor.config.toml * When using `publish` in GitHub Codespaces, the `--use-filesystem` flag will always be true * Ignore `__pycache__` directories when gathering app files for publishing *** ## v0.34.0 - 03/04/2024[​](/docs/create-apps/references/cli/changelog/.md#v0340---03042024 "Direct link to v0.34.0 - 03/04/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-10 "Direct link to Added") * Added `clean-start` command which combines `clear` + `install` + `start` * Support tag on `ci-publish` command ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-11 "Direct link to Changed") * Maximum length of publish tag increased from 20 to 128 characters *** ## v0.33.5 - 11/03/2024[​](/docs/create-apps/references/cli/changelog/.md#v0335---11032024 "Direct link to v0.33.5 - 11/03/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-11 "Direct link to Added") * Support environment variable `VIKTOR_CREDENTIALS` used for cloud-based development (e.g. GitHub Codespaces) ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-12 "Direct link to Changed") * Command `upgrade` logs new version when successfully upgraded * Set `x_axis_to_right=True` on `GeometryView` in demo * Command `check-system` now also verifies credentials * Removed neverssl check in `check-system` command *** ## v0.33.4 - 16/02/2024[​](/docs/create-apps/references/cli/changelog/.md#v0334---16022024 "Direct link to v0.33.4 - 16/02/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-13 "Direct link to Changed") * Improved internal error logging when freezing of virtual environment fails *** ## v0.33.3 - 12/02/2024[​](/docs/create-apps/references/cli/changelog/.md#v0333---12022024 "Direct link to v0.33.3 - 12/02/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-14 "Direct link to Changed") * Command `install` now uninstalls previous installation instead of removing the entire venv directory to resolve vscode intellisense (Pylance) issues * Omit the `` argument in the `create-app` command to create a new app in the current directory *** ## v0.33.2 - 02/02/2024[​](/docs/create-apps/references/cli/changelog/.md#v0332---02022024 "Direct link to v0.33.2 - 02/02/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-15 "Direct link to Changed") * Per user installation of CLI to no longer require administrator privileges *** ## v0.33.1 - 11/01/2024[​](/docs/create-apps/references/cli/changelog/.md#v0331---11012024 "Direct link to v0.33.1 - 11/01/2024") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-16 "Direct link to Changed") * Set default Python version of demo app to 3.12 ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-14 "Direct link to Fixed") * Unpin numpy in demo app to fix compatibility with Python 3.12 *** ## v0.33.0 - 08/01/2024[​](/docs/create-apps/references/cli/changelog/.md#v0330---08012024 "Direct link to v0.33.0 - 08/01/2024") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-12 "Direct link to Added") * Support for Python 3.12 * Show message to user if token has been deactivated ### Deprecated[​](/docs/create-apps/references/cli/changelog/.md#deprecated "Direct link to Deprecated") * Deprecated Python 3.8 *** ## v0.32.0 - 24/11/2023[​](/docs/create-apps/references/cli/changelog/.md#v0320---24112023 "Direct link to v0.32.0 - 24/11/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-13 "Direct link to Added") * Support 'packages' in viktor.config.toml *** ## v0.31.2 - 01/11/2023[​](/docs/create-apps/references/cli/changelog/.md#v0312---01112023 "Direct link to v0.31.2 - 01/11/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-17 "Direct link to Changed") * Add a flag to use pip truststore, this allows users to disable installation with truststore *** ## v0.31.1 - 31/10/2023[​](/docs/create-apps/references/cli/changelog/.md#v0311---31102023 "Direct link to v0.31.1 - 31/10/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-18 "Direct link to Changed") * Removed neverssl check from newAPI function *** ## v0.31.0 - 24/10/2023[​](/docs/create-apps/references/cli/changelog/.md#v0310---24102023 "Direct link to v0.31.0 - 24/10/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-19 "Direct link to Changed") * When available use `truststore` feature of pip to prevent SSL installation errors *** ## v0.30.7 - 23/10/2023[​](/docs/create-apps/references/cli/changelog/.md#v0307---23102023 "Direct link to v0.30.7 - 23/10/2023") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-15 "Direct link to Fixed") * Warning for Python version was always triggered instead of only for invalid Python versions *** ## v0.30.6 - 17/10/2023[​](/docs/create-apps/references/cli/changelog/.md#v0306---17102023 "Direct link to v0.30.6 - 17/10/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-20 "Direct link to Changed") * Log warning when found Python version with Python Launcher is not supported for use with VIKTOR *** ## v0.30.5 - 11/10/2023[​](/docs/create-apps/references/cli/changelog/.md#v0305---11102023 "Direct link to v0.30.5 - 11/10/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-21 "Direct link to Changed") * Added 'command' sentry tag on all commands * Print files to be uploaded during publish and prompt user to continue *** ## v0.30.4 - 19/09/2023[​](/docs/create-apps/references/cli/changelog/.md#v0304---19092023 "Direct link to v0.30.4 - 19/09/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-22 "Direct link to Changed") * Updated golang to v1.21 and the dependencies to the latest versions *** ## v0.30.3 - 28/08/2023[​](/docs/create-apps/references/cli/changelog/.md#v0303---28082023 "Direct link to v0.30.3 - 28/08/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-23 "Direct link to Changed") * Capture actual error message when activation code cannot be obtained *** ## v0.30.2 - 07/08/2023[​](/docs/create-apps/references/cli/changelog/.md#v0302---07082023 "Direct link to v0.30.2 - 07/08/2023") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-16 "Direct link to Fixed") * get-started now installs demo app in temporary dir to fix potential permission errors * `check-system` removed fall-back on ping command when curl is not available since it is unable to receive *** ## v0.30.1 - 18/07/2023[​](/docs/create-apps/references/cli/changelog/.md#v0301---18072023 "Direct link to v0.30.1 - 18/07/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-14 "Direct link to Added") * Added a prompt to overwrite configuration file entry if it is already present while rerunning the `get-started` command *** ## v0.30.0 - 11/07/2023[​](/docs/create-apps/references/cli/changelog/.md#v0300---11072023 "Direct link to v0.30.0 - 11/07/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-15 "Direct link to Added") * Read 'assets\_path' from viktor.config.toml and upload assets to S3 ### Removed[​](/docs/create-apps/references/cli/changelog/.md#removed "Direct link to Removed") * Removed `--region` flag from `publish`, `ci-publish`, `apps`, `describe` commands since apps are now automatically synced *** ## v0.29.11 - 16/06/2023[​](/docs/create-apps/references/cli/changelog/.md#v02911---16062023 "Direct link to v0.29.11 - 16/06/2023") * Only autoselect Python installation when running get-started, print the selected path and give hint how to change *** ## v0.29.10 - 09/06/2023[​](/docs/create-apps/references/cli/changelog/.md#v02910---09062023 "Direct link to v0.29.10 - 09/06/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-16 "Direct link to Added") * Add max-memory flag to install and test command to prevent container crashing on large packages ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-24 "Direct link to Changed") * `check-system` command shouldn't fail because curl or ping is not installed, instead a nil error is returned and message is logged in Sentry *** ## v0.29.9 - 24/05/2023[​](/docs/create-apps/references/cli/changelog/.md#v0299---24052023 "Direct link to v0.29.9 - 24/05/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-25 "Direct link to Changed") * Updated the text of the last step in demo app including utm source tag for tracking the clickthrough rate into the tutorial *** ## v0.29.8 - 16/05/2023[​](/docs/create-apps/references/cli/changelog/.md#v0298---16052023 "Direct link to v0.29.8 - 16/05/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-17 "Direct link to Added") * Added Stdout output to error tracking in Sentry when installation of the demo app fails ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-17 "Direct link to Fixed") * Properly skip virtual environment and .git directories during publish *** ## v0.29.7 - 26/04/2023[​](/docs/create-apps/references/cli/changelog/.md#v0297---26042023 "Direct link to v0.29.7 - 26/04/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-26 "Direct link to Changed") * Removed sentry error tracking when directory cannot be created or app files cannot be copied in `create-app` command *** ## v0.29.6 - 13/04/2023[​](/docs/create-apps/references/cli/changelog/.md#v0296---13042023 "Direct link to v0.29.6 - 13/04/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-27 "Direct link to Changed") * Select the currently active account by default instead of the default account when running configure without --name flag ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-18 "Direct link to Fixed") * Exclude false positive curl error from system check *** ## v0.29.5 - 12/04/2023[​](/docs/create-apps/references/cli/changelog/.md#v0295---12042023 "Direct link to v0.29.5 - 12/04/2023") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-19 "Direct link to Fixed") * Demo app crashes due to removed UserException in SDK v14 *** ## v0.29.4 - 12/04/2023[​](/docs/create-apps/references/cli/changelog/.md#v0294---12042023 "Direct link to v0.29.4 - 12/04/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-28 "Direct link to Changed") * Get latest SDK from PyPI instead of system ### Removed[​](/docs/create-apps/references/cli/changelog/.md#removed-1 "Direct link to Removed") * Removed U83 flag from app templates *** ## v0.29.3 - 17/03/2023[​](/docs/create-apps/references/cli/changelog/.md#v0293---17032023 "Direct link to v0.29.3 - 17/03/2023") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-20 "Direct link to Fixed") * Fixed numpy in demo app not compatible with Python 3.7 *** ## v0.29.2 - 17/03/2023[​](/docs/create-apps/references/cli/changelog/.md#v0292---17032023 "Direct link to v0.29.2 - 17/03/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-29 "Direct link to Changed") * Raise error when defining viktor in requirements.txt with a leading hashtag in combination with SDK > v13 ### Deprecated[​](/docs/create-apps/references/cli/changelog/.md#deprecated-1 "Direct link to Deprecated") * Python 3.7 *** ## v0.29.1 - 02/03/2023[​](/docs/create-apps/references/cli/changelog/.md#v0291---02032023 "Direct link to v0.29.1 - 02/03/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-30 "Direct link to Changed") * Cleaned up sentry error tracking and included curl exit status in sentry error tracking *** ## v0.29.0 - 24/02/2023[​](/docs/create-apps/references/cli/changelog/.md#v0290---24022023 "Direct link to v0.29.0 - 24/02/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-18 "Direct link to Added") * Added support for viktor in requirements.txt without a leading hashtag * Support Python 3.11 in viktor.config.toml ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-31 "Direct link to Changed") * Upgrade to go 1.20 * Added available options for app-type in `create-app` command help ### Deprecated[​](/docs/create-apps/references/cli/changelog/.md#deprecated-2 "Direct link to Deprecated") * Defining viktor in requirements.txt with a leading hashtag ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-21 "Direct link to Fixed") * Fix bug that autoreload didn't work if app folder name starts with "test" * Reverted pip install arguments back to a slice of strings as a single string doesn't work on Windows *** ## v0.28.0 - 08/02/2023[​](/docs/create-apps/references/cli/changelog/.md#v0280---08022023 "Direct link to v0.28.0 - 08/02/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-32 "Direct link to Changed") * Updated install command to be able to insert additional environment variables * Added "SDK version" to output of `apps` command * Added "App type", "SDK version", and "Python version" to output of `describe` command *** ## v0.27.6 - 03/02/2023[​](/docs/create-apps/references/cli/changelog/.md#v0276---03022023 "Direct link to v0.27.6 - 03/02/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-33 "Direct link to Changed") * Added provided path to error message when python installation is not valid * Added `--region` flag for multi-region architecture *** ## v0.27.5 - 02/02/2023[​](/docs/create-apps/references/cli/changelog/.md#v0275---02022023 "Direct link to v0.27.5 - 02/02/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-34 "Direct link to Changed") * Added clearer error messages why a Python version is not valid and when the activation code is expired *** ## v0.27.4 - 27/01/2023[​](/docs/create-apps/references/cli/changelog/.md#v0274---27012023 "Direct link to v0.27.4 - 27/01/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-35 "Direct link to Changed") * Track exact error that python path prompt returns, added cli version to sentry message *** ## v0.27.3 - 25/01/2023[​](/docs/create-apps/references/cli/changelog/.md#v0273---25012023 "Direct link to v0.27.3 - 25/01/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-36 "Direct link to Changed") * Add message to get-started command that window shouldn't be closed *** ## v0.27.2 - 23/01/2023[​](/docs/create-apps/references/cli/changelog/.md#v0272---23012023 "Direct link to v0.27.2 - 23/01/2023") ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-22 "Direct link to Fixed") * Fixed bug in regex that didn't handle spaces in Python paths correctly *** ## v0.27.1 - 20/01/2023[​](/docs/create-apps/references/cli/changelog/.md#v0271---20012023 "Direct link to v0.27.1 - 20/01/2023") ### Added[​](/docs/create-apps/references/cli/changelog/.md#added-19 "Direct link to Added") * Implemented Sentry to track errors in the get-started flow *** ## v0.27.0 - 17/01/2023[​](/docs/create-apps/references/cli/changelog/.md#v0270---17012023 "Direct link to v0.27.0 - 17/01/2023") ### Changed[​](/docs/create-apps/references/cli/changelog/.md#changed-37 "Direct link to Changed") * change configuration name generation to support multiregion * Place activation code for get-started on newline * Update warning for python version on how development version can be changed * Watch entire project folder, instead of just app.py or /app/ folder ### Fixed[​](/docs/create-apps/references/cli/changelog/.md#fixed-23 "Direct link to Fixed") * Support Python launcher 3.11 regex format when gathering available python installations *** --- # SDK --- # viktor.config.toml New in v13.2.0 The `viktor.config.toml` file is used to set configuration settings for your app, and is placed on the top-level of the application folder: ``` my-folder ├── app.py ├── requirements.txt └── viktor.config.toml ``` The `viktor.config.toml` file is written in [TOML](https://toml.io/en/) language, which is very similar to basic Python syntax. ## app\_type[​](/docs/create-apps/references/viktor-config-toml/.md#app_type "Direct link to app_type") Changed in v13.3.0 The entry `app_type` has become obligatory. The `app_type` entry in the `viktor.config.toml` file defines the type of app. App layout, requirements and corresponding feedback errors might differ depending on the chosen app type. Currently, the following types are available: * `editor`: allows for 1 (and only 1) entity type, of which the user can only edit a single entity. The entity is not shared among multiple users (i.e. every user works in a unique session). * `simple`: allows for 1 (and only 1) entity type, of which the user can make unlimited entities. Entities are shared among multiple users. * `tree`: no restriction on the number of entity types. An entity type hierarchy can be created by defining `children` on the parent entity type [controller](/docs/getting-started/fundamentals/basic-app-structure/.md#the-controller). Entities are shared among multiple users. ``` app_type = 'simple' # 'editor' | 'simple' | 'tree' ``` More information on these app types and tutorials can be found [here](/docs/getting-started/fundamentals/app-types/.md). ## assets\_path[​](/docs/create-apps/references/viktor-config-toml/.md#assets_path "Direct link to assets_path") New in v14.3.0 Defines the directory where assets (e.g. images) are stored. These assets can be used as, for example, [static images](/docs/create-apps/inform-end-user/static-image/.md). ``` assets_path = 'assets' ``` ## enable\_privileged\_api[​](/docs/create-apps/references/viktor-config-toml/.md#enable_privileged_api "Direct link to enable_privileged_api") With the `enable_privileged_api` key, the application code is able to [bypass user access restrictions](/docs/api/sdk/.md#bypassing-user-access-restrictions): ``` enable_privileged_api = true # true | false ``` ## packages[​](/docs/create-apps/references/viktor-config-toml/.md#packages "Direct link to packages") Any system dependency that is not a Python package can be listed here. System packages will be installed when the application is built and should be [apt-get compatible](https://linux.die.net/man/8/apt-get): ``` packages = [ "python3-opencv", "tesseract-ocr", ... ] ``` ## python\_version[​](/docs/create-apps/references/viktor-config-toml/.md#python_version "Direct link to python_version") note This Python version **does not** affect the Python version that is used for development with `venv` as isolation mode, which is specified using the [`configure`](/docs/create-apps/references/cli/.md#configure) command instead! Specify the Python version to publish the application with: ``` python_version = '3.13' # '3.10' | '3.11' | '3.12' | '3.13' ``` ## welcome\_text[​](/docs/create-apps/references/viktor-config-toml/.md#welcome_text "Direct link to welcome_text") note Supported for `app_type = 'tree'` only A welcome text can be customized, which will be shown to the user upon entering the application dashboard. The value is a path pointing to a file located relative to `viktor.config.toml`. The file supports [styling with Markdown](/docs/create-apps/layout-and-styling/style-text/.md): ``` welcome_text = "welcome.md" ``` With `welcome.md`: ``` ## Welcome to your very first [VIKTOR](https://www.viktor.ai/) application! Get started engineering the **awesome** today While automating the *boring*! ``` ![](/assets/images/formatting-welcome-text-6b965a61bd4526c48897e1f2973c8aff.png) ## registered\_name[​](/docs/create-apps/references/viktor-config-toml/.md#registered_name "Direct link to registered_name") Specify the app name you want to publish on. This value will be overwritten if the *registered-name* flag is specified in viktor-cli command such below: ``` viktor-cli publish --registered-name my-first-app ``` ## oauth2\_integrations[​](/docs/create-apps/references/viktor-config-toml/.md#oauth2_integrations "Direct link to oauth2_integrations") note Supported on non-public apps only. Otherwise OAuth 2.0 connection(s) will not be prompted to the users, when they enter the editor. Defines the OAuth 2.0 integration to be prompted to the user when they enter the editor. You can specify the integrations as below: ``` oauth2_integrations = [ "microsoft-entra" ] ``` In order to see the available OAuth 2.0 integrations, navigate to the app details page of your app. --- # Results & visualizations Within an editor, results are shown in so-called **views**. VIKTOR support various view classes for different type of results. For information on how to define a view, see [how to create an editor](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-view). ## Plots, charts & graphs[​](/docs/create-apps/results-and-visualizations/.md#plots-charts--graphs "Direct link to Plots, charts & graphs") ![](/img/docs/cards/plotly.svg) ## [Plot](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#using-plotly) Show (interactive) plots, graphs and charts ![](/img/docs/cards/plotly+data.svg) ## [Plot & data](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#using-plotly) Combined plot & data view ## Geometry[​](/docs/create-apps/results-and-visualizations/.md#geometry "Direct link to Geometry") ![](/img/docs/cards/geometry.svg) ## [3D model](/docs/create-apps/results-and-visualizations/threed-model/.md) Show a geometric 3D model, glTF/GLB, 3DM, or IFC file ![](/img/docs/cards/geometry+data.svg) ## [3D model & data](/docs/create-apps/results-and-visualizations/threed-model/.md) Combined 3D & data view ## Maps[​](/docs/create-apps/results-and-visualizations/.md#maps "Direct link to Maps") ![](/img/docs/cards/map.svg) ## [Map](/docs/create-apps/results-and-visualizations/map/.md#mapview) Display features on a map ![](/img/docs/cards/map+data.svg) ## [Map & data](/docs/create-apps/results-and-visualizations/map/.md#mapview) Combined map & data view
![](/img/docs/cards/GeoJSON.svg) ## [GeoJSON](/docs/create-apps/results-and-visualizations/map/.md#geojsonview) Display GeoJSON primitives on a map ![](/img/docs/cards/GeoJSON+data.svg) ## [GeoJSON & data](/docs/create-apps/results-and-visualizations/map/.md#geojsonview) Combined GeoJSON map & data view ## Data & tables[​](/docs/create-apps/results-and-visualizations/.md#data--tables "Direct link to Data & tables") ![](/img/docs/cards/table-view.svg) ## [Table](/docs/create-apps/results-and-visualizations/data-and-tables/.md#tableview) Present data in a table ![](/img/docs/cards/data.svg) ## [Grouped data](/docs/create-apps/results-and-visualizations/data-and-tables/.md#dataview) Present results in data groups ## Images[​](/docs/create-apps/results-and-visualizations/.md#images "Direct link to Images") ![](/img/docs/cards/png.svg) ## [PNG image](/docs/create-apps/results-and-visualizations/images/.md) Show a PNG image ![](/img/docs/cards/png+data.svg) ## [PNG & data](/docs/create-apps/results-and-visualizations/images/.md) Combined PNG & data view
![](/img/docs/cards/jpg.svg) ## [JPG image](/docs/create-apps/results-and-visualizations/images/.md) Show a JPG image ![](/img/docs/cards/jpg+data.svg) ## [JPG & data](/docs/create-apps/results-and-visualizations/images/.md) Combined JPG & data view
![](/img/docs/cards/svg.svg) ## [SVG image](/docs/create-apps/results-and-visualizations/images/.md) Show an SVG image ![](/img/docs/cards/svg+data.svg) ## [SVG & data](/docs/create-apps/results-and-visualizations/images/.md) Combined SVG & data view
New in v13.7.0 ![](/img/docs/cards/gif.svg) ## [GIF image](/docs/create-apps/results-and-visualizations/images/.md) Show a GIF image New in v13.7.0 ![](/img/docs/cards/gif+data.svg) ## [GIF & data](/docs/create-apps/results-and-visualizations/images/.md) Combined GIF & data view ## Documents & reports[​](/docs/create-apps/results-and-visualizations/.md#documents--reports "Direct link to Documents & reports") ![](/img/docs/cards/pdf.svg) ## [PDF report](/docs/create-apps/results-and-visualizations/report/.md) Present a PDF file directly in a view ## HTML[​](/docs/create-apps/results-and-visualizations/.md#html "Direct link to HTML") ![](/img/docs/cards/html.svg) ## [HTML](/docs/create-apps/results-and-visualizations/html/.md) Present interactive visualizations or other HTML (web) content ![](/img/docs/cards/html+data.svg) ## [HTML & data](/docs/create-apps/results-and-visualizations/html/.md) Combined HTML & data view --- # Show data & tables There are two different ways to present data in a view: * For a table-like presentation of data, you can use the [TableView](/docs/create-apps/results-and-visualizations/data-and-tables/.md#tableview) * For a tree-like presentation of grouped data (flat or nested), you can use the [DataView](/docs/create-apps/results-and-visualizations/data-and-tables/.md#dataview) ## TableView[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#tableview "Direct link to TableView") New in v14.13.0 note The `TableView` is a trade-off between simplicity and flexibility. If you need more control on styling, [this package](https://github.com/viktor-platform/viktor_table_view) might suit your needs. It uses a `WebView` under the hood. The [`TableView`](/sdk/api/views/.md#_TableView) provides means to present data in a tabular form. The view has a button to download the data as CSV. ![](/assets/images/view-table-746ed1cbfa21465b02b03787057ea62b.png) *Example TableView* A table view can be created by passing data to a [`TableResult`](/sdk/api/views/.md#_TableResult) in a view-method decorated with `@TableView`: ``` from datetime import date import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Student Grades") def table_view(self, params, **kwargs): data = [ [128, "John", 6.9, False, date(1994, 6, 3)], [129, "Jane", 8.1, True, date(1995, 1, 24)], [130, "Mike", 7.5, False, date(1989, 12, 4)], ] return vkt.TableResult(data) ``` ### Custom headers[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#custom-headers "Direct link to Custom headers") Custom headers can be set on both rows and columns by passing respectively `row_headers` and `column_headers` in the `TableResult`: ``` @vkt.TableView("Student Grades") def table_view(self, params, **kwargs): ... return vkt.TableResult( data, row_headers=["Person 1", "Person 2", "Person 3"], column_headers=["Student nr.", "Name", "Grade", "Cum laude", "Date of birth"] ) ``` If no headers are provided, the default headers (1, 2, 3, ...) will be shown. ### Sorting & filtering[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#sorting--filtering "Direct link to Sorting & filtering") Sorting & filtering is automatically enabled on the columns if each of the columns contains data of homogeneous type. You can disable sorting & filtering by setting `enable_sorting_and_filtering=False` on the `TableResult`: ``` return vkt.TableResult(..., enable_sorting_and_filtering=False) ``` ### Styling[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#styling "Direct link to Styling") Styling on a per-cell basis can be applied by replacing the value in data with a [`TableCell`](/sdk/api/views/.md#_TableCell) instance. The following styling can be applied on a per-cell basis: * `text_color`: color of the text. Can be any [`Color`](/sdk/api/core/.md#_Color) * `background_color`: color of the cell background. Can be any [`Color`](/sdk/api/core/.md#_Color) * `text_style`: style of the text. Can be one of: 'bold', 'italic' ``` import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Table") def table_view(self, params, **kwargs): data = [ [1, 2, 1], [2, TableCell(3, background_color=vkt.Color.green()), 2], [1, 2, 1], ] return vkt.TableResult(data) ``` Styling on a per-column/row basis can be applied by setting a [`TableHeader`](/sdk/api/views/.md#_TableHeader) on respectively `column_headers` or `row_headers` within `TableResult`. The following styling can be applied on a per-column/row basis: * `num_decimals`: number of decimals to which the value is rounded (numbers only) * `align`: alignment of the text within the column/row. Can be one of: 'left', 'center', 'right' ``` import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Student Grades") def table_view(self, params, **kwargs): data = [ ["John", 6.9], ["Jane", 8.1], ["Mike", 7.5], ] return vkt.TableResult(data, column_headers=[ "Name", vkt.TableHeader("Grade", num_decimals=0) ]) ``` ### Transposing the data[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#transposing-the-data "Direct link to Transposing the data") Sometimes it is preferred to present data in a transposed table (with homogeneous types on rows instead of columns), for example when the number of columns would otherwise be much larger than the number of rows. This can simply be achieved by transposing the data yourself, and exchanging `row_headers` and `column_headers` in the `TableResult`, as shown in the following example: note Sorting & filtering is disabled if one or more columns contain mixed-type data. ``` from datetime import date import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Student Grades") def table_view(self, params, **kwargs): data = [ [128, "John", 6.9, False, date(1994, 6, 3)], [129, "Jane", vkt.TableCell(8.1, background_color=vkt.Color.green()), True, date(1995, 1, 24)], [130, "Mike", 7.5, False, date(1989, 12, 4)], ] transposed_data = [list(d) for d in zip(*data)] return vkt.TableResult( transposed_data, row_headers=["Student nr.", "Name", "Grade", "Cum laude", "Date of birth"], column_headers=["Person 1", "Person 2", "Person 3"], ) ``` ![](/assets/images/view-table-transposed-5cd5293370b74629fb24c55d3c1a66c6.png) *Example of transposed table* ### Using pandas[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#using-pandas "Direct link to Using pandas") It is possible to pass a [pandas](https://pypi.org/project/pandas/) `DataFrame` or `Styler` object directly into a `TableResult`. The column and index names of the `DataFrame` will be taken as `columns_headers` and `row_headers` respectively: note Setting explicit `columns_headers` and `row_headers` in `TableResult` will override the column and index names of the pandas `DataFrame`. ``` from datetime import date import pandas as pd import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Table") def table_view(self, params, **kwargs): df = pd.DataFrame( data=[ [128, "John", 6.9, False, date(1994, 6, 3)], [129, "Jane", 8.1, True, date(1995, 1, 24)], [130, "Mike", 7.5, False, date(1989, 12, 4)], ], columns=["Student nr.", "Name", "Grade", "Cum laude", "Date of birth"], index=["Person 1", "Person 2", "Person 3"], ) return vkt.TableResult(df) ``` The following styling properties of a pandas `Styler` object are supported: * Background color (per cell) * Text color (per cell) * Text style (per cell, bold or italic) * Align (per column/row, only if all cells in a row/column have the same alignment) note To make use of pandas styling, you need to add the `pandas[output-formatting]` package to your `requirements.txt` ``` from datetime import date import pandas as pd import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Table") def table_view(self, params, **kwargs): df = pd.DataFrame( data=[ [128, "John", 6.9, False, date(1994, 6, 3)], [129, "Jane", 8.1, True, date(1995, 1, 24)], [130, "Mike", 7.5, False, date(1989, 12, 4)], ], columns=["Student nr.", "Name", "Grade", "Cum laude", "Date of birth"], index=["Person 1", "Person 2", "Person 3"], ) df = df.transpose() styler = df.style.highlight_max(color="green", axis='columns', subset=pd.IndexSlice[['Grade'], :]) return vkt.TableResult(styler) ``` ## DataView[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#dataview "Direct link to DataView") With a [`DataView`](/sdk/api/views/.md#_DataView), results can be grouped and be presented in a tree-like form. The data can be flat, or nested up to a maximum of 3 levels. ![](/assets/images/view-data-9bcd199b897b465b7fa34be0e08972ba.png) *Example DataView* The following steps have to be performed to visualize the desired results: 1. Create the data group(s) consisting of [`DataItem`](/sdk/api/views/.md#_DataItem)s for visualization. 2. Pass the group(s) to a decorated view method that returns a [`DataResult`](/sdk/api/views/.md#_DataResult). ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Results") def visualize_data(self, params, **kwargs): data = vkt.DataGroup( vkt.DataItem('Data item 1', 123) ) return vkt.DataResult(data) ``` ### Multilayered DataGroup[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#multilayered-datagroup "Direct link to Multilayered DataGroup") Below an example is given of a multilayered output group (maximum of three layers deep): ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Results") def visualize_data(self, params, **kwargs): value_a = 1 value_b = 2 * value_a value_total = value_a + value_b data = vkt.DataGroup( group_a=vkt.DataItem('Group A', 'some result', subgroup=vkt.DataGroup( sub_group=vkt.DataItem('Result', 1, suffix='N') )), group_b=vkt.DataItem('Group B', '', subgroup=vkt.DataGroup( sub_group=vkt.DataItem('Sub group', value_total, prefix='€', subgroup=vkt.DataGroup( value_a=vkt.DataItem('Value A', value_a, prefix='€'), value_b=vkt.DataItem('Value B', value_b, prefix='€', explanation_label='this value is a result of multiplying Value A by 2') )) )) ) return vkt.DataResult(data) ``` The `explanation_label` can be used to inform the user. The output result will look like this: ![](/assets/images/data-view-example-1-65c4d7593a0a51aa5bc081853619dbff.png) *Example DataView* ### Positional or key-worded DataItem?[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#positional-or-key-worded-dataitem "Direct link to Positional or key-worded DataItem?") In previous examples, we saw a DataGroup created with and without the use of keyword arguments. Using keywords is necessary to link the corresponding `DataItem` to the `Summary`. A detailed guide of the `Summary` can be found [here](/docs/create-apps/results-and-visualizations/show-summary/.md). ### Dynamic group length[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#dynamic-group-length "Direct link to Dynamic group length") The structure of `DataGroup`s allows for dynamic creation/addition of data to the overall result, as long as the maximum number of items is not exceeded. An example of dynamically creating data items is shown below: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Results") def visualize_data(self, params, **kwargs): dynamic_dict = { "item 1": 1, "item 2": 2, # etc. } # loop through items total_value = 0 data_items = [] for item, value in dynamic_dict.items(): data_items.append( vkt.DataItem(item, value) ) total_value += value # construct data group data = vkt.DataGroup(*data_items) return vkt.DataResult(data) ``` ### Setting warning/error statuses[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#setting-warningerror-statuses "Direct link to Setting warning/error statuses") Sometimes it is desired to warn a user when a result exceeds a certain values. For these cases, the `status` and `status_message` arguments of a `DataItem` can be considered. Suppose we want to warn the user if our shopping cart of the example above exceeds 5 euros, we can add the following: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Results") def visualize_data(self, params, **kwargs): shopping_cart = { 'Apple': 0.20, 'Pineapple': 1.80, 'Milk': 1, 'Cheese': 2.50 } # loop through products total_cost = 0 data_items = [] for item, price in shopping_cart.items(): data_items.append( vkt.DataItem(item, price, prefix='€') ) total_cost += price # construct data group if total_cost <= 5: status = vkt.DataStatus.SUCCESS status_msg = '' else: status = vkt.DataStatus.WARNING status_msg = 'Mind your wallet!' data = vkt.DataGroup( vkt.DataItem('Shopping cart', total_cost, prefix='€', status=status, status_message=status_msg, subgroup=vkt.DataGroup(*data_items)) ) return vkt.DataResult(data) ``` ![](/assets/images/data-view-example-2-a711f1319846127779c99ae12be0d68f.png) *Example status message* ## Testing[​](/docs/create-apps/results-and-visualizations/data-and-tables/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@TableView` and `@DataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing: ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_data_view(self): params = ... result = MyEntityTypeController().data_view(params=params) self.assertEqual(result.data, ...) ``` --- # Hide a view New in v14.22.0 A view can be hidden (or shown) based on other input fields by assigning a callback function to the `visible` argument within the view. The callback function needs to return a **boolean**: ``` def get_visibility(params, **kwargs): return params.param_x class Controller(vkt.Controller): ... @vkt.TableView("Results", visible=get_visibility) def my_table_view(self, params, **kwargs): ... ``` If a [`Page`](/docs/create-apps/layout-and-styling/pages/.md) or [`Step`](/docs/create-apps/layout-and-styling/steps/.md) is used, views will only be visible in the editor if they are both visible **and** defined in the page/step's `views`. When the visibility depends on data of another entity, the `entity_id` can be used to navigate and obtain data using the [SDK API](/docs/api/sdk/handling-entity-data/.md). tip Upon evaluation of the visibility constraint, the platform passes the `params`, `entity_id`, `entity_name`, and `workspace_id` to the callback function. All individual `kwargs` can be added explicitly in the signature if desired: ``` def get_visibility(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` --- # Show HTML Plotly For visualizations using [Plotly](https://github.com/plotly/plotly.py), it is recommended to use the dedicated [`PlotlyView`](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#using-plotly). This guide explains how to add a [`WebView`](/sdk/api/views/.md#_WebView) to an editor. This could for instance be used to incorporate [interactive visualizations](/docs/create-apps/results-and-visualizations/html/.md#interactive-visualizations) or present other dynamic or static HTML (web) content: ## Implementation[​](/docs/create-apps/results-and-visualizations/html/.md#implementation "Direct link to Implementation") ![](/assets/images/plotly-example-7cc2c057d48c72d55f332639cf4e3707.png) *Example of how an interactive visualization in a web view could look like (source: plot.ly)* There are 3 ways to pass the HTML content to a [`WebResult`](/sdk/api/views/.md#_WebResult): 1. From a [URL](/docs/create-apps/results-and-visualizations/html/.md#from-a-url) 2. From a [static HTML file](/docs/create-apps/results-and-visualizations/html/.md#from-a-static-html-file) 3. From a [dynamic HTML content](/docs/create-apps/results-and-visualizations/html/.md#from-dynamic-html-content) ### From a URL[​](/docs/create-apps/results-and-visualizations/html/.md#from-a-url "Direct link to From a URL") You can point to a live URL and use that HTML page: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.WebView('Python wiki') def get_web_view(self, params, **kwargs): return vkt.WebResult(url='https://en.wikipedia.org/wiki/Python_(programming_language)') ``` ### From a static HTML file[​](/docs/create-apps/results-and-visualizations/html/.md#from-a-static-html-file "Direct link to From a static HTML file") If the HTML page is always the same (it is not necessary to generate it on every call), use the `from_path` method to construct a `WebResult`: ``` import viktor as vkt from pathlib import Path class Controller(vkt.Controller): @vkt.WebView('Hello page') def get_web_view(self, params, **kwargs): static_html_path = Path(__file__).parent / 'page.html' return vkt.WebResult.from_path(static_html_path) ``` `page.html` (in this example next to controller.py): ``` Hello Everyone! ``` ### From dynamic HTML content[​](/docs/create-apps/results-and-visualizations/html/.md#from-dynamic-html-content "Direct link to From dynamic HTML content") If the HTML page is dependent on some input (so needs to be generated on every call), use the `html` argument in `WebResult`: ``` import viktor as vkt from io import StringIO class Controller(vkt.Controller): @vkt.WebView('Hello page') def get_web_view(self, params, **kwargs): name = 'John Doe' html_text = f'Hello {name}' return vkt.WebResult(html=html_text) ``` A web view can be combined with a data view using a [`WebAndDataView`](/sdk/api/views/.md#_WebAndDataView). ## Interactive visualizations[​](/docs/create-apps/results-and-visualizations/html/.md#interactive-visualizations "Direct link to Interactive visualizations") A very useful application of the web view is for interactive visualizations (for instance maps/graphs). ### VIKTOR JavaScript SDK[​](/docs/create-apps/results-and-visualizations/html/.md#viktor-javascript-sdk "Direct link to VIKTOR JavaScript SDK") VIKTOR provides a JavaScript SDK which can be used directly in a web view. With this SDK it is possible to fill the parametrization with inputs when a user clicks on a button in the view. To achieve this, you will need to import the SDK using and subsequently call the function `viktorSdk.sendParams`. This function accepts a dictionary of field names and corresponding values which are applied on the parametrization. An example HTML file looks like this: ``` ``` In the example above the source of the JavaScipt SDK is set by means of the variable `VIKTOR_JS_SDK`. You set it using the environment variable `VIKTOR_JS_SDK_PATH`, that is available automatically in your app's logic. This means dat you do not need to set it using the viktor-cli (`>v0.41.0`) or in your app settings. The example below shows how to properly reference the JavaScript SDK: ``` import viktor as vkt import os from pathlib import Path class Parametrization(vkt.Parametrization): hello = vkt.TextField("Hello") class Controller(vkt.Controller): parametrization = Parametrization @vkt.WebView('Web View') def get_web_view(self, params, **kwargs): html = (Path(__file__).parent / 'example.html').read_text() html = html.replace("VIKTOR_JS_SDK", os.environ["VIKTOR_JS_SDK_PATH"] + "v1.js") return vkt.WebResult(html=html) ``` Above `example.html` and app code will result in the following interactive view: ![](/assets/images/webview-interaction-8dce68fd01ac3b2a1e0163b2998e5939.gif) By default, a confirmation pop-up is shown. To **bypass the confirmation pop-up** and set parameters immediately, add an extra argument set to `true`: ``` ... function sendName() { viktorSdk.sendParams({ hello: "VIKTOR" }, true); } ... ``` caution * To set fields nested under a `Page`, `Step`, `Tab` or `Section` you can either return a nested object or use the dotted path (e.g. `"tab.section.hello"`) in the `sendParams` method. * Keep in mind that the `sendParams` function only accepts the **serialized** values. For example, the value of a `ColorField` is sent as: ``` viktorSdk.sendParams({ color: {r: 30, g: 144, b: 255} }); ``` Show all fields ``` viktorSdk.sendParams({ number: 12.3, integer: 12, text: "abcd", textarea: "defg", date: "2006-01-02", bool: true, select: "Green", autocomp: "Green", multiselect: ["Red", "Green"], table: [{c1: 1, c2: 2}, {c1: 3, c2: 4}], geopoint: {lat: 25.7617, lon: -80.1918}, geopolyline: [{lat: 25.7617, lon: -80.1918}, {lat: 18.4655, lon: -66.1057}], geopolygon: [{lat: 25.7617, lon: -80.1918}, {lat: 18.4655, lon: -66.1057}, {lat: 32.3078, lon: -64.7505}], entity: 123, // entity id color: {r: 30, g: 144, b: 255} }); ``` ### Python libraries[​](/docs/create-apps/results-and-visualizations/html/.md#python-libraries "Direct link to Python libraries") The following Python libraries offer the functionality to export interactive visualizations as an HTML page: * [Bokeh](https://github.com/bokeh/bokeh) * [Folium](https://github.com/python-visualization/folium) * [Geoplotlib](https://github.com/andrea-cuttone/geoplotlib) * [mpld3](https://github.com/mpld3/mpld3) * [altair-viz](https://github.com/altair-viz/altair) * [pygal](https://github.com/Kozea/pygal) ## Testing[​](/docs/create-apps/results-and-visualizations/html/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@WebView` or `@WebAndDataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_web_view(self): params = ... result = MyEntityTypeController().web_view(params=params) self.assertEqual(result.html, ...) ``` --- # Show an image New in v13.7.0 `ImageView` and `ImageAndDataView` as replacement for the specific image views. Currently, the following image types are supported: * PNG * JPG * SVG * GIF (>= v13.7.0) ## Implementation[​](/docs/create-apps/results-and-visualizations/images/.md#implementation "Direct link to Implementation") The easiest way to show an image in the [`ImageView`](/sdk/api/views/.md#_ImageView) is by using a static file: 1. Add an image to your app repository. ``` my-app ├── app.py ├── image.png └── ... ``` 2. Create a view method on the controller decorated with `ImageView` which returns an [`ImageResult`](/sdk/api/views/.md#_ImageResult): ``` from pathlib import Path import viktor as vkt class Controller(vkt.Controller): @vkt.ImageView("Image") def create_img_result(self, params, **kwargs): image_path = Path(__file__).parent / 'image.png' return vkt.ImageResult.from_path(image_path) ``` The image can also be dynamically created, for example using Matplitlib, svgwrite, drawSvg, etc. An example of Matplotlib is shown below: ``` import matplotlib.pyplot as plt import numpy as np import viktor as vkt from io import StringIO class Controller(vkt.Controller): @vkt.ImageView("Plot") def create_result(self, params, **kwargs): # initialize figure fig = plt.figure() # create plot data x = np.random.randn(10) plt.plot(x) # save figure svg_data = StringIO() fig.savefig(svg_data, format='svg') plt.close() return vkt.ImageResult(svg_data) ``` The `ImageView` is only suitable for static visualizations. See [`WebView`](/docs/create-apps/results-and-visualizations/html/.md) if interactivity is desired. An image view can be combined with data using an [`ImageAndDataView`](/sdk/api/views/.md#_ImageAndDataView). ## Testing[​](/docs/create-apps/results-and-visualizations/images/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@ImageView`, `@ImageAndDataView`, `@PNGView`, `@PNGAndDataView`, `@JPGView`, `@JPGAndDataView`, `@SVGView`, or `@SVGAndDataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_img_view(self): params = ... result = MyEntityTypeController().img_view(params=params) self.assertEqual(result.image.getvalue(), ...) ``` --- # Display a map A lot of VIKTOR applications (especially in the infra sector) are strongly related to locations on a map. In those cases it can be helpful to display locations in a map visualization. This guide explains how to add an OpenStreetMap view to a VIKTOR entity. There are 2 different VIKTOR objects to realize this: * If you want to build map elements using simple map geometry objects use the [`MapView`](/docs/create-apps/results-and-visualizations/map/.md#mapview) object * If you want to use exports from external software to generate a geojson format (e.g. GIS), please see if the [`GeoJSONView`](/docs/create-apps/results-and-visualizations/map/.md#geojsonview) is a better fit. ![](/assets/images/visualization-map-18a9f2daf418b5f76cb14cee043099eb.png) *Map view* note All features in the `MapView` and `GeoJSONView` expect coordinates in the WGS system. In case you are using the RD-system you can make use of the [`RDWGSConverter`](/sdk/api/geometry/.md#_RDWGSConverter) to obtain the corresponding WGS coordinates: ``` lat, lon = RDWGSConverter.from_rd_to_wgs((x, y)) ``` ## MapView[​](/docs/create-apps/results-and-visualizations/map/.md#mapview "Direct link to MapView") In the `MapView` the following map primitives (features) can be used: * `MapPoint`, to draw markers * `MapLine`, to draw a line between 2 points * `MapPolyline`, to draw a multi-segment line * `MapPolygon`, to draw a polygon surface * `MapCircle`, to draw a circular surface (New in v14.22.0) ### Example implementation[​](/docs/create-apps/results-and-visualizations/map/.md#example-implementation "Direct link to Example implementation") ``` import viktor as vkt class Controller(vkt.Controller): @vkt.MapView('Map view') def get_map_view(self, params, **kwargs): # Create some points using coordinates markers = [ vkt.MapPoint(25.7617, -80.1918, description='Miami'), vkt.MapPoint(18.4655, -66.1057, description='Puerto Rico'), vkt.MapPoint(32.3078, -64.7505, description='Bermudas') ] # Create a polygon polygon = vkt.MapPolygon(markers) # Visualize map features = markers + [polygon] return vkt.MapResult(features) ``` A map view can be combined with data using a [`MapAndDataView`](/sdk/api/views/.md#_MapAndDataView) ### Styling the map elements[​](/docs/create-apps/results-and-visualizations/map/.md#styling-the-map-elements "Direct link to Styling the map elements") VIKTOR supports the following arguments for styling the map elements: * title: Title of a clickable map feature. * description: Description of a clickable map feature. Supports [styling with Markdown](/docs/create-apps/layout-and-styling/style-text/.md). * color: Specifies the color of the map feature. * entity\_links: When clicking on the map feature, links towards multiple entities can be shown. * icon: Icon to be shown (`MapPoint` only). See [MapPoint](/sdk/api/views/.md#_MapPoint) for all available icons. * size: Marker size (`MapPoint` only). (>= v14.5.0) ``` import viktor as vkt link_1 = vkt.MapEntityLink('First entity', first_entity_id) link_2 = vkt.MapEntityLink('Second entity', second_entity_id) vkt.MapPoint( 51.99311570849245, 4.385752379894256, title='Location', description='I am blue', icon="pin", size="small", color=vkt.Color(90, 148, 230), entity_links=[link_1, link_2] ) ``` ### Linking geo-fields to the view[​](/docs/create-apps/results-and-visualizations/map/.md#linking-geo-fields-to-the-view "Direct link to Linking geo-fields to the view") When geo-fields (`GeoPointField`, `GeoPolylineField`, etc.) are used in the parametrization of an entity, corresponding geo-objects (`GeoPoint`, `GeoPolyline`, etc.) will be directly available in the `params`. These can easily be used in a `MapView`, by converting to the corresponding map feature (e.g. `GeoPointField` -> `GeoPoint` -> `MapPoint`). Assume the following `params`: ``` params = { 'geo_point': , 'geo_polyline': , 'geo_polygon': } ``` ``` @vkt.MapView(...) def get_map_view(self, params, **kwargs): features = [] if params.geo_point: features.append(vkt.MapPoint.from_geo_point(params.geo_point)) if params.geo_polyline: features.append(vkt.MapPolyline.from_geo_polyline(params.geo_polyline)) if params.geo_polygon: features.append(vkt.MapPolygon.from_geo_polygon(params.geo_polygon)) return vkt.MapResult(features) ``` Additional styling as explained in the previous section can be added via the class methods as well: ``` vkt.MapPoint.from_geo_point(params.geo_point, color=vkt.Color(90, 148, 230)) ``` ## GeoJSONView[​](/docs/create-apps/results-and-visualizations/map/.md#geojsonview "Direct link to GeoJSONView") In the `GeoJSONView` GeoJSON primitives can be used to construct markers, lines and surfaces on this map, to add user relevant information. Another possibility is an export from an existing GIS program which you want to show to the user. note GeoJSON is a standard format for encoding geographic data structures such as points, lines and polygons ([geojson.org](https://geojson.org/)). [geojson.io](https://geojson.io) is a good tool for quick experiments with geojson. ### Example implementation[​](/docs/create-apps/results-and-visualizations/map/.md#example-implementation-1 "Direct link to Example implementation") ``` import viktor as vkt class Controller(vkt.Controller): @vkt.GeoJSONView('GeoJSON view') def get_geojson_view(self, params, **kwargs): geojson = { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "Point", "coordinates": [ 4.385747015476227, 51.993107450558156 ] } } ] } return vkt.GeoJSONResult(geojson) ``` A GeoJSON view can be combined with data using a [`GeoJSONAndDataView`](/sdk/api/views/.md#_GeoJSONAndDataView) ### Styling the map elements - simplestyle-spec GeoJSON properties[​](/docs/create-apps/results-and-visualizations/map/.md#styling-the-map-elements---simplestyle-spec-geojson-properties "Direct link to Styling the map elements - simplestyle-spec GeoJSON properties") GeoJSON defines the geometrical properties of the map elements and not the styling. It does however allow to convey such information under the "properties" key of the respective element. Roughly following the [simplestyle-spec](https://github.com/mapbox/simplestyle-spec/tree/master/1.1.0), VIKTOR supports the following arguments for styling the map elements: * icon (geometry type 'Point' only): icon to be shown (default: "pin"). See [MapPoint](/sdk/api/views/.md#_MapPoint) for all available icons. * marker-symbol (geometry type 'Point' only): same as icon * marker-color: the color of a marker \* * marker-size: size of the marker ("small", "medium", "large") * title: A title to show when this item is clicked * description: text to show when this item is clicked. Supports [styling with Markdown](/docs/create-apps/layout-and-styling/style-text/.md) * stroke: the color of a line as part of a polygon, polyline, or multigeometry \* * fill: the color of the interior of a polygon \* * stroke-opacity: the opacity of the line component of a polygon, polyline, or multigeometry \*\* * fill-opacity: the opacity of the interior of a polygon \*\* * stroke-width: the width of the line component of a polygon, polyline, or multigeometry (value must be a floating point number greater than or equal to 0) * dash-size: size of the dashes of a dashed line, relative to the width of the path * gap-size: size of the gaps of a dashed line, relative to the width of the path - color rules; Colors can be in short form "#ace" or long form "#aaccee", and should contain the "#" prefix. Colors are interpreted the same as in CSS, in #RRGGBB and #RGB order
\*\* opacity rules: Opacity value must be a floating point number greater than or equal to zero and less or equal to than one ## Additional map elements[​](/docs/create-apps/results-and-visualizations/map/.md#additional-map-elements "Direct link to Additional map elements") Apart from geometrical features, the map can be enriched by passing the following VIKTOR specific elements in the `MapResult` or `GeoJSONResult`: * [`MapLegend`](/sdk/api/views/.md#_MapLegend) * [`MapLabel`](/sdk/api/views/.md#_MapLabel) (text directly printed on the map) ``` import viktor as vkt @vkt.MapView(...) def get_map_view(...): ... legend = vkt.MapLegend(...) labels = [ vkt.MapLabel(...), ... ] return vkt.MapResult(features, labels=labels, legend=legend) # or GeoJSONResult ``` ## Interaction with map: selecting objects[​](/docs/create-apps/results-and-visualizations/map/.md#interaction-with-map-selecting-objects "Direct link to Interaction with map: selecting objects") New in v13.2.0 Map view interaction enables the user to provide extra input by selecting features within a `MapView`, `GeoJSONView`, `MapAndDataView` or `GeoJSONAndDataView`. The interaction can be bound to all [action buttons](/docs/create-apps/user-input/action-buttons/.md). ### Implementation[​](/docs/create-apps/results-and-visualizations/map/.md#implementation "Direct link to Implementation") To setup an interaction on an map view, the following parts need to be implemented: * create an action button in the parametrization and assign an `interaction` * add unique `identifier`s on the map features that you want to be selectable * an `InteractionEvent` is inserted in the action method under the `event` argument. This event can be used to process the selection. The selection is not automatically stored (since you can also combine this with a DownloadButton and don't store anything on the entity). Choose the approriate button for processing the selection. For example selecting an option in an [`OptionField`](/sdk/api/parametrization/.md#_OptionField) by means of selection in a `MapView` is achieved by: * adding a [`SetParamsButton`](/sdk/api/parametrization/.md#_SetParamsButton) with `interaction=MapSelectInteraction` pointing to the correct view * add unique identifiers on [`MapFeature`](/sdk/api/views/.md#_MapFeature)s which are selectable * adding a controller method which processes the interaction event and returns a `SetParamsResult`. This makes sure the selection persists on the params. ``` import viktor as vkt class Parametrization(vkt.Parametrization): city = vkt.OptionField('City', ['Miami', 'Puerto Rico', 'Bermudas']) select_button = vkt.SetParamsButton('Select city from map', method='set_city_from_selection', interaction=vkt.MapSelectInteraction('get_map_view', max_select=1)) class Controller(vkt.Controller): parametrization = Parametrization @vkt.MapView('Map view') def get_map_view(self, params, **kwargs): # Create some points using coordinates miami_point = vkt.MapPoint(25.7617, -80.1918, description='Miami', identifier='Miami') puerto_rico_point = vkt.MapPoint(18.4655, -66.1057, description='Puerto Rico', identifier='Puerto Rico') bermudas_point = vkt.MapPoint(32.3078, -64.7505, description='Bermudas', identifier='Bermudas') # Create a polygon polygon = vkt.MapPolygon([miami_point, puerto_rico_point, bermudas_point]) # Add label of selected location labels = [] if params.city == 'Miami': labels = [vkt.MapLabel(miami_point.lat, miami_point.lon, "Miami", scale=3)] elif params.city == 'Puerto Rico': labels = [vkt.MapLabel(puerto_rico_point.lat, puerto_rico_point.lon, "Puerto Rico", scale=3)] # Visualize map features = [miami_point, puerto_rico_point, bermudas_point, polygon] return vkt.MapResult(features, labels) def set_city_from_selection(self, params, event, **kwargs): selected_city = event.value[0] return vkt.SetParamsResult({'city': selected_city}) ``` ### MapSelectInteraction settings[​](/docs/create-apps/results-and-visualizations/map/.md#mapselectinteraction-settings "Direct link to MapSelectInteraction settings") The following settings are available: * `min_select`: minimum number of selected objects by user (default 1) * `max_select`: maximum number of selected objects by user (optional) ### Interaction groups[​](/docs/create-apps/results-and-visualizations/map/.md#interaction-groups "Direct link to Interaction groups") Sometimes you want to select certain features for one action and other features for another action in the same view. This can be achieved by defining `interaction_groups` on the view result and define a `selection` on the action button. When `selection` is used, only the objects in the chosen `interaction_group` are considered. Objects which only have an identifier will not be selectable. An `interaction_group` is a dictionary with the following structure: * key (`str`), matching the `selection` filter as defined on the button * value: sequence of `MapFeature`s which are part of the group. They can be referenced using the `identifier` or you can use the variable itself ``` import viktor as vkt class Parametrization(vkt.Parametrization): btn1 = vkt.SetParamsButton('Select from European cities', method='set_city_from_selection', interaction=vkt.MapSelectInteraction('visualize_map', selection=['eu_cities'], max_select=1)) btn2 = vkt.SetParamsButton('Select from US cities', method='set_city_from_selection', interaction=vkt.MapSelectInteraction('visualize_map', selection=['us_cities'], max_select=1)) class Controller(vkt.Controller): parametrization = Parametrization @vkt.MapView("Cities", 2) def visualize_map(self, params, **kwargs): ... amsterdam = vkt.MapPoint(52.377956, 4.897070, identifier='Amsterdam') rotterdam = vkt.MapPoint(51.924419, 4.477733) berlin = vkt.MapPoint(52.520008, 13.404954, identifier='Berlin') new_york = vkt.MapPoint(40.712776, -74.005974, identifier='New York') ... my_interaction_groups = { 'eu_cities': [amsterdam, berlin], # or point to the identifier: ['Amsterdam', 'Berlin'] 'us_cities': [new_york], # or point to the identifier: ['New York'] } return vkt.MapResult(..., interaction_groups=my_interaction_groups) ``` ## Testing[​](/docs/create-apps/results-and-visualizations/map/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@MapView`, `@MapAndDataView`, `@GeoJSONView`, or `@GeoJSONAndDataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_map_view(self): params = ... result = MyEntityTypeController().map_view(params=params) self.assertEqual(result.features, ...) self.assertEqual(result.labels, ...) ``` --- # Perform an optimization routine An [optimization action](/docs/create-apps/user-input/action-buttons/.md#optimization-action) enables the user to perform an optimization routine upon clicking a button, in which different combinations of input parameters are linked to a specific result. The optimization routine should be defined in the app logic and this can either be a brute-force approach or a more sophisticated algorithm if desired. In this guide a brute-force example is demonstrated, to optimize the cost of a sphere. The input variable is the radius of a sphere, and the to be optimized result is the cost which is a function of the volume. ## Implementation[​](/docs/create-apps/results-and-visualizations/optimization-routine/.md#implementation "Direct link to Implementation") Usually an optimization can be split into the following steps: 1. Create an [`OptimizationButton`](/sdk/api/parametrization/.md#_OptimizationButton) in the parametrization 2. Add an optimization method on the corresponding controller class 3. Define and return the desired [`OptimizationResult`](/sdk/api/result/.md#_OptimizationResult) ### `parametrization.py`[​](/docs/create-apps/results-and-visualizations/optimization-routine/.md#parametrizationpy "Direct link to parametrizationpy") Create an `OptimizationButton` which refers to the controller method `optimize_cost`: ``` class Parametrization(vkt.Parametrization): ... button = vkt.OptimizationButton('Optimize', 'optimize_cost', longpoll=True) ``` ### `controller.py`[​](/docs/create-apps/results-and-visualizations/optimization-routine/.md#controllerpy "Direct link to controllerpy") In the `optimize_cost` method, each possible combination of input parameters with corresponding analysis result should be processed and stored in an `OptimizationResult`: ``` import viktor as vkt from math import pi class Controller(vkt.Controller): parametrization = Parametrization def optimize_cost(self, params, **kwargs): r_min = 5 r_max = 10 results = [] for radius in range(r_min, r_max): # override the existing radius for each loop params = {'radius': radius} # compute the cost volume = 4 / 3 * pi * radius ** 3 cost = volume * params.price_per_m3 # store input params with corresponding result dict results.append(vkt.OptimizationResultElement(params, {'optimized_cost': cost})) output_headers = {'optimized_cost': 'Cost'} return vkt.OptimizationResult(results, output_headers=output_headers) ``` When the optimization routine has finished, a result window like this will pop up: ![](/assets/images/optimization-window-1-232909132ef41c46e5b91a02bb5f3d01.png) Each analysis of the defined loop is listed, and when the result is selected, its corresponding input(s) will be set in the parametrization. It is convenient to link these optimization entries to the input radius. This can be passed to the `OptimizationResult` as follows: ``` def optimize_cost(self, params, **kwargs): ... input_columns = ['radius'] return vkt.OptimizationResult(results, input_columns, output_headers=output_headers) ``` ![](/assets/images/optimization-window-2-95bd362f6b39d0ea2ffc95dc17dc555a.png) Also notice the "Results" button just beneath the OptimizationButton, which can be clicked to switch to a different optimization result. It is recommended to keep the amount of results in the optimization overview limited, and provide a complete overview using an insightful plot which is explained in the next section. ## Add an image[​](/docs/create-apps/results-and-visualizations/optimization-routine/.md#add-an-image "Direct link to Add an image") Next to the table, an image can be shown to visualize the results. This can be done by using the `image` argument in the `OptimizationResult`: ``` def optimize_cost(self, params, **kwargs): ... image = vkt.ImageResult(...) # create image with matplotlib, pygal, plotly, etc. return vkt.OptimizationResult(results, input_columns, image=image, output_headers=output_headers) ``` This renders as follows in the interface: ![](/assets/images/optimization-with-graph-f5d968c4066973d970859b3296310c9d.png) See [how to create an image view](/docs/create-apps/results-and-visualizations/images/.md) for more information on how to create an image-result. --- # Show plots, charts & graphs ## Using Plotly[​](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#using-plotly "Direct link to Using Plotly") [Plotly](https://github.com/plotly/plotly.py) is a free and open source package that simplifies the creation of interactive graphs, such as line plots, scatter plots, histograms, etc. A Plotly graph can be incorporated in your VIKTOR app by making use of a [`PlotlyView`](/sdk/api/views/.md#_PlotlyView). ![](/assets/images/plotly-example-7cc2c057d48c72d55f332639cf4e3707.png) *Example of how an interactive visualization in the PlotlyView could look like (source: plot.ly)* The Plotly graph can either be passed to a [`PlotlyResult`](/sdk/api/views/.md#_PlotlyResult) as a `go.Figure` object, or as a valid Plotly `dict`: ``` import viktor as vkt import plotly.graph_objects as go class Controller(vkt.Controller): @vkt.PlotlyView("Plotly view") def get_plotly_view(self, params, **kwargs): fig = go.Figure( data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])], layout=go.Layout(title=go.layout.Title(text="A Figure Specified By A Graph Object")) ) return vkt.PlotlyResult(fig) ``` ``` import viktor as vkt class Controller(vkt.Controller): @vkt.PlotlyView("Plotly view") def get_plotly_view(self, params, **kwargs): fig = { "data": [{"type": "bar", "x": [1, 2, 3], "y": [1, 3, 2]}], "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} } return vkt.PlotlyResult(fig) ``` A Plotly view can be combined with data using a [`PlotlyAndDataView`](/sdk/api/views/.md#_PlotlyAndDataView) ### Testing[​](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@PlotlyView` or `@PlotlyAndDataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_plotly_view(self): params = ... result = MyEntityTypeController().plotly_view(params=params) self.assertEqual(result.figure, ...) ``` ## Using Matplotlib[​](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md#using-matplotlib "Direct link to Using Matplotlib") You can show Matplotlib figures as static images using [`ImageView`](/sdk/api/views/.md#_ImageView). If you want an interactive graph and have a more sophisticated data visualisation tool, we recommend using Plotly. Here is an example of how to use Matplotlib: ``` import viktor as vkt import numpy as np import matplotlib.pyplot as plt from io import StringIO class Parametrization(vkt.Parametrization): introduction = vkt.Text("Fill in values for A, B and C to plot the following equation: $y = Ax^2 + Bx + C$") constant_a = vkt.NumberField('A',default=1) constant_b = vkt.NumberField('B', default=1) constant_c = vkt.NumberField('C', default=1) class Controller(vkt.Controller): parametrization = Parametrization @vkt.ImageView("Plot") def createPlot(self, params, **kwargs): fig = plt.figure() x = np.arange(-10, 10, 1) y = params.constant_a*x**2 + params.constant_b*x + params.constant_c plt.plot(x, y) svg_data = StringIO() fig.savefig(svg_data, format='svg') plt.close() return vkt.ImageResult(svg_data) ``` --- # Display a report PDF files can directly be presented in a view using the [`PDFView`](/sdk/api/views/.md#_PDFView). ![](/assets/images/view-pdf-2d85cc0a2f99de62de4e63dcd6c9d5d6.png) *PDF view* ## Implementation[​](/docs/create-apps/results-and-visualizations/report/.md#implementation "Direct link to Implementation") There are 3 ways to create a PDF view: 1. [From a File-object](/docs/create-apps/results-and-visualizations/report/.md#from-a-file-object) 2. [From a URL](/docs/create-apps/results-and-visualizations/report/.md#from-a-url) 3. [From a path](/docs/create-apps/results-and-visualizations/report/.md#from-a-path) ### From a `File`-object[​](/docs/create-apps/results-and-visualizations/report/.md#from-a-file-object "Direct link to from-a-file-object") The easiest way to show a PDF document in the `PDFView` is by using a `File` object: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.PDFView("PDF Viewer") def get_pdf_view(self, params, **kwargs): ... return vkt.PDFResult(file=my_pdf_file) ``` note If `File.from_url` is used, the file will always be downloaded first and not rendered from the website, as in the case with the [direct URL](/docs/create-apps/results-and-visualizations/report/.md#from-a-url). ### From a URL[​](/docs/create-apps/results-and-visualizations/report/.md#from-a-url "Direct link to From a URL") If a PDF is located on the internet one can also use the URL directly. This does not download the file locally, but renders it directly from the hosting website: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.PDFView("PDF Viewer") def get_pdf_view(self, params, **kwargs): return vkt.PDFResult(url="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf") ``` Some websites don't allow files to be shared this way. This will result in the PDF not showing up in the view. If that is the case, the `PDFView` can be created from a 'file from url', which will download the file locally first and display it subsequently: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.PDFView("PDF Viewer") def get_pdf_view(self, params, **kwargs): file = vkt.File.from_url(url="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf") return vkt.PDFResult(file=file) ``` ### From a path[​](/docs/create-apps/results-and-visualizations/report/.md#from-a-path "Direct link to From a path") Finally, it is possible to create a `PDFView` directly from a path (for convenience, to skip creating a `File` from path first): ``` from pathlib import Path import viktor as vkt class Controller(vkt.Controller): @vkt.PDFView("PDF Viewer") def get_pdf_view(self, params, **kwargs): file_path = Path(__file__).parent / 'sample.pdf' return vkt.PDFResult.from_path(file_path) ``` ## Testing[​](/docs/create-apps/results-and-visualizations/report/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@PDFView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_pdf_view(self): params = ... result = MyEntityTypeController().pdf_view(params=params) self.assertEqual(result.file.getvalue_binary(), ...) ``` --- # Show a summary A [`Summary`](/sdk/api/views/.md#_Summary) is used to store important parameters of an entity. This enables easy sorting and comparing of different entities in an overview. A `Summary` can be defined per entity type (controller), and is optional. A summary can have a maximum of 6 summary items. ## Implementation: from parametrization[​](/docs/create-apps/results-and-visualizations/show-summary/.md#implementation-from-parametrization "Direct link to Implementation: from parametrization") One source of summary items is the parametrization. You can point to a field in the parametrization and the value of this field will be shown in the summary. The following fields can be used in a summary: * [`NumberField`](/sdk/api/parametrization/.md#_NumberField) * [`IntegerField`](/sdk/api/parametrization/.md#_IntegerField) * [`TextField`](/sdk/api/parametrization/.md#_TextField) Adding a summary is done with the following steps: 1. Add a controller `summary` attribute: ``` import viktor as vkt class Controller(vkt.Controller): summary = vkt.Summary() ... ``` 2. Add a SummaryItem and link to the parametrization: ``` import viktor as vkt class Controller(vkt.Controller): summary = vkt.Summary( item_1=vkt.SummaryItem('Length', float, 'parametrization', 'geometry.input.length', prefix='m') ) ... ``` Above example assumes the following parametrization: ``` import viktor as vkt class Parametrization(vkt.Parametrization): geometry = vkt.Tab(...) geometry.input = vkt.Section(...) geometry.input.length = vkt.NumberField(...) ``` ## Implementation: from results[​](/docs/create-apps/results-and-visualizations/show-summary/.md#implementation-from-results "Direct link to Implementation: from results") When a view contains data (e.g. `DataView`, `GeometryAndDataView`, etc.), that data can be used in the summary. note `SummaryItem`s can only be obtained from a "quick" view (i.e. without manual update button). 1. Add a controller `summary` attribute: ``` import viktor as vkt class Controller(vkt.Controller): summary = vkt.Summary() ... ``` 2. Create a `DataView` which returns the result(s) that should be shown on the summary: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.DataView("Cost") def calculate_cost(self, params, **kwargs): # app specific cost calculation material_cost = ... total_cost = material_cost + ... data = vkt.DataGroup( total_cost=vkt.DataItem('Total cost', total_cost, prefix='€', subgroup=vkt.DataGroup( material_cost=vkt.DataItem('Material', material_cost, prefix='€') )) ) return vkt.DataResult(data) ``` 3. Add a `SummaryItem` and link to the `DataItem` (in this example the material cost): ``` import viktor as vkt class Controller(vkt.Controller): summary = vkt.Summary(item_1=vkt.SummaryItem('Materials', float, 'calculate_cost', 'total_cost.material_cost', prefix='€')) ... ``` Keep in mind that when creating a `DataGroup` you can pass a list or dict of data items. When you use a list however, the items can not be used in the `Summary`, because there is no keyword that functions as link between the result and the summary. ## Prefix/suffix[​](/docs/create-apps/results-and-visualizations/show-summary/.md#prefixsuffix "Direct link to Prefix/suffix") The prefix/suffix that is defined on the `SummaryItem` is stored in the database and has to be static, such that it can be used to for example sort entities of a certain entity type. This means that there cannot be any inconsistency between prefix/suffix definitions of an entity type and they **should not be changed**. The prefix/suffix of a `DataItem` however can in most cases be dynamic. A good example is when the result of an analysis is a reaction force in Newtons. Since this result is dynamic and can potentially be extremely large, a user could find it more convenient to show this result in kN. This unit can switch with every call and this dynamic behavior holds for all `DataItem`s. However, when the result is used in the `Summary`, the prefix/suffix of the `DataItem` should be equal to the prefix/suffix of the `SummaryItem` and **static** as explained above. --- # Storing results ## Persistent storage[​](/docs/create-apps/results-and-visualizations/storing-results/.md#persistent-storage "Direct link to Persistent storage") VIKTOR offers a [`Storage`](/sdk/api/core/.md#_Storage) which can be used to store and retrieve files within an app workspace. The storage is persistent, meaning that the data will remain available with no time limit. This can be very helpful in cases where (intermediate) results need to be shared between jobs. For example, a long-running task is performed in job 'A', of which the results can be accessed in job 'B' without the need to rerun the task. ### Supported operations[​](/docs/create-apps/results-and-visualizations/storing-results/.md#supported-operations "Direct link to Supported operations") The storage can be accessed from an app with the `Storage` methods as shown below: ``` import viktor as vkt # Setting data on a key vkt.Storage().set('data_key_1', data=vkt.File.from_data('abc'), scope='entity') vkt.Storage().set('data_key_2', data=vkt.File.from_data('def'), scope='entity') # Retrieve the data by key vkt.Storage().get('data_key_1', scope='entity') # List available data keys (by prefix) vkt.Storage().list(scope='entity') # lists all files in current entity scope vkt.Storage().list(prefix='data_key_', scope='entity') # lists 'data_key_1', 'data_key_2', ... etc. # Delete data by key vkt.Storage().delete('data_key_1', scope='entity') ``` ### Storage scopes[​](/docs/create-apps/results-and-visualizations/storing-results/.md#storage-scopes "Direct link to Storage scopes") With the `scope` argument the 'accessibility' of the stored data can be set. The following scopes are available: * **entity**: when data needs to be accessed within a specific entity * **workspace**: when data needs to be accessed workspace-wide #### scope 'entity'[​](/docs/create-apps/results-and-visualizations/storing-results/.md#scope-entity "Direct link to scope 'entity'") The entity scope means that the data is assigned to a specific entity. A common use-case for this scope is to store results of a long-running task (analysis, file parsing, etc.) and retrieve it without the need to rerun the task. For example, data is stored in entity A1 on key `entity_data`. VIKTOR stores the data in a zone in the storage designated for entity A1: ``` vkt.Storage().set('entity_data', data=vkt.File.from_data('content set by A1'), scope='entity') ``` This data can then be retrieved in entity A1 using the `get` operation: ``` vkt.Storage().get('entity_data', scope='entity') # File content: 'content set by A1' ``` When we would try to perform this `get` operation in entity A2, a `FileNotFound` error will be raised because the file does not (yet) exist in the storage zone designated for entity A2. This also means that we can re-use the same key to set data, without overwriting the data stored in entity A1: ``` vkt.Storage().set('entity_data', data=vkt.File.from_data('content set by A2'), scope='entity') ``` It is also possible to store/retrieve data from one entity in another (even with entities of different type). This cross-entity referencing can be achieved by passing the relevant `Entity` object as `entity` argument: ``` entity = ... # retrieve entity A1 vkt.Storage().get('entity_data', scope='entity', entity=entity) # File content: 'content set by A1' ``` tip See [this guide](/docs/api/sdk/handling-entity-data/.md) on how to navigate to the correct entity using the API. #### scope 'workspace'[​](/docs/create-apps/results-and-visualizations/storing-results/.md#scope-workspace "Direct link to scope 'workspace'") The workspace scope means that the data is accessible workspace-wide. All entities of all types will point towards the same section in the storage with this scope. This scope can be seen as an extension of the [`memoize`](/docs/create-apps/results-and-visualizations/storing-results/.md#memoize) functionality, with the difference that the stored results are permanent. In entity A1 the following data is stored on key `workspace_data` using the workspace scope: ``` vkt.Storage().set('workspace_data', data=vkt.File.from_data('content set by A1'), scope='workspace') ``` Storing data in entity A2 on the same key using the workspace scope overwrites the previously stored data: ``` vkt.Storage().set('workspace_data', data=vkt.File.from_data('content set by A2'), scope='workspace') ``` When we retrieve this key in either entity A1, entity A2, or even an entity from TypeB, the returned file content will be the data which is stored last (in this case 'content set by A2'). ## Memoize[​](/docs/create-apps/results-and-visualizations/storing-results/.md#memoize "Direct link to Memoize") To store (long-running) results temporarily you can also make use of the [`memoize`](/sdk/api/utils/.md#_memoize) function. A practical use-case of `memoize` is when a function call has input and output that is relatively small compared to the time required for its evaluation. Cached results are kept for a maximum of 24 hours. In below example, a `DataView` performs a long-running calculation when calling `func`. When the user changes input in the editor and updates the view again, `func` will only be evaluated again if either one of `param_a`, `param_b`, or `param_c` is changed in-between jobs: ``` import viktor as vkt @vkt.memoize def func(*, param_a, param_b, param_c): # perform lengthy calculation return result class Controller(vkt.Controller): @vkt.DataView("Results", duration_guess=30) def get_data_view(self, params, **kwargs): ... result = func(param_a=..., param_b=..., param_c=...) ... return vkt.DataResult(...) ``` caution When using `memoize` on your **development environment** the cache is stored locally. The local storage is limited to 50 function calls for practical reasons. If the limit is exceeded, cached results are cleared based on the first-in-first-out principle. In production the storage is unlimited. --- # Show a 3D model This guide explains how to visualize 3D models. There are multiple ways to achieve this: 1. From [geometry elements](/docs/create-apps/results-and-visualizations/threed-model/.md#geometry-elements) from the `viktor.geometry` module 2. From a [glTF/GLB file](/docs/create-apps/results-and-visualizations/threed-model/.md#gltfglb-file) 3. From a [3DM file](/docs/create-apps/results-and-visualizations/threed-model/.md#rhinoceros-3dm-file) (>= v14.4.0) 4. From an [IFC file](/docs/create-apps/results-and-visualizations/threed-model/.md#ifcview) (>= v14.6.0) Depending on the method above, either a [`GeometryView`](/sdk/api/views/.md#_GeometryView) or an [`IFCView`](/sdk/api/views/.md#_IFCView) needs to be used. Both views can be combined with data using a [`GeometryAndDataView`](/sdk/api/views/.md#_GeometryAndDataView) and [`IFCAndDataView`](/sdk/api/views/.md#_IFCAndDataView). ![](/assets/images/view-geometry-c4890a2c034a8ebc6e476bd8367e66e9.png) ## GeometryView[​](/docs/create-apps/results-and-visualizations/threed-model/.md#geometryview "Direct link to GeometryView") ### Geometry elements[​](/docs/create-apps/results-and-visualizations/threed-model/.md#geometry-elements "Direct link to Geometry elements") New in v13.5.0 `Arc`, `Line`, and `Polyline` can be visualized in the `GeometryView` A [`GeometryResult`](/sdk/api/views/.md#_GeometryResult) can be constructed using geometry elements (`TransformableObject`) from the [`viktor.geometry`](/sdk/api/geometry/.md) module. The created 3D visualization uses a right-handed axis system with Z pointing upwards by default (see [view settings](/docs/create-apps/results-and-visualizations/threed-model/.md#view-settings) to overwrite this). #### Groups[​](/docs/create-apps/results-and-visualizations/threed-model/.md#groups "Direct link to Groups") A visualization group ([`Group`](/sdk/api/geometry/.md#_Group)) can be used to combine multiple visualization elements. A `Group` can contain two types of objects: `Group`, `TransformableObject`. This enables a hierarchical construction of visualization elements. Example: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.GeometryView("Geometry", x_axis_to_right=True) def get_geometry_view(self, params, **kwargs): # Define Materials glass = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) facade = vkt.Material("Facade", color=vkt.Color.white()) # Create one floor width = 30 length = 30 number_of_floors = 20 floor_glass = vkt.SquareBeam(width, length, 2, material=glass) floor_facade = vkt.SquareBeam(width + 1, length + 1, 1, material=facade) floor_facade.translate([0, 0, 1.5]) # Pattern (duplicate) the floor to create a building floor = vkt.Group([floor_glass, floor_facade]) building = vkt.LinearPattern(floor, direction=[0, 0, 1], number_of_elements=number_of_floors, spacing=3) return vkt.GeometryResult(building) ``` #### Specifying color[​](/docs/create-apps/results-and-visualizations/threed-model/.md#specifying-color "Direct link to Specifying color") Every `TransformableObject` has an assigned default material. This material can be overwritten with your own, specifying, for example, the color: ``` glass = vkt.SquareBeam(..., material=vkt.Material("Glass", color=vkt.Color(150, 150, 255))) # or glass = vkt.SquareBeam(...) glass.material = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) ``` #### Transformations[​](/docs/create-apps/results-and-visualizations/threed-model/.md#transformations "Direct link to Transformations") Transformation methods can be called on a `TransformableObject`, to position and orientate the object. The [`Vector`](/sdk/api/geometry/.md#_Vector) object can come in handy if your visualization requires vector transformations. The following methods are available on all geometric objects (through inheritance of `TransformableObject`): * [translate](/docs/create-apps/results-and-visualizations/threed-model/.md#translate) * [rotate](/docs/create-apps/results-and-visualizations/threed-model/.md#rotate) * [mirror](/docs/create-apps/results-and-visualizations/threed-model/.md#mirror) * [scale](/docs/create-apps/results-and-visualizations/threed-model/.md#scale) For each type of transformation an example is provided below. Chaining of transformations is possible, however be careful with the specified order. ##### translate[​](/docs/create-apps/results-and-visualizations/threed-model/.md#translate "Direct link to translate") ``` sphere = vkt.Sphere(vkt.Point(0, 0, 0), radius=10) # sphere is now centered around (0, 0, 0) sphere.translate([10, 0, 0]) # sphere is now centered around (10, 0, 0) ``` ##### rotate[​](/docs/create-apps/results-and-visualizations/threed-model/.md#rotate "Direct link to rotate") ``` import math box = vkt.RectangularExtrusion(1, 1, line=vkt.Line(vkt.Point(0, 0, -0.5), vkt.Point(0, 0, 0.5))) # box is now centered around (0, 0, 0) box.rotate(math.pi / 4, direction=[0, 0, 1]) # box is now rotated 45 degrees around the z-axis according to the right-hand-rule ``` ##### mirror[​](/docs/create-apps/results-and-visualizations/threed-model/.md#mirror "Direct link to mirror") ``` sphere = vkt.Sphere(vkt.Point(0, 0, 1), radius=10) # sphere is now centered around (0, 0, 1) sphere.mirror(vkt.Point(0, 0, 0), [0, 0, 1]) # sphere is a now mirrored in the x-y plane (normal vector in z-direction), centered around (0, 0, -1) ``` ##### scale[​](/docs/create-apps/results-and-visualizations/threed-model/.md#scale "Direct link to scale") ``` sphere = vkt.Sphere(vkt.Point(0, 0, 1), radius=10) # sphere is now centered around (0, 0, 1) sphere.scale([2, 2, 1]) # sphere is stretched in x- and y-direction, centered around (0, 0, 1) ``` ### glTF/GLB file[​](/docs/create-apps/results-and-visualizations/threed-model/.md#gltfglb-file "Direct link to glTF/GLB file") A `GeometryResult` can also be constructed from a [glTF/GLB (v2.0)](https://en.wikipedia.org/wiki/GlTF#glTF_2.0) file. This can be an existing local model: ``` from pathlib import Path import viktor as vkt class Controller(vkt.Controller): @vkt.GeometryView('Geometry view', x_axis_to_right=True) def get_geometry_view(self, params, **kwargs): geometry = vkt.File.from_path(Path(__file__).parent / "my_model.gltf") # or .glb return vkt.GeometryResult(geometry) ``` Or one available on the internet: ``` geometry = vkt.File.from_url("https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb") return vkt.GeometryResult(geometry) ``` Or can be generated by means of [trimesh](https://trimsh.org/) (or any other Python geometry package that allows for exporting to glTF/GLB): ``` import trimesh import viktor as vkt class Controller(vkt.Controller): @vkt.GeometryView('Geometry view', x_axis_to_right=True) def get_geometry_view(self, params, **kwargs): sphere = trimesh.creation.uv_sphere(10) scene = trimesh.Scene(geometry={'sphere': sphere}) geometry = vkt.File() # create a writable file with geometry.open_binary() as w: w.write(trimesh.exchange.gltf.export_glb(scene)) return vkt.GeometryResult(geometry) ``` note glTF/GLB models are defined with the Y-axis up. In VIKTOR the default up-axis is the Z-axis, resulting in the model to be shown on its side. In order to overwrite this, you can set the `up_axis` manually in the [view settings](/docs/create-apps/results-and-visualizations/threed-model/.md#view-settings): ``` @vkt.GeometryView("My glTF View", up_axis='Y') ``` ### Rhinoceros 3DM file[​](/docs/create-apps/results-and-visualizations/threed-model/.md#rhinoceros-3dm-file "Direct link to Rhinoceros 3DM file") New in v14.4.0 Similar to a glTF/GLB file, a 3DM file can be visualized by specifying the `geometry_type` argument (default: "gltf"): ``` geometry = vkt.File.from_url("https://github.com/mrdoob/three.js/raw/master/examples/models/3dm/Rhino_Logo.3dm") return vkt.GeometryResult(geometry, geometry_type="3dm") ``` ### Labels[​](/docs/create-apps/results-and-visualizations/threed-model/.md#labels "Direct link to Labels") Regardless of how the geometry is defined (geometry elements, glTF/GLB, or 3DM), additional labels can be added to the visualization: ``` import viktor as vkt labels = [ vkt.Label(vkt.Point(0, 0, 0), "Origin"), vkt.Label(vkt.Point(1, 0, 0), "x=1") ] return vkt.GeometryResult(solar_system, labels=labels) ``` ### View settings[​](/docs/create-apps/results-and-visualizations/threed-model/.md#view-settings "Direct link to View settings") The following settings can be applied to a `GeometryView`: * view\_mode: str value to switch between '3D' (default) and '2D'. The created 2D visualization shows the xy-plane. * default\_shadow: bool value to define whether shadow is turned off (default) or on when entering the editor. User can still overrule. * up\_axis: str value ('Y' or 'Z') to define the upwards pointing axis (view\_mode = '3D' only, default: 'Z'). Example: ``` @vkt.GeometryView("Top view", view_mode='2D', default_shadow=False) ``` ## IFCView[​](/docs/create-apps/results-and-visualizations/threed-model/.md#ifcview "Direct link to IFCView") New in v14.6.0 An IFC file can be visualized by using the [`IFCView`](/sdk/api/views/.md#_IFCView). This can be an existing local model: ``` import viktor as vkt class Controller(vkt.Controller): @vkt.IFCView('IFC view') def get_ifc_view(self, params, **kwargs): ifc = vkt.File.from_path(Path(__file__).parent / 'sample.ifc') return vkt.IFCResult(ifc) ``` Or one available on the internet: ``` ifc = vkt.File.from_url("https://raw.githubusercontent.com/buildingSMART/Sample-Test-Files/master/IFC%202x3/Duplex%20Apartment/Duplex_A_20110907.ifc") return vkt.IFCResult(ifc) ``` New in v14.6.1 In order to improve performance it is possible to use the value of a FileField (i.e. FileResource) directly: ``` IFCResult(params.file_field) ``` ## Selecting geometries[​](/docs/create-apps/results-and-visualizations/threed-model/.md#selecting-geometries "Direct link to Selecting geometries") New in 14.10.0 It is possible to let the user [select geometries](/docs/create-apps/user-input/geometry-selection/.md) directly in an `IFCView` or `GeometryView`. ## Testing[​](/docs/create-apps/results-and-visualizations/threed-model/.md#testing "Direct link to Testing") New in v13.3.0 `mock_View` decorator for easier testing of view methods Methods decorated with `@GeometryView`, `@GeometryAndDataView`, `@IFCView`, or `@IFCAndDataView` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ``` import unittest from viktor.testing import mock_View from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_View(MyEntityTypeController) def test_geometry_view(self): params = ... result = MyEntityTypeController().geometry_view(params=params) self.assertEqual(result.geometry, ...) self.assertEqual(result.labels, ...) ``` --- # Software integrations VIKTOR allows you to perform analyses using third-party software directly from your app interface. This guide explains how to integrate external software into your VIKTOR application. There are various ways to connect to third-party tools. Some software runs locally on the user's machine, while others are accessed through online servers. Each approach requires a different integration method, which will be covered in this guide. Summarizing the different methods to integrate with third-party software: | Integration | Installation | Usage | Admin required | | ------------------- | ------------ | -------- | -------------- | | Personal worker | local | personal | no | | Organization worker | local | shared | yes | | API tokens | cloud | shared | no | | OAuth 2.0 | cloud | personal | yes | ## Supported software[​](/docs/create-apps/software-integrations/.md#supported-software "Direct link to Supported software") Currently, we provide dedicated integrations for the software packages listed in the table below. If the software package that you want to interact with is not listed below, you can make use of our [generic integrations](/docs/create-apps/software-integrations/generic/.md). tip Whether or not the software package you want to integrate with is listed, please reach out to us if you need help setting up an integration through the [Community Forum](https://community.viktor.ai/)! | Software package | API reference | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | [Autodesk Platform Services](/docs/create-apps/software-integrations/autodesk-platform-services/.md) | [APS Documentation](https://aps.autodesk.com/developer/documentation) | | [AxisVM](/docs/create-apps/software-integrations/axisvm/.md) | [`viktor.external.axisvm`](/sdk/api/external/axisvm/.md) | | [Databricks](/docs/create-apps/software-integrations/databricks/.md) | [Databrick SDK for python](https://databricks-sdk-py.readthedocs.io/en/latest/) | | [D-Foundations](/docs/create-apps/software-integrations/dfoundations/.md) | [`viktor.external.dfoundations`](/sdk/api/external/dfoundations/.md) | | [D-Geo Stability](/docs/create-apps/software-integrations/dgeostability/.md) | [`viktor.external.dgeostability`](/sdk/api/external/dgeostability/.md) | | [D-Settlement](/docs/create-apps/software-integrations/dsettlement/.md) | [`viktor.external.dsettlement`](/sdk/api/external/dsettlement/.md) | | [D-Sheet Piling](/docs/create-apps/software-integrations/dsheetpiling/.md) | [`viktor.external.dsheetpiling`](/sdk/api/external/dsheetpiling/.md) | | [D-Stability](/docs/create-apps/software-integrations/dstability/.md) | [`viktor.external.dstability`](/sdk/api/external/dstability/.md) | | [Dynamo Nodes](/docs/create-apps/software-integrations/dynamo-nodes/.md) | [website](https://primer.dynamobim.org/index.html) | | [Dynamo Sandbox](/docs/create-apps/software-integrations/dynamo/.md) | [`viktor.external.dynamo`](/sdk/api/external/dynamo/.md) | | [ETABS and SAP2000](/docs/create-apps/software-integrations/etabs-and-sap2000/.md) | [`viktor.external.etabs`](/sdk/api/external/etabs/.md) / [`viktor.external.sap2000`](/sdk/api/external/sap2000/.md) | | [Excel](/docs/create-apps/software-integrations/excel/.md) | [`viktor.external.excel`](/sdk/api/external/excel/.md) | | [GEOLIB](/docs/create-apps/software-integrations/geolib/.md) | [website](https://github.com/Deltares/GEOLib) | | [GRLWEAP](/docs/create-apps/software-integrations/grlweap/.md) | [`viktor.external.grlweap`](/sdk/api/external/grlweap/.md) | | [IDEA StatiCa Concrete](/docs/create-apps/software-integrations/idea/.md) | [`viktor.external.idea_rcs`](/sdk/api/external/idea/.md) | | [Matlab](/docs/create-apps/software-integrations/matlab/.md) | [`viktor.external.matlab`](/sdk/api/external/matlab/.md) | | [PLAXIS](/docs/create-apps/software-integrations/plaxis/.md) | [`viktor.external.plaxis`](/sdk/api/external/plaxis/.md) | | [Revit](/docs/create-apps/software-integrations/revit/.md) | [`viktor.external.revit`](/sdk/api/external/revit/.md) | | Python | [`viktor.external.python`](/sdk/api/external/python/.md) | | [RFEM](/docs/create-apps/software-integrations/rfem/.md) | [`viktor.external.rfem`](/sdk/api/external/rfem/.md) | | [Rhino / Grasshopper](/docs/create-apps/software-integrations/rhino-grasshopper/.md) | [`viktor.external.grasshopper`](/sdk/api/external/grasshopper/.md) | | [Robot Structural Analysis](/docs/create-apps/software-integrations/robot/.md) | [`viktor.external.robot`](/sdk/api/external/robot/.md) | | [SCIA Engineer](/docs/create-apps/software-integrations/scia/.md) | [`viktor.external.scia`](/sdk/api/external/scia/.md) | | [Bentley STAAD.Pro](/docs/create-apps/software-integrations/staadpro/.md) | [`website`](https://docs.bentley.com/LiveContent/web/STAAD.Pro%20Help-v13/ja/GUID-576C4246-6A58-41D4-9F9A-9909FD744524.html) | | [Tekla](/docs/create-apps/software-integrations/tekla/.md) | [`viktor.external.tekla`](/sdk/api/external/tekla/.md) | ## Workers[​](/docs/create-apps/software-integrations/.md#workers "Direct link to Workers") A lot of engineering software runs locally on your machine. While you could integrate with this software during development (the code runs on the same computer), this will break if your app is used by others in production. In production your app runs on a server and this server does not have access to your machine. Workers solve this issue. A worker is a small application (executable) that is installed on the computer with access to the local software. It creates a secure connection with the VIKTOR platform, enabling the web applications to integrate with the local software and execute tasks. A worker is always assigned to one or multiple apps and when executed will run in the background and wait for a 'task'. This task consists of the input(s) required for the software. When the worker receives the task, it will call the software and perform an analysis with the provided input(s). Meanwhile, the application from which the task is sent waits until the worker finishes the calculation and sends back the results. The following schematic shows this concept: ![](/assets/images/explanation-worker-flow-a8742c706f9065c256b6358f19ca2e70.png) *VIKTOR worker flow* ### Installation[​](/docs/create-apps/software-integrations/.md#installation "Direct link to Installation") Please follow the steps listed in [installation](/docs/manage-apps/software-integrations/.md#installation) to set up a worker. ### Implementation example[​](/docs/create-apps/software-integrations/.md#implementation-example "Direct link to Implementation example") Each worker integration makes use of [`viktor.ExternalProgram`](/sdk/api/external/external-program/.md#_ExternalProgram). The [`ExternalProgram.execute`](/sdk/api/external/external-program/.md#ExternalProgram.execute) method is the trigger to send a task to the worker on the external machine. The following piece of code shows an example implementation of an integration with SCIA Engineer: ``` import viktor as vkt input_esa = ... input_xml = ... input_xml_def = ... scia_analysis = vkt.scia.SciaAnalysis(input_xml, input_xml_def, input_esa) scia_analysis.execute(timeout=300) # triggers the worker, wait until complete results = scia_analysis.get_xml_output_file() ``` ### Multiple worker instances[​](/docs/create-apps/software-integrations/.md#multiple-worker-instances "Direct link to Multiple worker instances") The VIKTOR - worker interaction is configured such that it can easily be scaled up (or down). For example, the worker application can execute multiple instances (processes) of the software package. ![](/assets/images/explanation-worker-flow-multiple-f5d5021a766adc51c68628c1458f50cb.png) *Worker running multiple processes on single machine* note Running parallel routines requires a worker version of at least v4.7.1 and should **not** be a generic worker. A worker can also be executed multiple times across multiple different machines. Tasks are distributed randomly over the running worker instances, and thus multiple users can make use of the external integration at the same time. ![](/assets/images/explanation-worker-flow-multiple-machines-f34342baf3e8a8a2a5a744f702509b2c.png) *Multiple workers across multiple machines* caution Parallel execution has to be supported by the software. Often each job will require an individual license of the software. So when 2 jobs run in parallel, this will probably require 2 software licenses as well. If no license is available, the worker will fail to execute the program and the external analysis will return a LicenseError to the VIKTOR application (unless a TimeoutError is returned first). ### Worker status[​](/docs/create-apps/software-integrations/.md#worker-status "Direct link to Worker status") Within the VIKTOR interface, a user can see the status of the connected workers via the icon in the top right corner: ![](data:image/png;base64,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) This gives a user insights in: * which workers are connected and available * how many workers per external package are connected * whether a worker is currently running a job or not ![](/assets/images/integration-status-modal-006f5ccee4c480b300cfcb62a74a7b88.png) *Worker status* Note that the worker status does not provide information about licenses being available or not. ### Personal workers vs Organization workers[​](/docs/create-apps/software-integrations/.md#personal-workers-vs-organization-workers "Direct link to Personal workers vs Organization workers") Personal workers connect software running on your personal computer to the VIKTOR cloud. This allows your own local tools to interact with VIKTOR securely. Organization workers connect software running on your organization or cloud servers to the VIKTOR cloud. This allows for centralized, scalable, and shared connections that mutliple users within your VIKTOR environment can access. | Integration | Installed on | Installed by | Purpose | | ------------------- | --------------------- | ---------------- | ---------------------------------- | | Personal worker | Personal computer | Individual users | Connect local software | | Organization worker | Organization's server | Admins | Connect organization-wide software | ## API tokens[​](/docs/create-apps/software-integrations/.md#api-tokens "Direct link to API tokens") When you want to integrate with online software, you don't need a worker, but you do need to take care of authentication. Most online programms support the use of API tokens for external access. An API token is a substitute for the username and password in a manual login flow. This token (sort of password) should be kept secret and not stored in the source code. In VIKTOR you can insert these tokens through [environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md). This environment variable is available for all instances of this app and all users using this app. ## OAuth 2.0[​](/docs/create-apps/software-integrations/.md#oauth-20 "Direct link to OAuth 2.0") Some online software supports (or requires) a more elaborate authentication flow, called OAuth 2.0. OAuth 2.0 is a widely supported authorization protocol that allows users to grant third-party applications limited access to their data, without requiring them to share their passwords. In this type of integration, users are directed to an external login page to authenticate. The authentication is personalized and will only give access to parts of the external software that this specific user has access to. Setting up and using an OAuth 2.0 integration is done as follows: 1. Creating an OAuth 2.0 integration (admin) 2. Implementing the integration in an app (developer) 3. Using the integration by logging in (user) VIKTOR provides both specific OAuth 2.0 integrations as well as a generic OAuth 2.0 integration, giving you the possibility to connect to any external software package that supports this protocol. ### 1. Creating an OAuth 2.0 integration (admin)[​](/docs/create-apps/software-integrations/.md#1-creating-an-oauth-20-integration-admin "Direct link to 1. Creating an OAuth 2.0 integration (admin)") A VIKTOR admin creates an OAuth 2.0 integration on the integrations page of the environment. This integration defines the connection between VIKTOR and the external software and needs to be assigned to specific applications that can use this integration. Each integration will get a unique name (e.g. `databricks-workspace-1`), which is used by the developer in the next step. More information on creating an OAuth 2.0 integration by the admin can be found [here](/docs/create-apps/software-integrations/generic/.md#generic-oauth-20-integration). ### 2. Implementing the integration in an app (developer)[​](/docs/create-apps/software-integrations/.md#2-implementing-the-integration-in-an-app-developer "Direct link to 2. Implementing the integration in an app (developer)") With the integration name, the developer can start the implementation. First the integration is added in the config file. This is used by the platform to know that this app needs an integration and to trigger a login button for the user. `viktor.config.toml` ``` oauth2_integrations = [ "databricks-workspace-1" ] ``` Secondly the logic that uses the integration can be implemented in the app. Often external software will provide examples and/or a Python SDK, making it easier to implement. In order to obtain the necessary token for authentication, you instantiate the `OAuth2Integration` class with the integration name and call the method `get_access_token`. ``` integration = vkt.external.OAuth2Integration('databricks-workspace-1') access_token = integration.get_access_token() # Example for Databricks (https://docs.databricks.com/aws/en/dev-tools/sdk-python#authenticate-the-databricks-sdk-for-python-with-your-databricks-account-or-workspace) from databricks.sdk import WorkspaceClient client = WorkspaceClient( host="http://myworkspace.cloud.databricks.com/", token=access_token ) for cluster in client.clusters.list(): print(cluster.cluster_name) ``` For more information about the configuration in app code refer to [viktor.config.toml](/docs/create-apps/references/viktor-config-toml/.md#oauth2_integrations). ### 3. Using the integration by logging in (user)[​](/docs/create-apps/software-integrations/.md#3-using-the-integration-by-logging-in-user "Direct link to 3. Using the integration by logging in (user)") With everything properly setup, the app is ready to be used. When a user enters the app for the first time, a pop-up will be shown, explaining that the user needs to login before the app can be used. The user logs in, thereby allowing the app to access the external software and the integration can be used. After a period of inactivity, the user needs to re-login to reactivate the integration. This duration is configurable per integration by the admin. ![](/assets/images/integration-connection-dialog-2c6ce841f9bf5556bcdc4a2a5e1136cf.png) *User asked to connect their account(s) when entering an app* --- # Autodesk Platform Services Autodesk Platform Services (APS) can be integrated with VIKTOR using the OAuth 2.0 workflow for token based authentication and authorization. A general introduction to OAuth 2.0 can be found [here](https://docs.viktor.ai/docs/create-apps/software-integrations/#oauth-20). ## Creating an OAuth 2.0 integration (admin)[​](/docs/create-apps/software-integrations/autodesk-platform-services/.md#creating-an-oauth-20-integration-admin "Direct link to Creating an OAuth 2.0 integration (admin)") First, an OAuth 2.0 integration must be set up by a VIKTOR admin. This must be done in APS and in VIKTOR, following these steps: ![](/assets/images/aps-integration-1-bd0b74c5a8fabdd3fd49f83ac25a95e6.png) 1. Navigate to the **Integrations** tab in the **Administrator** panel. 2. Select the **OAuth 2.0** tab. 3. Follow the steps in the modal: 1. Select **Autodesk Platform Services**. 2. Go to the "**Basic Information**" tab and fill the required fields, including the integration name, and select the applications that will use the APS integration. 3. Then, in the "**Configuration**" tab add the Authentication URL and Token URL as follows: * Authentication URL: * Token URL: 4. If you already have an active APS application, you can fill in the client ID and secret, as well as the [scopes](/docs/create-apps/software-integrations/autodesk-platform-services/.md#defining-scopes-for-aps-applications) and expiration date, if you do not have one, continue to the next step to create and set up the APS application. ![](/assets/images/aps-integration-2-3d419cb3185b6b6bcced49e9b053d764.png) 4. On the APS home page, go to your profile and click [**Applications**](https://aps.autodesk.com/hubs/@personal/applications/). 1. You can create a new application following this tutorial: [Create an app](https://aps.autodesk.com/en/docs/oauth/v2/tutorials/create-app/). 2. Or you can use an existing application. 5. In the APS application, open **App settings** and copy **Client ID** and **Client Secret** into the VIKTOR modal from **step 3**. ![](/assets/images/aps-integration-aps1-02f2d6ad8d8c35f2edf5a4e3c650660d.png) 6. Go to **General settings** and add the callback URL: ``` /api/integrations/oauth2/callback/ ``` Your environment URL should be `https://cloud.viktor.ai/` or similar, depending on your organization. ![](/assets/images/aps-integration-aps2-eba3b2bd103d50153f600bb2e4517233.png) 7. Open **App access** and select the APIs you want your application to access. ![](/assets/images/aps-integration-aps3-41d0302625669b769b92bfad63004993.png) 8. Save the configuration in each section and verify that everything is correctly set up. ### Defining Scopes for APS applications[​](/docs/create-apps/software-integrations/autodesk-platform-services/.md#defining-scopes-for-aps-applications "Direct link to Defining Scopes for APS applications") A scope defines what a token can do, it is the permission context for the token. A token that includes `data:read` can read data in APS, and it works with endpoints that require that scope. A token that lacks the scope cannot access those endpoints. Each endpoint page states the scopes it needs. The APS documentation lists all scope values in the **Scopes** section: [APS OAuth 2.0 scopes](https://aps.autodesk.com/en/docs/oauth/v2/developers_guide/scopes/). Common scopes include: * `data:read` * `data:write` * `data:create` * `code:all` * `data:search` * `viewables:read` Security best practices Use the minimum scopes required for your application to function when creating the integration in VIKTOR. This limits the impact in case of misuse. ## Integration with Autodesk Construction Cloud (ACC)[​](/docs/create-apps/software-integrations/autodesk-platform-services/.md#integration-with-autodesk-construction-cloud-acc "Direct link to Integration with Autodesk Construction Cloud (ACC)") Your **VIKTOR-APS** integration can connect to Autodesk Construction Cloud using **Custom integrations**. A custom integration connects your Autodesk Construction Cloud account to your APS application. The user must be an **Account Admin** to add the app integration. Follow these steps to connect your APS application to your ACC projects: 1. Log in to your ACC account. 2. Open **Custom integrations** and click **Add custom integration**. ![](/assets/images/aps-integration-acc1-19c9c4945c0379fe1727237bb9fa3011.png) 3. Enter the APS **Client ID** from the previous section. 4. Enter a name and a description for the custom integration. 5. Complete the integration by clicking **Add app**. ## Implementing the integration in an app (developer)[​](/docs/create-apps/software-integrations/autodesk-platform-services/.md#implementing-the-integration-in-an-app-developer "Direct link to Implementing the integration in an app (developer)") Once an administrator sets up and assigns the APS OAuth 2.0 integration to the app, the developer can start the implementation. ![](/assets/images/aps-integration-aps4-9af7fe8f522a7a431b7595f2bcc4421e.png) The developer should add the integration name to the app configuration. The platform uses it to show a login button when the user opens the app. Make sure your `viktor.config.toml` contains the name exactly as configured in the Administrator panel, and include an `oauth2_integrations` entry with the integration name, for example: `viktor.config.toml`: ``` app_type = "editor" python_version = "3.13" registered_name = "your-app-name" oauth2_integrations = [ "aps-integration-1" ] ``` Note The `OAuth2Integration` can only be used in local development. The [AppBuilder](https://docs.viktor.ai/docs/app-builder/) does not support this integration yet. Then implement the logic that uses the integration in the code. You can use raw REST requests or a Python SDK, as long as it is compatible with the VIKTOR OAuth flow. A popular library is `requests`. You can add it in your `requirements.txt` to use it in the application. ``` viktor==14.24.0 requests ``` To obtain an access token, instantiate `OAuth2Integration` with the integration name and call `get_access_token`. Below is a short example showing how to retrieve the user’s available hubs and display them in a [TableView](https://docs.viktor.ai/docs/create-apps/results-and-visualizations/data-and-tables/). It works when the VIKTOR APS integration is assigned to your app, the ACC custom integration is added to your account, and the user has granted access: ``` import viktor as vkt import requests class Parametrization(vkt.Parametrization): text = vkt.Text("# APS OAuth2 Integration") class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Get ACC Hubs") def get_hubs(self, params, **kwargs): integration = vkt.external.OAuth2Integration("aps-integration-1") token = integration.get_access_token() headers = {"Authorization": f"Bearer {token}"} endpoint = "https://developer.api.autodesk.com/project/v1/hubs" response = requests.get(endpoint, headers=headers, timeout=15) response.raise_for_status() hubs_data = response.json().get("data", []) data = [] for hub in hubs_data: hub_name = hub.get("attributes", {}).get("name", "") hub_id = hub.get("id", "") data.append([hub_name, hub_id]) return vkt.TableResult(data, column_headers=["Hub name", "ID"]) ``` Note The integration name in `OAuth2Integration` must match the value in `viktor.config.toml`. The ACC custom integration must be added in Account Admin, and the user must have access to projects in that account. --- # AxisVM An AxisVM binding has been developed by VIKTOR to simplify the process of creating and analyzing an AxisVM model. VIKTOR's AxisVM integration requires a specific AxisVM worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). note This binding was tested in AxisVM version 5. We cannot guarantee that the binding in combination with the worker will function properly with other versions of AxisVM. ## Creating a `Model`[​](/docs/create-apps/software-integrations/axisvm/.md#creating-a-model "Direct link to creating-a-model") An AxisVM model is made by starting off with an empty model and creating/modifying objects via their respective interfaces. The following [`Model`](/sdk/api/external/axisvm/.md#_Model) interfaces are available: * [`references`](/sdk/api/external/axisvm/.md#Model.references): for creating reference points, vectors, axes, planes and angles. * [`materials`](/sdk/api/external/axisvm/.md#Model.materials): for creating materials. * [`nodes`](/sdk/api/external/axisvm/.md#Model.nodes): for creating nodes. * [`cross_sections`](/sdk/api/external/axisvm/.md#Model.cross_sections): for creating cross-sections. * [`lines`](/sdk/api/external/axisvm/.md#Model.lines): for creating lines, beams, etc. * [`domains`](/sdk/api/external/axisvm/.md#Model.domains): for creating domains. * [`node_supports`](/sdk/api/external/axisvm/.md#Model.node_supports): for creating node supports. * [`line_supports`](/sdk/api/external/axisvm/.md#Model.line_supports): for creating line supports. * [`load_cases`](/sdk/api/external/axisvm/.md#Model.load_cases): for creating load cases. * [`loads`](/sdk/api/external/axisvm/.md#Model.loads): for creating loads. * [`load_combinations`](/sdk/api/external/axisvm/.md#Model.load_combinations): for creating load combinations. * [`sections`](/sdk/api/external/axisvm/.md#Model.sections): for creating sections, on which results can be obtained. * [`results`](/sdk/api/external/axisvm/.md#Model.results): for requesting results from the worker (only requested results will be returned). Below is an example of a model, representing a cantilever beam bending under its own weight: ``` import viktor as vkt model = vkt.axisvm.Model() # Initialize the empty model. material = model.materials.add_from_catalog('C12/15', vkt.axisvm.Material.DesignCode.EURO_CODE) cross_section = model.cross_sections.create_rectangular(0.01, 0.01) n1 = model.nodes.create(0, 0, 0) n2 = model.nodes.create(1, 0, 0) beam = model.lines.create(n1, n2).define_as_beam(material, cross_section) model.node_supports.create_relative_to_member(n1, stiffness_x=1e10, stiffness_y=1e10, stiffness_z=1e10, stiffness_xx=1e10, stiffness_yy=1e10, stiffness_zz=1e10) load_case = model.load_cases.create() model.loads.create_beam_self_weight(load_case, beam) model.results.nodal_displacements([n2]) ``` ## Running an AxisVM analysis[​](/docs/create-apps/software-integrations/axisvm/.md#running-an-axisvm-analysis "Direct link to Running an AxisVM analysis") The model can be fed to the [`AxisVMAnalysis`](/sdk/api/external/axisvm/.md#_AxisVMAnalysis) as follows: ``` import viktor as vkt # Run the analysis and obtain the results, model (.axs) and/or result file (.axe). analysis = vkt.axisvm.AxisVMAnalysis(model, return_results=True, return_model=True) analysis.execute(timeout=25) # make a conservative estimation of the time needed to finish results = analysis.get_results() # obtain the results in a dict model_file = analysis.get_model_file() # obtain the model file (.axs) result_file = analysis.get_result_file() # obtain the result file (.axe) ``` If `return_results` is set to `True`, an analysis will be performed and the following methods become available: * [`get_results`](/sdk/api/external/axisvm/.md#AxisVMAnalysis.get_results) * [`get_result_file`](/sdk/api/external/axisvm/.md#AxisVMAnalysis.get_result_file) If `return_model=True`, the model file will also become available: * [`get_model_file`](/sdk/api/external/axisvm/.md#AxisVMAnalysis.get_model_file) ## Testing[​](/docs/create-apps/software-integrations/axisvm/.md#testing "Direct link to Testing") New in v13.5.0 `mock_AxisVMAnalysis` decorator for easier testing of `AxisVMAnalysis` `AxisVMAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_AxisVMAnalysis`](/sdk/api/testing/.md#_mock_AxisVMAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_AxisVMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_AxisVMAnalysis( get_results={"Forces": ...}, get_model_file=File.from_path('test_file.axs'), get_result_file=File.from_path('test_file.axe'), ) def test_axis_vm_analysis(self): MyEntityTypeController().axis_vm_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). --- # Databricks Databricks supports various authentication methods, as outlined in their [documentation](https://docs.databricks.com/aws/en/dev-tools/auth/#databricks-authorization-methods). We recommend the use of OAuth 2.0 for users (OAuth U2M). A general introduction on OAuth 2.0 can be found [here](/docs/create-apps/software-integrations/.md#oauth-20). ## Creating an OAuth 2.0 integration (admin)[​](/docs/create-apps/software-integrations/databricks/.md#creating-an-oauth-20-integration-admin "Direct link to Creating an OAuth 2.0 integration (admin)") First an OAuth 2.0 integration needs be setup by one of the VIKTOR admins. This needs to be done in Databricks and in VIKTOR. ![](/assets/images/create-databricks-integration-for-admin-20e1c941728a50813fdf3a8d5999ce62.png) 1. Navigate to the "Integrations" tab in the Administrator panel 2. Select the OAuth 2.0 integrations tab 3. Click "Add OAuth 2.0 integration" 4. Follow the steps provided in the modal 1. Select "Databricks" 2. Fill in the basic information of the integration, including the app that the integration should be available to 3. Fill in the credentials needed to establish a connection. These credentials can found in your Databricks app. ![](/assets/images/create-oauth-integration-admin-configuration-details-7ced0828b6c88d9e12e5bb50d011c85e.png) 5. For gathering the OAuth 2.0 integration information, navigate to Databricks **account console** of your organization and then navigate to the **Settings**. Account console is if the Databricks setup does not live on Azure. 6. Go to **App Connections** tab and add a new connection. 1. Fill in basic connection information. 2. Add `/api/integrations/oauth2/callback/` to the allowed redirect urls. 3. Select the scope for your integration and make sure to enable generate a **client secret**. Security Best Practices * Use minimum scope for your application(s) to function when creating integration on VIKTOR. This would limit the impact when there is misuse of integrated software. * Use a short Time-to-Live for your Access Tokens when configuring the OAuth 2.0 application on the integration provider. ![](/assets/images/create-oauth-integration-admin-configuration-on-databricks-324bf62d8a28edb01e65f0f45146c4f8.png) 7. When the integration is created, you should copy the **Client ID** and **Client Secret** information and fill into the modal in the VIKTOR. You will not be able to gather these credentials again. 8. If you are intending to use **Accounts API** the urls can be set like below: * **Authentication URL**: `/oidc/accounts//v1/authorize` which is mostly resembling to `https://accounts.cloud.databricks.com/oidc/accounts/00000000-abcd-efgh-ijkl-000000000000/v1/authorize` * **Token URL**: `/oidc/accounts//v1/token` which is mostly resembling to `https://accounts.cloud.databricks.com/oidc/accounts/00000000-abcd-efgh-ijkl-000000000000/v1/token` * You can find your account id in your account console, profile section. ![](/assets/images/create-oauth-integration-admin-configuration-on-databricks-account-id-05e306fd976ca13dacc6ce3afda4a85e.png) 9. If you are intending to use **Workspace API** the urls can be set like below: * **Authentication URL**: `/oidc/v1/authorize` which is mostly resembling to `https://myworkspace.cloud.databricks.com/oidc/v1/authorize` * **Token URL**: `/oidc/v1/token` which is mostly resembling to `https://myworkspace.cloud.databricks.com/oidc/v1/token` * You can find your workspace url on the Browser URL part when you enter your Databricks workspace. ## Implementing the integration in an app (developer)[​](/docs/create-apps/software-integrations/databricks/.md#implementing-the-integration-in-an-app-developer "Direct link to Implementing the integration in an app (developer)") When the Databricks OAuth 2.0 integration has been set up and been assigned to the app, the developer can start implementing the integration. ![](/assets/images/OAuth-integrations-tab-app-details-f1c95d188c9ca211b7f6da1a05d1d0b9.png) *OAuth 2.0 integrations information in the app details page* First the integration is added in the config file, using the integration name. This is used by the platform to trigger a login button for the user when entering the app. `viktor.config.toml` ``` ... oauth2_integrations = [ "databricks-workspace-1" ] ... ``` Secondly the logic that uses the integration can be implemented in the app. Using Databrick's [Python SDK](https://docs.databricks.com/aws/en/dev-tools/sdk-python), you can quickly integrate. In order to obtain the necessary token for authentication, you instantiate the `OAuth2Integration` class with the integration name and call the method `get_access_token`. ``` import viktor as vkt from databricks.sdk import WorkspaceClient integration = vkt.external.OAuth2Integration('databricks-workspace-1') access_token = integration.get_access_token() client = WorkspaceClient( host="http://myworkspace.cloud.databricks.com/", token=access_token ) for cluster in client.clusters.list(): print(cluster.cluster_name) ``` --- # D-Foundations VIKTOR's D-Foundations integration requires a specific D-Foundations worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). note The D-Foundations binding is created to work with D-Foundations version v17. Other versions of D-Foundations might not be able to read the generated input files properly. A D-Foundations binding has been developed by VIKTOR to simplify the process of creating a D-Foundations model, running an analysis (worker required) and parsing the results. The process consists of the following steps: 1. Create the 'empty' model (optionally with default materials), applying the desired settings. 2. (Optional) Create material(s). Also possible to only use the default materials. 3. Create or import profile(s). 4. Create pile type(s). 5. Create pile(s). 6. Let VIKTOR generate the input file for you. 7. Run the D-Foundations analysis (worker required) with the input file. 8. Obtain and parse the results, and process them as desired. ## Supported model types[​](/docs/create-apps/software-integrations/dfoundations/.md#supported-model-types "Direct link to Supported model types") D-Foundations supports 4 type of models. The following types are currently (un)supported in the D-Foundations binding: * Bearing Piles (EC7-NL): supported * Bearing Piles (EC7-B): not supported * Tension Piles (EC7-NL): supported * Shallow Foundations (EC7-NL): not supported ## Creating the model (example: Bearing Piles (EC7-NL) model)[​](/docs/create-apps/software-integrations/dfoundations/.md#creating-the-model-example-bearing-piles-ec7-nl-model "Direct link to Creating the model (example: Bearing Piles (EC7-NL) model)") The class [`BearingPilesModel`](/sdk/api/external/dfoundations/.md#_BearingPilesModel) represents the Bearing Piles (EC7-NL) model in D-Foundations. The following code shows how a (minimal) bearing piles model can be created in Python using the binding. The Tension Piles (EC7-NL) model can be created in a similar way, using the [`TensionPilesModel`](/sdk/api/external/dfoundations/.md#_TensionPilesModel) class. ``` import viktor as vkt # Create the model with misc. options. options = vkt.dfoundations.BearingPilesCalculationOptions( vkt.dfoundations.CalculationType.BEARING_CAPACITY_AT_FIXED_PILE_TIP_LEVEL, False ) model = vkt.dfoundations.BearingPilesModel( vkt.dfoundations.ConstructionSequence.CPT_INSTALL_EXCAVATION, options, -5.0 ) # Create material (optional), or use one of the default material names. model.create_material("my_material", vkt.dfoundations.SoilType.SAND, 19.0, 19.0, 3.0) # Create profile(s). layers = [ vkt.dfoundations.ProfileLayer(0.0, "my_material"), vkt.dfoundations.ProfileLayer(-20.0, "my_material") ] measurements = [(0.0, 10.0), (-20.0, 20.0)] model.create_profile('my_profile', layers, 0.0, 0.0, measurements, -5.0, -15.0, 1.0, -10.0, -12.0, -0.11) # Create pile type(s). model.create_pile_type( "my_pile_type", vkt.dfoundations.RectPile(1.0, 1.0), vkt.dfoundations.PileType.PREFAB_CONCRETE, vkt.dfoundations.PileSlipLayer.NONE ) # Create pile(s). model.create_pile("my_pile", 0.0, 0.0, -1.0, 1.0, 0.0, 0.0) # Generate the input file for the model as if it was generated by D-Foundations. # Metadata can be used (not required) to update data such as titles, company, etc. metadata = vkt.dfoundations.Metadata(title_1='Example Model', company='VIKTOR') foi_file = model.generate_input_file(metadata) # Run the analysis with the generated input file (requires worker). analysis = vkt.dfoundations.DFoundationsAnalysis(foi_file) analysis.execute(300) # Obtain the result file. fod_file = analysis.get_output_file() ``` ## Parsing output using `OutputFileParser`[​](/docs/create-apps/software-integrations/dfoundations/.md#parsing-output-using-outputfileparser "Direct link to parsing-output-using-outputfileparser") After running a [`DFoundationsAnalysis`](/sdk/api/external/dfoundations/.md#_DFoundationsAnalysis), the fod file can be obtained and results can be extracted. The class [`OutputFileParser`](/sdk/api/external/dfoundations/.md#_OutputFileParser) makes the parsing more convenient and return Python objects that can be further processed: ``` parser = vkt.dfoundations.OutputFileParser(fod_file) # Calculation parameters. calculation_parameters = parser.calculation_parameters # Parsed results in the form of a dictionary. results = parser.results(False) # True (default) for returning pandas DataFrame(s). # Raw, unparsed results in the form of a string. # Manual parsing required. Useful, if parser.results is not sufficient. raw_results = parser.raw_results ``` ## Supported D-Foundation versions[​](/docs/create-apps/software-integrations/dfoundations/.md#supported-d-foundation-versions "Direct link to Supported D-Foundation versions") Currently, the parser supports the following versions (completely or partially) of D-Foundations: * v17: * Tension Piles model * Bearing Piles model - Preliminary Design (calculation options only) * v19: * Tension Piles model * Bearing Piles model - Verification ## Testing[​](/docs/create-apps/software-integrations/dfoundations/.md#testing "Direct link to Testing") New in v13.5.0 `mock_DFoundationsAnalysis` decorator for easier testing of `DFoundationsAnalysis` `BearingPilesModel.generate_input_file`, `TensionPilesModel.generate_input_file` and `DFoundationsAnalysis.execute` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DFoundationsAnalysis`](/sdk/api/testing/.md#_mock_DFoundationsAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_DFoundationsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DFoundationsAnalysis(get_output_file={ '.fod': File.from_path('test_output.fod'), '.fos': File.from_path('test_output.fos'), }) def test_dfoundations_analysis(self): MyEntityTypeController().dfoundations_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). --- # D-Geo Stability VIKTOR's D-Geo Stability integration requires a specific D-Geo Stability worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing a D-Geo Stability model in VIKTOR can be done using the [`DGeoStabilityAnalysis`](/sdk/api/external/dgeostability/.md#_DGeoStabilityAnalysis) class (worker required). No binding is provided by VIKTOR for this module, which means that the input file has to be generated manually: ``` import viktor as vkt # Generate the input STI file. input_file = ... # Run the analysis and obtain the output file. analysis = vkt.dgeostability.DGeoStabilityAnalysis(input_file) analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` ## Testing[​](/docs/create-apps/software-integrations/dgeostability/.md#testing "Direct link to Testing") New in v13.5.0 `mock_DGeoStabilityAnalysis` decorator for easier testing of `DGeoStabilityAnalysis` `DGeoStabilityAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DGeoStabilityAnalysis`](/sdk/api/testing/.md#_mock_DGeoStabilityAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_DGeoStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DGeoStabilityAnalysis(get_output_file={ '.sto': File.from_path('test_output.sto'), }) def test_dgeostability_analysis(self): MyEntityTypeController().dgeostability_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). --- # D-Settlement VIKTOR's D-Settlement integration requires a specific D-Settlement worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). A D-Settlement binding has been developed by VIKTOR to simplify the process of creating a D-Settlement model, running an analysis (worker required) and parsing the results. The process consists of the following steps: 1. Create the 'empty' model, applying the desired settings. 2. Extend the model with the desired objects (material, layers, pl-lines, loads, verticals, calculation times, etc.). 3. Let VIKTOR generate the input file for you. 4. Run the D-Settlement analysis (worker required) with the input file mentioned above. 5. Obtain and parse the results, and process them as desired. It is possible to create both a 1D-model and a 2D-model using VIKTOR's D-Settlement binding. The following sections describe how each of these models can be made. ## 1D-model[​](/docs/create-apps/software-integrations/dsettlement/.md#1d-model "Direct link to 1D-model") The class [`Model1D`](/sdk/api/external/dsettlement/.md#_Model1D) represents the 1D-model in D-Settlement. Its geometry is defined by a list of depths versus materials. ``` import viktor as vkt # Create the model with misc. default parameters. model = vkt.dsettlement.Model1D( vkt.dsettlement.CalculationModel.NEN_KOPPEJAN, vkt.dsettlement.ConsolidationModel.TERZAGHI ) # Create material(s). model.create_material("my_mat", 21.0, 19.0, color=vkt.Color(0, 0, 0)) # Update the geometry. model.update_geometry(-1.0, [(1.0, "Loam"), (0.0, "my_mat")], phreatic_level=-3.0) # Create loads. model.create_uniform_load("my_load", 0, 0.001, 0.0, 0.0) # Generate the input file for the model as if it was generated by D-Settlement. # Metadata can be used (not required) to update data such as created_by, titles, etc. metadata = vkt.dsettlement.Metadata(title_1='Example Model', created_by='VIKTOR') input_file = model.generate_input_file(metadata) # Run the analysis with the generated input file (requires worker). analysis = vkt.dsettlement.DSettlementAnalysis(input_file) analysis.execute(300) # Obtain the result file. sld_file = analysis.get_sld_file() ``` ## 2D-model[​](/docs/create-apps/software-integrations/dsettlement/.md#2d-model "Direct link to 2D-model") The class [`Model2D`](/sdk/api/external/dsettlement/.md#_Model2D) represents the 2D-model in D-Settlement. Its geometry can be built-up from layers, consisting of points. It is possible to create a model using VIKTOR's binding that will result in errors in D-Settlement (e.g. intersecting boundaries). Notice that it is not guaranteed that these errors are captured in the code upon creation of the model, such that the error only shows up during the analysis. It is the responsibility of the developer to build-up a 'valid' model. ``` import viktor as vkt # Initialize the settings for vertical drains. vertical_drain = vkt.dsettlement.VerticalDrain( vkt.dsettlement.DrainType.SAND_WALL, 5.0, 90.0, 0.0, 2.0, 4.0, start_of_drainage=2.0, phreatic_level_in_drain=4.0 ) # Create the model with a starting bottom boundary, vertical drainage settings and misc. default parameters. model = vkt.dsettlement.Model2D( vkt.dsettlement.CalculationModel.NEN_KOPPEJAN, vkt.dsettlement.ConsolidationModel.TERZAGHI, boundary_bottom=[(0.0, 0.0), (100.0, 0.0)], vertical_drain=vertical_drain ) # Create points for defining boundaries and pl-lines. points_boundary1 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 2.5)]] points_boundary2 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 7.5)]] points_boundary3 = [model.create_point(x, y) for (x, y) in [(0.0, 10.0), (25, 10.0), (75, 10.0), (100.0, 10.0)]] points_plline1 = [model.create_point(x, y) for (x, y) in [(0.0, 4.0), (100.0, 4.0)]] points_plline2 = [model.create_point(x, y) for (x, y) in [(0.0, 6.0), (100.0, 6.0)]] # Create the pl-lines. plline1 = model.create_pl_line(points_plline1, is_phreatic=True) plline2 = model.create_pl_line(points_plline2) # Create the layers. model.create_layer(points_boundary1, 'Sand', pl_line_top=99, pl_line_bottom=plline2) model.create_layer(points_boundary2, 'Soft Clay', pl_line_top=99, pl_line_bottom=99) model.create_layer(points_boundary3, 'Loam', pl_line_top=plline1, pl_line_bottom=99) # Create verticals. model.create_vertical(45.0) model.create_vertical(50.0) model.create_vertical(55.0) # Create loads. model.create_non_uniform_load('load1', [(25, 10.0), (50.0, 12.0), (75, 10.0)]) # Create calculation/residual times. model.set_calculation_times(1, 4, 2, 5) # Generate the input file for the model as if it was generated by D-Settlement. # Metadata can be used (not required) to update data such as created_by, titles, etc. metadata = vkt.dsettlement.Metadata(title_1='Example Model', created_by='VIKTOR') input_file = model.generate_input_file(metadata) # Run the analysis with the generated input file (requires worker). analysis = vkt.dsettlement.DSettlementAnalysis(input_file) analysis.execute(300) # Obtain the result file. sld_file = analysis.get_sld_file() ``` ## Supported features[​](/docs/create-apps/software-integrations/dsettlement/.md#supported-features "Direct link to Supported features") Currently, the following 1D-Model features are supported: * Defining consolidation and calculation model and various settings. * Creating materials (or using the default ones). * Defining the geometry. * Creating uniform loads. * Adding calculation times (residual times). Currently, the following 2D-Model features are supported: * Defining consolidation and calculation model and various settings. * Creating materials (or using the default ones). * Creating points (for the creation of layers and pl-lines). * Creating layers. * Creating pl-lines. * Creating uniform loads. * Creating non-uniform loads. * Creating verticals. * Adding calculation times (residual times). ## Parsing output using `OutputFileParser`[​](/docs/create-apps/software-integrations/dsettlement/.md#parsing-output-using-outputfileparser "Direct link to parsing-output-using-outputfileparser") After running a [`DSettlementAnalysis`](/sdk/api/external/dsettlement/.md#_DSettlementAnalysis), the sld file can be obtained and results can be extracted. The class [`OutputFileParser`](/sdk/api/external/dsettlement/.md#_OutputFileParser) makes the parsing more convenient and return Python objects that can be further processed: ``` parser = vkt.dsettlement.OutputFileParser(sld_file) vertical_results = parser.vertical_results residual_times = parser.residual_times ``` ## Testing[​](/docs/create-apps/software-integrations/dsettlement/.md#testing "Direct link to Testing") New in v13.5.0 `mock_DSettlementAnalysis` decorator for easier testing of `DSettlementAnalysis` `Model1D.generate_input_file`, `Model2D.generate_input_file` and `DSettlementAnalysis.execute` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DSettlementAnalysis`](/sdk/api/testing/.md#_mock_DSettlementAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_DSettlementAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSettlementAnalysis(get_output_file={ '.sld': File.from_path('test_output.sld'), '.slo': File.from_path('test_output.slo') }) def test_dsettlement_analysis(self): MyEntityTypeController().dsettlement_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/StringIO object (with empty content) is returned each time the corresponding method is called (endlessly). --- # D-Sheet Piling VIKTOR's D-Sheet Piling integration requires a specific D-Sheet Piling worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing a D-Sheet Piling model in VIKTOR can be done using the [`DSheetPilingAnalysis`](/sdk/api/external/dsheetpiling/.md#_DSheetPilingAnalysis) class (worker required). No binding is provided by VIKTOR for this module, which means that the input file has to be generated manually or by using the [GEOLIB](/docs/create-apps/software-integrations/geolib/.md): ``` import viktor as vkt # Generate the input SHI file. input_file = ... # Run the analysis and obtain the output file. analysis = vkt.dsheetpiling.DSheetPilingAnalysis(input_file) analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` ## Testing[​](/docs/create-apps/software-integrations/dsheetpiling/.md#testing "Direct link to Testing") New in v13.5.0 `mock_DSheetPilingAnalysis` decorator for easier testing of `DSheetPilingAnalysis` `DSheetPilingAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DSheetPilingAnalysis`](/sdk/api/testing/.md#_mock_DSheetPilingAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_DSheetPilingAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSheetPilingAnalysis(get_output_file={ '.shd': File.from_path('test_output.shd'), '.shl': File.from_path('test_output.shl'), '.shs': File.from_path('test_output.shs'), '.sho': File.from_path('test_output.sho') }) def test_dsheetpiling_analysis(self): MyEntityTypeController().dsheetpiling_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). --- # D-Stability VIKTOR's D-Stability integration requires a specific D-Stability worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing a D-Stability model in VIKTOR can be done using the [`DStabilityAnalysis`](/sdk/api/external/dstability/.md#_DStabilityAnalysis) class (worker required). No binding is provided by VIKTOR for this module, which means that the input file has to be generated manually or by using the [GEOLIB](/docs/create-apps/software-integrations/geolib/.md): ``` import viktor as vkt # Generate the input STIX file. input_file = ... # Run the analysis and obtain the output file. analysis = vkt.dstability.DStabilityAnalysis(input_file) analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` ## Testing[​](/docs/create-apps/software-integrations/dstability/.md#testing "Direct link to Testing") New in v13.5.0 `mock_DStabilityAnalysis` decorator for easier testing of `DStabilityAnalysis` `DStabilityAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DStabilityAnalysis`](/sdk/api/testing/.md#_mock_DStabilityAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_DStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DStabilityAnalysis(get_output_file={ '.stix': File.from_path('test_output.stix') }) def test_dstability_analysis(self): MyEntityTypeController().dstability_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). --- # Dynamo Nodes \[BETA] caution The VIKTOR Dynamo nodes are currently in **BETA**, which means we reserve the right to make breaking changes without providing an upgrade strategy. VIKTOR offers a Dynamo library for easy drag-and-drop of custom VIKTOR nodes within Dynamo. The functionalities of these nodes strongly resemble the functionalities of the [`viktor.api_v1`](/sdk/api/api-v1/.md) module and can be used to communicate with certain entities that are present in a workspace of a VIKTOR application. ## Installation[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#installation "Direct link to Installation") The VIKTOR package can be installed through the Dynamo interface: * In the toolbar navigate to "Packages > Search for a Package..." * In the search bar type "VIKTOR" * Find VIKTOR (by viktor.ai) and click on `+ Install` to install ![](/assets/images/dynamo-viktor-library-cecf3e450c3a5f98f2649d8c4953dd2f.png) After the package has been installed successfully, you will see "VIKTOR" has been added to the Add-ons in the library bar: ![](/assets/images/dynamo-viktor-add-on-67811871d6cc90d8862a99bcec5efbe7.png) ## Implementation[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#implementation "Direct link to Implementation") The starting point is logging in to VIKTOR using the `Login.login` node. This requires three input text nodes consisting of your username, password, and environment which you want to connect to. The login method returns an `Environment` object. With this object we can select the workspace of interest. This is done using the `Environment.SelectWorkspace` node, which triggers a dropdown menu with the available workspaces. In case the environment consists of a single workspace, this will automatically be selected. ![](/assets/images/dynamo-viktor-login-247fe0d93493104c379f21f7e6b58d30.png) Alternatively, you may store your credentials in a separate file. This way you will be able to share dynamo projects amongst colleagues without sharing personal credentials: ![](/assets/images/dynamo-viktor-login-file-9a7abf40bfee21f3a8fa89663db6d4f3.png) The `Environment.SelectWorkspace` method returns the `Workspace` object. The next step is to obtain the root entities using the `Workspace.GetRootEntities` node. The root entities are returned as a list of `Entity` objects. This list can be passed to the `Workspace.SelectFromEntities` node, to trigger another dropdown menu. After selecting the entity of interest, properties such as the entity name or last saved params can be retrieved, or you can obtain different entities such as the children or siblings: ![](/assets/images/dynamo-viktor-select-entity-f47dc9610215eb448e94495ff221b38e.png) The example above displays the general flow of the VIKTOR Dynamo nodes. See [Available Nodes](/docs/create-apps/software-integrations/dynamo-nodes/.md#available-nodes) for an overview of all the nodes and the actions that can be performed. caution Dynamo will only re-execute nodes that have been subjected to a change in input. When, for example, an entity has been updated in the VIKTOR interface, this will not automatically be detected by Dynamo. For such cases, you will need to manually trigger a complete rerun, for example: * disconnect the nodes `Login.login` and `Environment.SelectWorkspace` * click "Run" to trigger an entire rerun * reconnect the two nodes * click "Run" to trigger an entire rerun ## Available Nodes[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#available-nodes "Direct link to Available Nodes") ### Login[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#login "Direct link to Login") ![](data:image/png;base64,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) ### Environment[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#environment "Direct link to Environment") ![](data:image/png;base64,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) ### Workspace[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#workspace "Direct link to Workspace") ![](/assets/images/dynamo-node-Workspace-084792ab71dd8287c8ac036bd6226bd8.png) ### Entity[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#entity "Direct link to Entity") ![](/assets/images/dynamo-node-Entity-6d72d6abb0135f08ff7eeb6249236b62.png) ### EntityType[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#entitytype "Direct link to EntityType") ![](data:image/png;base64,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) ### EntityRevision[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#entityrevision "Direct link to EntityRevision") ![](data:image/png;base64,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) ## Limitations[​](/docs/create-apps/software-integrations/dynamo-nodes/.md#limitations "Direct link to Limitations") The Dynamo package has a couple of limitations in contrast to the actual [`viktor.api_v1`](/sdk/api/api-v1/.md) module: * Not able to perform "privileged" API calls to [bypass user access restrictions](/docs/api/sdk/.md#bypassing-user-access-restrictions). * No deserialization of params, which means that the params are returned as raw data. For example, a `GeoPoint` will be returned as dictionary containing a `lat` and `lon` property, an `Entity` will be returned as integer (entity id) etc. * Less efficient (no caching). For example, an API call is performed to get the params of an entity for each single `LastSavedParams` node. --- # Dynamo Sandbox caution This guide is only relevant for **Dynamo Sandbox**, not to be confused with the Dynamo plugin for Revit! tip This guide provides the basis information about our Dynamo Sandbox integration. **If you setup this integration for the first time, we recommend to follow the [Dynamo tutorial](/docs/tutorials/integrate-dynamo/.md).** A [`dynamo`](/sdk/api/external/dynamo/.md) module has been developed by VIKTOR which can be used for easy updating of Dynamo input files and processing output files (results + geometry). With the Dynamo worker you will also be able to completely automate an integration with Dynamo Sandbox. ## Install a Dynamo worker[​](/docs/create-apps/software-integrations/dynamo/.md#install-a-dynamo-worker "Direct link to Install a Dynamo worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Dynamo** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the DynamoWPFCLI executable 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Dynamo** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the DynamoWPFCLI executable 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ## Updating a model[​](/docs/create-apps/software-integrations/dynamo/.md#updating-a-model "Direct link to Updating a model") An existing Dynamo model can be passed to VIKTOR's [`DynamoFile`](/sdk/api/external/dynamo/.md#_DynamoFile) as shown below. With the `update` method, the value of input nodes can be updated. When all inputs have been updated as desired, the `generate` method can be used to generate an updated `File` object. ``` import viktor as vkt file = vkt.File.from_path("template.dyn") dyn_file = vkt.dynamo.DynamoFile(file) # update input nodes radius = params.radius dyn_file.update('Radius', radius) # input node called "Radius" ... # generate updated file input_file = dyn_file.generate() ``` ## Running an analysis[​](/docs/create-apps/software-integrations/dynamo/.md#running-an-analysis "Direct link to Running an analysis") Integrating with Dynamo Sandbox can be done using the [`DynamoAnalysis`](/sdk/api/external/dynamo/.md#_DynamoAnalysis) class (worker required): ``` files = [ ('input.dyn', input_file), ] # run the analysis analysis = vkt.dynamo.DynamoAnalysis(files=files, output_filenames=["output.xml", "geometry.json"]) analysis.execute(timeout=60) ``` The `executable_key` in the example above refers to the "dynamo" command. This command should also be specified in the configuration file on the server, located in the same directory as the worker. By pointing to the file location of `DynamoWPFCLI.exe` (Dynamo Sandbox command-line interface), the Dynamo Sandbox integration can be established. With additional arguments we can specify where the input model is located and where the results should be exported to. See the [Dynamo Sandbox documentation](https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Command-Line-Interface) for more info on running Dynamo from the command-line. **config.yaml** ``` executables: dynamo: path: 'C:\path\to\DynamoSandbox\DynamoWPFCLI.exe' arguments: - '-o' - 'input.dyn' - '-v' - 'output.xml' maxParallelProcesses: 1 ``` Geometry can also be exported, for which an installation of either "FormIt" or "Revit" is required: ``` arguments: ... - '-gp' - 'C:\Program Files\Autodesk\FormIt' # or Revit - '-g' - 'geometry.json' ``` ## Processing results[​](/docs/create-apps/software-integrations/dynamo/.md#processing-results "Direct link to Processing results") After running the analysis, the output file (.xml) can be obtained using: ``` output_file = analysis.get_output_file("output.xml", as_file=True) ``` With the `as_file` flag, VIKTOR is instructed to return a `File` object which can directly be passed to the [`get_dynamo_result`](/sdk/api/external/dynamo/.md#_get_dynamo_result) function. The results can then be obtained by node id, which corresponds to the same node id as the input file. ``` import viktor as vkt dyn_file = vkt.dynamo.DynamoFile(file) ... output_id = dyn_file.get_node_id("Area") # output node called "Area" with output_file.open_binary() as f: result = vkt.dynamo.get_dynamo_result(f, id_=output_id) ``` note Results will be returned as `str` type, which means you will need to take care of conversions in the app. ## Processing geometry[​](/docs/create-apps/software-integrations/dynamo/.md#processing-geometry "Direct link to Processing geometry") In a similar matter the geometry file can be obtained after the analysis has been performed. With the helper function [`convert_geometry_to_glb`](/sdk/api/external/dynamo/.md#_convert_geometry_to_glb), you can convert it to a GLB type file, which can directly be visualized in a `GeometryResult`. ``` import viktor as vkt @vkt.GeometryView(...) def geometry_view(self, params, **kwargs): ... geometry_file = analysis.get_output_file('geometry.json', as_file=True) glb_file = vkt.dynamo.convert_geometry_to_glb(geometry_file) return vkt.GeometryResult(glb_file) ``` ## Testing[​](/docs/create-apps/software-integrations/dynamo/.md#testing "Direct link to Testing") `DynamoAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_DynamoAnalysis`](/sdk/api/testing/.md#_mock_DynamoAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_DynamoAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DynamoAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). --- # ETABS and SAP2000 ## Introduction[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#introduction "Direct link to Introduction") 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. ## The worker[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#the-worker "Direct link to 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. ![worker](/assets/images/integration_etabs_worker-ee5b31b4ce7e118aef4f514a2b036f73.png) Here is what happens during the integration: 1. The user enters input parameters in the **VIKTOR UI**. 2. The `app.py` in the VIKTOR app sends these parameters to the worker. 3. The worker (running on your local machine or a virtual machine) creates the model using the input parameters in ETABS/SAP2000. 4. The worker sends back the result of the **calculation** to your VIKTOR app. 5. **VIKTOR UI** displays the result of the calculation. ## Install an ETABS worker[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#install-an-etabs-worker "Direct link to Install an ETABS worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **ETABS** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your 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 the following command in your terminal ``` where python ``` 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your default Python environment can usually be found in `C:\Users\\AppData\Local\Programs\Python\Python31X\python.exe`. If you cannot find it, try running `where python` in your terminal. 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. note For SAP2000, follow the same steps, but select `SAP2000` instead. ## Install Python dependencies[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#install-python-dependencies "Direct link to Install Python dependencies") The worker will control ETABS and SAP2000 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. 1. Install the necessary libraries (`pywin32` and `comtypes`) using `pip` in the python environment selected during installation: ``` pip install pywin32 comtypes ``` ## Set up the app[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#set-up-the-app "Direct link to Set up the app") 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.py` contains the logic of your VIKTOR app. It will use the `inputs.json` file as input for the worker and reads the `output.json` generated by the worker. * The worker executes the `run_etabs_model.py` using the Python environment defined during worker installation (also defined in the `config.yaml`). This file will generate `output.json` which 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() ``` info You can check the following [tutorial](/docs/tutorials/integrate-etabs-sap2000/.md) to see the worker in action! ## Conclusion[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#conclusion "Direct link to Conclusion") By following this guide, you’ve learned how to set up your worker and now have the templates you need to integrate SAP2000 and ETABS with your app. You’re ready to automate all your designs and analysis. ## Testing[​](/docs/create-apps/software-integrations/etabs-and-sap2000/.md#testing "Direct link to Testing") `ETABSAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_ETABSAnalysis`](/sdk/api/testing/.md#_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'), # : '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). --- # Excel VIKTOR provides an integration with Excel to be able to use an Excel sheet **with macros** within your app. If you want to use an Excel sheet **without macros** as a calculation tool, you can also consider using [`SpreadsheetCalculation`](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md). VIKTOR's Excel integration requires a specific Excel worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Instances of [`NamedInputCell`](/sdk/api/external/spreadsheet/.md#_NamedInputCell) (cells which can be found using a certain key) and [`DirectInputCell`](/sdk/api/external/spreadsheet/.md#_DirectInputCell) (cell which can be found by a direct address `{sheet, column, row}`) can be used to fill the template. Similarly, instances of [`NamedOutputCell`](/sdk/api/external/spreadsheet/.md#_NamedOutputCell) and [`DirectOutputCell`](/sdk/api/external/spreadsheet/.md#_DirectOutputCell) can be used to specify which cells should be returned. Below example assumes the template is available. The sheet can be filled with predefined values: ``` import viktor as vkt def run_excel(): named_input_cells = [ vkt.excel.NamedInputCell('named_cell_1', 'text_to_be_placed'), vkt.excel.NamedInputCell('named_cell_2', 5), ] macros = [vkt.excel.Macro('caculate_mean'), vkt.excel.Macro('calculate_area')] area_cell = vkt.excel.DirectOutputCell('sheet1', 'B', 9) direct_output_cells = [ area_cell ] excel = vkt.excel.Excel(template=my_template, named_input_cells=named_input_cells, macros=macros, direct_output_cells=direct_output_cells) # The timeout in excel.execute() is the time in seconds the whole cycle of # sending the job, executing the job, and receiving the job result may take. excel.execute(timeout=120) return area_cell.result # or excel.get_direct_cell_result('sheet1', 'B', 9) ``` The macros are run in the order in which they are present in the list. Thus, in above example 'calculate\_mean' is run first and 'calculate\_area' second. ## Testing[​](/docs/create-apps/software-integrations/excel/.md#testing "Direct link to Testing") New in v13.5.0 `mock_Excel` decorator for easier testing of `Excel` `Excel.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_Excel`](/sdk/api/testing/.md#_mock_Excel) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_Excel from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_Excel( get_named_cell_result={ 'cell_1': 1, # : 'cell_2': 2, ... }, get_direct_cell_result={ ('sheet_1', 'A', 1): 1, # (, , ): ('sheet_1', 'C', 1): 3, ... }, get_filled_template=File.from_path('test_file.xlsx'), ) def test_excel_analysis(self): MyEntityTypeController().excel_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). --- # Other Software VIKTOR comes with a list of specific integrations, but also enables you to integrate with other software packages not listed. This is possible using * Generic worker * Generic OAuth 2.0 integration. A general introduction on OAuth 2.0 and a comparison with other integration types can be found here [here](/docs/create-apps/software-integrations/.md). ## Generic worker[​](/docs/create-apps/software-integrations/generic/.md#generic-worker "Direct link to Generic worker") VIKTOR offers a Generic [worker](/docs/create-apps/software-integrations/.md#workers), which can be used to integrate with any software package that supports command-line interaction. The [`GenericAnalysis`](/sdk/api/external/generic/.md#_GenericAnalysis) class is used for this, which requires one or multiple input files. Furthermore, you need to specify an `executable_key` to instruct the worker to call a specific task as defined in the configuration file (`config.yaml`). ``` from viktor.external.generic import GenericAnalysis # Generate the input file(s) files = [ ('input1.txt', file1), ('input2.txt', file2) ] # Run the analysis and obtain the output file. generic_analysis = GenericAnalysis(files=files, executable_key="some_executable", output_filenames=["output.txt"]) generic_analysis.execute(timeout=60) output_file = generic_analysis.get_output_file("output.txt") ``` The `executable_key` in the example above refers to the "some\_executable" command. This command should also be specified in the configuration file on the server, located in the same directory as the worker: **config.yaml** ``` executables: some_executable: path: 'C:\path\to\executable.exe' arguments: - '-arg1' - '-arg2' - '-arg3' workingDirectoryPath: 'C:\path\to\script' maxParallelProcesses: 1 # must be 1 if any of the above workingDirectoryPath is not '' (stateful path) ``` note If a fixed `workingDirectoryPath` is defined in the configuration file the maximum number of parallel processes should be 1. When the `workingDirectoryPath` is not specified a temporary directory will be created to run each job. This allows for a `maxParallelProcesses > 1`. note The worker reads the config file once during startup. So when you change the config file, you will need to restart the worker for your changes to take effect. With this setup, we can basically run any third-party software which supports command-line execution. ### Testing[​](/docs/create-apps/software-integrations/generic/.md#testing "Direct link to Testing") New in v13.5.0 `mock_GenericAnalysis` decorator for easier testing of `GenericAnalysis` `GenericAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_GenericAnalysis`](/sdk/api/testing/.md#_mock_GenericAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_GenericAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GenericAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). ## Generic OAuth 2.0 integration[​](/docs/create-apps/software-integrations/generic/.md#generic-oauth-20-integration "Direct link to Generic OAuth 2.0 integration") VIKTOR offers a generic OAuth 2.0 integration, enabling you to connect to any software which supports the OAuth 2.0 protocol. ### Creating a generic OAuth 2.0 integration (admin)[​](/docs/create-apps/software-integrations/generic/.md#creating-a-generic-oauth-20-integration-admin "Direct link to Creating a generic OAuth 2.0 integration (admin)") First a generic OAuth 2.0 integration needs be setup by one of the VIKTOR admins. This needs to be done in the third-party software and VIKTOR. ![](/assets/images/create-oauth-generic-integration-admin-211e3cf4e5083ecb6b34b9d09f49e084.png) 1. Navigate to the "Integrations" tab in the Administrator panel 2. Select the "OAuth 2.0 integrations" tab 3. Click "Add OAuth 2.0 integration" 4. Follow the steps provided in the modal 1. Select "Generic" 2. Fill in the basic information of the integration, including the app that the integration should be available to 3. Fill in the credentials needed to establish a connection. These credentials can found in your third-party software app. 5. Consult the vendor's documentation on how to set up an "OAuth 2.0" application. In general, the steps are: 1. Create an OAuth 2.0 application within the relevant software. 2. Make sure you gather **Client ID** and **Client Secret** * Most vendors use the terminology **Public App** or **Non-Confidential App** for creating OAuth 2.0 applications for public usage (lacking a **Client Secret**). Since VIKTOR Platform does not support public applications, make sure not to enable public usage for the relevant application. 3. Make sure you allow `/api/integrations/oauth2/callback/` within redirect urls (e.g. `https://acme.viktor.ai/api/integrations/oauth2/callback/`) 4. Determine the relevant scopes for your integration. 5. Some example integration documentation you can refer to: * [Microsoft Entra OAuth 2.0 Integration](https://learn.microsoft.com/en-us/entra/identity-platform/) * [Autodesk Platform Services](https://aps.autodesk.com/en/docs/oauth/v2/developers_guide/overview/) Security Best Practices * Use minimum scope for your application(s) to function when creating integration on VIKTOR. This would limit the impact when there is misuse of integrated software. * Use a short Time-to-Live for your Access Tokens when configuring the OAuth 2.0 application on the integration provider. ![](/assets/images/create-oauth-integration-admin-configuration-details-7ced0828b6c88d9e12e5bb50d011c85e.png) ### Implementing the integration in an app (developer)[​](/docs/create-apps/software-integrations/generic/.md#implementing-the-integration-in-an-app-developer "Direct link to Implementing the integration in an app (developer)") With the integration name, the developer can start the implementation. First the integration is added in the config file. This is used by the platform to know that this app needs an integration and to trigger a login button for the user. `viktor.config.toml` ``` oauth2_integrations = [ "my-integration-1" ] ``` Secondly the logic that uses the integration can be implemented in the app. Often external software will provide examples and/or a Python SDK, making it easier to implement. In order to obtain the necessary token for authentication, you instantiate the `OAuth2Integration` class with the integration name and call the method `get_access_token`. ``` integration = vkt.external.OAuth2Integration('my-integration-1') access_token = integration.get_access_token() # code using the token inside your Python code to integrate ``` --- # GEOLIB The [GEOLIB](https://github.com/Deltares/GEOLib) is a [publicly available Python library](https://pypi.org/project/d-geolib/) developed by Deltares. The GEOLIB provides functionality for the following Deltares software: * DFoundations * DSettlement * DSheetPiling * DStability note The GEOLIB replaces VIKTOR's D-Series bindings. These bindings won't be removed for now, but there won't follow any updates anymore. ## Using GEOLIB[​](/docs/create-apps/software-integrations/geolib/.md#using-geolib "Direct link to Using GEOLIB") To make use of the GEOLIB, add the following to your `requirements.txt`: ``` d-geolib==0.1.6 # or any other available version ``` For more information on how to use the GEOLIB, see the online [documentation](https://deltares.github.io/GEOLib/latest/index.html). ## Executing jobs[​](/docs/create-apps/software-integrations/geolib/.md#executing-jobs "Direct link to Executing jobs") All GEOLIB models have an `execute()` method. However, it's not possible to use this in a VIKTOR app. Fortunately, there is still a way to execute your model, making use of VIKTOR's corresponding analysis class and worker, by serializing your model into VIKTOR's writable [`File`](/sdk/api/core/.md#_File) object: ``` from geolib import DSettlementModel from pathlib import Path import viktor as vkt ... model = DSettlementModel() # build up your model ... file = vkt.File() # create a writable file (GEOLIB is going to write to it) path = Path(file.source) # source returns the path in `str`, GEOLIB requires (in most cases) a Path object model.serialize(path) # let GEOLIB write the serialized model to the file dsettlement_analysis = vkt.dsettlement.DSettlementAnalysis(input_file=file) # pass the input file to the analysis as usual dsettlement_analysis.execute() # requires a worker ``` The GEOLIB can be used in conjunction with the following VIKTOR analysis classes and workers: * [`DFoundationsAnalysis`](/sdk/api/external/dfoundations/.md#_DFoundationsAnalysis) * [`DSettlementAnalysis`](/sdk/api/external/dsettlement/.md#_DSettlementAnalysis) * [`DSheetPilingAnalysis`](/sdk/api/external/dsheetpiling/.md#_DSheetPilingAnalysis) * [`DStabilityAnalysis`](/sdk/api/external/dstability/.md#_DStabilityAnalysis) ## Parsing in-memory data[​](/docs/create-apps/software-integrations/geolib/.md#parsing-in-memory-data "Direct link to Parsing in-memory data") GEOLIB also features the parsing of output files for the different models. It does however work with paths and includes a check on the file's suffix. If you have in-memory data (e.g. `StringIO` or `BytesIO`), you can convert it to a path with suffix by creating a temporary file with `NamedTemporaryFile`: note Creating a temporary path with VIKTOR's `File.from_data(...).copy()` does not work here, because GEOLIB requires the file path to have a valid suffix. ``` import os from geolib import DSettlementModel from pathlib import Path from tempfile import NamedTemporaryFile ... temp_file = NamedTemporaryFile(suffix='.sld', delete=False, mode='wb') # create a temporary file with correct suffix; don't delete on close(); remove mode 'b' in case of StringIO/str temp_file.write(my_bytesio.getvalue()) # write in-memory content (bytes in this case) to file temp_file.close() # close (does not delete) the file to ensure the data is actually written to file (instead of kept in buffer) path = Path(temp_file.name) # name returns the path in `str`, GEOLIB requires (in most cases) a Path object dsettlement_model = DSettlementModel() # create empty model dsettlement_model.parse(path) # parse file into DSettlementModel() model os.remove(temp_file.name) # remove the temporary file to avoid cluttering of files ``` --- # GRLWEAP VIKTOR's GRLWEAP integration requires a specific GRLWEAP worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing a GRLWEAP model in VIKTOR can be done using the [`GRLWeapAnalysis`](/sdk/api/external/grlweap/.md#_GRLWeapAnalysis) class (worker required). No binding is provided by VIKTOR for this module, which means that the input file has to be generated manually: ``` import viktor as vkt # Generate the input GWT file. input_file = ... # Run the analysis and obtain the output file. analysis = vkt.grlweap.GRLWeapAnalysis(input_file) analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` ## Testing[​](/docs/create-apps/software-integrations/grlweap/.md#testing "Direct link to Testing") New in v13.5.0 `mock_GRLWeapAnalysis` decorator for easier testing of `GRLWeapAnalysis` `GRLWeapAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_GRLWeapAnalysis`](/sdk/api/testing/.md#_mock_GRLWeapAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_GRLWeapAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GRLWeapAnalysis(get_output_file=File.from_path('test_file.GWO')) def test_grlweap_analysis(self): MyEntityTypeController().grlweap_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). --- # IDEA StatiCa Concrete Supported (tested) IDEA StatiCa versions: * v24 * v23 * v22 * v21 An IDEA StatiCa Concrete binding has been developed by VIKTOR to simplify the process of creating a model, running an analysis (worker required) and parsing the results. VIKTOR's IDEA-RCS integration requires a specific IDEA worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). ## Creating a model[​](/docs/create-apps/software-integrations/idea/.md#creating-a-model "Direct link to Creating a model") A model can be created using the binding in two different ways: 1. [`Model`](/sdk/api/external/idea/.md#_Model): create a model with the least effort. Limited set of features. 2. [`OpenModel`](/sdk/api/external/idea/.md#_OpenModel): resembles the API of IDEA StatiCa Concrete. Less intuitive than `Model`, but can be used if the latter lacks desired features. ### Creating a model using `Model`[​](/docs/create-apps/software-integrations/idea/.md#creating-a-model-using-model "Direct link to creating-a-model-using-model") The process consists of the following steps: 1. Create the 'empty' [`Model`](/sdk/api/external/idea/.md#_Model). Optionally [`ProjectData`](/sdk/api/external/idea/.md#_ProjectData) and/or [`CodeSettings`](/sdk/api/external/idea/.md#_CodeSettings) can be specified (see [this section](/docs/create-apps/software-integrations/idea/.md#projectdata-and-codesettings)) 2. Create one or more materials for the cross section(s) using [`Model.create_concrete_material`](/sdk/api/external/idea/.md#Model.create_concrete_material). 3. Create one or more materials for the reinforcement(s) using [`Model.create_reinforcement_material`](/sdk/api/external/idea/.md#Model.create_reinforcement_material). 4. Create members to be checked using [`Model.create_beam`](/sdk/api/external/idea/.md#Model.create_beam) (or similar methods, see below). 5. Create reinforcement(s) using [`Beam.create_bar`](/sdk/api/external/idea/.md#Beam.create_bar). 6. Create extreme(s) with corresponding internal forces using [`Beam.create_extreme`](/sdk/api/external/idea/.md#Beam.create_extreme) (or similar). 7. Generate the input XML file using [`Model.generate_xml_input`](/sdk/api/external/idea/.md#Model.generate_xml_input). ``` import viktor as vkt model = vkt.idea_rcs.Model() # Initialize the model. # Create the desired material(s). cs_mat = model.create_concrete_material(vkt.idea_rcs.ConcreteMaterial.C12_15) mat_reinf = model.create_reinforcement_material(vkt.idea_rcs.ReinforcementMaterial.B_400A) # Create a beam (or other type of member) to be checked. cross_section = vkt.idea_rcs.RectSection(0.5, 1.0) beam = model.create_beam(cross_section, cs_mat) # Create bars (and stirrups) as desired bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): beam.create_bar(coords, diameter, mat_reinf) # Add extreme(s) freq = vkt.idea_rcs.LoadingSLS(vkt.idea_rcs.ResultOfInternalForces(N=-100000, My=210000)) fund = vkt.idea_rcs.LoadingULS(vkt.idea_rcs.ResultOfInternalForces(N=-99999, My=200000)) beam.create_extreme(frequent=freq, fundamental=fund) # Generate the input XML file. input_file = model.generate_xml_input() ``` caution `Model.generate_xml_input` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. Currently, `Model` supports the following member types: * [Beam](/sdk/api/external/idea/.md#Model.create_beam) * [Compression member](/sdk/api/external/idea/.md#Model.create_compression_member) * [One-way slab](/sdk/api/external/idea/.md#Model.create_one_way_slab) Currently, `Model` supports the following section types: * [General](/sdk/api/external/idea/.md#_GeneralShape) * [Rectangular](/sdk/api/external/idea/.md#_RectSection) ### Creating a model using `OpenModel`[​](/docs/create-apps/software-integrations/idea/.md#creating-a-model-using-openmodel "Direct link to creating-a-model-using-openmodel") The process consists of the following steps: 1. Create the 'empty' [`OpenModel`](/sdk/api/external/idea/.md#_OpenModel). Optionally [`ProjectData`](/sdk/api/external/idea/.md#_ProjectData) and/or [`CodeSettings`](/sdk/api/external/idea/.md#_CodeSettings) can be specified (see [this section](/docs/create-apps/software-integrations/idea/.md#projectdata-and-codesettings)) 2. Create one or more materials for the cross section(s) using [`OpenModel.create_matconcrete_ec2`](/sdk/api/external/idea/.md#OpenModel.create_matconcrete_ec2). 3. Create a concrete cross-section using one of: * [`OpenModel.create_cross_section_parameter`](/sdk/api/external/idea/.md#OpenModel.create_cross_section_parameter) * [`OpenModel.create_cross_section_component`](/sdk/api/external/idea/.md#OpenModel.create_cross_section_component) note In case of a `CrossSectionParameter`, the `**parameters` argument should contain keys and values corresponding to the `cross_section_type`, else the input file will be invalid. For more information on what `**parameters` are required for a certain `cross_section_type`, please see [`create_cross_section_parameter`](/sdk/api/external/idea/.md#OpenModel.create_cross_section_parameter) 4. Create one or more materials for the reinforcement(s) using [`OpenModel.create_matreinforcement_ec2`](/sdk/api/external/idea/.md#OpenModel.create_matreinforcement_ec2). 5. Create the reinforced cross section(s) using [`OpenModel.create_reinforced_cross_section`](/sdk/api/external/idea/.md#OpenModel.create_reinforced_cross_section). 6. Create reinforcement(s) using [`ReinforcedCrossSection.create_bar`](/sdk/api/external/idea/.md#ReinforcedCrossSection.create_bar). 7. Create check member(s) using [`OpenModel.create_check_member1d`](/sdk/api/external/idea/.md#OpenModel.create_check_member1d). 8. Couple the check member and reinforced cross section using [`OpenModel.add_check_section`](/sdk/api/external/idea/.md#OpenModel.add_check_section). 9. Create extreme(s) with corresponding internal forces using [`CheckSection.create_extreme`](/sdk/api/external/idea/.md#CheckSection.create_extreme). 10. Add additional data to the check member using [`OpenModel.add_member_data_ec2`](/sdk/api/external/idea/.md#OpenModel.add_member_data_ec2). note The `member_type` and `two_way_slab_type` should correspond to the chosen reinforced cross section 11. Generate the input XML file using [`OpenModel.generate_xml_input`](/sdk/api/external/idea/.md#OpenModel.generate_xml_input). ``` import viktor as vkt model = vkt.idea_rcs.OpenModel() # Initialize the model. # Create the concrete section. mat = model.create_matconcrete_ec2(vkt.idea_rcs.ConcreteMaterial.C12_15) cs = model.create_cross_section_parameter( name='cs', cross_section_type=vkt.idea_rcs.CrossSectionType.RECT, material=mat, Width=2.0, Height=2.0 ) # Create the reinforced cross section. rcs = model.create_reinforced_cross_section(name='rcs', cross_section=cs) # Create bars (and stirrups) as desired mat_reinf = model.create_matreinforcement_ec2(vkt.idea_rcs.ReinforcementMaterial.B_400A) bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): rcs.create_bar(coords, diameter, mat_reinf) # Create a CheckMember. member = model.create_check_member1d() # 'Assign' the CheckMember to a CheckSection with the previously defined reinforced section and add extremes. check_section = model.add_check_section(description='S 1', check_member=member, reinf_section=rcs) freq = vkt.idea_rcs.LoadingSLS(vkt.idea_rcs.ResultOfInternalForces(N=-100000, My=210000)) fund = vkt.idea_rcs.LoadingULS(vkt.idea_rcs.ResultOfInternalForces(N=-99999, My=200000)) check_section.create_extreme(frequent=freq, fundamental=fund) # 'Assign' the necessary additional data to the CheckMember. model.add_member_data_ec2(member, vkt.idea_rcs.MemberType.BEAM_SLAB, vkt.idea_rcs.TwoWaySlabType.SHELL_AS_PLATE) # Generate the input XML file. input_file = model.generate_xml_input() ``` caution `OpenModel.generate_xml_input` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. ### ProjectData and CodeSettings[​](/docs/create-apps/software-integrations/idea/.md#projectdata-and-codesettings "Direct link to ProjectData and CodeSettings") When a `Model` or `OpenModel` is initialized, optionally project data and/or code settings can be specified. Currently, `ProjectData` supports: * Project name (>= v14.6.0) * Project number (>= v14.6.0) * Project description (>= v14.6.0) * Author (>= v14.6.0) * Date (>= v14.6.0) * National Annex (no annex, Dutch, Belgium) * Fatigue check * Design working life (>= v14.6.0) Currently, `CodeSettings` supports: * [`EvaluationInteractionDiagram`](/sdk/api/external/idea/.md#_EvaluationInteractionDiagram) * [`NoResistanceConcreteTension1d`](/sdk/api/external/idea/.md#_NoResistanceConcreteTension1d) * [`TypeSLSCalculation`](/sdk/api/external/idea/.md#_TypeSLSCalculation) * `theta`, `theta_min`, `theta_max` * `n_cycles_fatigue` ## Running an analysis[​](/docs/create-apps/software-integrations/idea/.md#running-an-analysis "Direct link to Running an analysis") After having generated an input XML file, it can be fed to the [`IdeaRcsAnalysis`](/sdk/api/external/idea/.md#_IdeaRcsAnalysis): ``` import viktor as vkt # Generate the input XML file from `Model` or `OpenModel`, or generate one yourself. input_file = ... # Run the analysis and obtain the output file. analysis = vkt.idea_rcs.IdeaRcsAnalysis(input_file) analysis.execute(60) output_file = analysis.get_output_file() ``` ## Extracting results using `RcsOutputFileParser`[​](/docs/create-apps/software-integrations/idea/.md#extracting-results-using-rcsoutputfileparser "Direct link to extracting-results-using-rcsoutputfileparser") After running an analysis, the obtained output file can be fed to the `RcsOutputFileParser` for convenient extraction of the results: ``` import viktor as vkt # Obtain the XML output file from `IdeaRcsAnalysis`, or obtain one yourself. xml_file = idea_rcs_analysis.get_output_file(as_file=True) # Obtain the results for specific or all section(s). with xml_file.open_binary() as f: parser = vkt.idea_rcs.RcsOutputFileParser(f) # loop through all sections for section in parser.section_results(): capacity_results = section.capacity() shear_results = section.shear() # or get results for a single section section_4 = parser.section_result(4) ... ``` Currently, `RcsOutputFileParser` supports the following results (partially): * [`Capacity`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.capacity) * [`Shear`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.shear) * [`Torsion`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.torsion) (>= v13.4.0) * [`Interaction`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.interaction) (>= v13.4.0) * [`Crack width`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.crack_width) * [`Detailing`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.detailing) * [`Stress limitation`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.stress_limitation) * [`Fatigue`](/sdk/api/external/idea/.md#RcsOutputFileParser.SectionResult.fatigue) In case you require results which are not supported, you can retrieve the raw results using the [`OutputFileParser`](/sdk/api/external/idea/.md#_OutputFileParser). We do not advice to use this when handling very large result files: ``` # Obtain the raw results as a dictionary xml_file = idea_rcs_analysis.get_output_file(as_file=True) parser = OutputFileParser(xml_file) raw_results = parser.raw_results() ``` ## Testing[​](/docs/create-apps/software-integrations/idea/.md#testing "Direct link to Testing") New in v13.5.0 `mock_IdeaRcsAnalysis` decorator for easier testing of `IdeaRcsAnalysis` `IdeaRcsAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_IdeaRcsAnalysis`](/sdk/api/testing/.md#_mock_IdeaRcsAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_IdeaRcsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_IdeaRcsAnalysis( get_output_file=File.from_path('test_file.xml'), get_idea_rcs_file=File.from_path('test_file.ideaRcs'), ) def test_idea_analysis(self): MyEntityTypeController().idea_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). --- # Matlab Matlab can be executed through command-line instructions, which allows executing complete Matlab scripts. These scripts can, for example, be generated dynamically within VIKTOR. See the [Matlab documentation](https://www.mathworks.com/help/matlab/ref/matlabwindows.html) for more info on running Matlab from the command-line. ## Install a Matlab worker[​](/docs/create-apps/software-integrations/matlab/.md#install-a-matlab-worker "Direct link to Install a Matlab worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Matlab** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the Matlab executable 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Matlab** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the Matlab executable 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ## Setup app[​](/docs/create-apps/software-integrations/matlab/.md#setup-app "Direct link to Setup app") ``` import viktor as vkt # Generate the input file(s) files = [ ('input1.txt', file1), ('input2.txt', file2) ] # Run the analysis and obtain the output file analysis = vkt.matlab.MatlabAnalysis(files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` ## Testing[​](/docs/create-apps/software-integrations/matlab/.md#testing "Direct link to Testing") `MatlabAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_MatlabAnalysis`](/sdk/api/testing/.md#_mock_MatlabAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_MatlabAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_MatlabAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). --- # PLAXIS PLAXIS has a [Python API](https://communities.bentley.com/products/geotech-analysis/w/plaxis-soilvision-wiki/45393/api-python-scripting---plaxis) that is distributed in a Python installer. The API can be used to build-up PLAXIS models and process results, integrating the PLAXIS workflow within your VIKTOR app. For more information on the PLAXIS API, see the [website](https://communities.bentley.com/products/geotech-analysis/w/plaxis-soilvision-wiki/45454/identify-python-commands-from-plaxis-command-line). note A 'Bentley Geotechnical SELECT Entitlement' (previously 'PLAXIS-vip') license is required To integrate PLAXIS in your application, the following is needed: * A Plaxis worker * A machine on which PLAXIS is installed (with the correct licensing) ### Install Plaxis worker[​](/docs/create-apps/software-integrations/plaxis/.md#install-plaxis-worker "Direct link to Install Plaxis worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Plaxis** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your 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 the following command in your terminal ``` where python ``` 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Plaxis** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your default Python environment can usually be found in `C:\Users\\AppData\Local\Programs\Python\Python31X\python.exe`. If you cannot find it, try running `where python` in your terminal. 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ## Set up the app[​](/docs/create-apps/software-integrations/plaxis/.md#set-up-the-app "Direct link to Set up the app") From within the VIKTOR app, the Python script is sent, via the plaxis worker, to the server. After the analysis, the worker sends back the specified files to the app, after which the developer can process the results (visualize, download, etc.). In the following code snippet two files are sent to the worker: `run_plaxis.py` and `input.json`. For additional ideas on how to pass parameters to PLAXIS have a look at the [PLAXIS sample application](https://github.com/viktor-platform/sample-plaxis/). ``` import viktor as vkt script = vkt.File.from_path(Path(__file__).parent / "run_plaxis.py") files = [('input.json', vkt.File.from_data(b'{parameter_a: 1, parameter_b: 2}')] analysis = vkt.plaxis.PlaxisAnalysis( script=script, files=files, output_filenames=["output.txt"] ) analysis.execute(timeout=300) output_file = analysis.get_output_file("output.txt") ``` The file `run_plaxis.py` and the other file represented as bytes is then sent to the Python distribution PLAXIS is set to work with. You can specify [which Python distribution PLAXIS should use](https://communities.bentley.com/products/geotech-analysis/w/plaxis-soilvision-wiki/51822/how-to-install-additional-python-modules-in-plaxis), in the "Using a custom Python distribution" section. **run\_plaxis.py** The Python script that is sent to the worker should consist of the following parts: * Starting of the [PLAXIS remote scripting service](https://communities.bentley.com/products/geotech-analysis/w/plaxis-soilvision-wiki/46005/using-plaxis-remote-scripting-with-the-python-wrapper) * Code to build-up the PLAXIS model and read-out the desired results * Creation of output files in the working directory of the worker, to be returned to the app * Close the PLAXIS application Starting of the PLAXIS remote scripting service can be done as follows: ``` import subprocess, time PLAXIS_PATH = r'C:\Program Files\Bentley\Geotechnical\PLAXIS 2D CONNECT Edition V20\\Plaxis2DXInput.exe' # Specify PLAXIS path on server. PORT_I = 10000 # Define an input port number. PORT_O = 10001 # Define an output port number. PASSWORD = 'secret' # Define a password. subprocess.Popen([PLAXIS_PATH, f'--AppServerPassword={PASSWORD}', f'--AppServerPort={PORT}']) # Start the PLAXIS remote scripting service. time.sleep(30) # Wait for PLAXIS to boot before sending commands to the scripting service. # Start the scripting server. global g_i, s_i s_i, g_i = new_server('localhost', PORT_I, password=PASSWORD) s_o, g_o = new_server('localhost', PORT_O, password=PASSWORD) # Execute code. ... # Extract required data and write files to working directory. ... # Close the application g_o.close() # Close the output window g_i.kill() # Close the input window ``` caution The resulting files can be very large. Consider sending back files to the app with only the relevant information, by filtering out unnecessary results, to reduce in size. An example can be found in the [sample application](https://github.com/viktor-platform/sample-plaxis/) ## Testing[​](/docs/create-apps/software-integrations/plaxis/.md#testing "Direct link to Testing") `PlaxisAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_PlaxisAnalysis`](/sdk/api/testing/.md#_mock_PlaxisAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_PlaxisAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_PlaxisAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). --- # Autodesk Revit tip This guide provides the basic information about our Revit integration. **If this is your first time setting up an integration, we recommend to follow one of the [Intermediate tutorials](/docs/tutorials/.md#intermediate-level).** ## System requirements:[​](/docs/create-apps/software-integrations/revit/.md#system-requirements "Direct link to System requirements:") * 💻 Windows PC * 🐍 Python =< 3.10 * A version of Revit (we use 2024 in this guide) To integrate Revit into a VIKTOR application, you will require some additional software. ### Download and install pyRevit[​](/docs/create-apps/software-integrations/revit/.md#download-and-install-pyrevit "Direct link to Download and install pyRevit") In order to use Revit with Python, you will need to download and install the [pyRevit extension for Revit](https://github.com/eirannejad/pyRevit). You can find all the information you need to install pyRevit and connect it to your version of Revit in the [pyRevit documentation](https://pyrevitlabs.notion.site/Install-pyRevit-98ca4359920a42c3af5c12a7c99a196d). After following the steps of the installer, continue to the next section. ### Additional information[​](/docs/create-apps/software-integrations/revit/.md#additional-information "Direct link to Additional information") You may want to consult some additional information about the software we are using, below you can find some useful links: * [Revit API](https://www.revitapidocs.com/) * [pyRevit CLI](https://pyrevitlabs.notion.site/pyRevit-CLI-c50de95259114db795db5bd3f19f8e2a) ## Setup work environment[​](/docs/create-apps/software-integrations/revit/.md#setup-work-environment "Direct link to Setup work environment") Before you can start building your VIKTOR - Revit apps, you will need to complete some steps for the setup. ### Step 1: Install Revit worker[​](/docs/create-apps/software-integrations/revit/.md#step-1-install-revit-worker "Direct link to Step 1: Install Revit worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Revit** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your 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 the following command in your terminal ``` where python ``` 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Revit** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your default Python environment can usually be found in `C:\Users\\AppData\Local\Programs\Python\Python31X\python.exe`. If you cannot find it, try running `where python` in your terminal. 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ### Step 2: Start a VIKTOR app[​](/docs/create-apps/software-integrations/revit/.md#step-2-start-a-viktor-app "Direct link to Step 2: Start a VIKTOR app") You will need to create, install and start an empty app. If you would like a quick reminder on how to do this, you can follow the steps [here](/docs/getting-started/starter-guide/.md). ### Step 3: Add a run script to your VIKTOR app[​](/docs/create-apps/software-integrations/revit/.md#step-3-add-a-run-script-to-your-viktor-app "Direct link to Step 3: Add a run script to your VIKTOR app") In the folder of the VIKTOR app, copy the code below into a Python file. This code will let the worker's operating system know which script to run ``` import os # command to run: command = 'pyrevit run "C:\PATH\TO\pyrevit_script.py" "C:\PATH\TO\MODEL.RVT\IF\APPLICABLE" if __name__ == '__main__': # run the command os.system(command) ``` ### Step 4: Activate the scripts on the worker[​](/docs/create-apps/software-integrations/revit/.md#step-4-activate-the-scripts-on-the-worker "Direct link to Step 4: Activate the scripts on the worker") The next step is to connect the VIKTOR app to the worker via a Generic Analysis, feel free to copy the example function below, into your VIKTOR app. Depending on the view you are using for your output, you may need to replace the output files with an output that can be processed by python or your chosen view. ``` import viktor as vkt from pathlib import Path def run_pyrevit(params): pyrevit_command = vkt.File.from_path(Path(__file__).parent / "pyrevit_run.py") pyrevit_script vkt.File.from_path(Path(__file__).parent / "pyrevit_script.py") analysis = vkt.revit.RevitAnalysis( script=pyrevit_command, files=[("pyrevit_script.py", pyrevit_script)], output_filenames=["output.pdf"] ) analysis.execute(timeout=300) return analysis.get_output_file("output.pdf") ``` You are now ready to build a GUI in the VIKTOR app and you can write your instructions for the worker in the 'script.py' file. ## Useful tips and tricks[​](/docs/create-apps/software-integrations/revit/.md#useful-tips-and-tricks "Direct link to Useful tips and tricks") Before setting up a worker on another machine, it is recommended to try it on your computer first. That way you will be able to test and debug your pyRevit code before it is placed on an external machine. As you may have noticed, there are quite a few filepaths that need to be taken into account. There is definetly some bookkeeping required to make sure all goes well. The easiest way to keep track of the filepaths is to keep a note (possibly in your VIKTOR app) in which you can keep the filepaths of the worker. The documentation for the Revit API is quite generic and may not seem to be for Python and you would be correct, it is for C#. However, the names and conventions are all the same in pyRevit and because the Revit API is well documented, you can use it just like any other API you would use for python. In the documentation, you can find out more and some [examples](https://www.revitapidocs.com/code/) to help you on your way. ## Would you like to see an example?[​](/docs/create-apps/software-integrations/revit/.md#would-you-like-to-see-an-example "Direct link to Would you like to see an example?") VIKTOR offers a wide variety of sample repositories on GitHub, one of which is the [pyRevit integration app](https://github.com/viktor-platform/pyrevit-integration). If you have a version of Revit installed on your computer, you can try out the proof-of-concept app to get an idea of how such an app works and behaves. ## Testing[​](/docs/create-apps/software-integrations/revit/.md#testing "Direct link to Testing") `RevitAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_RevitAnalysis`](/sdk/api/testing/.md#_mock_RevitAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_RevitAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RevitAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). --- # RFEM 5 VIKTOR's RFEM 5 integration requires a specific RFEM worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing an RFEM 5 model in VIKTOR can be done using the [`RFEMAnalysis`](/sdk/api/external/rfem/.md#_RFEMAnalysis) class (worker required). The RFEM model is defined by: * input .rfx file which has to be created manually * list of actions which are to be performed sequentially ## Creating the actions[​](/docs/create-apps/software-integrations/rfem/.md#creating-the-actions "Direct link to Creating the actions") The following actions can be defined: * [`EnergyOptimizationAction`](/sdk/api/external/rfem/.md#_EnergyOptimizationAction) * [`CopyNodalLoadAction`](/sdk/api/external/rfem/.md#_CopyNodalLoadAction) * [`WriteResultsAction`](/sdk/api/external/rfem/.md#_WriteResultsAction) Please click on the actions above to navigate to their reference for more detail on the meaning of each action. ``` import viktor as vkt # SLS sls_cases = [1, 2, 3] sls_optimization = vkt.rfem.EnergyOptimizationAction(sls_cases, goal=10000, accuracy=0.1) # goal = 10 kNm, accuracy = 10 cm # ALS als_cases = [4, 5, 6] als_optimization = vkt.rfem.EnergyOptimizationAction(als_cases, goal=15000, accuracy=0.1) # goal = 15 kNm, accuracy = 10 cm # ULS uls_cases = [7, 8, 9] uls_creation = vkt.rfem.CopyNodalLoadAction(list(zip(sls_cases, uls_cases)), factor=1.5) # ULS = SLS x 1.5 # Write action write_result_action = vkt.rfem.WriteResultsAction(sls_cases + als_cases + uls_cases) # or can be left empty = all cases actions = [sls_optimization, als_optimization, uls_creation, write_result_action] ``` ## Running an RFEM analysis[​](/docs/create-apps/software-integrations/rfem/.md#running-an-rfem-analysis "Direct link to Running an RFEM analysis") The model can be fed to the [`RFEMAnalysis`](/sdk/api/external/rfem/.md#_RFEMAnalysis) as follows: ``` # Generate the input RFX file. input_file = ... # Run the analysis and obtain the results. analysis = vkt.rfem.RFEMAnalysis(input_file, actions=actions) analysis.execute(timeout=300) model = analysis.get_model() result_lc1 = analysis.get_result(load_case=1) result_lc2 = analysis.get_result(load_case=2) ``` ## Testing[​](/docs/create-apps/software-integrations/rfem/.md#testing "Direct link to Testing") New in v13.5.0 `mock_RFEMAnalysis` decorator for easier testing of `RFEMAnalysis` `RFEMAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_RFEMAnalysis`](/sdk/api/testing/.md#_mock_RFEMAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_RFEMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RFEMAnalysis( get_model=File.from_path('test_file.rfx'), get_result={ 1: File.from_path('test_file.json'), # : ... }, ) def test_rfem_analysis(self): MyEntityTypeController().rfem_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). --- # Rhino / Grasshopper tip This guide provides the basic information about our Rhino/Grasshopper integration. **If you setup this integration for the first time, we recommend to follow the [Rhino/Grasshopper tutorial](/docs/tutorials/integrate-grasshopper/.md).** There are 2 ways to integrate VIKTOR with Rhino/Grasshopper: 1. Connect to Rhino/Grasshopper on your local computer via the Hops component and a dedicated worker 2. Connect to a Rhino Compute Server Scalability We recommend to use the worker (1) when you don't have a Rhino Compute server yet and you want to get started quickly, and to setup a Rhino Compute server (2) when you want to go to production with your app. Having the basic RhinoCompute setup running may be fine for developing/testing purposes but might not be the ideal solution for production apps, in terms of license billing. Please check [RhinoCompute: Licensing & Billing](https://developer.rhino3d.com/guides/compute/core-hour-billing/) for further details. ## System requirements:[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#system-requirements "Direct link to System requirements:") * 💻 Windows PC * 🦏 Rhino 7 with Hops plugin installed * 🐍 Python =< 3.13 (Check this with your version of Rhino) ## Method 1: Connect to Rhino/Grasshopper on your local computer[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#method-1-connect-to-rhinograsshopper-on-your-local-computer "Direct link to Method 1: Connect to Rhino/Grasshopper on your local computer") VIKTOR's Rhino / Grasshopper integration can be set up using the dedicated Grasshopper worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). tip If you don't want to have to start Grasshopper; check out how to [run RhinoCompute (locally) without running Rhino or Grasshopper](https://developer.rhino3d.com/guides/compute/development/) ### VIKTOR app[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#viktor-app "Direct link to VIKTOR app") In the VIKTOR app, the input files for the worker are defined and the `GrasshopperAnalysis` is executed to run the Grasshopper worker on the server. Start by adding your grasshopper script to the app folder (if you would like a script, you can find one in our [tutorial](/docs/tutorials/integrate-grasshopper/.md)) and add the code below to your `app.py` file: ``` import viktor as vkt import json import rhino3dm from pathlib import Path class Parametrization(vkt.Parametrization): # Input fields that correspond with the HOPS components ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("Geometry", duration_guess=10, x_axis_to_right=True, update_label='Run Grasshopper') def run_grasshopper(self, params, **kwargs): grasshopper_script_path = Path(__file__).parent / "your_grasshopper_script.gh" script = vkt.File.from_path(grasshopper_script_path) input_parameters = dict(params) # Run the Grasshopper analysis and obtain the output data analysis = vkt.grasshopper.GrasshopperAnalysis(script=script, input_parameters=input_parameters) analysis.execute(timeout=30) output = analysis.get_output() # Convert output data to mesh file3dm = rhino3dm.File3dm() obj = rhino3dm.CommonObject.Decode(json.loads(output["values"][0]["InnerTree"]['{0}'][0]["data"])) file3dm.Objects.AddMesh(obj) # Write to geometry_file geometry_file = vkt.File() file3dm.Write(geometry_file.source, version=7) return vkt.GeometryResult(geometry=geometry_file, geometry_type="3dm") ``` Then you will need to add your input fields that correspond to the Hops components in your grasshopper file (see next section) and make sure to replace `your_grasshopper_script.gh` with the name of your script. For a full example on how the components relate to the inputs, feel free to check out the [grasshopper tutorial](/docs/tutorials/integrate-grasshopper/.md). ### Grasshopper script[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#grasshopper-script "Direct link to Grasshopper script") The Grasshopper script should be defined so that the Hops 'Get components' are connected to the inputs and outputs. The 'Get components' can be found under Params Tab > Util Group. Components preceded by 'Get' can be used as an input parameter. The 'Context bake' and 'Context print' components should connected to the desired output components to return geometry or text respectively. See the [Rhino documentation](https://developer.rhino3d.com/guides/compute/hops-component/#create-a-hops-function) for an extensive explanation. ![](/assets/images/tutorial_grasshopper_script-4ccb11f965a8f7f97e55b0026c389671.png) ## Method 2: Connect your app to a Rhino Compute Server[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#method-2-connect-your-app-to-a-rhino-compute-server "Direct link to Method 2: Connect your app to a Rhino Compute Server") Instead of using the worker and the local version of Rhino Compute with Hops, you can also connect the VIKTOR app directly to a Rhino Compute Server: ![](/assets/images/tutorial_grasshopper_setup_rhino_compute-c5fe9bf70ffa40f53eb8455cd5bedf96.png) This has the following advantages: * Faster (the worker creates some overhead running time) * More robust and scalable, you can make sure the compute server is always running The main disadvantage is that it takes time and effort to setup a Rhino Compute Server, which takes time and needs to be done by someone who is familiar with setting up Virtual Machines (i.e. an IT department). We recommend to use the worker when you don't have a Rhino Compute server yet and you want to get started quickly, and to setup a Rhino Compute server when you want to go to production with your app. The following steps are needed to connect your app to a Rhino Computer Server: ### 1. Setup the Rhino Compute Server[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#1-setup-the-rhino-compute-server "Direct link to 1. Setup the Rhino Compute Server") McNeel has documented how to setup a Rhino Compute Server very clear and extensively, see the [Compute Guides](https://developer.rhino3d.com/guides/compute/). Once you have the Rhino Compute Server running, you should have a `URL` and an `API key`. Now you can connect your VIKTOR app to this Rhino Compute server. ### 2. Adjust your app code[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#2-adjust-your-app-code "Direct link to 2. Adjust your app code") Since the compute server is available via the internet, we can now directly communicate with this server in the app code. Change `app.py` to the following code: ``` import viktor as vkt import compute_rhino3d.Grasshopper as gh import compute_rhino3d.Util import json import os import rhino3dm import tempfile from pathlib import Path class Parametrization(vkt.Parametrization): # Input fields that correspond with the HOPS components ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("Geometry", x_axis_to_right=True, update_label='Run Grasshopper') def run_grasshopper(self, params, **kwargs): # Credentials for Rhino Compute api compute_rhino3d.Util.url = os.getenv("RHINO_COMPUTE_URL") compute_rhino3d.Util.apiKey = os.getenv("RHINO_COMPUTE_API_KEY") # Create an input tree with the input parameters input_trees = [] for key, value in params.items(): tree = gh.DataTree(key) tree.Append([{0}], [str(value)]) input_trees.append(tree) # Evaluate the Grasshopper definition output = gh.EvaluateDefinition( str(Path(__file__).parent / 'your_grasshopper-script.gh'), input_trees ) # Create a new rhino3dm file and add resulting geometry to file file = rhino3dm.File3dm() output_geometry = output['values'][0]['InnerTree']['{0}'][0]['data'] obj = rhino3dm.CommonObject.Decode(json.loads(output_geometry)) file.Objects.AddMesh(obj) # Write a temporary file temp_file = tempfile.NamedTemporaryFile(suffix=".3dm", delete=False, mode="wb") temp_file.close() file.Write(temp_file.name, 7) return vkt.GeometryResult(geometry=vkt.File.from_path(Path(temp_file.name)), geometry_type="3dm") ``` Since we need to send the Grasshopper file to the Rhino Compute server (line 37), **place `your_grasshopper_script.gh` in the same folder as `app.py`**. As you can see, we are now using the packages `compute-rhino3d` and `rhino3dm` in the app code, so we should add these to the `requirements.txt`: ``` viktor==X.X.X compute-rhino3d==0.12.2 rhino3dm==8.17.0 ``` Make sure to set the right Python version to match the rhino3dm distribution in `viktor.config.toml`: ``` app_type = 'editor' python_version = '3.13' ``` Because of these changes to the requirements and Python version, reinstall the app in the terminal: ``` > viktor-cli install ``` Now we can start the app! credentials in app code As you can see in line 34 and 35, we have not placed the URL and API Key in the code **because of security reasons** (you do not want to leak these credentials). When you start the app, add the credentials as follows: ``` > viktor-cli start --env RHINO_COMPUTE_URL="YOUR_URL" --env RHINO_COMPUTE_API_KEY="YOUR_API_KEY" ``` Now open the app and you should see a running app with the Rhino Compute server running behind it! 🚀 ### 3. Publish your app with the API credentials[​](/docs/create-apps/software-integrations/rhino-grasshopper/.md#3-publish-your-app-with-the-api-credentials "Direct link to 3. Publish your app with the API credentials") If you want to make your app available for other people to use, you can easily do this by [publishing the app](/docs/publish-apps/.md). In that case you'll need to add the environment variables for the URL and API key to the app as described in [this guide](/docs/create-apps/development-tools-and-tips/environment-variables/.md#defining-environment-variables-for-published-apps).
Note that these environment variables are only visible to the maintainers of the app, users will never have access to these variables unless specifically been assigned so. ![](/assets/images/tutorial_grasshopper_setup_environment_variables-42b8fe171173ae46f098e15780493ebd.png) --- # Robot Structural Analysis VIKTOR's Autodesk Robot integration requires a specific Autodesk Robot worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Analyzing an Autodesk Robot model in VIKTOR can be done using the [`RobotAnalysis`](/sdk/api/external/robot/.md#_RobotAnalysis) class (worker required). No binding is provided by VIKTOR for this module, which means that the input file has to be generated manually: ``` import viktor as vkt # Generate the input STR file. input_file = ... # Run the analysis and obtain the results. analysis = vkt.robot.RobotAnalysis(input_file) analysis.execute(timeout=10) results = analysis.get_results() # obtain the results in a dict model_file = analysis.get_model_file() # obtain the model file (.rtd) ``` If `return_results` is set to `True`, a result dictionary can be retrieved: * [`get_results`](/sdk/api/external/robot/.md#RobotAnalysis.get_results) If `return_model=True`, the model file will also become available: * [`get_model_file`](/sdk/api/external/robot/.md#RobotAnalysis.get_model_file) ## Testing[​](/docs/create-apps/software-integrations/robot/.md#testing "Direct link to Testing") New in v13.5.0 `mock_RobotAnalysis` decorator for easier testing of `RobotAnalysis` `RobotAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_RobotAnalysis`](/sdk/api/testing/.md#_mock_RobotAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_RobotAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RobotAnalysis( get_model_file=File.from_path('test_file.rtd'), get_results={'bar_forces': {...}, ...}, ) def test_robot_analysis(self): MyEntityTypeController().robot_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/dict object (with empty content) is returned each time the corresponding method is called (endlessly). --- # SCIA Engineer tip This guide is an informative piece to help you if you have questions about our SCIA Engineer integration. If you would like a more instructive lesson, take a look at the [SCIA Engineer tutorial](/docs/tutorials/integrate-scia/.md) we have available. New in v14.1.0 Create selections using `Model.create_selection()` New in v13.1.0 Several new objects can be constructed: * `SolverSetup` to configure (general) solver settings * `ProjectData` to set basic project information * Library cross-sections using `Model.create_library_cross_section()` * Cross-links using `Model.create_cross_link()` Supported (tested) SCIA versions: * v25 * v24 * v23 * v22 * v21 * v20 * v19 VIKTOR's SCIA integration requires a specific SCIA worker which can be installed using [these instructions](/docs/manage-apps/software-integrations/.md#installation). Creating and analyzing a SCIA model in VIKTOR consists of the following steps: 1. Create the empty model. 2. Fill the model with the desired parts (e.g. nodes, beams, load cases, forces, etc.), by calling the corresponding create\_xxx() methods. 3. Generate the XML representation of the SCIA model. 4. Run the SCIA analysis with the generated XML input file and a user-created esa template file. 5. Obtain the results In code this looks like: ``` import viktor as vkt # 1. Create the empty model model = vkt.scia.Model() # 2. Fill the model with the parts (to be extended as desired) cross_section = model.create_rectangular_cross_section( 'rectangular_section', vkt.scia.Material(455, 'test_material'), 100, 100 ) n1 = model.create_node('n1', 0, 0, 0) n2 = model.create_node('n2', 1, 0, 0) model.create_beam(n1, n2, cross_section, name='test_beam') # 3. Generate the XML input file xml_file, def_file = model.generate_xml_input() # 4. Run the SCIA analysis esa_file = vkt.File.from_path('my_template.esa') scia_analysis = vkt.scia.SciaAnalysis(xml_file, def_file, esa_file) scia_analysis.execute(300) # Obtain the results analysis_result = scia_analysis.get_xml_output_file() ``` ## The ESA template file[​](/docs/create-apps/software-integrations/scia/.md#the-esa-template-file "Direct link to The ESA template file") The ESA file must be created by the user by using the SCIA interface. It functions as the template to which the model is added. The materials used in the VIKTOR model must exist in the ESA template file: both the name and id of the material must match. The SCIA version in which the template file was created must match the SCIA version called by the worker. note An I/O document has to be defined in the `.esa` file, which has to be named "output". If not defined, the worker will not be able to write this expected document and fails to execute. ![](data:image/png;base64,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) *Example I/O document of the esa model* ## Supported parts[​](/docs/create-apps/software-integrations/scia/.md#supported-parts "Direct link to Supported parts") Currently, the creation of the following SCIA parts is (fully, or partially) supported in VIKTOR: Libraries: * [Circular composed cross-section](/sdk/api/external/scia/.md#Model.create_circular_composed_cross_section) * [Circular cross-section](/sdk/api/external/scia/.md#Model.create_circular_cross_section) * [Circular hollow cross-section](/sdk/api/external/scia/.md#Model.create_circular_hollow_cross_section) * [General cross-section](/sdk/api/external/scia/.md#Model.create_general_cross_section) (>= v14.7.0, polygon + openings only) * [Layer](/sdk/api/external/scia/.md#Model.create_layer) * [Library cross section](/sdk/api/external/scia/.md#Model.create_library_cross_section) (>= v13.1.0) * [Non-linear function](/sdk/api/external/scia/.md#Model.create_nonlinear_function) * [Numerical cross section](/sdk/api/external/scia/.md#Model.create_numerical_cross_section) * [Orthotropy](/sdk/api/external/scia/.md#Model.create_orthotropy) * [Rectangular cross-section](/sdk/api/external/scia/.md#Model.create_rectangular_cross_section) * [Selections](/sdk/api/external/scia/.md#Model.create_selection) (>= v14.1.0) * [Subsoil](/sdk/api/external/scia/.md#Model.create_subsoil) * [Updating of material properties](/sdk/api/external/scia/.md#Model.update_concrete_material) Structure: * [Arbitrary profile](/sdk/api/external/scia/.md#Model.create_arbitrary_profile) * [Arbitrary profile span](/sdk/api/external/scia/.md#Model.create_arbitrary_profile_span) * [Beam](/sdk/api/external/scia/.md#Model.create_beam) * [Circular plane](/sdk/api/external/scia/.md#Model.create_circular_plane) * [Cross-link](/sdk/api/external/scia/.md#Model.create_cross_link) (>= v13.1.0) * [Node](/sdk/api/external/scia/.md#Model.create_node) * [Open slab](/sdk/api/external/scia/.md#Model.create_open_slab) * [Plane](/sdk/api/external/scia/.md#Model.create_plane) * [Rigid arm](/sdk/api/external/scia/.md#Model.create_rigid_arm) Results: * [Integration strip](/sdk/api/external/scia/.md#Model.create_integration_strip) * [Averaging strip](/sdk/api/external/scia/.md#Model.create_averaging_strip) (>= v14.3.0; Point type only) * [Section on beam](/sdk/api/external/scia/.md#Model.create_section_on_beam) * [Section on 2D-member](/sdk/api/external/scia/.md#Model.create_section_on_plane) Supports: * [Hinge on beam](/sdk/api/external/scia/.md#Model.create_hinge_on_beam) * [Hinge on plane](/sdk/api/external/scia/.md#Model.create_hinge_on_plane) * [Line support on beam](/sdk/api/external/scia/.md#Model.create_line_support_on_beam) * [Line support on 2D-member edge](/sdk/api/external/scia/.md#Model.create_line_support_on_plane) * [Point support on beam](/sdk/api/external/scia/.md#Model.create_point_support_on_beam) * [Support in node](/sdk/api/external/scia/.md#Model.create_point_support) * [Surface support](/sdk/api/external/scia/.md#Model.create_surface_support) Sets: * [Load case permanent](/sdk/api/external/scia/.md#Model.create_permanent_load_case) * [Load case variable](/sdk/api/external/scia/.md#Model.create_variable_load_case) * [Load combination](/sdk/api/external/scia/.md#Model.create_load_combination) * [Load group](/sdk/api/external/scia/.md#Model.create_load_group) * [Nonlinear load combination](/sdk/api/external/scia/.md#Model.create_nonlinear_load_combination) * [Result class](/sdk/api/external/scia/.md#Model.create_result_class) Loads: * [Free line force](/sdk/api/external/scia/.md#Model.create_free_line_load) * [Free point force](/sdk/api/external/scia/.md#Model.create_free_point_load) * [Free surface load](/sdk/api/external/scia/.md#Model.create_free_surface_load) * [Line force on beam](/sdk/api/external/scia/.md#Model.create_line_load) * [Line force on 2D-member edge](/sdk/api/external/scia/.md#Model.create_line_load_on_plane) * [Line moment on beam](/sdk/api/external/scia/.md#Model.create_line_moment_on_beam) * [Line moment on 2D-member edge](/sdk/api/external/scia/.md#Model.create_line_moment_on_plane) * [Moment in node](/sdk/api/external/scia/.md#Model.create_point_moment_node) * [Point force on beam](/sdk/api/external/scia/.md#Model.create_point_load) * [Point force in node](/sdk/api/external/scia/.md#Model.create_point_load_node) * [Surface load](/sdk/api/external/scia/.md#Model.create_surface_load) * [Thermal load on beam](/sdk/api/external/scia/.md#Model.create_thermal_load) * [Thermal load on 2D-member](/sdk/api/external/scia/.md#Model.create_thermal_surface_load) Misc.: * [Mesh setup](/sdk/api/external/scia/.md#_MeshSetup) * [Project data](/sdk/api/external/scia/.md#_ProjectData) (>= v13.1.0) * [Solver setup](/sdk/api/external/scia/.md#_SolverSetup) (>= v13.1.0) ## Testing[​](/docs/create-apps/software-integrations/scia/.md#testing "Direct link to Testing") New in v13.3.0 `mock_SciaAnalysis` decorator for easier testing of `SciaAnalysis` `Model.generate_xml_input` and `SciaAnalysis.execute` need to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_SciaAnalysis`](/sdk/api/testing/.md#_mock_SciaAnalysis) decorator that facilitate mocking of workers: ``` import unittest from viktor import File from viktor.testing import mock_SciaAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_SciaAnalysis( get_engineering_report=File.from_path('test_file.pdf'), get_updated_esa_model=File.from_path('test_file.esa'), get_xml_output_file=File.from_path('test_file.xml'), ) def test_scia_analysis(self): MyEntityTypeController().scia_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). --- # STAAD.Pro ## Introduction[​](/docs/create-apps/software-integrations/staadpro/.md#introduction "Direct link to Introduction") This guide provides detailed instructions for setting up the VIKTOR worker with STAAD.Pro. The steps outlined are similar to those used for other structural analysis software. It is designed to offer the necessary context and file templates to facilitate the integration process. ## The worker[​](/docs/create-apps/software-integrations/staadpro/.md#the-worker "Direct link to 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 STAAD.Pro 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: ![worker](/assets/images/tutorial_staad_worker_integration-bac3cd80b2a1f7c50ab474e8370ef540.png) Here is what happens during the integration: 1. The user enters input parameters in the `VIKTOR UI`. 2. The `app.py` in the VIKTOR app sends these parameters to the worker. 3. The worker (running on your local machine or a virtual machine) creates the model using the input parameters in STAAD.Pro. 4. The worker sends back the result of the **calculation** to your VIKTOR app. 5. **VIKTOR UI** displays the result of the calculation. ## Install a generic worker[​](/docs/create-apps/software-integrations/staadpro/.md#install-a-generic-worker "Direct link to Install a generic worker") Follow these steps to install the worker: 1. Navigate to the "My Integrations" tab in your personal settings. 2. Click "Add integration." 3. Follow the steps provided in the modal. ![Integration](/assets/images/tutorial_staad_create_integration-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Generic.** 3.2. Download the worker `.msi` (Microsoft Installer) and run it on the machine of choice. 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click **Finish.** Continue the installation in the installer wizard. CONNECTION KEY The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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. tip Your 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 the following command in your terminal:
`where python`
Do **not** use a Python path that contains `venv` anywhere in the path. 5. Make sure to launch and test the worker once the installation is finished. If you closed the worker, you can restart it through the desktop shortcut you created during the installation. ## Set up the worker[​](/docs/create-apps/software-integrations/staadpro/.md#set-up-the-worker "Direct link to Set up the worker") The worker will control STAAD.Pro through a Python environment where `pywin32`, `comtypes`, and `openstaad` need to be installed. This environment can be on your local Windows machine or a **remote server** where STAAD.Pro is installed with a valid license. Make sure to use Python **version 3.9 or higher**. For this integration, we will set up the worker in a separate folder from the VIKTOR app, **simulating a remote setup**. ### Step 1: Create the worker directory[​](/docs/create-apps/software-integrations/staadpro/.md#step-1-create-the-worker-directory "Direct link to Step 1: Create the worker directory") Create a new folder named `StaadServer` to store the worker files. working directory Installing the worker on the same machine as your app? Make this folder somewhere different from your app. We recommend navigating to 'C:' in your windows file explorer to experience similar behaviour as connecting to a server running STAAD.Pro. ### Step 2: Set up Python and install dependencies[​](/docs/create-apps/software-integrations/staadpro/.md#step-2-set-up-python-and-install-dependencies "Direct link to Step 2: Set up Python and install dependencies") 1. Ensure that the correct Python environment is used to execute the code, and keep the path at hand, as the worker will need it to run Python code for the STAAD.Pro API. 2. Now, install the necessary libraries ('`pywin32`, `comtypes`, and `openstaad`) using `pip` in the identified Python environment: ``` pip install pywin32 comtypes openstaad ``` This Python environment will be used to execute all Python code that involves working with the STAAD.Pro API. Let’s proceed with the YAML configuration file. ### Step 3: YAML file configuration[​](/docs/create-apps/software-integrations/staadpro/.md#step-3-yaml-file-configuration "Direct link to Step 3: YAML file configuration") 1. Navigate to the worker installation directory. By default, this is located at: `C:\Program Files\VIKTOR\` 2. Open the `config.yaml` file and update it with your actual Python path (the one you kept from step 1). Complete the rest of the YAML configuration for STAAD.Pro as shown below. ``` executables: run_staad: path: 'C:\Users\\AppData\Local\Programs\Python\PythonXX\' arguments: - 'run_staad_model.py' workingDirectoryPath: 'C:\StaadServer' maxParallelProcesses: 1 ``` Note that in the `arguments` value, we add a Python file called `run_staad_model.py`. This file will be located in your VIKTOR app folder, and we will push it to the `workingDirectoryPath` to be executed. 3. Save the `config.yaml` file. 4. Optionally, restart the worker from the [task scheduler](https://learn.microsoft.com/en-us/windows/win32/taskschd/about-the-task-scheduler). ## Connecting your app to the worker[​](/docs/create-apps/software-integrations/staadpro/.md#connecting-your-app-to-the-worker "Direct link to Connecting your app to the worker") You can use the following `app.py` template to set up the communication with your worker. In the current state you will need to add some code to the 'Parametrization' class as well as functions to generate 'inputs.json'. The code to generate 'output.json' needs to be added to the 'run\_staad\_model.py' file (see next section). If you would like an example of these feel free to follow our [STAAD.Pro tutorial](/docs/tutorials/integrate-staadpro/.md). ``` from viktor.external.generic import GenericAnalysis from viktor.core import File from pathlib import Path class Parametrization(vkt.Parametrization): # add your parameters here class Controller(vkt.Controller): ... # Add a function inside the Controller to create an `inputs.json` file. def run_staad(self, params, **kwargs): inputs_path = Path(__file__).parent / "inputs.json" script_path = Path(__file__).parent / "run_staad_model.py" files = [ ("inputs.json", File.from_path(inputs_path)), ("run_staad_model.py", File.from_path(script_path)) ] # Note that executable_key matches the config.yaml of the worker (run_staad) generic_analysis = GenericAnalysis( files=files, executable_key="run_staad", output_filenames=["output.json"] ) generic_analysis.execute(timeout=300) output_file = generic_analysis.get_output_file("output.json", as_file=True) # Further logic to handle the output.json data ``` The following template can be used to define the content of your `run_staad_model.py` to communicate with the worker and your VIKTOR app: ``` # run_staad_model.py import json from pathlib import Path def create_staad_model(): """ 1. Your code reads the inputs.json file and uses the content for structural analysis in STAAD.Pro. """ 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 STAAD.Pro API, possibly through openstaad. """ outputs = { "some_result": 123 # Example placeholder data } """ 3. Store the results of your analysis in the output.json file to be sent to your VIKTOR app. """ output_file = Path.cwd() / "output.json" with open(output_file, "w") as jsonfile: json.dump(outputs, jsonfile) create_staad_model() ``` ## Conclusion[​](/docs/create-apps/software-integrations/staadpro/.md#conclusion "Direct link to Conclusion") By following this guide, you have learned how to set up your worker for use with STAAD.Pro. With the provided templates, you are ready to integrate STAAD.Pro into your VIKTOR app and automate design and analysis tasks. Want to dive right in and build a complete STAAD.Pro automation? Follow our [STAAD.Pro tutorial](/docs/tutorials/integrate-staadpro/.md). --- # Tekla Structures tip This guide provides the basic information about the Tekla integration. **If this is your first time setting up an integration, we recommend to follow one of the [Intermediate tutorials](/docs/tutorials/.md#intermediate-level).** ## System requirements:[​](/docs/create-apps/software-integrations/tekla/.md#system-requirements "Direct link to System requirements:") * 💻 Windows PC * 🐍 Python =< 3.11 (pyTekla requirement) * PyTekla (Tekla Open API wrapper) * Tekla Structures (with an active model on the worker) ### Additional information[​](/docs/create-apps/software-integrations/tekla/.md#additional-information "Direct link to Additional information") Below you can find some useful information for this integration. * [Tekla Open API](https://developer.tekla.com/tekla-structures/api/28/8180) * [PyTekla API](https://efdiloreto.github.io/PyTekla/api_reference/) ### Download and install pyTekla[​](/docs/create-apps/software-integrations/tekla/.md#download-and-install-pytekla "Direct link to Download and install pyTekla") PyTekla is a Python wrapper that provides a thin wrapper around the Tekla Open API. The Tekla Open API is an API that provides a range of tools and functions that allow developers to automate processes, integrate with other software (VIKTOR in this case) and customise the behaviour of Tekla Structures software. You can follow the instructions to installing PyTekla [here](https://efdiloreto.github.io/PyTekla/install/). ## Setup environment[​](/docs/create-apps/software-integrations/tekla/.md#setup-environment "Direct link to Setup environment") Before you can start building your VIKTOR - Tekla apps, you will need to complete some steps for the setup. ### Step 1: Start a VIKTOR app[​](/docs/create-apps/software-integrations/tekla/.md#step-1-start-a-viktor-app "Direct link to Step 1: Start a VIKTOR app") You will need to create, install and start an empty app. If you would like a quick reminder on how to do this, you can follow the steps [here](/docs/getting-started/starter-guide/.md). For your VIKTOR app, you will not need to add any extra packages to your `requirements.txt` as they will be installed on the worker. Furthermore you can copy `app.py` below to get started with the VIKTOR - Tekla integration. In this example, the `app.py` dumps the parameters into a `.json` file that the worker will be able to use for `run_tekla.py`. ``` import viktor as vkt import json from pathlib import Path class Parametrization(vkt.Parametrization): # Add your parameters here class Controller(vkt.Controller): parametrization = Parametrization @vkt.IFCView("IFC Viewer", duration_guess=5) def show_ifc(self, params, entity_id, **kwargs): # Create empty file to dump the params json in file = File() params['export_ifc'] = True with file.open() as f: json.dump(params, f) # Run the python script and obtain the output files analysis = vkt.tekla.TeklaAnalysis(files=[('input.json', file)], output_filenames=["output.ifc"]) analysis.execute(timeout=60) return_ifc = analysis.get_output_file("output.ifc", as_file=True) return vkt.IFCResult(return_ifc) ``` ### Step 2: Install Tekla worker[​](/docs/create-apps/software-integrations/tekla/.md#step-2-install-tekla-worker "Direct link to Step 2: Install Tekla worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Tekla** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your 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 the following command in your terminal ``` where python ``` 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Tekla** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. 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 tip Your default Python environment can usually be found in `C:\Users\\AppData\Local\Programs\Python\Python31X\python.exe`. If you cannot find it, try running `where python` in your terminal. 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ### Step 3: Configure PyTekla[​](/docs/create-apps/software-integrations/tekla/.md#step-3-configure-pytekla "Direct link to Step 3: Configure PyTekla") Open a python environment on the machine that hosts the worker, make sure this is the Python version that you have configured in your worker. run the following commands: ``` import pytekla ``` ``` pytekla.config.set_tekla_path("C:/Program Files/Tekla Structures/2023.0/bin") ``` Make sure that the Tekla path is set to the bin folder of your Tekla Structures. You may now run the VIKTOR worker, and connect it to your workspace. ### Step 4: Start using Tekla in a VIKTOR app[​](/docs/create-apps/software-integrations/tekla/.md#step-4-start-using-tekla-in-a-viktor-app "Direct link to Step 4: Start using Tekla in a VIKTOR app") There are two options to using Tekla in VIKTOR. One way is to use the PyTekla Wrapper to perform all the operations on the Tekla model. The other option is to use Tekla through Grasshopper. #### Method 1: use PyTekla[​](/docs/create-apps/software-integrations/tekla/.md#method-1-use-pytekla "Direct link to Method 1: use PyTekla") You can use PyTekla's wrpapper to open, save and close models Tekla models. You can copy the boiler plate code into your `run_tekla.py` file to get started. Then you can add your own code to start developing with pyTekla. This boiler plate allows you to edit an active model in Tekla. Note that this boiler plate is for opening and closing models you will require some extra code. ``` # THIS FILE HAS TO BE ON THE VIKTOR WORKER DIRECTORY FOR THIS EXAMPLE # Pip install required packages [on worker] import os import json import math import ctypes # An included library with Python install. from pytekla import wrap from Tekla.Structures.Model import Model from Tekla.Structures.Model.Operations import Operation from System import String def save_model_as_ifc(path: str) -> bool: """This is a function to save the active Tekla model as IFC""" model = wrap("Model.Model") myie = List[String]() myie.Add("..//default//General//Shared//IFC//AdditionalPSets//CIP Construction data.xml") flags = Operation.IFCExportFlags() flags.IsLocationFromOrganizer = True flags.IsPoursEnabled = True success = Operation.CreateIFC4ExportFromAll( path, Operation.IFCExportViewTypeEnum.REFERENCE_VIEW, myie, Operation.ExportBasePoint.GLOBAL, "__Name__", "ByObjectClass", flags, "") return success # Define path to local working directory workdir = os.getcwd() + '\\' # Read input parameters from JSON file with open(workdir + 'input.json') as f: params = json.load(f) # Clear the model to prevent overwriting model = wrap('Model.Model') for tekla_obj in model.get_objects_with_types(["Beam"]): if tekla_obj: tekla_obj.Delete() # Add your code here model.commit_changes("Viktor changes") # Delete this line if you dont want Tekla visualization # Save ifc path = workdir + 'output.ifc' success = save_model_as_ifc(path) ``` #### Method 2: use Grasshopper[​](/docs/create-apps/software-integrations/tekla/.md#method-2-use-grasshopper "Direct link to Method 2: use Grasshopper") A powerful connection can also be made with the Grasshopper-Tekla link. Tekla structures are easily created with Grasshopper and the GH-components available. When creating a VIKTOR - Tekla app, Grasshopper can also be used. The main issue is that we want a .ifc from the Tekla model; and Grasshopper nodes don't allow for saving / export Tekla files. This can be solved like this: * Follow this [guide](/docs/create-apps/software-integrations/rhino-grasshopper/.md) to set up your VIKTOR app that communicates with GH. * Have your worker look for an `output.ifc` in your worker-directory * Use [these Grasshopper nodes](https://www.food4rhino.com/en/resource/rhinoinside-tekla-structures) to create a Tekla model * Add the following C# component to your Grasshopper file (feel free to replace some defaults, [documentation here](https://developer.tekla.com/tekla-structures/api/28/26130)): ``` if (run){ Model model = new Model(); success = Operation.CreateIFC4ExportFromAll( ifc_path, Operation.IFCExportViewTypeEnum.REFERENCE_VIEW, new List { @"..\\default\\General\\Shared\\IFC\\AdditionalPSets\\CIP Construction data.xml" }, Operation.ExportBasePoint.GLOBAL, "__Name__", "ByObjectClass", new Operation.IFCExportFlags { IsLocationFromOrganizer = true, IsPoursEnabled = true}, string.Empty); } success = true; ``` * you can then add the success output to a context print (this way the worker will know the script is finished). Below you can find an example of how this may look: ![](/assets/images/tekla-integration-1-a27ea382fe21a637da3c1b22830746b4.png) ## Would you like to see an example?[​](/docs/create-apps/software-integrations/tekla/.md#would-you-like-to-see-an-example "Direct link to Would you like to see an example?") VIKTOR offers a wide variety of sample repositories on GitHub, one of which is the [PyTekla integration app](https://github.com/viktor-rick/tekla-viktor-example). ## Testing[​](/docs/create-apps/software-integrations/tekla/.md#testing "Direct link to Testing") `TeklaAnalysis.execute` needs to be [mocked](/docs/create-apps/automated-testing/mocking/.md) within the context of (automated) testing. The `viktor.testing` module provides the [`mock_TeklaAnalysis`](/sdk/api/testing/.md#_mock_TeklaAnalysis) decorator that facilitate mocking of workers: ``` import unittest import viktor as vkt from viktor.testing import mock_TeklaAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_TeklaAnalysis(get_output_file={ 'result.xml': vkt.File.from_path('test_file.xml'), # : '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). --- # User input, fields and buttons The parametrization is built up by means of input fields that can be filled in and/or buttons that can be clicked by the user. ## Input fields[​](/docs/create-apps/user-input/.md#input-fields "Direct link to Input fields") Different types of input fields can be used, For each input field, arguments can be specified to set specific options and/or constraints such as the default, minimum, or maximum value. See [`Field`](/sdk/api/parametrization/.md#_Field) for all possible options. The following input fields are available: ### Numeric input[​](/docs/create-apps/user-input/.md#numeric-input "Direct link to Numeric input") ![](/img/docs/cards/numberfield.png) ## [Decimal number](/docs/create-apps/user-input/numeric-input/.md#numberfield---decimal-numbers) Numbers with decimals can be specified using a NumberField ![](/img/docs/cards/slider.png) ## [Slider](/docs/create-apps/user-input/numeric-input/.md#numberfield---decimal-numbers) Slider is a visual variant of the NumberField ![](/img/docs/cards/integerfield.png) ## [Integer](/docs/create-apps/user-input/numeric-input/.md#integerfield---whole-numbers) The IntegerField can contain integers only ### Textual input[​](/docs/create-apps/user-input/.md#textual-input "Direct link to Textual input") ![](/img/docs/cards/textfield.png) ## [Short text](/docs/create-apps/user-input/textual-input/.md#textfield---short-texts) Short text can be specified in a TextField ![](/img/docs/cards/textareafield.png) ## [Long text](/docs/create-apps/user-input/textual-input/.md#textareafield---longer-texts) Long text can be specified in a TextAreaField ### Options & selections[​](/docs/create-apps/user-input/.md#options--selections "Direct link to Options & selections") ![](/img/docs/cards/optionfield.png) ## [Single option](/docs/create-apps/user-input/options-and-selections/.md#single-option) A single option can be selected in an OptionField ![](/img/docs/cards/optionfield-radio.png) ## [Radio button](/docs/create-apps/user-input/options-and-selections/.md#variants) An OptionField can be visualized as a radio button ![](/img/docs/cards/optionfield-radio-inline.png) ## [Radio button (horizontal)](/docs/create-apps/user-input/options-and-selections/.md#variants) An OptionField can also be visualized as a horizontal radio button ![](/img/docs/cards/autocompletefield.svg) ## [Autocomplete](/docs/create-apps/user-input/options-and-selections/.md#autocomplete) Filter options through typing using an AutocompleteField ![](/img/docs/cards/multiselectfield.svg) ## [Multi-select](/docs/create-apps/user-input/options-and-selections/.md#multi-select) Select multiple items from a list using a MultiSelectField ### Entity selection[​](/docs/create-apps/user-input/.md#entity-selection "Direct link to Entity selection") ![](/img/docs/cards/childentityoptionfield.svg) ## [Select single child](/docs/create-apps/user-input/entity-selection/.md#select-children) Select a single child entity using a ChildEntityOptionField ![](/img/docs/cards/childentitymultiselectfield.svg) ## [Select children](/docs/create-apps/user-input/entity-selection/.md#select-children) Select from a list of child entities using a ChildEntityMultiSelectField ![](/img/docs/cards/siblingentityoptionfield.svg) ## [Select single sibling](/docs/create-apps/user-input/entity-selection/.md#select-siblings) Select a single sibling entity using a SiblingEntityOptionField ![](/img/docs/cards/siblingentitymultiselectfield.svg) ## [Select siblings](/docs/create-apps/user-input/entity-selection/.md#select-siblings) Select from a list of sibling entities using a SiblingEntityMultiSelectField ![](/img/docs/cards/entityoptionfield.svg) ## [Select generic entity](/docs/create-apps/user-input/entity-selection/.md#select-generic-entity) Select a single generic entity using an EntityOptionField ![](/img/docs/cards/entitymultiselectfield.svg) ## [Select generic entities](/docs/create-apps/user-input/entity-selection/.md#select-generic-entity) Select from a list of generic entities using an EntityMultiSelectField ### Geometry selection[​](/docs/create-apps/user-input/.md#geometry-selection "Direct link to Geometry selection") ![](/img/docs/cards/select_geometry.png) ## [Select a geometry](/docs/create-apps/user-input/geometry-selection/.md#select-a-geometry) Select a geometry in a Geometry or IFCView using a GeometrySelectField ![](/img/docs/cards/select_geometries.png) ## [Select multiple geometries](/docs/create-apps/user-input/geometry-selection/.md#select-multiple-geometries) Select multiple geometries in a Geometry or IFCView using a GeometryMultiSelectField ### Map features[​](/docs/create-apps/user-input/.md#map-features "Direct link to Map features") ![](/img/docs/cards/geopointfield.svg) ## [Define a point](/docs/create-apps/user-input/map-features/.md#draw-a-point) Define a geo-point on a MapView using a GeoPointField ![](/img/docs/cards/geopolylinefield.svg) ## [Define a polyline](/docs/create-apps/user-input/map-features/.md#draw-a-polyline) Define a geo-polyline on a MapView using a GeoPolylineField ![](/img/docs/cards/geopolygonfield.svg) ## [Define a polygon](/docs/create-apps/user-input/map-features/.md#draw-a-polygon) Define a geo-polygon on a MapView using a GeoPolygonField ### File upload[​](/docs/create-apps/user-input/.md#file-upload "Direct link to File upload") ![](/img/docs/cards/filefield.png) ## [Upload single file](/docs/create-apps/user-input/upload-files/.md#upload-a-single-file) Upload a single file using a FileField ![](/img/docs/cards/multifilefield.png) ## [Upload multiple files](/docs/create-apps/user-input/upload-files/.md#upload-multiple-files) Upload multiple files at once using a MultiFileField ### Other[​](/docs/create-apps/user-input/.md#other "Direct link to Other") New in v14.0.0 ![](/img/docs/cards/colorfield.png) ## [Select a color](/docs/create-apps/user-input/other-fields/.md#select-a-color) Pick a color from a palette using a ColorField ![](/img/docs/cards/datefield.svg) ## [Select a date](/docs/create-apps/user-input/other-fields/.md#select-a-date) Pick a date on a calendar using a DateField ![](/img/docs/cards/booleanfield.png) ## [Toggle button](/docs/create-apps/user-input/other-fields/.md#toggle-button) Switch on/off using a BooleanField ![](/img/docs/cards/hiddenfield.png) ## [Store JSON data](/docs/create-apps/user-input/other-fields/.md#generic-json-data) Store hidden JSON data on a HiddenField ![](/img/docs/cards/linebreak.svg) ## [Line break](/docs/create-apps/user-input/other-fields/.md#manual-line-break) Style your editor by manually arrange fields using a LineBreak ## Tables & arrays[​](/docs/create-apps/user-input/.md#tables--arrays "Direct link to Tables & arrays") If the user must be able to make a dynamic number of objects sharing the same properties, tables or arrays can be used. ![](/img/docs/cards/table.svg) ## [Table](/docs/create-apps/user-input/tables-and-arrays/.md#table) Draw a table consisting of rows and columns using Table ![](/img/docs/cards/dynamicarray.svg) ## [Array](/docs/create-apps/user-input/tables-and-arrays/.md#dynamicarray) Bundle fields in rows and let the user add rows using a DynamicArray ## Action buttons[​](/docs/create-apps/user-input/.md#action-buttons "Direct link to Action buttons") In addition to the input fields, action buttons can be added to the parametrization to enable user actions. The following table gives an overview of all action buttons: ![](/img/docs/cards/actionbutton.png) ## [Action without result](/docs/create-apps/user-input/action-buttons/.md#action-without-result) Perform an action without returning any result using an ActionButton ![](/img/docs/cards/downloadbutton.png) ## [File download](/docs/create-apps/user-input/action-buttons/.md#download-action) Perform an action that returns a file download using a DownloadButton ![](/img/docs/cards/setparamsbutton.png) ## [Set params](/docs/create-apps/user-input/action-buttons/.md#set-params-action) Set params by means of a button click using a SetParamsButton ![](/img/docs/cards/optimizationbutton.png) ## [Optimization routine](/docs/create-apps/user-input/action-buttons/.md#optimization-action) Perform an optimization routine using an OptimizationButton ## Read-only fields[​](/docs/create-apps/user-input/.md#read-only-fields "Direct link to Read-only fields") The fields below can be used to guide users by providing more context, without the user being able to edit the values. ![](/img/docs/cards/outputfield.png) ## [Show output](/docs/create-apps/inform-end-user/output-field/.md) Show a (dynamic) value using an OutputField ![](/img/docs/cards/static-text.svg) ## [Static text](/docs/create-apps/inform-end-user/text-blocks/.md) Show a static text using Text ![](/img/docs/cards/static-image.svg) ## [Static image](/docs/create-apps/inform-end-user/static-image/.md) Show a static image using Image ## LLM chat[​](/docs/create-apps/user-input/.md#llm-chat "Direct link to LLM chat") ![](/img/docs/cards/chat.png) ## [Chat](/docs/create-apps/user-input/llm-chat/.md) Enable the potential of LLM in your app --- # Action buttons Action buttons can be added to a parametrization to enable the user to perform certain actions. All action buttons have a (required) `method` argument that represents the name of the method on the corresponding [controller class](/docs/getting-started/fundamentals/basic-app-structure/.md#the-controller). Various buttons exist for different type of actions, which all require a different return on the corresponding button method. Reference For a more technical API reference, please see the following pages: * [`ActionButton`](/sdk/api/parametrization/.md#_ActionButton) * [`DownloadButton`](/sdk/api/parametrization/.md#_DownloadButton) * [`OptimizationButton`](/sdk/api/parametrization/.md#_OptimizationButton) * [`SetParamsButton`](/sdk/api/parametrization/.md#_SetParamsButton) ## ActionButton - action without result[​](/docs/create-apps/user-input/action-buttons/.md#actionbutton---action-without-result "Direct link to ActionButton - action without result") To perform an action without returning any result, the `ActionButton` can be used: ``` import viktor as vkt class Parametrization(vkt.Parametrization): button = vkt.ActionButton('ActionButton', method='perform_action') ``` ![](data:image/png;base64,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) Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` button = vkt.ActionButton('ActionButton', method='perform_action', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` button = vkt.ActionButton('ActionButton', method='perform_action', flex=50) ``` * **interaction**: enable view interaction ``` button = vkt.ActionButton( 'ActionButton', method='perform_action', interaction=MapSelectInteraction('my_map_view', selection=['points']) ) ``` * **longpoll**: set to True if the triggered method cannot be completed within the timeout limit (15s) ``` button = vkt.ActionButton('ActionButton', method='perform_action', longpoll=True) ``` * **method**: controller method that will be triggered ``` button = vkt.ActionButton('ActionButton', method='perform_action') ``` * **visible**: can be used when the visibility depends on other input fields ``` button = vkt.ActionButton('ActionButton', method='perform_action', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. The button method is expected to return nothing (`None`): ``` class Controller(vkt.Controller): def perform_action(self, params, **kwargs): ... # no return ``` ## DownloadButton - download a file[​](/docs/create-apps/user-input/action-buttons/.md#downloadbutton---download-a-file "Direct link to DownloadButton - download a file") To perform an action that returns a file download, the `DownloadButton` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): button = vkt.DownloadButton('DownloadButton', method='perform_download') ``` ![](data:image/png;base64,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) Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` button = vkt.DownloadButton('DownloadButton', method='perform_download', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` button = vkt.DownloadButton('DownloadButton', method='perform_download', flex=50) ``` * **interaction**: enable view interaction ``` button = vkt.DownloadButton( 'DownloadButton', method='perform_download', interaction=MapSelectInteraction('my_map_view', selection=['points']) ) ``` * **longpoll**: set to True if the triggered method cannot be completed within the timeout limit (15s) ``` button = vkt.DownloadButton('DownloadButton', method='perform_download', longpoll=True) ``` * **method**: controller method that will be triggered ``` button = vkt.DownloadButton('DownloadButton', method='perform_download') ``` * **visible**: can be used when the visibility depends on other input fields ``` button = vkt.DownloadButton('DownloadButton', method='perform_download', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. The button method is expected to return a [`DownloadResult`](/sdk/api/result/.md#_DownloadResult): ``` import viktor as vkt class Controller(vkt.Controller): def perform_download(self, params, **kwargs): ... return vkt.DownloadResult(...) ``` For more information, refer to the guide on [how to handle downloading of files](/docs/create-apps/managing-files/downloading-files/.md). ## SetParamsButton - set params action[​](/docs/create-apps/user-input/action-buttons/.md#setparamsbutton---set-params-action "Direct link to SetParamsButton - set params action") To set the `params` by means of a button click, the `SetParamsButton` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): button = vkt.SetParamsButton('SetParamsButton', method='set_params') ``` ![](data:image/png;base64,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) Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` button = vkt.SetParamsButton('SetParamsButton', method='set_params', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` button = vkt.SetParamsButton('SetParamsButton', method='set_params', flex=50) ``` * **interaction**: enable view interaction ``` button = vkt.SetParamsButton( 'SetParamsButton', method='set_params', interaction=MapSelectInteraction('my_map_view', selection=['points']) ) ``` * **longpoll**: set to True if the triggered method cannot be completed within the timeout limit (15s) ``` button = vkt.SetParamsButton('SetParamsButton', method='set_params', longpoll=True) ``` * **method**: controller method that will be triggered ``` button = vkt.SetParamsButton('SetParamsButton', method='set_params') ``` * **visible**: can be used when the visibility depends on other input fields ``` button = vkt.SetParamsButton('SetParamsButton', method='set_params', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. The button method is expected to return a [`SetParamsResult`](/sdk/api/result/.md#_SetParamsResult): ``` import viktor as vkt class Controller(vkt.Controller): def set_params(self, params, **kwargs): ... return vkt.SetParamsResult(...) ``` For more information, refer to the guide on [how to set params using a button](/docs/create-apps/user-input/set-params-using-button/.md). ## OptimizationButton - optimization action[​](/docs/create-apps/user-input/action-buttons/.md#optimizationbutton---optimization-action "Direct link to OptimizationButton - optimization action") The `OptimizationButton` can be used to perform an optimization routine. ``` import viktor as vkt class Parametrization(vkt.Parametrization): button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization') ``` ![](data:image/png;base64,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) Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization', flex=50) ``` * **interaction**: enable view interaction ``` button = vkt.OptimizationButton( 'OptimizationButton', method='perform_optimization', interaction=MapSelectInteraction('my_map_view', selection=['points']) ) ``` * **longpoll**: set to True if the triggered method cannot be completed within the timeout limit (15s) ``` button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization', longpoll=True) ``` * **method**: controller method that will be triggered ``` button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization') ``` * **visible**: can be used when the visibility depends on other input fields ``` button = vkt.OptimizationButton('OptimizationButton', method='perform_optimization', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. The button method is expected to return a [`OptimizationResult`](/sdk/api/result/.md#_OptimizationResult): ``` import viktor as vkt class Controller(vkt.Controller): def perform_optimization(self, params, **kwargs): ... return vkt.OptimizationResult(...) ``` For more information, refer to the guide on [how to perform an optimization routine](/docs/create-apps/results-and-visualizations/optimization-routine/.md). --- # Entity selection When an entity depends on data of one or more other entities, the entity selection fields enable the user to make this selection. This is especially useful when [making a tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app). If none of the below entity selection fields are sufficient, data between entities can be shared [using the API](/docs/api/sdk/handling-entity-data/.md). Reference For a more technical API reference, please see the following pages: * [`ChildEntityOptionField`](/sdk/api/parametrization/.md#_ChildEntityOptionField) / [`ChildEntityMultiSelectField`](/sdk/api/parametrization/.md#_ChildEntityMultiSelectField) * [`EntityOptionField`](/sdk/api/parametrization/.md#_EntityOptionField) / [`EntityMultiSelectField`](/sdk/api/parametrization/.md#_EntityMultiSelectField) * [`SiblingEntityOptionField`](/sdk/api/parametrization/.md#_SiblingEntityOptionField) / [`SiblingEntityMultiSelectField`](/sdk/api/parametrization/.md#_SiblingEntityMultiSelectField) ## ChildEntityOptionField - select child(ren)[​](/docs/create-apps/user-input/entity-selection/.md#childentityoptionfield---select-children "Direct link to ChildEntityOptionField - select child(ren)") For the selection of a single child entity, the `ChildEntityOptionField` can be used. For example, when the entity type structure of your application looks similar to the following, and you need your users to select one of the child entities of a `Parent`, the following code can be used: ``` Parent └── Child ``` ``` import viktor as vkt class Parametrization(vkt.Parametrization): entity = vkt.ChildEntityOptionField('Select a child entity') ``` ![](/assets/images/childentityoptionfield-3e7506b5ac7c8975050af10e4b411c74.svg) The user input can be obtained through the **params** argument and can have the following values: * `Entity` object: when user selects an entity * `None`: when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entity = vkt.ChildEntityOptionField('Select a child entity', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entity = vkt.ChildEntityOptionField('Select a child entity', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entity = vkt.ChildEntityOptionField('Select a child entity', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entity = vkt.ChildEntityOptionField('Select a child entity', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entity = vkt.ChildEntityOptionField('Select a child entity', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Select multiple children[​](/docs/create-apps/user-input/entity-selection/.md#select-multiple-children "Direct link to Select multiple children") In case multiple children should be selectable, the `ChildEntityMultiSelectField` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): entities = vkt.ChildEntityMultiSelectField('Select child entities') ``` ![](/assets/images/childentitymultiselectfield-d34f730e4810222516430ec724b2edd9.svg) The user input can be obtained through the **params** argument and can have the following values: * `list` of `Entity` objects: when user selects an entity * empty list when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entities = vkt.ChildEntityMultiSelectField('Select child entities', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entities = vkt.ChildEntityMultiSelectField('Select child entities', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entities = vkt.ChildEntityMultiSelectField('Select child entities', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entities = vkt.ChildEntityMultiSelectField('Select child entities', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entities = vkt.ChildEntityMultiSelectField('Select child entities', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## SiblingEntityOptionField - select sibling(s)[​](/docs/create-apps/user-input/entity-selection/.md#siblingentityoptionfield---select-siblings "Direct link to SiblingEntityOptionField - select sibling(s)") Similar to children, siblings can be selected using the `SiblingEntityOptionField`. For example, when the entity type structure of your application looks similar to the following, and you need your users to select entities of type `SiblingB` from an editor in `SiblingA`, the following code can be used: ``` Parent ├── SiblingA └── SiblingB ``` ``` import viktor as vkt class Parametrization(vkt.Parametrization): entity = vkt.SiblingEntityOptionField('Select a sibling') ``` ![](/assets/images/siblingentityoptionfield-6dd1c4a77f6cd17f67249e09f8212b03.svg) The user input can be obtained through the **params** argument and can have the following values: * `Entity` object: when user selects an entity * `None`: when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entity = vkt.SiblingEntityOptionField('Select a sibling', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entity = vkt.SiblingEntityOptionField('Select a sibling', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entity = vkt.SiblingEntityOptionField('Select a sibling', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entity = vkt.SiblingEntityOptionField('Select a sibling', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entity = vkt.SiblingEntityOptionField('Select a sibling', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Select multiple siblings[​](/docs/create-apps/user-input/entity-selection/.md#select-multiple-siblings "Direct link to Select multiple siblings") In case multiple siblings should be selectable, the `SiblingEntityMultiSelectField` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): entities = vkt.SiblingEntityMultiSelectField('Select sibling entities') ``` ![](/assets/images/siblingentitymultiselectfield-00ebec8fdffb08a7edef0fccab886ff5.svg) The user input can be obtained through the **params** argument and can have the following values: * `list` of `Entity` objects: when user selects an entity * empty list when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entities = vkt.SiblingEntityMultiSelectField('Select sibling entities', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entities = vkt.SiblingEntityMultiSelectField('Select sibling entities', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entities = vkt.SiblingEntityMultiSelectField('Select sibling entities', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entities = vkt.SiblingEntityMultiSelectField('Select sibling entities', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entities = vkt.SiblingEntityMultiSelectField('Select sibling entities', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## EntityOptionField - select any entity[​](/docs/create-apps/user-input/entity-selection/.md#entityoptionfield---select-any-entity "Direct link to EntityOptionField - select any entity") In some cases, both the `ChildEntityOptionField` and `SiblingEntityOptionField` may not be sufficient because the entities you need to select are in a different part of the entity type tree. In the following example, we want to select a `CPTFile` entity in a `Foundation` entity: ``` ProjectFolder └── Project ├── CPTFolder │ └── CPTFile └── Foundation ``` We can make use of the `EntityOptionField` and the `entity_type_names` attribute to filter which entity type(s) should be selectable: ``` import viktor as vkt class Parametrization(vkt.Parametrization): selected_cpt = vkt.EntityOptionField('CPT File', entity_type_names=['CPTFile']) ``` ![](/assets/images/entity-option-field-37e8ba8f3d8edca46624bdc7c1d23e64.png) The user input can be obtained through the **params** argument and can have the following values: * `Entity` object: when user selects an entity * `None`: when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entity = vkt.EntityOptionField('CPT File', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entity = vkt.EntityOptionField('CPT File', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entity = vkt.EntityOptionField('CPT File', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entity = vkt.EntityOptionField('CPT File', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entity = vkt.EntityOptionField('CPT File', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Select multiple entities[​](/docs/create-apps/user-input/entity-selection/.md#select-multiple-entities "Direct link to Select multiple entities") Multiple entities can be selected by using `EntityMultiSelectField`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): selected_cpt = vkt.EntityMultiSelectField('CPT File(s)', entity_type_names=['CPTFile']) ``` ![](/assets/images/entity-multi-select-field-f4125415a008c687c930a8fe17be4feb.png) The user input can be obtained through the **params** argument and can have the following values: * `list` of `Entity` objects: when user selects an entity * empty list when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` entities = vkt.EntityMultiSelectField('CPT File(s)', description="This field represents the ...") ``` * **entity\_type\_names**: users will only be able to select entities of types within this list ``` entities = vkt.EntityMultiSelectField('CPT File(s)', entity_type_names=["TypeA", "TypeC"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` entities = vkt.EntityMultiSelectField('CPT File(s)', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` entities = vkt.EntityMultiSelectField('CPT File(s)', name="e") # obtained using params.e ``` * **visible**: can be used when the visibility depends on other input fields ``` entities = vkt.EntityMultiSelectField('CPT File(s)', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## Entity object[​](/docs/create-apps/user-input/entity-selection/.md#entity-object "Direct link to Entity object") When the user selects an entity with these fields, the entity is returned in the `params` as `Entity` object. For more detail on how to use an `Entity`, see [this guide](/docs/api/sdk/handling-entity-data/.md). ``` import viktor as vkt class Parametrization(vkt.Parametrization): cpt_entity = vkt.EntityOptionField('Select a CPT', entity_type_names=['CPTFile']) class Controller(vkt.Controller): parametrization = Parametrization @vkt.DataView("CPT data") def visualize(self, params, **kwargs): cpt_entity = params.cpt_entity # Entity | None if cpt_entity: return vkt.DataResult(vkt.DataGroup( x=vkt.DataItem('CPT X coordinate', cpt_entity.last_saved_params.x_coordinate), y=vkt.DataItem('CPT Y coordinate', cpt_entity.last_saved_params.y_coordinate) )) return vkt.DataResult(vkt.DataGroup()) ``` --- # Geometry selection New in v14.10.0 The geometry selection fields, enable the user to select geometries in an [`IFCView`](/docs/create-apps/results-and-visualizations/threed-model/.md#ifcview) or a [`GeometryView`](/docs/create-apps/results-and-visualizations/threed-model/.md#geometryview). Reference For a more technical API reference, please see the following pages: * [`GeometrySelectField`](/sdk/api/parametrization/.md#_GeometrySelectField) * [`GeometryMultiSelectField`](/sdk/api/parametrization/.md#_GeometryMultiSelectField) ## GeometrySelectField - select a geometry[​](/docs/create-apps/user-input/geometry-selection/.md#geometryselectfield---select-a-geometry "Direct link to GeometrySelectField - select a geometry") The `GeometrySelectField` enables the user to select a single (sub-)geometry in a geometric view. It should be used in combination with an `IFCView` or `GeometryView` (showing `TransformableObject` or `.3dm` files). ``` import viktor as vkt class Parametrization(vkt.Parametrization): geometry = vkt.GeometrySelectField("Select Geometry") ``` ![](data:image/png;base64,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) The user input can be obtained through the **params** argument and can have the following values: * `string`: when a geometry is selected * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` geometry = vkt.GeometrySelectField("Select Geometry", default="cube1") ``` * **description**: add a tooltip with additional information ``` geometry = vkt.GeometrySelectField("Select Geometry", description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` geometry = vkt.GeometrySelectField("Select Geometry", flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` geometry = vkt.GeometrySelectField("Select Geometry", name="g") # obtained using params.g ``` * **view**: view method to which the field is connected (default: first GeometryView / IFCView) ``` geometry = vkt.GeometrySelectField("Select Geometry", view="geometry_view") ``` * **visible**: can be used when the visibility depends on other input fields ``` geometry = vkt.GeometrySelectField("Select Geometry", visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Select multiple geometries[​](/docs/create-apps/user-input/geometry-selection/.md#select-multiple-geometries "Direct link to Select multiple geometries") The `GeometryMultiSelectField` enables the user to select multiple (sub-)geometries in a geometric view. It should be used in combination with an `IFCView` or `GeometryView`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): geometries = vkt.GeometryMultiSelectField("Select Geometries") ``` ![](data:image/png;base64,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) The user input can be obtained through the **params** argument and can have the following values: * list of `string`: when geometries are selected * empty list when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", default=["cube1", "cube3"]) ``` * **description**: add a tooltip with additional information ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", flex=50) ``` * **max\_select**: maximum amount of objects the user is allowed to select ``` geometry = vkt.GeometryMultiSelectField("Select Geometries", max_select=5) ``` * **min\_select**: minimum amount of objects the user needs to select ``` geometry = vkt.GeometryMultiSelectField("Select Geometries", min_select=3) ``` * **name**: defines the position of the parameter in the *params* ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", name="g") # obtained using params.g ``` * **view**: view method to which the field is connected (default: first GeometryView / IFCView) ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", view="geometry_view") ``` * **visible**: can be used when the visibility depends on other input fields ``` geometries = vkt.GeometryMultiSelectField("Select Geometries", visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## Example[​](/docs/create-apps/user-input/geometry-selection/.md#example "Direct link to Example") To support geometry selection, the following parts need to be implemented in the app: * IFCView * GeometryView 1. Create an [IFCView](/docs/create-apps/results-and-visualizations/threed-model/.md#ifcview) in the controller 2. Create a `FileField` and `GeometrySelectField` (or `GeometryMultiSelectField`) in the parametrization 3. Use the `identifier` retrieved from the params in subsequent calculations An IFC-file contains unique identifiers per geometry feature. ``` import viktor as vkt import ifcopenshell import ifcopenshell.util.element from pathlib import Path from tempfile import NamedTemporaryFile class Parametrization(vkt.Parametrization): ifc = vkt.FileField("Please provide an IFC file") geometry = vkt.GeometrySelectField("Select Geometry") class Controller(vkt.Controller): parametrization = Parametrization @vkt.IFCAndDataView("IFC", x_axis_to_right=True) def get_ifc_and_data_view(self, params, **kwargs): ifc_file = params.ifc.file if selected_geometry := params.geometry: # If user has made a selection, add its properties to `data` # parse your ifc file (e.g. with ifcopenshell as below) with NamedTemporaryFile(suffix=".ifc", delete=False, mode="w") as temp_f: temp_f.write(ifc_file.getvalue()) model = ifcopenshell.open(Path(temp_f.name)) elem = model.by_id(int(selected_geometry)) # See https://wiki.osarch.org/index.php?title=IFC_attributes_and_properties # for a list of available IFC attributes and properties data_items = [] for key, val in ifcopenshell.util.element.get_psets(elem).items(): sub_data_items = [] for k,v in val.items(): sub_data_items.append(vkt.DataItem(k, v)) data_items.append(vkt.DataItem(key, '', subgroup=vkt.DataGroup(*sub_data_items))) data = vkt.DataGroup(*data_items) else: data = vkt.DataGroup(vkt.DataItem('No geometries selected', '')) return vkt.IFCAndDataResult(ifc=ifc_file, data=data) ``` 1. Create a [GeometryView](/docs/create-apps/results-and-visualizations/threed-model/.md#geometryview) in the controller 2. Create a `GeometrySelectField` (or `GeometryMultiSelectField`) in the parametrization 3. Use the `identifier` retrieved from the params in subsequent calculations Identifiers can be assigned to the VIKTOR geometry objects, to make them selectable in the view. This also works with .3dm files, in which case the `Name` parameter of an objects attributes will be used as an identifier. note * If several objects have an identifier assigned, then only these objects will be selectable in the View. * If none of the objects in the GeometryResult have an identifier assigned, default identifiers are assigned to all of them (enabling them for selection). * If there are multiple objects with the same name, a number will automatically be appended to enforce uniqueness. ``` import viktor as vkt class Parametrization(vkt.Parametrization): geometry = vkt.GeometrySelectField("Select Geometry") geometries = vkt.GeometryMultiSelectField("Select Geometries") class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryAndDataView('Geometry', x_axis_to_right=True) def get_geometry_and_data_view(self, params, **kwargs): cubes = { 'cube1': vkt.SquareBeam(1, 1, 5, identifier="cube1"), 'cube2': vkt.SquareBeam(1, 4, 1, identifier="cube2"), 'cube3': vkt.SquareBeam(3, 1, 1, identifier="cube3") } # Calculate data if selected_geometry := params.geometry: volume = cubes[selected_geometry].inner_volume data_1 = vkt.DataItem('Volume of GeometrySelectField', volume, suffix="m3") else: data_1 = vkt.DataItem('No geometry selected in GeometrySelectField', '') if selected_geometries := params.geometries: volume = sum(cubes[selected_geometry].inner_volume for selected_geometry in selected_geometries) data_2 = vkt.DataItem('Volume of GeometryMultiSelectField', volume, suffix="m3") else: data_2 = vkt.DataItem('No geometries selected in GeometryMultiSelectField', '') return vkt.GeometryAndDataResult(geometry=cubes.values(), data=vkt.DataGroup(data_1, data_2)) ``` --- # Hide a field Any field can be hidden (or shown) using the `visible` argument: ``` vkt.NumberField('X', visible=...) ``` If the visibility needs to be calculated 'dynamically' (based on other input fields), one of the below methods can be used. ## Depending on BooleanField[​](/docs/create-apps/user-input/hide-field/.md#depending-on-booleanfield "Direct link to Depending on BooleanField") If the visibility depends on another [`BooleanField`](/docs/create-apps/user-input/other-fields/.md#toggle-button), the easiest solution is to use a [`Lookup`](/sdk/api/parametrization/.md#_Lookup). This looks up the value of the field with given name upon evaluation of the visibility constraint: ``` import viktor as vkt class Parametrization(vkt.Parametrization): param_x = vkt.BooleanField('X') param_y = vkt.NumberField('Y', visible=vkt.Lookup('param_x')) ``` In case of a nested parametrization structure, the dotted path should be used: ``` vkt.Lookup('tab.section.param_x') ``` When the Lookup cannot find the target field, a warning is raised and the visibility constraint is set to its default (i.e. `visible=True`). ## Depending on other field(s)[​](/docs/create-apps/user-input/hide-field/.md#depending-on-other-fields "Direct link to Depending on other field(s)") If the visibility depends on multiple other fields or on a field that is not a `BooleanField`, the so-called 'boolean operators' can be used. VIKTOR offers the following boolean operators: | Operator | Can be used to | | ---------- | ---------------------------------------- | | And | evaluate multiple operands to be True | | Or | evaluate if at least one operand is True | | Not | evaluate an operand to be False | | IsEqual | evaluate two operands to be equal | | IsNotEqual | evaluate two operands to be NOT equal | | IsTrue | evaluate an operand to be True | | IsFalse | evaluate an operand to be False | | IsNotNone | evaluate an operand to be NOT None | For example, if `param_z` should be visible only when the following conditions are met: * `param_x` is equal to `False` * `param_y` is not equal to `5` ``` import viktor as vkt _param_z_visible = vkt.And( vkt.IsFalse(vkt.Lookup('param_x')), vkt.IsEqual(vkt.Lookup('param_y'), 5) ) class Parametrization(vkt.Parametrization): param_x = vkt.BooleanField('X') param_y = vkt.NumberField('Y') param_z = vkt.NumberField('Z', visible=_param_z_visible) ``` If an inconsistent type is used in a boolean operator, a warning is raised and the visibility constraint is set to its default (i.e. `visible=True`). caution In Python, arbitrary types may be implicitly treated as booleans (e.g. `1 == True` evaluates to `True`, as well as `bool('text')`). Note that that VIKTOR's boolean operators **do not perform this implicit conversion**. For example, the following `IsEqual` operator evaluates to `False`: ``` vkt.IsEqual(1, True) ``` If implicit conversion is desired, a [callback function](/docs/create-apps/user-input/hide-field/.md#using-a-function) can be used. ## Using a function[​](/docs/create-apps/user-input/hide-field/.md#using-a-function "Direct link to Using a function") The most generic way to dynamically set the visibility is to use a 'callback function'. Upon evaluation of the visibility constraint, the platform passes the `params`, `entity_id`, `entity_name`, and `workspace_id` (>= v14.7.1) to the custom function: ``` import viktor as vkt def param_y_visible(params, **kwargs): return params.param_x class Parametrization(vkt.Parametrization): param_x = vkt.BooleanField('X') param_y = vkt.NumberField('Y', visible=param_y_visible) ``` tip All individual `kwargs` can be added explicitly in the signature if needed: ``` def param_y_visible(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` When the visibility depends on data of another entity, the `entity_id` can be used to navigate and obtain data using the [SDK API](/docs/api/sdk/handling-entity-data/.md). ## Fields in a DynamicArray[​](/docs/create-apps/user-input/hide-field/.md#fields-in-a-dynamicarray "Direct link to Fields in a DynamicArray") ### RowLookup[​](/docs/create-apps/user-input/hide-field/.md#rowlookup "Direct link to RowLookup") If the visibility depends on the result of another field within a [`DynamicArray`](/docs/create-apps/user-input/tables-and-arrays/.md#dynamicarray), a [`RowLookup`](/sdk/api/parametrization/.md#_RowLookup) can be used. Using the `RowLookup`, a field of a specific row within the array can be made dependent of another field **within the same row**: ``` import viktor as vkt class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.BooleanField('X') array.param_y = vkt.NumberField('Y', visible=vkt.RowLookup('param_x')) ``` caution Note that it is currently not possible to combine a `RowLookup` with one of the boolean operators above. For example, the following is NOT supported: `IsEqual(RowLookup("shape"), "Circular")` ### Using a function[​](/docs/create-apps/user-input/hide-field/.md#using-a-function-1 "Direct link to Using a function") Another option is to make use of a callback function. Make sure that such functions return a list of the constraint values, one for each row in the array. The length of this list must be equal to the number of rows in the array, otherwise (a warning is logged and) the constraint is ignored: ``` import viktor as vkt def param_y_visible(params, **kwargs): return [row.param_x for row in params.array] class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.BooleanField('X') array.param_y = vkt.NumberField('Y', visible=param_y_visible) ``` --- # Input validation New in v13.7.0 There are two types of input validation: * **generic**: automatically detected by the platform during user input * **specific**: custom logic to handle more complex validation Both types provide the possibility to mark fields invalid in the interface, which helps users to correct input mistakes. ## Generic field constraints[​](/docs/create-apps/user-input/input-validation/.md#generic-field-constraints "Direct link to Generic field constraints") The following constraints are automatically assessed by the platform: * [Numeric min/max boundary](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary) * [Non-existing option](/docs/create-apps/user-input/input-validation/.md#non-existing-option) * [Non-existing coordinate](/docs/create-apps/user-input/input-validation/.md#non-existing-coordinate) * [Invalid color value](/docs/create-apps/user-input/input-validation/.md#invalid-color-value) * [Invalid date format](/docs/create-apps/user-input/input-validation/.md#invalid-date-format) When any of these are violated, all actions are blocked until the user fixes the fields (invisible fields are not considered). This way it can be ensured that wrong inputs are never used in one of the calculations. The actions that are blocked are: * [action buttons](/docs/create-apps/user-input/action-buttons/.md) * [view calculations](/docs/create-apps/results-and-visualizations/.md) * next-button on a [Step](/docs/create-apps/layout-and-styling/steps/.md) caution When using an SDK version lower than v14, constraints do only block actions when the controller flag `viktor_enforce_field_constraints` is set to True (see [U83](/sdk/upgrades/.md#U83) for more detail). The platform currently **does not** automatically invalidate: * a [selected entity](/docs/create-apps/user-input/entity-selection/.md) that has been deleted * a [selected file](/docs/create-apps/user-input/upload-files/.md) that has been deleted ### Numeric min/max boundary[​](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary "Direct link to Numeric min/max boundary") Input value is not within the [configured min/max](/docs/create-apps/user-input/numeric-input/.md#setting-minmax) bounds: ``` NumberField("Number", min=10, max=20) # also on IntegerField / DynamicArray ``` ![](data:image/png;base64,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) ![](data:image/png;base64,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) ### Non-existing option[​](/docs/create-apps/user-input/input-validation/.md#non-existing-option "Direct link to Non-existing option") The selected option is no longer available, for example due to [dynamic options](/docs/create-apps/user-input/options-and-selections/.md#dynamic-options): ``` OptionField("Please select...", options=dynamic) # also on MultiSelectField / AutocompleteField ``` ![](data:image/png;base64,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) ### Non-existing coordinate[​](/docs/create-apps/user-input/input-validation/.md#non-existing-coordinate "Direct link to Non-existing coordinate") Invalid latitude / longitude pair in a `GeoPointField`: ![](data:image/png;base64,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) ### Invalid color value[​](/docs/create-apps/user-input/input-validation/.md#invalid-color-value "Direct link to Invalid color value") Invalid value in a `ColorField`: ![](/assets/images/input-validation-color-7460e78b5e21ddf86bde62b668647660.png) ### Invalid date format[​](/docs/create-apps/user-input/input-validation/.md#invalid-date-format "Direct link to Invalid date format") Format in a `DateField` which does not adhere to *YYYY-MM-DD*: ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAREAAABkCAYAAAChDARIAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAudEVYdENyZWF0aW9uIFRpbWUARnJpIDI4IE9jdCAyMDIyIDA1OjEzOjAzIFBNIENFU1TJgVEFAAAOqklEQVR4nO3dfVBUV5rH8W/TLxchIDgCszOQbJSaSDq6STtqeteNTl4wWovGGUNlB0miYaNGY+E4UYKJRCeymIzRSjSuxiEmhmQGyajJlkbLnZiXXVKb0FZgO6uzSGrEzS6QSmNDN9xumrt/8M420HIbBpLnU+Ufdp9+zgNV/ePcc2/3NWiapiGEEMMU8eduQAgxvkmICCF0kRARQugiISKE0EVCRAihi4SIEEIXCREhhC4SIkIIXSREhBC6SIgIIXSREBFC6CIhIoTQRUJECKGLhIgQQhcJESGELhIiQghdJESEELpIiAghdJEQEULoIiEihNBFQkQIoYuEiBBCF5PuCoEavJkbaa3u+K8hJo4I2zyUVfcTaY3WXV4IMbaFaSViJiL7KWKPv0TMy+tQfnCBlpw8vOf9IVfwbV+B64kPkZvgCDG+6F+JdDLEJ2G6MRlIxjRjBhE8juf5E1jeXBa+SYQQY84I7YmYsSy7m4jqcnydhzk01dC6PY/GuZl8M3s5VzeU4WsEAhU0z1tK89uNaGd247JtpbWp4yXa5U/wrF6Na3YmroV5NP/zFVmpCDHGjNzGakoyEcZaApf9gAd1+1ZaaqYTdfggE3+3AXNdKZ7dFWjGmUSfeYPr7ovGcOda4sqfRokBmqrwrN1L200Pc13ZC1y3Kom2HTtpcY5Yx0KIYRi5Iw2TGYMFNC+ABfOq7cROnoIxDmAmSsYU1GMXCDATkxINRjOYLBgUMwag/cxR/BMWErP+dkxG4PpHifxgBa1nLhJlvWnE2hZCXJuRC5E2P5oPiAIwEzHZT8vuragf16B5fRDwo6VMhwBgDPLyC7Vo1Rdosp/ofkxr82NId41Yy0KIazdyIVJ7ifZAEubrzUAjrVt+hWrJIvp3T2OebCbwVh7ussFLGGZnEZN/O4beD0ZNGrGWhRDXboRCxIPvzY9o/8u/xXIjELhAmwNMRQsxT+4cog5++tc4JQk+uEJ7UhIWpec1mmIemZaFEMMSto1VzV1H4PIV2ioraNm+Fc8pM5Yn7uvYzzAmEpHiwV9ahq/yIr63D9J8qAbN5+8+22KIUdBqLuCvrqM9AMZ77sMU+ADvUyfwVdcRqPyQ5hWP03zGE66WhRBhYNA0Td9Z035XrBIVR4TNTuRjWX2uWNUunqL56RLaqn0YrHaUuyz4TpqZcPhRLFGgfXmK5sdexd80g6jjTxE5GbTqs3iKyvBX1kFMMqafPkzU6pkYg+yhCCH+PPSHiBDiO00+gCeE0EVCRAihi4SIEEIXCREhxrhNmzaxadOmsI0LNwkRIYQucnZGiDHo0qVLlJaW4nIN72Me8fHxZGZmMnXq1DB39v/JSkSIMUhPgAC4XC5KS0vD2NHAwhMiai2nd69h2R23kpaWxpx7ssh7zYG737CG8n3k/mwet96Sxq1/nc7KZ9+hWu1TiOpjhaz8uzncmpZG2px0Vm4rpdrbt477/BEKHkxnzi1ppN06j4w1uzj9J5XBuXGW5JF1z5yeHkucw+hxuLVDm18IQFeAhLNGKMIQIm7OPb2c3DcasD6yk+Li/WycB+8/u5I1JbU9w/50hNw1e/niL7LZ+U/F7Flvx31sM48UldP1Hq0tyyUr/wTq3I3sKS5m/3obDcfyyHryNA1ddf54iJUrCjkXvYQte4spLsxmavUhcnMKKe8XNr01vLuVlc+8j7JoC/uL97MlXeH9Z1ay9d2GnkEh9Djc2iHNL8Q4pP8DeP97glfercdeUMa2BxIAsNutUHMHBSdOU5uVQwrg/H0pjtgl7H8uh/lRAHamep2kv/g6pzfYWRztpPTwOVi0h/15C4jtKESy20nGvuOUuxawOB7Kj7yCMyGbkj1rsSkddWzx9Zx/sJQT/74N+/xgTdby3m9Poy7YyZ4Niztr26DmDjYffY+GjGwSQukxdri1Q5tfiPFIf4h4JmLNyGHm3N5vgwRSfhgLlSpqADC6cVZVw4x/wB7VMypllp0U9TT/cQkWz4DEGUt4cJGd3u/VlORkCLi52gagQspPWJJ6L1alZ4ySkkKySaXVqwK9nuiiXqLiAljX39ardiy3zUqFfU6cKsxXQujxtiA/fyi1CWX+wX/N4rvpueeeG9brRvNUr/4QmbqY/P4/Z8CJ47ybxFk2UowA9TRchdgfJvR9i8dPJJZ63N8ARivZhUX9Cqk4HF/AjzKxTwJQsD9ahL3fKPf5CpxGGxttA7wTvfW4vRA7KbHPwxPjE8BbT70XUELocbi1CWX+AeoLMcaNyNmZ6jcKeeV/bOQ8bO94bwRUUAkSWQoKKq1tweuoVXvZdbSVBTmZpA70yV13ObtePM3E+9eR+f3OxwIqqqqiqnR8c5qqogJKvxpKVz9t19Cj2qt21/+Hqh3KGCHGqbCHiLu8kA3PV2P7RRHZN+go1HCagvWHaFiwnS0ZA+wYBGop3ZxLqTGbog2dgVW1i/RpaaSlpZGWNoU5z5TraKKv2uJlnXU7/q15d8jTNkJ864X1m83UPx4hN/cIPFDMnqyUnieMSsdyvf9f3ICKikJk/6W818G+tZt5L2EdJb9aMMCmo5tzzz5CgcNK/pv52Ls2G370IC+fuLdjLwZQElJBqUWB7se6++3qRwmtx5SlRZTN6gmO2BsUCChD1w5ljBDXKNi+x3D3UPQIX4g0nKNgbSGXZu3kjSf7bo5CIgmTwP11A27oee6betwkkvC9XkMDtZRu2sBe9xL2H1mLNYogVJwH15B7LJacQ3vI7n1RnpJA6s39YkdNJDEKahvqgZ5wu9rQALGpJEaH2GN8Ktb4/q2EULstlPmFGJ/CczjjdbJvbS7vJa7j5V2LOzdTe4vFNiMVPv83HL2u5aj+1EFt1M3c0h0Cbsr/8TEKHDez7cA25g9wFNNwcjOPvdjAvTv3s/HHQc+79qVYsVrBWV5Orys3KP+0Gqw2rMZr6XEYtUOaX4jxKQwrkVreefIx9l6yklNoR61y4Oj1bOwNNlITIHVpNvbDBRRsTCH/QTvKf7/H3gNOUpZu7LwmQ6X6tTXkvlbP/Cc3ktrgwNH7OqyEVGw3xKKe38Wa/NMoi7ax5Hu1OD7rdUGbkoB1ekqQo4MElmQtYO+6XeQ+H8m6nyTQ8NEr7DqnsGDvvd2HS0P3GEwotUObX4jxSP8H8NzvsHJOLueC7jEqzC/8kOLOi9Dcnx1i63NHOFdVjxqbgj1jHflPLCZVAajlUGY6hZ8F36xUlu7nP3ctwFGUzrKD1UHHcEMOZWfzsQX9y67i/G0hhb85geOKipJsY8kj+eQ/YO0TOoP3OJBQaoc2vxDQs98x2B7HYHsiobw+XORTvEKMQXpDYDRDRD7FK4TQZeTugCeEGLbIyEhaW1t1Xb4eH9//VOLIkJWIEGPQQw89pCsEur6UaDTInogQQhdZiQghdJEQEULoIiEihNBFQkQIoYvuU7zf/NXScPQhhBhFkz4/FrZashIRQugip3iFELrISkQIoYuEiBBCFwkRIYQuEiJCCF0kRIQQukiICCF0GfMhop3ZiSvnFO1DDQxU0Zy+Ee8A35zYp+bFEq4uPIg/MPRYIcTg9IdIoIrm9NV4nWHoZih1p3Cn76S1aRTmAsCD/+0y1MujNZ8Q48+YX4n0kWRnwo77scSM1oQu2o4fx//laM0nxPgT9hAJvLUV1/rDeNeuxjU7k8acw/gagcBFPBmP96xYAlU0L3wc70UAD77fPEvjXZm45q7m6q8/IeiRxtfltKw/2n0Yon15lubM5bhmL+dq3lkCgxyeBM4c5Gpn/ebXL9L7Mt3AHw7jzliOy76cxrUlnf1W4bkvj1anB/+WFbjfquvsoQrv+sdxzc7Elbmb1mq/vl+YEOPcCKxEfGif10BOEXH/UoRFPUnLu3VgvAnL3/jxn6tBAzRnBW1RMzGngvaHg3hOJhL1dilxx39OxJkDtHw81JvzCq1bDxOwb2biRwe47k7QmnzBh359Fu8OB8YtLxF3ZhtKvAetK3DqzuLZcQFT0QHiP96Fwim8r9egGacTfbyISGs05h2vEvv3SUAjrQUv4L/xUSZ+VELMUhet204EDzwhviNG5HDGMHsRE26LwxAzBbNtElpdIxpgusuG9q8O2oG2cxUw7w5MRsD2c2JeXoElDgyT7ZineWiv8ww+SV0Fvi+noeRMJ0KJxph+N6Y4S9Ch2qef0HbjQibcmYQhKglzho2IrnvTxP2Y6EN5TLBGgzEJy+3JaLX1A8xZjvr51M45zZh+ugjTV5X46ob5ixLiW2AUvu3d3H2TbIPNjslVgu/y7WifgGXLFAwAE/wEXn0Bz8dXOg4zvoKIuYNX1RqbISYR44B3puvR3tgM308KnpiKmXZHCd4tVQRUoLEObAPM+XUdmreClvRMWrofTSGiCUgaug8hvo1G95YRxmlY5jbSWnoSzTuTqGkdDwfe2E3L5YXEvLkZo+KndUMWAxyYdDPETQJvPe1twBD3so2Ii4dGFxp0hFYvWmUJnsN+og69hCUJAkfycFcOMGdMPIb4O4g6uQGL3LZOCGDUz86YMd85nfbSs2hz7R2HMkC7y9OxAvF5CJw/id8JQ240JE3HcmMl6u87Vi/tlRUEBtgTMcyaiem/ztJa6QH8BMqraO+q3zm3FvDQ/mUF6gdXoDvCrgOjj/avOw7HuH4mlh9U0nKg4/XaVxV4f32WNtkUEd9ho36K12C7HVPcJMx33dS9KjBnP4ylqQx3+iqaDrkw2pLA+w2Df9FJMpEFWUQcy6PxrtU0vVoHMcH3RJh8N1Gbb8L/y1W4Fv4Cr9OCoTPADHPvZ4KthpafreDqL8/CtGkY2jydF7fFYcmYQfvOR3EfvtIx585VmL7Yx1V7Jo2PHKV92jSMQ6yEhPg2ky8lEkLoMr4uNhNCjDkSIkIIXSREhBC6SIgIIXSREBFC6CIhIoTQRUJECKGLhIgQQhcJESGELhIiQghdJESEELpIiAghdJEQEULoIiEihNBFQkQIoYuEiBBCFwkRIYQu/wdo7vGkA+SANAAAAABJRU5ErkJggg==) ## Specific input validation[​](/docs/create-apps/user-input/input-validation/.md#specific-input-validation "Direct link to Specific input validation") Custom logic can be implemented in the application code to handle specific or more complex validation. This is achieved by means of raising a `UserError`, accompanied by the input violations: ``` import viktor as vkt def calculate_block_volume(params): block_width = params.width block_length = params.length block_height = params.height violations = [] if block_width is None: violations.append(vkt.InputViolation("Input 'width' cannot be empty!", fields=['width'])) if block_length is None: violations.append(vkt.InputViolation("Input 'length' cannot be empty!", fields=['length'])) if block_height is None: violations.append(vkt.InputViolation("Input 'height' cannot be empty!", fields=['height'])) if violations: raise vkt.UserError("Cannot calculate block volume", input_violations=violations) return block_width * block_length * block_height ``` A `UserError` can be raised on the following actions: * [action buttons](/docs/create-apps/user-input/action-buttons/.md) * [view calculations](/docs/create-apps/results-and-visualizations/.md) * next-button on a [Step](/docs/create-apps/layout-and-styling/steps/.md#validation-of-user-input) The message defined in the `UserError` functions as a generic message to the user, while the message in the `InputViolation` is shown on the field itself and can be more specific: ![](/assets/images/input-validation-usererror-c69ec122e6953b07bd999c7964b02186.png) Multiple fields can be passed to the `InputViolation` if the message holds for all of them: ``` violations.append(InputViolation("Input cannot be empty!", fields=['width', 'length', 'height'])) ``` ![](data:image/png;base64,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42bjhN6qHx4MjXvO4e1c2FnMlF+MvU1DJLuhR9GWb2dK7afchCyT7rPE5NT2x4gHfjzuNg2RrIYeRet7+TlCc653Y251nyUmxxh4cAPuj14gVHpNGyc3EY0L5VNxY50M7jyKubRCHx6RW1T69EEG37ZGtn6KyK3FsXEO7Sb51wVYozz+X25dGhvKxDntxL/dQCJ4H6HqbF/oEpEvMvf32+n5/g7cmvrhrZ8icmtJNTXQ83QnVsP3JrzbQW4N12UrlIiIiIiIfLFoxUJERERERDxTYiEiIiIiIp4psRAREREREc+UWIiIiIiIiGdKLERERERExDMlFiIiIiIi4pkSCxERERER8UyJhYiIiIiIeKbEQkREREREPFNiISIiIiIinimxEBERERERz5RYiIiIiIiIZ0osRERERETEMyUWIiIiIiLimRILERERERHxTImFiIiIiIh4psRCREREREQ8U2IhIiIiIiKeKbEQERERERHPlFiIiIiIiIhnSixERERERMQzJRYiIiIiIuKZEgsREREREfFMiYWIiIiIiHimxEJERERERDxTYiEiIiIiIp4psRAREREREc+UWIiIiIiIiGdKLERERERExDMlFiIiIiIi4pkSCxERERER8UyJhYiIiIiIeKbEQkREREREPFNiISIiIiIinimxEBERERERz5RYiIiIiIiIZ0osRERERETEs/8PizxgsdPJbRcAAAAASUVORK5CYII=) In case there are multiple issues with a field, multiple messages can be provided: ``` violations.append(vkt.InputViolation("Message A", fields=['field'])) violations.append(vkt.InputViolation("Message B", fields=['field'])) violations.append(vkt.InputViolation("Message C", fields=['field'])) ``` ![](data:image/png;base64,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) When you are using a nested parametrisation, you can refer to the field als follows: ``` violations.append(vkt.InputViolation("Message A", fields=['my_page_name.my_tab_name.field'])) ``` Invisible fields Be careful with marking fields invalid which have dynamic visibility. A user will not be able to fix an invisible field and might be stuck in the validation process! --- # LLM Chat New in v14.21.0 BETA This feature is currently in **BETA**, which means: * We reserve the right to make breaking changes without prior notice. * You might lose the chat's history when resetting to an old entity revision. If this happens, you can solve the associated error by clearing the chat's history. A `Chat` enables the user to have a conversation with an LLM from within the app editor. ![](/assets/images/chat-73edacc407999cf81f9358cca8e66cc3.png) ``` import viktor as vkt class Parametrization(vkt.Parametrization): chat = vkt.Chat("Chatbot", method="call_llm") class Controller(vkt.Controller): ... def call_llm(self, params, **kwargs): conversation = params.chat messages = conversation.get_messages() ... # here code is added to call the LLM return vkt.ChatResult(...) ``` The `Controller` accesses user messages by calling the `get_messages` method on the `ChatConversation` object obtained from `params.chat` [`get_messages`](/sdk/api/api-v1/.md#ChatConversation.get_messages) can be used to get the full history of the conversation, which returns a list of messages with format, where 'role' indicates who sent the message (user or assistant): ``` { 'role': str, # user | assistant 'content': str, # the actual message } ``` The current state of the conversation is sent to the LLM and retrieves its response, which is returned from the Chat method within a [`ChatResult`](/sdk/api/result/.md#_ChatResult). Before the controller can pass the retrieved conversation history to any LLM client, the application must have access to a valid **API key**. The following section will explain how this is done for the different providers ## API key configuration[​](/docs/create-apps/user-input/llm-chat/.md#api-key-configuration "Direct link to API key configuration") Integrating a Large Language Model (LLM) into a VIKTOR application requires an API key from the chosen LLM provider. This key must be securely stored and made accessible to the application using environment variables. ### Obtaining an API key[​](/docs/create-apps/user-input/llm-chat/.md#obtaining-an-api-key "Direct link to Obtaining an API key") API keys are obtained directly from the respective LLM provider. The table below provides links to pages where you can find or generate your key toeg: | Provider | API key link | Safety | | ---------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | **OpenAI (GPT)** | [API keys](https://platform.openai.com/api-keys) | [Safety tips](https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety) | | **Anthropic (Claude)** | [API keys](https://console.anthropic.com/settings/keys) | [Key safety](https://support.anthropic.com/en/articles/9767949-api-key-best-practices-keeping-your-keys-safe-and-secure) | | **Google (Gemini)** | [API keys](https://aistudio.google.com/app/apikey) | [Security](https://ai.google.dev/gemini-api/docs/api-key#security) | ### Setting API keys as environment variables[​](/docs/create-apps/user-input/llm-chat/.md#setting-api-keys-as-environment-variables "Direct link to Setting API keys as environment variables") You can set environment variables directly when running VIKTOR CLI commands using the `--env` or `-e` flag when running the `install`, `start` and `run` commands. For example, to start your app with a specific OpenAI API key: ``` viktor-cli start --env OPENAI_API_KEY="your-api-key" ``` Replace `"your-api-key"` with the actual API key you want to use for this session. The CLI will connect the local app code to your VIKTOR environment as usual, but with the addition that the environment variable has been set on the running Python process. ### Accessing API keys in application code:[​](/docs/create-apps/user-input/llm-chat/.md#accessing-api-keys-in-application-code "Direct link to Accessing API keys in application code:") Environment variables can be accessed within `app.py` or other relevant Python modules using the built-in `os` module in combination with the `os.getenv()` function. ``` # app.py import viktor as vkt import os # Example: Accessing OpenAI API Key OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") # OPENAI_API_KEY is now available for use with LLM clients if set in the environment class Parametrization(vkt.Parametrization): chat = vkt.Chat("Chatbot", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat messages = conversation.get_messages() ... # here code is added to call the LLM return vkt.ChatResult(...) ``` ## Calling the LLM from the controller[​](/docs/create-apps/user-input/llm-chat/.md#calling-the-llm-from-the-controller "Direct link to Calling the LLM from the controller") With the correct API key set up, we can connect the app with the actual LLM. A multi-turn chat workflow can be implemented for each of the main LLM providers as shown below. Each provider requires the installation of its corresponding Python client and may need specific handling of the chat history to meet its role formatting requirements (e.g., user, assistant). * Anthropic Client * OpenAI Client * Gemini Client To use the Anthropic client, you need to add the `anthropic` Python library to your `requirements.txt` file and install it for your app. ``` import os import viktor as vkt from anthropic import Anthropic # don't for get to add in requirements.txt and re-install client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY")) class Parametrization(vkt.Parametrization): chat = vkt.Chat("LLM Chat", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None response = client.messages.create( model="claude-3-5-sonnet-latest", max_tokens=1024, messages=conversation.get_messages(), system="You are a helpful assistant that responds using simple and formal British English." ) return vkt.ChatResult(conversation, response.content[0].text) ``` For streaming responses, the LLM client yields parts of the response as they are generated, rather than waiting for the complete response. This can improve perceived performance for the user. The `ChatResult` can accept an iterable of strings for streaming. ``` import os import viktor as vkt from anthropic import Anthropic # don't for get to add in requirements.txt and re-install class Parametrization(vkt.Parametrization): chat = vkt.Chat("LLM Chat", method="call_llm") client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY")) class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None llm_response_stream = client.messages.create( model="claude-3-5-sonnet-latest", max_tokens=1024, messages=conversation.get_messages(), system="You are a helpful assistant that responds using simple and formal British English.", stream=True, ) text_stream = map( lambda chunk: chunk.delta.text, filter( lambda chunk: chunk.type == "content_block_delta" and chunk.delta.text, llm_response_stream ) ) return vkt.ChatResult(conversation, text_stream) ``` To use the OpenAI client, you need to add the `openai` Python library to your `requirements.txt` file and install it for your app. Remark When using OpenAI's chat completion API, prepend a 'system' message to the history manually, as VIKTOR’s `ChatConversation` does not include the 'system' role by default. ``` import viktor as vkt import os from openai import OpenAI # don't for get to add in requirements.txt and re-install client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) class Parametrization(vkt.Parametrization): chat = vkt.Chat("LLM Chat", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None vkt_messages = conversation.get_messages() openai_messages = [ { "role": "system", "content": "You are a helpful assistant that responds with simple but formal British English.", } ] openai_messages.extend(vkt_messages) completion = client.chat.completions.create( model="gpt-4.1", messages=openai_messages ) return vkt.ChatResult(params.chat, completion.choices[0].message.content) ``` For streaming responses, the LLM client yields parts of the response as they are generated, rather than waiting for the complete response. This can improve perceived performance for the user. The `ChatResult` can accept an iterable of strings for streaming. ``` import viktor as vkt import os from openai import OpenAI # don't for get to add in requirements.txt and re-install client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) class Parametrization(vkt.Parametrization): chat = vkt.Chat("LLM Chat", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None vkt_messages = conversation.get_messages() openai_messages = [ { "role": "system", "content": "You are a helpful assistant that responds with simple but formal British English.", } ] openai_messages.extend(vkt_messages) stream = client.chat.completions.create( model="gpt-4.1", messages=openai_messages, stream=True, ) # Stream text from the event chunks text_stream = ( chunk.choices[0].delta.content for chunk in stream if chunk.choices[0].delta.content is not None ) return vkt.ChatResult(params.chat, text_stream) ``` To use the Gemini client, you need to add the `google-genai` Python library to your `requirements.txt` file and install it for your app. Remark Google's Gemini client handles multi-turn conversations using specific types like `UserContent`, `ModelContent`, and `Part`. You'll need to convert the VIKTOR message format (`{'role': str, 'content': str}`) into this structure for the chat history. ``` import os import viktor as vkt from google import genai # don't for get to add in requirements.txt and re-install from google.genai import types client = genai.Client(api_key=os.getenv("GEMINI_API_KEY")) def viktor_messages_to_genai(messages): history = [] for msg in messages: role = msg.get("role") text = msg.get("content", "") if role == "user": history.append(types.UserContent(parts=[types.Part(text=text)])) elif role == "assistant": history.append(types.ModelContent(parts=[types.Part(text=text)])) return history class Parametrization(vkt.Parametrization): chat = vkt.Chat("Chatbot", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None messages = conversation.get_messages() history_msgs = messages[:-1] user_msg = messages[-1] history = viktor_messages_to_genai(history_msgs) system_instruction = "You are a helpful assistant that responds with simple but formal British English" chat_session = client.chats.create( config=types.GenerateContentConfig( system_instruction=system_instruction, temperature=0.5, ), model="gemini-2.0-flash", history=history ) response = chat_session.send_message(user_msg["content"]) return vkt.ChatResult(params.chat, response.text) ``` For streaming responses, the LLM client yields parts of the response as they are generated, rather than waiting for the complete response. This can improve perceived performance for the user. The `ChatResult` can accept an iterable of strings for streaming. ``` import os import viktor as vkt from google import genai # don't for get to add in requirements.txt and re-install from google.genai import types client = genai.Client(api_key=os.getenv("GEMINI_API_KEY")) def viktor_messages_to_genai(messages): history = [] for msg in messages: role = msg.get("role") text = msg.get("content", "") if role == "user": history.append(types.UserContent(parts=[types.Part(text=text)])) elif role == "assistant": history.append(types.ModelContent(parts=[types.Part(text=text)])) return history class Parametrization(vkt.Parametrization): chat = vkt.Chat("Chatbot", method="call_llm") class Controller(vkt.Controller): parametrization = Parametrization def call_llm(self, params, **kwargs): conversation = params.chat if not conversation: return None messages = conversation.get_messages() history_msgs = messages[:-1] user_msg = messages[-1] history = viktor_messages_to_genai(history_msgs) system_instruction = "You are a helpful assistant that responds with simple but formal British English" chat_session = client.chats.create( config=types.GenerateContentConfig( system_instruction=system_instruction, temperature=0.5, ), model="gemini-2.0-flash", history=history ) chunk_iter = chat_session.send_message_stream(user_msg["content"]) text_stream = (chunk.text for chunk in chunk_iter) return vkt.ChatResult(params.chat, text_stream) ``` ## Publishing an app[​](/docs/create-apps/user-input/llm-chat/.md#publishing-an-app "Direct link to Publishing an app") For published applications, API keys can be set, updated, or removed from the **'Apps'** section in your VIKTOR environment. Once configured, these environment variables are securely stored and available in the application’s code during runtime. This replaces the use of `.env` files or passing keys through the VIKTOR CLI for deployed apps. Detailed guidance is available in the [VIKTOR environment variables documentation](https://docs.viktor.ai/docs/create-apps/development-tools-and-tips/environment-variables/). ## More info[​](/docs/create-apps/user-input/llm-chat/.md#more-info "Direct link to More info") The technical API reference, can be found here: [`Chat`](/sdk/api/parametrization/.md#_Chat) Expand to see all available arguments In alphabetical order: * **first\_message** (optional): the first message that will appear on top of the empty conversation ``` chat = vkt.Chat(..., first_message="How can I help you?") ``` * **flex** (optional): the width of the field between 0 and 100 (default=33) ``` chat = vkt.Chat(..., flex=50) ``` * **method** (required): the controller method that will be triggered when the user clicks the "send" button ``` chat = vkt.Chat(..., method='call_llm') ``` * **placeholder** (optional): placeholder message in the user prompt ``` chat = vkt.Chat(..., placeholder="Ask anything") ``` * **visible** (optional): can be used when the visibility depends on other input fields ``` chat = vkt.Chat(..., visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Limitations[​](/docs/create-apps/user-input/llm-chat/.md#limitations "Direct link to Limitations") note The VIKTOR SDK currently supports only the **'user'** and **'assistant'** roles for messages within the `ChatConversation`. For other roles (e.g., 'system', 'tool'), additional processing may be required depending on the specific LLM client being used. note The maximum response size in the [`ChatResult`](/sdk/api/result/.md#_ChatResult) is 75000 characters. --- # Map features The geo-fields, enable the user to define geo-objects on a [`MapView`](/docs/create-apps/results-and-visualizations/map/.md#mapview) / [`GeoJSONView`](/docs/create-apps/results-and-visualizations/map/.md#geojsonview). Reference For a more technical API reference, please see the following pages: * [`GeoPointField`](/sdk/api/parametrization/.md#_GeoPointField) * [`GeoPolygonField`](/sdk/api/parametrization/.md#_GeoPolygonField) * [`GeoPolylineField`](/sdk/api/parametrization/.md#_GeoPolylineField) ## GeoPointField - draw a point[​](/docs/create-apps/user-input/map-features/.md#geopointfield---draw-a-point "Direct link to GeoPointField - draw a point") The `GeoPointField` enables the user to draw a point on the map. It should be used in combination with a `MapView` or `GeoJSONView`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): geo_point = vkt.GeoPointField('Draw a point') ``` ![](/assets/images/geopointfield-da6f4fd062c334530f1aa80c5f122f5c.svg) The user input can be obtained through the **params** argument and can have the following values: * `GeoPoint` object: when a point is drawn (see [link geo-fields to a view](/docs/create-apps/results-and-visualizations/map/.md#linking-geo-fields-to-the-view) for an example of usage) * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` geo_point = vkt.GeoPointField('Draw a point', default=vkt.GeoPoint(lat=51.9225, lon=4.4719)) ``` * **description**: add a tooltip with additional information ``` geo_point = vkt.GeoPointField('Draw a point', description="This field represents the ...") ``` * **name**: defines the position of the parameter in the *params* ``` geo_point = vkt.GeoPointField('Draw a point', name="g") # obtained using params.g ``` * **visible**: can be used when the visibility depends on other input fields ``` geo_point = vkt.GeoPointField('Draw a point', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## GeoPolylineField - draw a (poly)line[​](/docs/create-apps/user-input/map-features/.md#geopolylinefield---draw-a-polyline "Direct link to GeoPolylineField - draw a (poly)line") The `GeoPolylineField` enables the user to draw a polyline on the map. It should be used in combination with a `MapView` or `GeoJSONView`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): geo_polyline = vkt.GeoPolylineField('Draw a polyline') ``` ![](/assets/images/geopolylinefield-966ca2d5eda12142232d16939fb7321c.svg) The user input can be obtained through the **params** argument and can have the following values: * `GeoPolyline` object: when a point is drawn (see [link geo-fields to a view](/docs/create-apps/results-and-visualizations/map/.md#linking-geo-fields-to-the-view) for an example of usage) * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` geo_polyline = vkt.GeoPolylineField( 'Draw a polyline', default=vkt.GeoPolyline( vkt.GeoPoint(lat=51.9225, lon=4.4719), vkt.GeoPoint(lat=52.3600, lon=4.8853), ) ) ``` * **description**: add a tooltip with additional information ``` geo_polyline = vkt.GeoPolylineField('Draw a polyline', description="This field represents the ...") ``` * **name**: defines the position of the parameter in the *params* ``` geo_polyline = vkt.GeoPolylineField('Draw a polyline', name="g") # obtained using params.g ``` * **visible**: can be used when the visibility depends on other input fields ``` geo_polyline = vkt.GeoPolylineField('Draw a polyline', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## GeoPolygonField - draw a polygon[​](/docs/create-apps/user-input/map-features/.md#geopolygonfield---draw-a-polygon "Direct link to GeoPolygonField - draw a polygon") The `GeoPolygonField` enables the user to draw a polygon on the map. It should be used in combination with a `MapView` or `GeoJSONView`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): geo_polygon = vkt.GeoPolygonField('Draw a polygon') ``` ![](/assets/images/geopolygonfield-f3ce137f0b77b118dbd948909756d4a9.svg) The user input can be obtained through the **params** argument and can have the following values: * `GeoPolygon` object: when a point is drawn (see [link geo-fields to a view](/docs/create-apps/results-and-visualizations/map/.md#linking-geo-fields-to-the-view) for an example of usage) * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` geo_polygon = vkt.GeoPolygonField( 'Draw a polygon', default=default=vkt.GeoPolygon( vkt.GeoPoint(lat=51.9225, lon=4.4719), vkt.GeoPoint(lat=52.3600, lon=4.8853), vkt.GeoPoint(lat=52.0908, lon=5.1216), ) ) ``` * **description**: add a tooltip with additional information ``` geo_polygon = vkt.GeoPolygonField('Draw a polygon', description="This field represents the ...") ``` * **name**: defines the position of the parameter in the *params* ``` geo_polygon = vkt.GeoPolygonField('Draw a polygon', name="g") # obtained using params.g ``` * **visible**: can be used when the visibility depends on other input fields ``` geo_polygon = vkt.GeoPolygonField('Draw a polygon', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## Visualize geo-objects on the map[​](/docs/create-apps/user-input/map-features/.md#visualize-geo-objects-on-the-map "Direct link to Visualize geo-objects on the map") The above geo-fields let the user 'draw' geo-objects, but does not actually visualize it on the map. If visualizing the geo-objects on the map is desired, this can easily be achieved by making use of the class-method on the corresponding map feature as described [here](/docs/create-apps/results-and-visualizations/map/.md#linking-geo-fields-to-the-view). ## Interact with geo-objects on the map[​](/docs/create-apps/user-input/map-features/.md#interact-with-geo-objects-on-the-map "Direct link to Interact with geo-objects on the map") In addition to visualizing geo-objects, it is also possible to let the user [interact](/docs/create-apps/results-and-visualizations/map/.md#interaction-with-map-selecting-objects) with the geo-objects on the map. --- # Numeric input Reference For a more technical API reference, please see the following pages: * [`IntegerField`](/sdk/api/parametrization/.md#_IntegerField) * [`NumberField`](/sdk/api/parametrization/.md#_NumberField) ## NumberField - decimal numbers[​](/docs/create-apps/user-input/numeric-input/.md#numberfield---decimal-numbers "Direct link to NumberField - decimal numbers") A `NumberField` is a generic numeric field that can contain numbers with decimals. It can be visualized as numerical input or slider variant: ``` import viktor as vkt class Parametrization(vkt.Parametrization): number = vkt.NumberField('Insert a Number here') slider = vkt.NumberField('Adjust the Number', min=0, max=8, variant='slider') ``` ![](data:image/png;base64,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) ![](data:image/png;base64,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) The user input can be obtained through the **params** argument and can have the following values: * `float`: when user inputs a decimal number (e.g. 1.5) * `int`: when user inputs a whole number (e.g. 1) * `None`: when empty (not applicable to the slider variant) Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` number = vkt.NumberField('Insert a Number here', default=7.5) ``` * **description**: add a tooltip with additional information ``` number = vkt.NumberField('Insert a Number here', description="This number represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` number = vkt.NumberField('Insert a Number here', flex=50) ``` * **max**: when the user enters a value higher than the maximum boundary, the field is [marked as invalid](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary) ``` number = vkt.NumberField('Insert a Number here', max=10) ``` See ['Setting min/max'](/docs/create-apps/user-input/numeric-input/.md#setting-minmax) for more information on setting a dynamic boundary. * **min**: when the user enters a value lower than the minimum boundary, the field is [marked as invalid](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary) ``` number = vkt.NumberField('Insert a Number here', min=0) ``` See ['Setting min/max'](/docs/create-apps/user-input/numeric-input/.md#setting-minmax) for more information on setting a dynamic boundary. * **name**: defines the position of the parameter in the *params* ``` number = vkt.NumberField('Insert a Number here', name="n") # obtained using params.n ``` * **num\_decimals**: defines the number of decimals shown in the interface ``` number = vkt.NumberField('Insert a Number here', num_decimals=2) ``` * **prefix**: a prefix will be put in front of the ui name ``` number = vkt.NumberField('Insert a Number here', prefix="€") ``` * **step**: stepping interval when clicking the increment / decrement buttons ``` number = vkt.NumberField('Insert a Number here', step=0.5) ``` * **suffix**: a suffix will be placed behind the ui name ``` number = vkt.NumberField('Insert a Number here', suffix="mm") ``` * **variant**: the field can be shown as slider, in this case specifying a `min` and `max` is required ``` number = vkt.NumberField('Adjust the Number', min=0, max=8, variant='slider') ``` ![](data:image/png;base64,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) note The variants are ignored within a [`Table`](/docs/create-apps/user-input/tables-and-arrays/.md#table) * **visible**: can be used when the visibility depends on other input fields ``` number = vkt.NumberField('Insert a Number here', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## IntegerField - whole numbers[​](/docs/create-apps/user-input/numeric-input/.md#integerfield---whole-numbers "Direct link to IntegerField - whole numbers") An `IntegerField` is a numeric field that can contain integers only. ``` import viktor as vkt class Parametrization(vkt.Parametrization): integer = vkt.IntegerField('Input an Integer') ``` ![](data:image/png;base64,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OlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3LmdpbXAub3JnL3htcC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1wTU06RG9jdW1lbnRJRD0iZ2ltcDpkb2NpZDpnaW1wOjNhZGYxZjQ4LTg3MGMtNDI4Zi1hNTg0LTNlZWM1Y2UzMmNkYyIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpiMjJlZTVkNS02NjRmLTQ3YjItOGM0NS1mOWVlODU2MmYwNWQiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpkYjU2MDA3OC0xOTYyLTQ2ODAtOWRmZi1lYTdjM2VkYWQ5ZjIiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICBHSU1QOkFQST0iMi4wIgogICBHSU1QOlBsYXRmb3JtPSJMaW51eCIKICAgR0lNUDpUaW1lU3RhbXA9IjE2NjE4NjE4MDIyNTYwNTQiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zMiIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjI6MDg6MzBUMTQ6MTY6NDIrMDI6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDIyOjA4OjMwVDE0OjE2OjQyKzAyOjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZWZiYzZhZWUtNGRiMy00NjMxLWFjM2QtMzAyMjc1YTU4NDk1IgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKExpbnV4KSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMi0wOC0zMFQxNDoxNjo0MiswMjowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz4Vw5OpAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5ggeDBAqFBwbsQAAC0NJREFUeNrt3V9MW2UDx/Gfr7gWYkYZvGWMUWZHkC0ZJbxZSqMm3Zzuj1EmN8ZwMWMaEnVLNDHc6MUSr/RiMWHeNLtwMY0XipoZx+LcqGMEugRCmSEMAaGMDci6FobAGGbvhekZh8L+OWbZvp9kyXL+9HnO6Tk/nuc5f/rEzZs3bwoAVoD/sAsAEFgAQGABILAAgMACAAILAIEFAAQWABBYAAgsACCwAIDAAkBgAQCBBQAEFgACCwAILAAgsAAQWABAYAEAgQWAwAIAAgsACCwABBYAEFgAQGABILAAgMACQGABAIEFAAQWHjOT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) The user input can be obtained through the **params** argument and can have the following values: * `int`: when user inputs a number (e.g. 1) * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` integer = vkt.IntegerField('Input an Integer here', default=7.5) ``` * **description**: add a tooltip with additional information ``` integer = vkt.IntegerField('Input an Integer here', description="This number represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` integer = vkt.IntegerField('Input an Integer here', flex=50) ``` * **max**: when the user enters a value higher than the maximum boundary, the field is [marked as invalid](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary) ``` integer = vkt.IntegerField('Input an Integer here', max=10) ``` See ['Setting min/max'](/docs/create-apps/user-input/numeric-input/.md#setting-minmax) for more information on setting a dynamic boundary. * **min**: when the user enters a value lower than the minimum boundary, the field is [marked as invalid](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary) ``` integer = vkt.IntegerField('Input an Integer here', min=0) ``` See ['Setting min/max'](/docs/create-apps/user-input/numeric-input/.md#setting-minmax) for more information on setting a dynamic boundary. * **name**: defines the position of the parameter in the *params* ``` integer = vkt.IntegerField('Input an Integer here', name="i") # obtained using params.i ``` * **prefix**: a prefix will be put in front of the ui name ``` integer = vkt.IntegerField('Input an Integer here', prefix="€") ``` * **step**: stepping interval when clicking the increment / decrement buttons ``` integer = vkt.IntegerField('Input an Integer here', step=3) ``` * **suffix**: a suffix will be placed behind the ui name ``` integer = vkt.IntegerField('Input an Integer here', suffix="mm") ``` * **visible**: can be used when the visibility depends on other input fields ``` integer = vkt.IntegerField('Input an Integer here', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## Setting min/max[​](/docs/create-apps/user-input/numeric-input/.md#setting-minmax "Direct link to Setting min/max") The min and max value of the field can be set using the `min` and `max` arguments respectively: ``` vkt.NumberField('X', min=0, max=10) # also on IntegerField ``` When the user enters a value that exceeds these bounds, the fields are [marked as invalid](/docs/create-apps/user-input/input-validation/.md#numeric-minmax-boundary). If the value for min or max needs to be calculated 'dynamically', one of the below methods can be used. ### Depending on another field[​](/docs/create-apps/user-input/numeric-input/.md#depending-on-another-field "Direct link to Depending on another field") If the constraint depends on another numeric field, the easiest solution is to use a `Lookup`: ``` import viktor as vkt class Parametrization(vkt.Parametrization): param_x = vkt.NumberField('X') param_y = vkt.NumberField('Y', min=vkt.Lookup('param_x')) ``` In case of a nested parametrization structure, the dotted path should be used: ``` vkt.Lookup('tab.section.param_x') ``` When the target field cannot be found, a warning is logged in your terminal and **the constraint is ignored**. ### Inside a DynamicArray[​](/docs/create-apps/user-input/numeric-input/.md#inside-a-dynamicarray "Direct link to Inside a DynamicArray") If the value for min or max depends on the result of another numeric field within a `DynamicArray`, a `RowLookup` can be used. Using the `RowLookup`, a field of a specific row within the array can be made dependent of another field **within the same row**: ``` import viktor as vkt class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.NumberField('X') array.param_y = vkt.NumberField('Y', min=vkt.RowLookup('param_x')) ``` ### Using a function[​](/docs/create-apps/user-input/numeric-input/.md#using-a-function "Direct link to Using a function") The most generic way to dynamically set the min/max value is to use a **callback function**. Upon evaluation of the min or max constraint, the platform passes the `params`, `entity_id`, `entity_name`, and `workspace_id` (>= v14.7.1) to the custom function: ``` import viktor as vkt def param_y_min(params, **kwargs): return params.param_x class Parametrization(vkt.Parametrization): param_x = vkt.NumberField('X') param_y = vkt.NumberField('Y', min=param_y_min) ``` For constraints that have to be applied to fields within a `DynamicArray`, make sure that the callback function returns a list of the constraint values, one for each row in the array. The length of this list must be equal to the number of rows in the array, otherwise (a warning is logged and) the constraint is ignored: ``` import viktor as vkt def param_y_min(params, **kwargs): return [row.param_x for row in params.array] class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.param_x = vkt.NumberField('X') array.param_y = vkt.NumberField('Y', min=param_y_min) ``` tip All individual `kwargs` can be added explicitly in the signature if needed: ``` def param_y_min(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` When the value for min/max depends on data from another entity, the `entity_id` can be used to navigate and obtain data using the [SDK API](/docs/api/sdk/handling-entity-data/.md). --- # Options & selections Reference For a more technical API reference, please see the following pages: * [`AutocompleteField`](/sdk/api/parametrization/.md#_AutocompleteField) * [`MultiSelectField`](/sdk/api/parametrization/.md#_MultiSelectField) * [`OptionField`](/sdk/api/parametrization/.md#_OptionField) ## OptionField - single option[​](/docs/create-apps/user-input/options-and-selections/.md#optionfield---single-option "Direct link to OptionField - single option") To present a dropdown list with options to select from, an `OptionField` can be used. ``` import viktor as vkt fruits = ['Avocado', 'Banana', 'Coconut'] class Parametrization(vkt.Parametrization): option = vkt.OptionField('Pick your favorite fruit', options=fruits) radio_v = vkt.OptionField('Pick your favorite fruit', options=fruits, variant='radio') radio_h = vkt.OptionField('Pick your favorite fruit', options=fruits, variant='radio-inline') ``` ![](/assets/images/optionfield-77b9894a62eaa38ba7e0a14265abad69.png) ![](data:image/png;base64,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) ![](data:image/png;base64,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) The user input can be obtained through the **params** argument and can have the following values: * `int` / `float` / `str`: when user selects an option * `None`: when empty Expand to see all available arguments In alphabetical order: * **autoselect\_single\_option**: (default=False) automatically select when only a single option is available, relevant in case of [dynamic options](/docs/create-apps/user-input/options-and-selections/.md#dynamic-options) ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, autoselect_single_option=True) ``` * **default**: a default value will be prefilled ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, default="Coconut") ``` * **description**: add a tooltip with additional information ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, description="This input represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, name="o") # obtained using params.o ``` * **options**: available options a user can select from can be defined as list of strings ``` option = vkt.OptionField('Pick your favorite fruit', options=['Avocado', 'Banana', 'Coconut']) ``` ..or as list of numbers ``` option = vkt.OptionField('...', options=[1, 2, 3]) ``` ..or as list of `OptionListElement` objects ``` option = vkt.OptionField( 'Pick your favorite fruit', options=[ OptionListElement(value=1, label="Avocado"), # when selected, params.option will be 1 OptionListElement(value=2, label="Banana"), OptionListElement(value=3, label="Coconut"), ] ) ``` * **prefix**: a prefix will be put in front of the ui name ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, prefix="..") ``` * **suffix**: a suffix will be placed behind the ui name ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, suffix="..") ``` * **variant**: the field can be shown as radio buttons ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, variant='radio') ``` ![](data:image/png;base64,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) ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, variant='radio-inline') ``` ![](data:image/png;base64,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) note The variants are ignored within a [`Table`](/docs/create-apps/user-input/tables-and-arrays/.md#table) * **visible**: can be used when the visibility depends on other input fields ``` option = vkt.OptionField('Pick your favorite fruit', options=fruits, visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Autocomplete[​](/docs/create-apps/user-input/options-and-selections/.md#autocomplete "Direct link to Autocomplete") If there are many options, it might be desirable for the user to filter options by typing. This is possible using the `AutocompleteField`. ``` import viktor as vkt fruits = ['Avocado', 'Banana', 'Coconut'] class Parametrization(vkt.Parametrization): option = vkt.AutocompleteField('Pick your favorite fruit (type to filter)', options=fruits) ``` Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, default="Coconut" ) ``` * **description**: add a tooltip with additional information ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, description="This input represents the ..." ) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, flex=50 ) ``` * **name**: defines the position of the parameter in the *params* ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, name="o" ) # obtained using params.o ``` * **options**: available options a user can select from can be defined as list of strings ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=['Avocado', 'Banana', 'Coconut'] ) ``` ..or as list of numbers ``` option = vkt.AutocompleteField('...', options=[1, 2, 3]) ``` ..or as list of `OptionListElement` objects ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=[ OptionListElement(value=1, label="Avocado"), # when selected, params.option will be 1 OptionListElement(value=2, label="Banana"), OptionListElement(value=3, label="Coconut"), ] ) ``` * **prefix**: a prefix will be put in front of the ui name ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, prefix=".." ) ``` * **suffix**: a suffix will be placed behind the ui name ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, suffix=".." ) ``` * **visible**: can be used when the visibility depends on other input fields ``` option = vkt.AutocompleteField( 'Pick your favorite fruit (type to filter)', options=fruits, visible=vkt.Lookup("another_field") ) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Selecting an entity[​](/docs/create-apps/user-input/options-and-selections/.md#selecting-an-entity "Direct link to Selecting an entity") In case you need to create an option field with entities as options, you can make use of dedicated [entity selection fields](/docs/create-apps/user-input/entity-selection/.md). ## MultiSelectField - multiple options[​](/docs/create-apps/user-input/options-and-selections/.md#multiselectfield---multiple-options "Direct link to MultiSelectField - multiple options") If multiple options need to be selectable, a `MultiSelectField` can be used. ``` import viktor as vkt fruits = ['Avocado', 'Banana', 'Coconut'] class Parametrization(vkt.Parametrization): options = vkt.MultiSelectField('Pick your favorite fruit(s)', options=fruits) ``` The user input can be obtained through the **params** argument and can have the following values: * `list`: when user selects one or multiple options * empty list when nothing is selected Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, default=["Avocado", "Coconut"] ) ``` * **description**: add a tooltip with additional information ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, description="This input represents the ..." ) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, flex=50 ) ``` * **name**: defines the position of the parameter in the *params* ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, name="o" ) # obtained using params.o ``` * **options**: available options a user can select from can be defined as list of strings ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=['Avocado', 'Banana', 'Coconut'] ) ``` ..or as list of numbers ``` options = vkt.MultiSelectField('...', options=[1, 2, 3]) ``` ..or as list of `OptionListElement` objects ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=[ OptionListElement(value=1, label="Avocado"), # when selected, params.options will be [1] OptionListElement(value=2, label="Banana"), OptionListElement(value=3, label="Coconut"), ] ) ``` * **prefix**: a prefix will be put in front of the ui name ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, prefix=".." ) ``` * **suffix**: a suffix will be placed behind the ui name ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, suffix=".." ) ``` * **visible**: can be used when the visibility depends on other input fields ``` options = vkt.MultiSelectField( 'Pick your favorite fruit(s)', options=fruits, visible=vkt.Lookup("another_field") ) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Selecting entities[​](/docs/create-apps/user-input/options-and-selections/.md#selecting-entities "Direct link to Selecting entities") In case you need to create an option field with entities as options, you can make use of dedicated [entity selection fields](/docs/create-apps/user-input/entity-selection/.md). ## Dynamic options[​](/docs/create-apps/user-input/options-and-selections/.md#dynamic-options "Direct link to Dynamic options") Sometimes it is desired to create options dynamically (depending on other parameters). This can be achieved in several ways: * [Dynamically setting options using a callback function](/docs/create-apps/user-input/options-and-selections/.md#using-a-function) * [Setting the visibility of the `OptionListElement`](/docs/create-apps/user-input/options-and-selections/.md#optionlistelement-visibility) ### Using a function[​](/docs/create-apps/user-input/options-and-selections/.md#using-a-function "Direct link to Using a function") The most generic way to dynamically set the options is to use a 'callback function'. Upon evaluation of the options, the platform passes the `params`, `entity_id`, `entity_name`, and `workspace_id` (>= v14.7.1) to the custom function. For example, material options can be set based on a pre-selected material type as follows: ``` import viktor as vkt def get_material_options(params, **kwargs): if params.material_group == 'Aluminium': return ['Aluminium 5083', 'Aluminium 6082'] elif params.material_group == 'Steel': return ['Steel S355', 'Steel S690'] else: return [] class Parametrization(vkt.Parametrization): material_group = vkt.OptionField('Material group', options=['Aluminium', 'Steel']) material_type = vkt.OptionField('Material', options=get_material_options) ``` ![](data:image/png;base64,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) tip All individual `kwargs` can be added explicitly in the signature if needed: ``` def get_material_options(params, entity_id, entity_name, workspace_id, **kwargs): ... ``` With a callback function it is also possible to make use of the `entity_id` to navigate to and obtain data from other entities [using the API](/docs/api/sdk/handling-entity-data/.md). ### OptionListElement visibility[​](/docs/create-apps/user-input/options-and-selections/.md#optionlistelement-visibility "Direct link to OptionListElement visibility") The same dynamic options as above can be achieved by making use of the `visible` argument on an `OptionListElement`. By using the `IsEqual` and `Lookup` operators, we can make use of the visibility to hide/show options, similar as [hiding/showing fields](/docs/create-apps/user-input/hide-field/.md): ``` import viktor as vkt material_options = [ vkt.OptionListElement('Aluminium 5083', visible=vkt.IsEqual(vkt.Lookup('material_group'), 'Aluminium')), vkt.OptionListElement('Aluminium 6082', visible=vkt.IsEqual(vkt.Lookup('material_group'), 'Aluminium')), vkt.OptionListElement('Steel S355', visible=vkt.IsEqual(vkt.Lookup('material_group'), 'Steel')), vkt.OptionListElement('Steel S690', visible=vkt.IsEqual(vkt.Lookup('material_group'), 'Steel')) ] class Parametrization(vkt.Parametrization): material_group = vkt.OptionField('Material group', options=['Aluminium', 'Steel']) material_type = vkt.OptionField('Material', options=material_options) ``` ### Inside a DynamicArray[​](/docs/create-apps/user-input/options-and-selections/.md#inside-a-dynamicarray "Direct link to Inside a DynamicArray") New in v14.8.0 If the options should be filled depending on another field within a DynamicArray, a callback function can be used to return a **list of lists**. Each sublist represents the options of the corresponding array row. Make sure that the length of the list is equal to the number of rows in the array: ``` import viktor as vkt def get_material_options(params, **kwargs): options = [] for row in params.array: if row['material_group'] == 'Aluminium': options.append(['Aluminium 5083', 'Aluminium 6082']) elif row['material_group'] == 'Steel': options.append(['Steel S355', 'Steel S690']) return options class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.material_group = vkt.OptionField('Material group', options=['Aluminium', 'Steel']) array.material_type = vkt.OptionField('Material', options=get_material_options) ``` --- # Other fields Reference For a more technical API reference, please see the following pages: * [`BooleanField`](/sdk/api/parametrization/.md#_BooleanField) * [`ColorField`](/sdk/api/parametrization/.md#_ColorField) * [`DateField`](/sdk/api/parametrization/.md#_DateField) * [`HiddenField`](/sdk/api/parametrization/.md#_HiddenField) ## BooleanField - toggle true / false[​](/docs/create-apps/user-input/other-fields/.md#booleanfield---toggle-true--false "Direct link to BooleanField - toggle true / false") The `BooleanField` acts as a toggle button which can be either `True` or `False`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): is_true = vkt.BooleanField('False / True') ``` ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAScAAAB7CAYAAAA2YUZ5AAAJMnpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHja5Zhdlty6DYTfuYosgQQJglwOwZ9zsoMsPx/VPRPP2Dcnvn5Myy1p1BIJogqFksP+1z9P+AcfqaWGotZqrzXyKb10GZy0+PqMZ59iefbPR+x9lr5eD+bvh4RLmWN+/dnq65g+rr8f+DimwZn+MFCb7x/86w+9vMdv3waS1yHfiO75eg/U3wNlef2Q3gOM17Ji7c1+XILv1/H9/CsNfMPdlfY17J/+NrK3lHmyyM4pR/Y5yyuAfL8S8uCksc/53phy4fy1l9zfg5GQX+Xp88N94dxQyy9v+oLK59k3tOo7BeE7WkXet+RvSa6fx19eD0m//ZA/55cfZy7tfSZfr5Pj/oroW/bv95zVzrNmVjFKJdX1vaiPJT5n3AcLy526BUKr0fgqQ9izdbYGqydUWHFGZ5upJwGuk0paaaST9nOcaRJikR3EOBGZkp+LLZt0mfmFH1s6YrnnBbKS5wN7yfIZS3qm7XGGZ7bGzCtxqyQGS5cXv7uF333gnFsKKd1c1vHkirhEbrIJ4yJ399wGIum8k6pPgj+275+LawZBvVkOD3wj+msI1/QfJcgP0JkbleOrBpOt9wCkiKmVYFIGAVBLWVNN0UQsJRLZAGgQuuQiDgJJVRZBSsm5gk2TOzWPWHpuFRUuB64jZiChuWYDm54HYJWi8MdKg0NDsxZVrWratOuoGUnUWqvVK4rDspVgatXMmnUbLbfStNVmrbXeRpeeEU3ttVtvvfcxmHMw8uDpwQ1juHj24hq8unnz7mNCn1mmzjptttnnWLLyQj9WXbba6mvstKHSLlt33bbb7nscqHZyOOXoqcdOO/2MT9TesP60/QZq6Y2aPEjdG+0TNa6afQyRrpzoxQzAJJQE4nYhgNByMYstlSIXuYtZ7EJVqBCkXsxWuoiBYNlJ9KQP7IK8EL3I/RFuwcoX3OTvIhcudL+J3M+4/Qq1dTV4Poi9qvAmNWaqj3uGNP7Rq34+hr/64XeP//tAJKWvQ2SLYruoJhxDr1RuUaQstDWnrePXMLgXgKGl9TUxF5MEjzav1h0STPJOyh2wlh+wkfhADBwr6woLrRqAXMniQubTrFuT0zRmpj13Jis0yMwUtoGoZRoDOUcb2vS5t8ZcxvGgClW7lH6mDF2yT9kjMTQVXXmowukd02zb22SUmfZdrayVtBND1z0PDAop7X6qp9J63cvT2krJ7F1nteg0llUMNu5js4yoQ1uGLjV32btIKz5lSWwnpD5P9AUv4Po8jsswOE05KEHcKqjulmttO3J1xnf/0rkpgZ5n3IVFnKBEW0e+BL99qM4Rm+7SqBjyNV2S7rjvJDHvftPVKZbocLRK71bLbgseBtS0s05hHEagsd4e1inDM0frptXzhRQYjZpMRNYHaZijV4o/kd2W5o5KF1EI6yJx2Vhrn73GjN0MljRc5a6jFESA8PsEAjLhZhDEdCxKxXuuK60VCM9FC11youcLBYI5ec9ryWrTpM1GPq0N4gcukQ6iybpwtyclnh7Luf6oEJiVuXQvxCKyjhsxtIQnBk0ZUEHcoZDp9qsEcW4Epy1nOOzFWPAwjNuACCXCEsitf7fcwkApINA2u3oyvLY2kY5RNsiT3ZlM5xVVaDfTWHemmKFezujHGCwzCgQPsjZYtsHdfWUwcidm7mVJ89A71ZXSG9oPZUTahdRBwFwqFdrPtR3nKiRVsfBBCO+W4uU4deETdsKNRIkktZNThWy7xjMr/maPEnftB4fUHfYp3FmBguqVNBWZJe2MsndyX/f13XDVKhR6VhMfwDBXe59B6JE8tLatA1R0/FF3EgGImqkVE+g7V9FIBRruwXdrLnQCp6J9LizFLgVhzp3S8FQJnu6geMiqPBOnp+15+GwnuQxebugSiRl5tcCGTttZYUe9g6xM/aET1vHo1yFSihd+YGcGKcR1tqofxic0ipBsUPn0G9RnEqxOWhxxweaTcYvbmtzSub40zMIKR1ksB+FfFW9J0zp3y6K9U6qHPpSNNrDpUWPDEAi3DSlEZ+g/ewnJprSqOJp3Dt2uqs7T6znST2cNSFxl5ZsiQ2Jt1JurOY9QQidPRm1tWeLmMDNVzUvbJpOvtLGsG5Bib/HY5Ky7ERhZVadW69VvWRNJ3c617pG0Of4okyz8G8jdkkJebuCKO77ZuOXU4CzqQY4WvPSGRdalMhpdXdMlLpYu3PczvR3lT46WTxhudIMCMAgxC2grl0m76QSJAC10dNCG3ekSFzxkD9XoYERxUPuY074POYpZYXFBxmTOS59d0Mjti+ExMW3zWrCHFpoQViHOyVrqSOUYQxplcnmIu0IhM7qv5zTGbbjX67FdTnm6KkXp18aZUWY+Ufe9cT3mlRbnt55JLlo9I+8iK6LXBqJorcscdrsinEMwDu2VoCr04e90TcnpaeOcERkC6Xey9kwWPmZDj4xXn4oBoo/2uqhqfM6htum5hgt1rQj34gXICpmF8eu2SYxgIwXhoNl7VJR02VWRsopkCvtQTLxWrYWSLCxRRYYJOMc9fOOBFDebKBOtHZXnXQTTZMZj23nT63tiC3PphkXElG2CmJ0A6c+4wOp3KRvfhVSSRqqZzkvTiNkDrTEfrIGSIKoDswZwclgoTZuxkoqC1iPNGL7/otl/5rEu9SqOYAa85MHr0NqTLshWplSEQKdpAqHLslIQf5CKRIneJ1oTXdqo21Hr8EzVlBoMLpDuc5u7jIXFsEGinX7rOSc6FZnu4E7ZYUFrxuBjgzFwCPERuW4VUvO6Pmjvjj8ekwbc1tmICA1P4tmtUOwPV+KYFa6SIvJ9uXQIFNrgHBr0bjLCefwqcUBr8p3nVe7crltGQuYzDBys5UrHRYKMZ9LBOBg12he6tGFNcJ6DPpjjTdOaHg/PwB3cRF8+EM4tNAkM4OAF+i4E50UHFMM98DZIVWAtlwSXvXBLtAzYgHriFyq6pKeUdvDXp5CGBmvQa7xppe3T16hx55NvvHLfvjyIYt8zUteSWMHcQFAW4iiro+JUOQlFZlBHY7f9yiEyryOtlm9Foew0Sphtk74TqX5gPFQvr6heLku8VXv+9wBdgdy4NswyrtDKL/gZ/tzz/78PBL70zvBvrrs5T5VOvEIAAAGFaUNDUElDQyBwcm9maWxlAAB4nH2RPUjDQBzFX1ulRVoc7CAikqGKgwVREUetQhEqhFqhVQeTS7+gSUOS4uIouBYc/FisOrg46+rgKgiCHyCOTk6KLlLi/5JCixgPjvvx7t7j7h3gb1SYanaNA6pmGelkQsjmVoXgK0IYQhgRjErM1OdEMQXP8XUPH1/v4jzL+9yfI6LkTQb4BOJZphsW8Qbx9Kalc94njrKSpBCfE48ZdEHiR67LLr9xLjrs55lRI5OeJ44SC8UOljuYlQyVeIo4pqga5fuzLiuctzirlRpr3ZO/MJzXVpa5TnMQSSxiCSIEyKihjAosxGnVSDGRpv2Eh3/A8YvkkslVBiPHAqpQITl+8D/43a1ZmJxwk8IJoPvFtj+GgeAu0Kzb9vexbTdPgMAzcKW1/dUGMPNJer2txY6A3m3g4rqtyXvA5Q7Q/6RLhuRIAZr+QgF4P6NvygF9t0DPmttbax+nD0CGukrdAAeHwEiRstc93h3q7O3fM63+fgBwtnKmMcJ+8gAADXhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6N2E2MDEwOTQtMjAxMC00YWNhLThjNDQtODA2Y2U4NDJiN2NjIgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmVhM2EzYjM1LTdjZTMtNGRmZS04ODc4LWFiZTBkZjIwMDc0NSIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmFlOTI0YmVjLTRjMTAtNDFhOS1hOTFhLTE3ZmMyODE0ZTcxOCIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IkxpbnV4IgogICBHSU1QOlRpbWVTdGFtcD0iMTY2MTg2MTY2OTY3OTc0NSIKICAgR0lNUDpWZXJzaW9uPSIyLjEwLjMyIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAgMi4xMCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMjowODozMFQxNDoxNDoyOSswMjowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjI6MDg6MzBUMTQ6MTQ6MjkrMDI6MDAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2OTZjMjlkZC00OTIwLTRjOTEtYjEwMS1lNjgwZDk1ZDhkNDYiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoTGludXgpIgogICAgICBzdEV2dDp3aGVuPSIyMDIyLTA4LTMwVDE0OjE0OjI5KzAyOjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PoD2zsoAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgA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) The user input can be obtained through the **params** argument and can have the following values: * `True`: when toggled true * `False`: when toggled false Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` is_true = vkt.BooleanField('False / True', default=True) ``` * **description**: add a tooltip with additional information ``` is_true = vkt.BooleanField('False / True', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` is_true = vkt.BooleanField('False / True', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` is_true = vkt.BooleanField('False / True', name="b") # obtained using params.b ``` * **visible**: can be used when the visibility depends on other input fields ``` is_true = vkt.BooleanField('False / True', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## ColorField - select a color[​](/docs/create-apps/user-input/other-fields/.md#colorfield---select-a-color "Direct link to ColorField - select a color") New in v14.0.0 The `ColorField` enables a user to select a color from a color palette. ``` import viktor as vkt class Parametrization(vkt.Parametrization): color = vkt.ColorField('Pick a color') ``` ![](/assets/images/colorfield-8a9cef03845389cc64871c4f75f57007.png) The user input can be obtained through the **params** argument and can have the following values: * [`Color`](/sdk/api/core/.md#_Color) object: when user selects a color * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` color = vkt.ColorField('Pick a color', default=vkt.Color.red()) ``` * **description**: add a tooltip with additional information ``` color = vkt.ColorField('Pick a color', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` color = vkt.ColorField('Pick a color', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` color = vkt.ColorField('Pick a color', name="c") # obtained using params.c ``` * **visible**: can be used when the visibility depends on other input fields ``` color = vkt.ColorField('Pick a color', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## DateField - select a date[​](/docs/create-apps/user-input/other-fields/.md#datefield---select-a-date "Direct link to DateField - select a date") The `DateField` enables a user to select a date on a calendar. ``` import viktor as vkt class Parametrization(vkt.Parametrization): date = vkt.DateField('Pick a date') ``` ![](/assets/images/datefield-b4121de4959ee60c53e55fe4de1e42ab.svg) The user input can be obtained through the **params** argument and can have the following values: * [`datetime.date`](https://docs.python.org/3/library/datetime.html#date-objects) object: when user selects a data * `None`: when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` date = vkt.DateField('Pick a date', default=datetime.date(2021, 3, 14)) ``` * **description**: add a tooltip with additional information ``` date = vkt.DateField('Pick a date', description="This field represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` date = vkt.DateField('Pick a date', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` date = vkt.DateField('Pick a date', name="d") # obtained using params.d ``` * **visible**: can be used when the visibility depends on other input fields ``` date = vkt.DateField('Pick a date', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## HiddenField - store JSON data[​](/docs/create-apps/user-input/other-fields/.md#hiddenfield---store-json-data "Direct link to HiddenField - store JSON data") The purpose of the `HiddenField` is to store JSON-type data in the `params`, without showing this information to the user in the editor. For example, when doing [upload file processing](/docs/create-apps/managing-files/uploading-files/.md#file-processing). ``` import viktor as vkt class Parametrization(vkt.Parametrization): json_data = vkt.HiddenField('') ``` caution Use the `HiddenField` with moderation. Prefer to store specific type of data on its corresponding field (e.g. number on a `NumberField`), if necessary with `visible=False` to hide if from the user. Also, prevent storing very large amounts of data if not necessary, as this might make your application slow and unstable! The input can be obtained through the **params** argument and can have the following values: * `json`: when data is stored * `None`: when empty Expand to see all available arguments In alphabetical order: * **name**: defines the position of the parameter in the *params* ``` json_data = vkt.HiddenField('', name="h") # obtained using params.h ``` --- # Read-only fields ![](/img/docs/cards/outputfield.png) ## [Show output](/docs/create-apps/inform-end-user/output-field/.md) Show a (dynamic) value using an OutputField ![](/img/docs/cards/static-text.svg) ## [Static text](/docs/create-apps/inform-end-user/text-blocks/.md) Show a static text using Text ![](/img/docs/cards/static-image.svg) ## [Static image](/docs/create-apps/inform-end-user/static-image/.md) Show a static image using Image --- # Set params using a button A [set params action](/docs/create-apps/user-input/action-buttons/.md#set-params-action) enables the user to click a button to directly set some or all values on the `params`. ## Example use case[​](/docs/create-apps/user-input/set-params-using-button/.md#example-use-case "Direct link to Example use case") One can filter entries in a table. For example in the ground layers, one could filter out all layers that are thinner than some threshold, while also allowing the user to reset the table to the start. ## Implementation[​](/docs/create-apps/user-input/set-params-using-button/.md#implementation "Direct link to Implementation") 1. Add a [`SetParamsButton`](/sdk/api/parametrization/.md#_SetParamsButton) in the parametrization class 2. Implement the button method on the corresponding controller class Adding a button in the parametrization: ``` import viktor as vkt class Parametrization(vkt.Parametrization): set_params = vkt.SetParamsButton('Set params to some fixed value', method='set_params') clear_params = vkt.SetParamsButton('Reset params', method='clear_params') ``` Implementing the method on the controller: The first example would be how to set parameters, the second example is how you can clear a parameter. * You do not need to specify every parameter, if you do not specify a parameter it will not be altered. * If you on the other hand specify a parameter that has no associated field in the input specification, it will be ignored. ``` import viktor as vkt class Controller(vkt.Controller): def set_params(self, params, **kwargs): return vkt.SetParamsResult({ "number": 12.3, "integer": 12, "text": "abcd", "textarea": "defg", "date": datetime.date(2054, 1, 23), "bool": True, "select": "Green", "autocomp": "Green", "multiselect": ["Red", "Green"], "table": [{"c1": 123, "c2": 123}, {"c1": 321, "c2": 123}], "geopoint": vkt.GeoPoint(...), "geopolyline": vkt.GeoPolyline(...), "geopolygon": vkt.GeoPolygon(...), "entity": vkt.api_v1.API().get_entity(...), "color": vkt.Color(...), # (>= v14.0.0) }) def clear_params(self, params, **kwargs): return vkt.SetParamsResult({ "number": None, "integer": None, "text": "", "textarea": "", "date": None, "bool": False, "select": None, "autocomp": None, "multiselect": [], "table": [], "geopoint": None, "geopolyline": None, "geopolygon": None, "entity": None, "color": None, }) ``` In case of a nested parametrization structure, the return value is a nested dictionary: ``` vkt.SetParamsResult({ "tab": { "section": { "number": None, ... } } }) ``` --- # Tables & arrays Both a `Table` and a `DynamicArray` can be used if the user must be able to make a dynamic number of objects sharing the same properties. The similarities and differences between the two are discussed below. ![](/assets/images/editor-table-array-5680e2d6870a0463cd05e9b2bd1f7d0d.png) *Table (top) and DynamicArray (bottom)* Reference For a more technical API reference, please see the following pages: * [`Table`](/sdk/api/parametrization/.md#_Table) * [`DynamicArray`](/sdk/api/parametrization/.md#_DynamicArray) ## Table[​](/docs/create-apps/user-input/tables-and-arrays/.md#table "Direct link to Table") Set up a `Table` and add fields using the dot-notation as follows: ``` import viktor as vkt class Parametrization(vkt.Parametrization): table = vkt.Table('Table') table.col_1 = vkt.TextField('TextField as table column') ``` Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` table = vkt.Table('Table', default=[{'col1': 'A', 'col2': 'B'}, {'col1': 'C', 'col2': 'D'}]) ``` * **description**: add a tooltip with additional information ``` table = vkt.Table('Table', description="This input represents the ...") ``` * **name**: defines the position of the parameter in the *params* ``` table = vkt.Table('Table', name="t") # obtained using params.t ``` * **visible**: can be used when the visibility depends on other input fields ``` table = vkt.Table('Table', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. Let's assume a user has entered two rows of data in the table as shown in the figure below. ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAw4AAACuCAYAAACftlo+AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AABjiSURBVHic7d17dFXlva/xxxrXopYEhICXUGKDWDFYEqkmqITskoQWgrtErFxaBd0iaBW0JXgDtgg9BY6WqJVLsaD1Ah4KFoEOS2w1UE1oN8QKxg2FNmg0kACaoMOVpub8AQgiOCVXhOczBgPIfC+/d+JI5tf5zrlOqaurq0OSJEmSPsdXWroASZIkScc/g4MkSZKkQAYHSZIkSYEMDpIkSZICGRwkSZIkBTI4SJIkSQpkcJAkSZIUyOAgSZIkKZDBQZIkSVIgg4MkSZKkQAYHSZIkSYEaFBxW3NSTDh26H/nXuTfz2w8+v/9f7utHpx8u5f2jHN8+fzidMuexuSFFSpIkSWqwqIZ0zrx/OX/+aQSAHU+PY+iLKSx8bCidAaJiiP9aI1QoSZIkqcU1KDiEO8Zxfsd9f27VPgzhDnTumsD5jVGZJEmSpONGkz/jsPPFhxiZmc55nbpz3mXDuXPpNiKHNvighF/fdjU9z+vJeRdfzbhnDjt+WNuncodz+Td70inxSoZOy2d7bVOvQJIkSVLTBoeSeQy5YSXh6/P447oXWDamA6vvmMhj/zjYJFK4mr+dfysLn3+SOdd2YPVd43ig+EiDVbIidwwPvtOH+55bzh/nDqXN7yYwbn5Zky5BkiRJUlMHh3MGkPf7X5M3tAedz4njoqFDyWzzJn974+A9hfAVNzH9x2lc1K0bGePu4Y7kMlb+7rXPjrVlKY++0IU7HhxFRrc4zr9iKHePuoB1K1azvUkXIUmSJKlBzzgEahNLm5cfZvT41azbUkkE+KgKsv99SJtwmPAnf4njW92jKd3+NhF6fGqoyOY3+NsHRfzt0p5MOPhVIh0vZEctdG7alUiSJEkntaa93P7rwwwdX0TGQ7OZ1TeBNhRx56U3897ndPnoaM8s/Btol8H058bT+9CqwzGcaWiQJEmSmlSTXnJvLiyitOsAbuiXQBuASISPDn/yORI55GHoMja/WU18UqdD7kLsE05I4PwP8tkZiaNz1086E4mEP9NWkiRJUuNq0mcczvxGHG02LuXRZ4t4/a/5PHrbNJbsjBD5qOaTNpG1c5nwSAGvl5SQP2saD26IY/BVPT47WPeruCG1gl/eOomniraxfUsRT912Nd+ZWnT0tzBJkiRJahRNesehzYB7ySuewOSJN/BkVAKZPxrBzQOeYUtVBRC9r02/HK7Y/DAj/m8J77frweAZs7i5+5FGi2P43Dl8NHEGD157JRP+Hcu3+o1g1u0p3nGQJEmSmtgpdXV1dS1dhCRJkqTjW5N/AJwkSZKkLz+DgyRJkqRABgdJkiRJger9cHRpaWlj1iFJkiSpmcTHxx9znwa9VenMM89qSPcG21mxi1bhUIvWIEmSJDW3Vq3qfw28Z8+eevVzq5IkSZKkQAYHSZIkSYEMDpIkSZICGRwkSZIkBTI4SJIkSQpkcJAkSZJOIMuXL2+ScQ0OkiRJ0gniQGhoivBgcJAkSZJOAIeHhcYODwYHSZIk6UvuaCGhMcODwaHJ7aXg/iH06nsnS98JaFpbyMQ+6SR+bzbFtZ89vG3ejSQnZjFuVU2TVHpsyln4o3QSk+9kZdURDm+czcAe6fS6t6DZKip74haSE9MZs2xvs80pSZJ0PLjyyiuP+quxRDXaSMed3Tx9Yw7TXjny0dClY1ix4Bri6jFy1cZVLFq7m7j0HzDgghBsmc/gwU9ScvjF/gU/ZMniawm3bU9sbDui6//J4M2knIInVvDmqd3JGZ5KbEuXI0mSpOPGCRwcWnNhv2sYcQFQ+y5FSwooIZ7MwanERUEorjvR9Ry5+rWVzH54E6mx/RlwQbuDBzpfzLCMrhzIB6EO3ekQFaLbrb/k+VsbuJzmUPtP1jz+JE+HBnHpNanEnsD/dUiSJOnYnMBblUIkDR7D+J+MYfxP+tPtdOD0RHJ+su9rY4ckEkMN21blMeb72SQnZ5E1bBIL1+8Fynl6dBaJPa4j77UaKF/FmMvTSRyYx+onbiH7Z5uoAQom55A1ff3BGeMzuPUnB+Ycw9hrU4llLyvHZpGYfCMLt+1rV7VxGRNHDqHXJVn0+t4tTFy2hSNuPqotZ/X0W8jqlUWv793BnPXVR24H8N56Ft51I1mXp5PcK4fhdy2m+MAWog+3sHTyLfuOXZLNwFtms3r74XMVMq3fnTxdDmxfxvBL7mBpZcC4ALzLivtvpM8lWfQaeAd5r+w+SoFHO9dHsL2AmbdcR59L0knucx1jHi6k8sDdnPJC5o2/kaxeWSRfPoTr719FyYdHGKN8Gdcnp5N84zIqAWoLyL0kncSr5lNSC8UPDCGxxxDGPTCD67+XRXKvHK5/oICCRVMZ3DeL5F5DGPPweqoA8ieRnJjO8Mnzyb0mZ1/9o+cfdh4kSZJObCdwcAhW9cosRt+1jEK6M2xEBp12FDDz9hmsfu8sho37Ad2+UsqiR57l6UfmU7C3NQN+fAN90n/E+EFnAdBt8FjGDzj3k/FqSguYmzebvLzZ5OXNZ+nGI1zmV+Yz9ZY8lm6OpveQQfQ+o5Sl/z2Rmes+27ZsyQwmPbGJ6nNSyUlvR1lJ+VFWspuVkycxc9UuugwZy9i+0byxfDa5s/eFmpJfTWTic6V0+UEuU29NhVcWkzt5MWWHDhF1Pjm515DSFoi9mFH3/ZCUmM8fd/+i2VrdlexBFxNbvp55d81i9REuqI9+rg9rWLuFvNsnsXBdhAsHXcPg86spmDOJic+VQ+0W5t0xibw/7KJT1iCGpYQpWTSD0ffnU69r+Npyil7ZS7eMDJJDuyn69STGLtpLypUZJJ9eTsGvZ7N028HmxS8VEb40k+zuIcrWPMlDzx/t30OSJOnEcxJvRtlL0bJ8yjiLEXffy9ikEBVnlJI9vZDVRTVk9hvC+JxVXL9oPtOAmMvGMrZfa0Kk0qdbe2YuK6fDRX3I7N4OtuwfcnshC+cVfjJDWuch5HT/9KyV+atYXQlJY3OZOiIeSmDbtYt5OX8j91x8aMvdFL20nqqoeMb+fAqjusK2NlsY+PC7R1hLiITBucwadDYp6V2JKYeClXls+HsplVxM1Qc1QAi+2o6EjJuZc+kgqmhPh0+N0Y5ufZPpMmMxRaF4+vS/mLiovVQdddxz9k+dyuif55LTFtJOzeH6J9ZT8FoNmWccy7k+5OGPTfnk/x1iB44j7+5UQu8l0npaPmUf7oJNBTy/qYaY/uOYc18aIfrTYdh1zMzPJ39CBinH8s8PQGsybp3C+HQori1k+BM1ZI+bwvj0EMUfFTL86XfZeki66jY0l/tHd4V11RTcuIq3S98BzjrmWSVJkhpLcXHxF26blJTUoLlO6uBQVl4DteUsHJnNwkOOVO7ZC7Qj5cpMEpYsZlttiJSBmYEPUod65/LynP7EHDbPoSp2vEMNUJx3I8l5h/St3E0NrQ9pWU1lFRCKJ+7AxF8JceTnq1sTF7OLpfN+w0PT3qXywxo+OuQGRsqoXMbumMWCX97J4DyI6ZrKyLvvpVvAeoLGPSC8/75Vp7PPJsQmqvfUwGHBIehcf2LPLiprIe7M9vvW2jaNsTPT9h17adm+Y/Fn7z8PZxMXF4KSXVRWBC7myE7d/3tUCKJqIBQ6+Pfawxd74FiYMBCp55SSJElfRidxcGhNhw4hiGpHzn9P5KqE/V/+N8R0bgfsZuXjK9lWC6FQDS8/tYiS/v9FtwaesZjY9oQop8u1U7j3u+0/mZPYeEJsPKRle2LPCEHtLireA07/nEFr1vPwT/N4mjTumX4vfUJrmPij+WwAYC9l26HHddN54f4w29YuY+a0xeT97Df0XjLm89fzueMeFPl43+8VFbuooTXRMYfHm6BzfYgz2hMbBRWVu6ihK6EPt7BySREVnXsz4sCxt9/dd4x3KSurgahoYjscNuWBddXW7LvA//h4eIWtJEnSl9dJHRx6D8og7sVVrJj3GK2+eyGtd29g5fqzGb8gkU7rfsOcF/cS2y+Xe+MXkzvvWR5aks3sIWcRHb3vfUxv/O5R8qJ/xNiEgKkOEdd3AH3mbWL1c4+xkN58I6qcdflbSLrvlySd8+n60v6jOzEvrefpKbMJZZzGuue3UHOkew61e3n/Q4Bd/KO4kIotL1PyMfsvmmsofnIquX9qzYDb/4vMaAgDofBphD8zUDStTwfefpWFeZ0ZOqz954y7X00hc+7J462EXaxZUg6xaaQlheDtL36uP3X6EjPIOG8x81bNIvf0PnTY/jJLXtpN8oQMRlyRwcDEZeStnMXo8Ca6VRWydBPEZvUnre1hdwBizqZLOyjauIyZD1QTtz2f1Ud6iFqSJElfyEn9cHRM73HMmXENqadvZsnCJ1m0DlKuHkRK2y0snLWSbaGujPxxfzJH3kD2WTUUPDaf1e9BTPoPGHFZO6o2FpBfvOvYJj2rP1Pm5jKse4QNS55k4fKNhHtfQ3b31p9pGvv9XKZcmwivLWbm3A1EX9D1yFuVTk9j7KRBpLQrZcns37COeJLaQk3lbipq2zFg0nTGfzea4rlTGfezlVRcOIiJU68l4fDYGJXI4Osz6Hb6bl5eXkRZ3eeNe2A9qfQ5YyNLFxVQFnsxo6aOI7PtMZzrwz8sIqorY38xhRE9w2xYspglb4bpM3oKM4adBVFdGfXgFEalRbN1+WKefiVCt++PZc7EjM9+5kQolRG5/UmK2c3Li56j6NTzSfaDKSRJkurtlLq6urr6dCwtLeXMM1v2wdCdFbtoFT7uP1VNkiRJalStWu27Bq7Pw9F79uwhPj7+mOc8qe84SJIkSfpiDA6SJEmSAhkcJEmSJAUyOEiSJEkKZHCQJEmSFMjgIEmSJCmQwUGSJElSIIODJEmSpEAGB0mSJEmBDA6SJEmSAhkcJEmSJAWKakjniopdjVVHvVx2ef8WnV+SJElqCW9sLGj2ORsUHL7+9XMaq456K95Y3NIlSJIkSc0mqXtSi8zrViVJkiRJgQwOkiRJkgIZHCRJkiQFMjhIkiRJCmRwkCRJkhTI4CBJkiQpkMFBkiRJUiCDgyRJkqRABgdJ0hdURsGvF1JYXv8RKl/PZ8G0mxk2/CFKahuvMklS02uR4PCvvZVsff01/rS+nH+1RAGSpGNXu5WCx56h4O36dS+YlM6gCc+w9d232bqnho8atzpJUhNrgeBQy5533+fUNq049V8fN//0knTSq2bDExMYltaTHsnpDLt7KVsj+44UTkone8JDzLi+HykX9qT39yfw263A/85j5BW38/8qy3hqdC9GztsGtSXM6t+LYT8eR05qT0b+ahlT03ox/vfVn8zzh3G9yJhWBEDq7c+zZtVjTL26G6EWWbckqSFaIDhE0bFrF85t/1X3SUlSC6hcMoHbFsGI37zCa3/Mo0/ZTMY/WrL/aIStr24j7vYlrPnrcsadW8Ss2fnUfHMUC9b+gqtj4xg+51UWjErY376anVEpTPv9KywY2Z+MvmEKXyigCuDDIlYXxpDVNwWA0BnRLbBaSVJj8dpdkk4qZTy/rIgLrxtPVnwYzujByGFpVLy8hq0AhInrN5LhF0UTOj2OzCu6UPPW21QcdbxokgcOpdsZYYgKk9ovk3DhagqroOYvBRSenkbmt5trbZKkphTV0gVIkppRbSUV70YouC+dHvcd8vWzhlKx/2HlVp/qED628b+dTVbMaFb/uZKYVwto03c6yf6kkaQTgt/OJelkEhVNm3bRZN3+B/IGfnbrUGGDx+9BZt8Ybnt+LuE3w6TNSGnoiJKk44RblSTppJJARv8E1s+dyR+2RoAIZS8+xIynSqgJ7NuGULiKiopq+JxXqSb3z6TNS8/wPGlkJjVe5ZKkltVyweFrnbki5RxOa7ECJOnk1OX6PGZ+t4o5115Gj+R0bnqikgu/nRD8pqOoC8i8OoHC3HRy5pQcvV23AWQkwNf7ZrtNSZJOIKfU1dXV1adjaWkp8fHxjV3PMenUOYnijcUtWoMk6XDbWHDNGCrGv0CuD0ZLUqNL6p7EGxsLACgu/uLXwklJ+24D79mzp17X8W5VkiQ1nkg1W5fN5beRAQx0m5IknVAMDpKkRlLNip9kMWx2NVdNvolublOSpBOK39YlSY0kmuxHXiW7pcuQJDUJ7zhIkiRJCuQdB0mSJOk4l9S95R8c846DJEmSpEAGB0mSJEmBDA6SJEmSAjXoGYcdOysbq456Ox72e0mSJEknugYFhzM7xjZWHfXyP3/Nb/EaJEmSpOZWVVXV7HO6VUmSJElSIIODJEmSpEAGB0mSJEmBDA6SJEmSAhkcJEmSJAUyOEiSJEkKZHCQJEmSFMjgIEmSJCmQwUGS9AWVkT9nIWveqV/vyD9WMnnIlSSe25NO3+xHzl0r2Rxp3AolSU2nBYLDx+z95ybWrt3A2jUbWP/Wh81fgiTp2NVuJX/2M+S/VZ++JTxw/VT+knQPf/r7/7A1fzyd/zyJcb/a1uhlSpKaRvMHh39V8mZpiMTLk7ki9Ww+3lrGnrpmr0KSTmLV/GX+BPpf3JNO56XT/46ln/yf/zW56Vx+20NMHtKP8zr1JDFzAk9tAUrmkdPjdp7cWcZj1/Yi55FtUFvCz9J60f+GcXwnsSc5jyzjzot7MXp59SfzrLipFz0nFsHubVSdeRV3jEmhYxSEv57B8D6xlG5+u6VOgiTpGDV/cDitHRelduGMU4A64LQoTjul2auQpJPWzmcmMOIJuPm3r/D2ujwy35rJ6F+U7D8aYfPabXS+cwmb/nc5dycU8bNZ+US6jWLpa7/ghx3juOGJV1n644T97avZEZVC3ppXWDq6PwP6hVmzsoD3AT4oYsXaGLL7pUDHAfx80U/JaLO/W+021m6IcGn6hc2+fklS/bTAVqUowuGvALXsLHmXr5wbR+vmL0KSTlJlLHm2iG/dOJ7sb4ShXQ9uHpHGjhfXsBmAMJ0HjOSGpGjCX4sjO70LkdK32XHU8aK5JGcoF7ULQ1SY3gMyabV2NWveh0hhAWu+lkZ26uF9qlkzfQJPtr2J+66MbbqlSpIaVVTLTPsxe/9RwuZT40mJC7VMCZJ0MqqtZEdZhPy70ul01yFfP2coO2r3/bHVpzqEj2381Gyy24xmxcuVtFlbQNt+07nkUz9pIrz+yGjGrU1h1lND6dxCP4UkSceuRb5l/2vnVl6vbM/F327HaS1RgCSdrKKiads+muw7/8CCnOjPHF7T4PF7kN0vhhFL59LqjTAZD6cccjDC5gW3M+J3FzL9qZ/Su11DJ5MkNafm36pUt5s3XtvJhzUVvL7uNYqKSvhndXA3SVJjSGDAfyaw7uGZrNgSASJsf+EhJi8oIfjNqG0Ih6vYsaMaao/e6pL/zKRt/jMsIY3snge/vv3ZCYx8Ipb7Hr+HjI4NX4kkqXk1/x2HU9rRI/PyZp9WkrTP+aPzmPPBVCYPvozRH4SIT87kjikJwZuSoi4ge1gCI25L5ztbnuSPY4/SrvsABnRdyMorsg9uU6rN58G789n8UZjRl6082DacwvQ1jzLcICFJx71T6urq6vUy1NLSUuLj4xu7nmOyY2clZ3b0wTpJOr5s49HsMeyY+AL3pQS3liQdu6qqKgCKi4u/cJ+kpCQA9uzZU6/reD85WpLUeCLVbH52Lk9FBjC4Z3BzSdKXh8FBktRIqvntzVn0n1XN8P9zExf5xiRJOqH4bV2S1EiiueqxV7mqpcuQJDUJ7zhIkiRJCmRwkCRJkhTI4CBJkiQpkMFBkiRJUiCDgyRJkqRADXqr0va33mmsOupl9573iERqWrQGSZIkqbm1bdO62edsUHDo2KF9Y9Xxpa5BkiRJak41NZFmn9OtSpIkSZICGRwkSZIkBTI4SJIkSQpkcJAkSZIUyOAgSZIkKZDBQZIkSVIgg4MkSZKkQAYHSZIkSYEMDpIkSZICGRwkSZIkBTI4SJIkSQpkcJAkSZIUyOAgSZIkKZDBQZIkSVIgg4MkSZKkQAYHSZIkSYEMDpIkSZICGRwkSZIkBTI4SJIkSQpkcJAkSZIUyOAgSZIkKZDBQZIkSVIgg4MkSZKkQAYHSZIkSYEMDpIkSZICRbV0AZIkSZLqJykpqdnmalBweL+qurHqqJe9H3xAOBxq0RokSZKk5vbVVs1/Ddyg4HBmx9jGquNLXYMkSZLUnKqqqpp9Tp9xkCRJkhTI4CBJkiQpkMFBkiRJUiDfqiRJkiR9yV133XVHPfb44483yhzecZAkSZK+5I4WDhorNIDBQZIkSTohHB4SGjM0gMFBkiRJOmEcCAuNHRrA4CBJkiSdUJoiNIDBQZIkSdIXYHCQJEmSFMjgIEmSJCmQwUGSJElSIIODJEmSpEAN+uTo0tLSxqqjATV80NIlSJIkSSe8U+rq6upaughJkiRJxze3KkmSJEkKZHCQJEmSFMjgIEmSJCmQwUGSJElSIIODJEmSpEAGB0mSJEmBDA6SJEmSAhkcJEmSJAUyOEiSJEkKZHCQJEmSFMjgIEmSJCmQwUGSJElSIIODJEmSpED/H7ntQ5uP5GzPAAAAAElFTkSuQmCC) The data entered in the table is available as a list of dictionaries in your app code and can be accessed using `params.table`. The resulting data has the following format: `[{"col_1": "entry1"}, {"col_1": "entry2"}]`. ## DynamicArray[​](/docs/create-apps/user-input/tables-and-arrays/.md#dynamicarray "Direct link to DynamicArray") Set up a `DynamicArray` and add fields using the dot-notation as follows: ``` import viktor as vkt class Parametrization(vkt.Parametrization): array = vkt.DynamicArray('Array') array.col_1 = vkt.TextField('TextField as array field') ``` Expand to see all available arguments In alphabetical order: * **copylast**: copy the last row when clicking the + button (takes precedence over field defaults) ``` array = vkt.DynamicArray('Array', copylast=True) ``` * **default**: a default value will be prefilled ``` array = vkt.DynamicArray('Array', default=[{'col1': 'A', 'col2': 'B'}, {'col1': 'C', 'col2': 'D'}]) ``` * **description**: add a tooltip with additional information ``` array = vkt.DynamicArray('Array', description="This input represents the ...") ``` * **max**: maximum number of rows in the array ``` array = vkt.DynamicArray('Array', max=30) ``` * **min**: minimum number of rows in the array ``` array = vkt.DynamicArray('Array', min=3) ``` * **name**: defines the position of the parameter in the *params* New in v14.18.0 ``` array = vkt.DynamicArray('Array', name="a") # obtained using params.a ``` * **row\_label**: label to be shown at each row (max. 30 characters) ``` array = vkt.DynamicArray('Array', row_label="Item") ``` * **visible**: can be used when the visibility depends on other input fields ``` array = vkt.DynamicArray('Array', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. Let's consider the same example as above, but now the user has entered the data in the array. ![](/assets/images/dynamic-array-params-example-1538adeb70c814c54f30f8d6578c4eb2.png) Again, the data entered in the table is available as a list of dictionaries in your app code and can be accessed using `params.array`. The resulting data has the following format: `[{"col_1": "entry1"}, {"col_1": "entry2"}]`. ## Differences Table vs. DynamicArray[​](/docs/create-apps/user-input/tables-and-arrays/.md#differences-table-vs-dynamicarray "Direct link to Differences Table vs. DynamicArray") In addition to visual difference, there are more practical differences between the input fields which may determine the best solution for your use-case. The following comparison can be made: | Table | DynamicArray | | ------------------------------------------------------- | ------------------------------------------------------------- | | Compact | Less compact | | Rectangular | Not necessarily rectangular | | Defaults when adding a new row **is not** supported | Defaults when adding a new row **is** supported | | Options in OptionField **cannot** make use of a `label` | Options in OptionField **can** make use of a `label` | | Supports copy-paste of complete table content | Supports copy-paste per input field only | | User can create rows | User can create rows | | User **cannot** create columns | User **cannot** create fields, but may use dynamic visibility | Furthermore, not all regular fields can be used in both of these multi-row fields. The table below shows which fields are supported in the `Table` and `DynamicArray` | Field | Table | DynamicArray | | ----------------------------- | ----- | ---------------- | | Text | ❌ | ❌ | | TextField | ✅ | ✅ | | TextAreaField | ❌ | ✅ | | NumberField | ✅ | ✅ | | IntegerField | ✅ | ✅ | | BooleanField | ✅ | ✅ | | DateField | ❌ | ✅ | | OutputField | ❌ | ✅ (>= v14.20.0) | | HiddenField | ❌ | ❌ | | LineBreak | ❌ | ✅ | | OptionField | ✅ | ✅ | | MultiSelectField | ❌ | ✅ | | AutocompleteField | ✅ | ✅ | | EntityOptionField | ❌ | ✅ | | ChildEntityOptionField | ❌ | ✅ | | SiblingEntityOptionField | ❌ | ✅ | | EntityMultiSelectField | ❌ | ✅ | | ChildEntityMultiSelectField | ❌ | ✅ | | SiblingEntityMultiSelectField | ❌ | ✅ | | FileField | ❌ | ✅ | | MultiFileField | ❌ | ✅ | | GeoPointField | ❌ | ✅ | | GeoPolylineField | ❌ | ✅ | | GeoPolygonField | ❌ | ✅ | | ColorField | ❌ | ✅ (>= v14.0.0) | | ActionButton | ❌ | ❌ | | DownloadButton | ❌ | ❌ | | OptimizationButton | ❌ | ❌ | | SetParamsButton | ❌ | ❌ | In the comparison, rectangular means that each row in the `Table` contains the same columns visually as well as in the parameter set. Rows in a `DynamicArray` on the other hand could contain different input fields, by [hiding](/docs/create-apps/user-input/hide-field/.md) certain fields when, for example, the user triggers a toggle. ``` import viktor as vkt class Parametrization(vkt.Parametrization): field = vkt.TextField('This is an example field') # table table = vkt.Table('Table') table.col_1 = vkt.TextField('TextField as table column') table.col_2 = vkt.BooleanField('BooleanField') table.col_3 = vkt.NumberField('NumberField') # visible not supported # dynamic array array = vkt.DynamicArray('Array') array.col_1 = vkt.TextField('TextField as array field') array.col_2 = vkt.BooleanField('BooleanField') array.col_3 = vkt.NumberField('NumberField', visible=vkt.RowLookup('col_2')) ``` In this example, a `DynamicArray` row in which the toggle (`col_2`) is active will also show the NumberField (`col_3`). In a `Table` `col_3` is always visible. ![](/assets/images/editor-table-array2-166018ede00e1d2b8ae6c1cf9d01c48a.png) *Visibility of columns/fields* --- # Textual input Reference For a more technical API reference, please see the following pages: * [`Text`](/sdk/api/parametrization/.md#_Text) * [`TextAreaField`](/sdk/api/parametrization/.md#_TextAreaField) * [`TextField`](/sdk/api/parametrization/.md#_TextField) ## TextField - short texts[​](/docs/create-apps/user-input/textual-input/.md#textfield---short-texts "Direct link to TextField - short texts") A `TextField` is a simple textual input field. ``` import viktor as vkt class Parametrization(vkt.Parametrization): text = vkt.TextField('This is a TextField') ``` ![](/assets/images/textfield-8cc52f6dfda628891aaca87a2476fabc.png) The user input can be obtained through the **params** argument and can have the following values: * `str`: when user inputs a text (e.g. "some text") * empty string when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` text = vkt.TextField('This is a TextField', default="John Doe") ``` * **description**: add a tooltip with additional information ``` text = vkt.TextField('This is a TextField', description="This input represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` text = vkt.TextField('This is a TextField', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` text = vkt.TextField('This is a TextField', name="t") # obtained using params.t ``` * **prefix**: a prefix will be put in front of the ui name ``` text = vkt.TextField('This is a TextField', prefix="..") ``` * **suffix**: a suffix will be placed behind the ui name ``` text = vkt.TextField('This is a TextField', suffix="..") ``` * **visible**: can be used when the visibility depends on other input fields ``` text = vkt.TextField('This is a TextField', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## TextAreaField - longer texts[​](/docs/create-apps/user-input/textual-input/.md#textareafield---longer-texts "Direct link to TextAreaField - longer texts") For lengthier inputs, the `TextAreaField` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): text = vkt.TextAreaField('This is a TextAreaField') ``` ![](data:image/png;base64,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) The user input can be obtained through the **params** argument and can have the following values: * `str`: when user inputs a text (e.g. "some very very very ... long text") * empty string when empty Expand to see all available arguments In alphabetical order: * **default**: a default value will be prefilled ``` text = vkt.TextAreaField('This is a TextAreaField', default="Multiple lines \n are possible") ``` * **description**: add a tooltip with additional information ``` text = vkt.TextAreaField('This is a TextAreaField', description="This input represents the ...") ``` * **flex**: the width of the field between 0 and 100 (default=100) ``` text = vkt.TextAreaField('This is a TextAreaField', flex=50) ``` * **name**: defines the position of the parameter in the *params* ``` text = vkt.TextAreaField('This is a TextAreaField', name="t") # obtained using params.t ``` * **visible**: can be used when the visibility depends on other input fields ``` text = vkt.TextAreaField('This is a TextAreaField', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ## Text - static text blocks[​](/docs/create-apps/user-input/textual-input/.md#text---static-text-blocks "Direct link to Text - static text blocks") For more information on how to add a static text to the parametrization, that cannot be modified by the user, see [`Text`](/docs/create-apps/inform-end-user/text-blocks/.md). There is no value associated with an `Text` field within the `params`. --- # Upload files Reference For a more technical API reference, please see the following pages: * [`FileField`](/sdk/api/parametrization/.md#_FileField) * [`MultiFileField`](/sdk/api/parametrization/.md#_MultiFileField) ## FileField - upload a file[​](/docs/create-apps/user-input/upload-files/.md#filefield---upload-a-file "Direct link to FileField - upload a file") The `FileField` lets the user upload a single file. Explicit permission for certain file types can optionally be set using the `file_types` argument. The max size in bytes of the file to be uploaded can be set with `max_size`. ``` import viktor as vkt class Parametrization(vkt.Parametrization): file = vkt.FileField('Upload a file') ``` ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARYAAABVCAYAAACM9ss5AAAKZElEQVR4Xu2da2gVRxiGP0Eab01ErQpJjDZ4ayJaLyTBUFRMUiMVvNBC/dU25IcXmqagCFpsEQQJqUWlYG37K6UtjYItaoygxoQkKFbRqIgJ1ERRG8HEexHa/cbOcbNn9+ye3clusvsOHCSendszu09mvplzMuRfLRESCIAACCgkMARiUUgTRYEACAgCEAtuBBAAAeUEIBblSFEgCIAAxIJ7AARAQDkBiEU5UhQIAiAAseAeAAEQUE4AYlGOFAWCAAhALLgHQAAElBOAWJQjRYEgAAIQC+4BEAAB5QQgFuVIUSAIgADEgnsABEBAOQGIRTlSFAgCIACx4B4AARBQTgBiUY4UBYIACEAsuAdAAASUE4BYlCNFgSAAAhAL7gEQAAHlBCAW5UhRIAiAAMSCewAEQEA5gQEnlr1799LNmzdp165dyjubqMAjR47QqVOnqKysjKZNm6a87idPntChQ4fo4sWLomyu5+nTp3TmzBkqLi6O1blp0yaaNGkSbdiwQWkb7ty5Q/fv36dnz56J16hRo8QrPT2dhg0bprQuFAYCrsVy/fp1OnDgAC1atIhKS0vjSLoVhNt8Xoeyv8VSU1MjpJKXl0fDhw8X/3Z1dRH//9q1a2n27NmiC6rF8ujRI2praxMysUoZGRmUnZ3tFSHyg0CMAMTyP4r+Fsu2bdtowoQJtjMRlWJhqbDMXrx4YXvLT5w4kaZPn257HS4AAScEIBafxOJUGE6vczK4LS0t9Pz58z6XpqSkiKVPT09PXBEsFhYMEgh4JeCbWHiJw2n+/Pl04sQJ6u3tpdTUVFq6dCnl5+fH+mG1FOIZxfnz50U+fjhmzJhBK1eupBEjRsTyyjjGtWvXxAPF5c+dOzduqdbZ2Ul1dXXEyzlOvAzhh621tdU2xuKkHfpBkTMh/f/JGIrZLMlMLBwb4fiMbC/HgEpKSigzM9Ny/HmZ1d7eHvd+VlYWTZ48mU6fPh333tChQ2nhwoVe7ynkBwH3f1co2RgLC+Pu3btCCvywc7py5Qrdu3evT4zBTCwyPsECWLBgAV26dIkuXLhAaWlptG7duphcqqqqxG/iJUuWiKBkQ0ODeBj1cSCWz86dO0X9c+bMEfGO27dvxx7aRMHb2tpaIR+Oj8yaNYtu3LghAr6Jgq0sBX5xPGr8+PG0YsUKUSdLwYlYOO/u3btFXwsLC0W7GxsbRT8rKipo7NixprfxuXPn6PHjx3HvsUD59eDBA9N8OTk5NG7cODwaIOCJgK8zFhbLli1bYiLgh7y6ulp0YOvWreJfo1isBMaxAxbOsmXLaPHixUIM/PCuWrWqzwyIZcOBS1m+VSyF83IZicTCswmWGwdbZZKy2bx5s+VDzteazUSciIX7yDMwI7ft27fHtUV/J5jNSPj9REshfl/OaDzdVcgceQK+ioVpG7dR5YO5ceNG8VvcKJZED+6OHTto9OjRCQOixvL4Z/5tLUUj7wC3wVun+dyKxUxmUsBmPGV/rMSSaCkEsUTeB8oABC4WDjAePHgwNlMwE4HVuRbjtbxsOHbsmPgNbwxaynMxVrszTgTBMyxe+shYj34U7M6/uBELx4L27NmTcLCtzvtALMqeERTkgkBoxKKPRRQVFYk4BqfDhw+LOI4KscgYzvLly2nMmDGi/LNnz4ot3f4Qi1zeydiS2fhaHea7fPmyiO0Yk92MZd68eeLgHBIIeCEQuFjkTMFuKcQxBf0OEHdavxSS5RhjHaqWQlYxHCczHW6rmxmLzGeM6zgZ8O7ubnEwLhmxjBw5UuzaIYGAVwKuxcIV87KCg4GVlZV9Hno5hdc/EHJXSFXwVj7oMnhrFBS3TwaHeYtazlhOnjxJR48ejZth2AVvjfVJ8Hb55HVuxSK5lZeX99le5iXk1KlTEwaMeefM7LyK1U3D48UxKyQQ8ErAk1jkzow8L8KN4c+/8A3NSb8dKmcOvOWq3zZ1s93M27zNzc19tpvlg69vC8dCONbCLykWKRv+v2S2m822qTs6OsQWOpfVH0shZsiS3r9/v+DJ2+i8BOP+87a31ccp5E3BJ255LMy2nY03Dg7HeX2UBl7+zl6iWw9ftis/3d/2eRILN5UfaHlehH/mB3vKlClxh9fkATk+J9HU1NQvB+RYdPX19SKmwjOpgoICQZMDrnKpxT8bD5w5PSBndrAuNze3z7a31fC5nbFIuegP9Ek56w8WWtXLcmERsQDNkjxsiJmKvw9ef9XW3EX0g/Z7/Xj82Ugq1j4OVqK91szsr9pfletZLE6bKMWi+lO7TuuP+nV8lofjLsZPN+MwXDjujB7tkxvlfxC1aGKxS/kZRFVFRJmpdle6fx9icc8OOUFgQBBo+/ulVLq0pY/TlJpC9PNqopw3nOZI7jqIJTleuBoEBhQBnqmU/pScVGQHMrQZy5EPidI0yahOEItqoigPBHwkUHmcqPaq+wpXa/GW6mL3+a1y+iYW9U1HiSAQTQJ1WmCWA7R28ZSZ2mdJv3uP6OuWxPJp/Eh9vAViiea9iV4PQgLJBGhZKr+sebXMSTSz+eIdok/eVgsEYlHLE6WBQL8ReP83otZb9sUbpSJzWMmFA7lr3iIq0HaLit+0L9/JFRCLE0q4BgQCJvD9n0RfNdg3wkoqdnKR76vaioZY7McKV4BA4ARyvyV6+E/iZthJReZ+t4board1WTyD4biLl90iiCXwWwYNAAF7AlnfqJEKl8Kxmg+0ZVUiufDM5RftnIvbBLG4JYd8IOAjATuxGJvy16fxjUu2DC+7RRCLjzcHqgIBtwSSlYIKsXjZLYJY3I408oGAjwSCEEtFHtFnr/6ARlK9hViSwoWLQSAYAkGIBTOWYMYatYKAbwTKfieq73BenYqlEGIsznnjShAYlAT4S5sKf/Sv6XnaF0P9qp3cdZuwFHJLDvlCQ4C/rIy/stRp4r9jZfUl5k7LcHMdf0boc+1Dh3bnWdyUrc/z+mtETR/jHItXjsgPAuKbB/lll/gvQPArqMTfvfKl9tdxnRztd9NG+cFFr18ChRmLG/rIE0oCdnIJWip66PwVlPzpZhZNr3bgzWvi72bhr63kl4oEsaigiDJCQ8BKLgNJKoMBNsQyGEYJbfSVgFEukEry+CGW5JkhRwQISLlAKu4GG2Jxxw25IkCgvb2dsrMVBR0iwEvfRYglYgOO7oKAHwQgFj8oow4QiBgBiCViA47ugoAfBCAWPyijDhCIGAGIJWIDju6CgB8EIBY/KKMOEIgYAYglYgOO7oKAHwQgFj8oow4QiBgBiCViA47ugoAfBCAWPyijDhCIGAGIJWIDju6CgB8EIBY/KKMOEIgYAYglYgOO7oKAHwQgFj8oow4QiBgBiCViA47ugoAfBFyLZd++fX60D3WAwKAlsH79+kHbdq8Ndy0WrxUjPwiAQHgJQCzhHVv0DAQCIwCxBIYeFYNAeAlALOEdW/QMBAIjALEEhh4Vg0B4CUAs4R1b9AwEAiMAsQSGHhWDQHgJQCzhHVv0DAQCIwCxBIYeFYNAeAlALOEdW/QMBAIjALEEhh4Vg0B4CfwHVoy+XCsy+MYAAAAASUVORK5CYII=) The user input can be obtained through the **params** argument and can have the following values: * `FileResource` object: when a file is selected (see [uploading files](/docs/create-apps/managing-files/uploading-files/.md) for an example of usage) * `None`: when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` file = vkt.FileField('Upload a file', description="This field represents the ...") ``` * **file\_types**: optional restriction of file type(s) (case-insensitive) ``` file = vkt.FileField('Upload a file', file_types=[".png", ".jpg", ".jpeg"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` file = vkt.FileField('Upload a file', flex=50) ``` * **max\_size**: optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB) ``` file = vkt.FileField('Upload a file', max_size=10_000_000) ``` * **name**: defines the position of the parameter in the *params* ``` file = vkt.FileField('Upload a file', name="f") # obtained using params.f ``` * **visible**: can be used when the visibility depends on other input fields ``` file = vkt.FileField('Upload a file', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. ### Upload multiple files[​](/docs/create-apps/user-input/upload-files/.md#upload-multiple-files "Direct link to Upload multiple files") If multiple files need to be uploaded at the same time, the `MultiFileField` can be used. ``` import viktor as vkt class Parametrization(vkt.Parametrization): files = vkt.MultiFileField('Upload Multiple Files') ``` ![](data:image/png;base64,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cC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6YTBiMmQyNjctZWZlOC00NTBlLWE2YmItYjY1NDE1MzEwZTk2IgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjM2YzI2YWY1LTQ5NzItNDkxZC05Y2E5LTNkNTE3MjEwODc3NCIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmI3NzczMGQ1LTcwNGEtNDMwNC05MTA5LTU2MTgxNGUwNzMwMiIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IkxpbnV4IgogICBHSU1QOlRpbWVTdGFtcD0iMTY2MTg2MTcwOTcxOTE1NSIKICAgR0lNUDpWZXJzaW9uPSIyLjEwLjMyIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAgMi4xMCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMjowODozMFQxNDoxNTowOSswMjowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjI6MDg6MzBUMTQ6MTU6MDkrMDI6MDAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5NmE5OGRlZC0wN2RjLTQ1MzctOTU3Zi1lNDcwOWUzNmU5ZDYiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoTGludXgpIgogICAgICBzdEV2dDp3aGVuPSIyMDIyLTA4LTMwVDE0OjE1OjA5KzAyOjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PukQwcMAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfmCB4MDwl7IWRdAAAMeklEQVR42u3db0xT5x4H8O+uxNK624vAGE4sAaXpdFBidC2Jix3RedW4xep2b9bshUsvL5xLtsV0b/aC3O3NFq65iY4XrHfLstRkmdRsrmu4vPBENLTBcVtUxA6YFDDyd7Ui2DsX7gt2zqX/CxYo8P0kSyY9p+ec55x++3ue57R9Ynp6ehpEREvkD2wCImIIERFDiIiIIUREDCEiIoYQETGEiIgYQkTEECIiYggREUOIiIghREQMISIihhARMYSIiBhCRMQQIiJiCBERQ4iIiCFERAwhIiKGEBExhIiIGEJExBAiImIIERFDiIiIIUREDCEiotnW1NbW1i7Xnff5fPj444/x66+/oqysbFG3bbFYcOvWLTz//PPL4vitVitu3ryJioqKOW3jhx9+wGeffYbi4mLk5eUt+DGNjY3h888/x4MHD1BSUpIRbT06OoqRkREMDg7i/v37mJqawtq1a5GVlcUESYNFa8UzZ87A7/fjk08+iflislqtMBgMOHDgwIpoWPGYAOD9999P+AL+6KOPEAwGF/T4A4EAAoHAkraJxWJJ+Lh4bQwNDWHDhg1Lfg5HR0fR09ODhw8fRj3W3d2NwsJCbN68mWG0XEJoNXO73XHDxev1IhgMpj38IgPt5MmTGdEWSqUS27dvj/t4Xl4ePvzwwyXfz7t37+LWrVtJl5mYmIBWq2UQMYQyl0wmQ3t7e9wQamtrg0wmQygUWhXtkZOTk/HVbiAQSBpAoomJCdy4cQNarZYX+0oKIfHd3GQyoa2tDT6fDwCgVqvx+uuvQ6FQJFy/v78fTU1N0noFBQXYu3dv1IXi9XrR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) The user input can be obtained through the **params** argument and can have the following values: * list of `FileResource` objects: when a file is selected (see [uploading files](/docs/create-apps/managing-files/uploading-files/.md) for an example of usage) * empty list when empty Expand to see all available arguments In alphabetical order: * **description**: add a tooltip with additional information ``` files = vkt.MultiFileField('Upload Multiple Files', description="This field represents the ...") ``` * **file\_types**: optional restriction of file type(s) (case-insensitive) ``` files = vkt.MultiFileField('Upload Multiple Files', file_types=[".png", ".jpg", ".jpeg"]) ``` * **flex**: the width of the field between 0 and 100 (default=33) ``` files = vkt.MultiFileField('Upload Multiple Files', flex=50) ``` * **max\_size**: optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB) ``` files = vkt.MultiFileField('Upload Multiple Files', max_size=10_000_000) ``` * **name**: defines the position of the parameter in the *params* ``` files = vkt.MultiFileField('Upload Multiple Files', name="f") # obtained using params.f ``` * **visible**: can be used when the visibility depends on other input fields ``` files = vkt.MultiFileField('Upload Multiple Files', visible=vkt.Lookup("another_field")) ``` See ['Hide a field'](/docs/create-apps/user-input/hide-field/.md) for elaborate examples. --- # Frequently Asked Questions tip Can’t find your question or solution here? Please reach out to our [Community Forum](https://community.viktor.ai/), so our community can help you! ## Account[​](/docs/faq/.md#account "Direct link to Account") **What is my Personal Access Token and where can I find it?** Your Personal Access Token is a personal unique token, that can be used to securely access the API without needing a username and password. It looks something like: `vktrpat_●●●●●●●●●●●●●●_●●●●●●●●●●●●●●●●●●●●●●●●●●`. To access it: 1. Log in to your VIKTOR environment (`{company}.viktor.ai` or `cloud.viktor.ai`) 2. Go to the settings page by clicking the three dots next to your name in the top-right corner and after that clicking 'Settings'. Select the 'Access Tokens' tab. 3. Click on *Generate new personal access token*. 4. Copy the token and **store it somewhere safe**. ![](/assets/images/generate-pat-a31dd3a9d856b96c760ac0630d44f1c4.png) Storing your Personal Access Token Your Personal Access Token can be used to **access or alter your sensitive data**. You should therefore treat it the same as a (username &) password. Make sure to **securely store this token** (e.g. in a password manager or Key Management System) and never store it directly in source-code or share it with someone else. If you cannot store it securely, consider rotating your token (by generating a new token) each time after use. **What is my developer token and where can I find it?** Your developer token is a unique key needed to [configure the CLI](/docs/create-apps/references/cli/.md#configure). To access it: 1. Log in to your VIKTOR environment (`{company}.viktor.ai` or `cloud.viktor.ai`) 2. Go to the settings page by clicking the three dots next to your name in the top-right corner and after that clicking 'Settings'. Select the 'Developer Account' tab. 3. Click on *Generate new token*. 4. Copy the token and use it directly in the CLI configuration ![](/assets/images/generate-token-6324916ce9c4cafb13a000f0c633bcb7.png) *How to generate a new token* Sharing your Developer Token Your Developer Token can be used to **access or alter your development data** on your behalf. Make sure not to share it with anyone else. ## Installing VIKTOR[​](/docs/faq/.md#installing-viktor "Direct link to Installing VIKTOR") **I get a warning that "viktor-cli-installer.msi isn't commonly downloaded". How do I proceed?** Click "Keep", "Show more" and "Keep anyway" to download the installer. For more information have a look at the gif below: ![](/assets/images/windows-warning-1975206f95d781da9e71494d8f47fc41.gif) **Windows defender does not allow me to install the VIKTOR CLI** Sometimes, Windows defender prevents the CLI installer from running. To solve this: 1. Click “More info”. 2. Click on “Run anyway”. ![](/assets/images/windows-defender-8dcdc78ceb8ce76493ca69e075080def.png) *Windows defender* **How can I use VIKTOR within an enterprise IT environment?** It is possible that your company has set restrictions on either your machine or the company's network that cause problems when working with VIKTOR. If you want to use VIKTOR within an enterprise IT environment, please make sure that your machine meets all requirements. See the [enterprise IT guide](/docs/manage-apps/enterprise-it/.md) for more information. ## Using the CLI[​](/docs/faq/.md#using-the-cli "Direct link to Using the CLI") **I get the error *"the provided email address and token are not registered at VIKTOR. Please rerun the 'configure' command with valid credentials"*** * Do you have a VIKTOR account? If not, you can create one for free [here](https://www.viktor.ai/try-for-free). * Make sure you provide the email you used to create your account. * Make sure you are using a valid token. To generate a new token you need to log in to VIKTOR, click the three dots next to your name and select 'Settings'. Subsequently, select 'Developer Account' and click the 'Generate new token' button. The token can be inserted into the CLI by running the following command: ``` viktor-cli configure ``` * If the steps above do not fix this problem for you, reach out to our [community forum](https://community.viktor.ai/) so that we can help you find a solution. **My command-line interface seems to be frozen** In case you accidentally clicked somewhere in the command prompt window, it could cause the process to freeze. You can resume the process by hitting enter. The frozen state can also completely be avoided by disabling "QuickEdit Mode": * Open a command prompt * Right-click the title bar and select "Properties" * Uncheck "QuickEdit Mode" * In addition, you can enable copy-pasting with Ctrl+C / Ctrl+V by deselecting "Use legacy console" and selecting "Enable Ctrl key shortcuts" * Restart the command prompt ![](data:image/png;base64,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) ![](/assets/images/cmd-enable-ctrl-keys-f92e05f63950e42fd2b5bc424f843ffd.png) **I’m not able to install my app and get the error *"Exiting because of an error: no requirements.txt file"*** When you run `viktor-cli install`, you ask VIKTOR to install the app stored inside the folder where you run the command. The error occurs when there is no `requirements.txt` file in the folder, or there is no app stored in that folder at all. To solve the latter: 1. Inside your command-line shell, first navigate to the folder with the app files. 2. Then, run: ``` viktor-cli install ``` **I get the error *"Manifest is invalid: Manifest misses entity type XXXX, which is present in the database"*** This error commonly occurs when you start a new app while the database still has information about a previously run app. The solution is to clear the database by running the following command in your command-line shell: ``` viktor-cli clear ``` **I’m not able to install my app and get an `SSLError`** Some companies use a proxy that modifies the SSL certification chain. This may cause an error when installing Python packages, or when performing requests within the app. See the [enterprise IT guide](/docs/manage-apps/enterprise-it/.md#ssl-certificates) for possible solutions. **I get the error *"ModuleNotFoundError: No module named "XXXX”"*** This error commonly occurs when you try to use an external library in your app, but you did not install the library. You can solve this problem by: 1. Open the `requirements.txt` file found in your app folder. 2. Add the library name you want to use and save the file. 3. Install your app again by running `viktor-cli install` in the command-line shell. 4. Start your app with `viktor-cli start`. For example, if you want to use NumPy in your app, the `requirements.txt` file should look something like this: ``` viktor==X.X.X numpy ``` **I use an Anaconda / Miniconda distribution of Python and I get an error while using VIKTOR** An error often seen when using Anaconda / Miniconda is a *"SLL module not available"* error. The Anaconda distribution of Python is structured differently than the official distribution. Some modules (including the SSL module) are installed at a different location. A solution to use VIKTOR with an Anaconda / Miniconda distribution is to use the `viktor-cli` from the Anaconda (Powershell) Prompt, instead of Windows' own Powershell. You can open the Anaconda (Powershell) Prompt from the Windows start menu. #### Using Anaconda Prompt in PyCharm[​](/docs/faq/.md#using-anaconda-prompt-in-pycharm "Direct link to Using Anaconda Prompt in PyCharm") In order to use the Anaconda Prompt within Pycharm, you can change the terminal path at `settings -> tools -> terminal`: 1. Right-click 'Anaconda Powershell Prompt' in the start menu and select 'Open file location'. 2. Right-click 'Anaconda Powershell Prompt' in file explorer and select 'Properties'. 3. Under the tab 'Shortcut', copy the entry at 'Target', excluding the first part ending with ".exe". For example, if the entry at 'Target' is... `%windir%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -NoExit -Command "& 'C:\ProgramData\Anaconda3\shell\condabin\conda-hook.ps1' ; conda activate 'C:\ProgramData\Anaconda3' "` ...only copy: `-ExecutionPolicy ByPass -NoExit -Command "& 'C:\ProgramData\Anaconda3\shell\condabin\conda-hook.ps1' ; conda activate 'C:\ProgramData\Anaconda3' "` 4. In PyCharm, go to `settings -> tools -> terminal`. Paste the above by appending to the existing powershell path (don't overwrite!) and press 'Apply' and 'OK'. This will then look similar to: `powershell.exe -ExecutionPolicy ByPass -NoExit -Command "& 'C:\ProgramData\Anaconda3\shell\condabin\conda-hook.ps1' ; conda activate 'C:\ProgramData\Anaconda3' "` 5. Restart the terminal in PyCharm. ## Running apps[​](/docs/faq/.md#running-apps "Direct link to Running apps") **When I open my app I get the error *"failed to load the editor"*** This error occurs when your app loses connection with the CLI, for example, because: 1. You closed the command-line shell used to `viktor-cli start` your app. 2. You were inactive for an extended period, and the CLI disconnected automatically. The solution is simple. In your command-line shell, start your app again by running the following command: ``` viktor-cli start ``` **How do I use a Python package which is not available on Windows?** Some dependencies do not provide a [wheel](https://packaging.python.org/en/latest/glossary/#term-Wheel) for Windows on PyPI. In this case you can download unofficial Windows wheels provided by a third party such as [Christoph Gohlke](https://www.lfd.uci.edu/~gohlke/pythonlibs/) from the University of California. Because wheels are OS and Python version dependent, you will need to add [environment markers](https://www.python.org/dev/peps/pep-0508/#environment-markers) to `requirements.txt` for condition-based installation of dependencies. An example implementation is shown below for `some_dependency` that doesn't provide Windows wheels on PyPI. In that case your app can be structured as follows: ``` my-app ├── app ├── local-wheels │ └── some_dependency-1.0.0-cp312-cp312-win_amd64.whl ├── requirements.txt └── viktor.config.toml ``` and refer to the wheel in the `requirements.txt` as shown below: ``` viktor==X.X.X ./local-wheels/some_dependency-1.0.0-cp312-cp312-win_amd64.whl; platform_system == "Windows" some_dependency==1.0.0; platform_system != "Windows" ``` caution Make sure to use CPython wheels, recognized by the ['cp' tag](https://peps.python.org/pep-0425/#python-tag) in the wheel's name (e.g. `-cp312-cp312-`) **Why is my published application not behaving the same as during development?** The apps you publish on the VIKTOR platform run on Linux. When you choose to develop using a Python virtual environment (venv), there will be several differences with respect to published apps on the platform. It is good to be aware of these differences to prevent unexpected errors after publishing an app. An overview of most common issues are listed below: **Python package works during development but not in production** If you are using a virtual environment on Windows you will be running the app and its Python dependencies on Windows. Some Python dependencies are not available on Linux, causing your app to break in production while it works without any problems during development. You can find the information on which operating systems you can use for a certain package on the [Python Package Index](https://pypi.org). **Python feature works during development but not in production** The application can be published on a specific Python version by setting the `python_version` in the [viktor.config.toml file](/docs/create-apps/references/viktor-config-toml/.md#python_version), which could differ from the Python version you are using for development. If you are developing with a newer version, please make sure that you are not using features that are not supported by the Python version used for publishing. **System dependencies work during development but not in production** If you are using a virtual environment during development, you will be able to use Python packages that require system dependencies (e.g. `OpenCV`). System dependencies can be included in your published application by setting the `packages` in the [viktor.config.toml file](/docs/create-apps/references/viktor-config-toml/.md#packages). **I can access my filesystem during development but not in production** When using a Python virtual environment as isolation mode it is possible to access the entire filesystem from the app code during development. If you publish an application on the platform however, only the folder containing the app is uploaded. If you access any resources outside this folder your app will not work. **My application is working during development but running out of memory in production** It is not possible to limit the memory usage of the Python process when using a virtual environment. Please keep in mind that standard apps on the platform have 500 MB of RAM available. Memory heavy operations that work in your virtual environment might not work in production. ## Docker[​](/docs/faq/.md#docker "Direct link to Docker") **I am experiencing network / WiFi problems after changes in Hyper-V settings** If one experiences network or WiFi problems after turning on Hyper-V, then possible solutions are described on the [Docker website](https://docs.docker.com/docker-for-windows/troubleshoot/#networking-issues). This is a known issue that sometimes occurs during the Docker installation. **I get the error *"Deny write access to fixed drives not protected by Bitlocker"*** Please see for more information. **I get a warning *"WARNING: Running pip as the 'root' user..."* when I install my app** You can ignore this warning. --- # Get started with VIKTOR Follow the steps below to get started with the VIKTOR platform and get ready to develop your own applications! 1. [Install](/docs/getting-started/installation/.md) VIKTOR and activate your account by following the installation instructions [Learn more](/docs/getting-started/installation/.md) [ ](/docs/getting-started/installation/.md) 2. [Create](/docs/getting-started/starter-guide/.md) your first app by following step-by-step instructions [Learn more](/docs/getting-started/starter-guide/.md) [ ](/docs/getting-started/starter-guide/.md) 3. [Publish](/docs/publish-apps/.md) your first app [Learn more](/docs/publish-apps/.md) [ ](/docs/publish-apps/.md) 4. [Learn](/docs/tutorials/.md) more by following one of our tutorials [Learn more](/docs/tutorials/.md) [ ](/docs/tutorials/.md) --- # Fundamentals Gaining a good understanding of the fundamental building blocks of a VIKTOR app will help you in creating the most effective applications. We have split these fundamentals in the **core concepts**, which elaborates on the absolute minimum knowledge of creating an app, and **advanced concepts** which are relevant if you have more experience with VIKTOR. * #### Core concepts[​](/docs/getting-started/fundamentals/.md#core-concepts "Direct link to Core concepts") Basic app structure - get familiar with the app files, and building blocks required to create a basic app. [Learn more](/docs/getting-started/fundamentals/basic-app-structure/.md) * App code execution flow - learn how and when the VIKTOR platform triggers your application code, and the stateless behavior when running calculations. [Learn more](/docs/getting-started/fundamentals/call-flow/.md) - #### Advanced concepts[​](/docs/getting-started/fundamentals/.md#advanced-concepts "Direct link to Advanced concepts") App types - VIKTOR offers different app types, each having their own pros and cons. [Learn more](/docs/getting-started/fundamentals/app-types/.md) - Entity vs. entity type - dive into the differences between a so-called *entity* and an *entity-type*. [Learn more](/docs/getting-started/fundamentals/entities-and-entity-types/.md) --- # App types The type of app can be set in the [viktor.config.toml](/docs/create-apps/references/viktor-config-toml/.md#app_type) file by means of the `app_type` entry. App layout, requirements and corresponding feedback errors might differ depending on the chosen app type. Currently, the following types are available: * Editor: the app consists of a single editor. Every users gets a 'fresh' editor upon entry and data is not saved. [Tutorial](/docs/tutorials/app-type-editor/.md) * Simple: the app consists of a single entity type. Users can create, save and edit instances of this type. Entities are shared among multiple users. [Tutorial](/docs/tutorials/app-type-simple/.md) * Tree: the app consists of multiple entity types in a developer-specified hierarchy. Entities are shared among multiple users. [Tutorial](/docs/tutorials/app-type-tree/.md) ## Editor-type app[​](/docs/getting-started/fundamentals/app-types/.md#editor-type-app "Direct link to Editor-type app") The simplest app structure consists of a single editor only. The user automatically enters the editor when opening the application workspace, with no additional navigation functionalities. When a user opens the workspace, a unique session is created. Sessions are not shared among multiple users, and are automatically closed when leaving the editor (state is not saved). info The following are not available for the 'editor' app type: * [`InitialEntity`](/sdk/api/core/.md#_InitialEntity) * [`ParamsFromFile`](/sdk/api/core/.md#_ParamsFromFile) * [`Storage`](/sdk/api/core/.md#_Storage) * [`Summary`](/sdk/api/views/.md#_Summary) ## Simple-type app[​](/docs/getting-started/fundamentals/app-types/.md#simple-type-app "Direct link to Simple-type app") The `simple` is similar to the `editor` type, however the user is able to create multiple entities of an entity type and the state of an entity can be saved. Earlier created revisions can be restored if desired. The user enters a folder and can navigate to the desired entity by selecting from the entity table. ## Tree-type app[​](/docs/getting-started/fundamentals/app-types/.md#tree-type-app "Direct link to Tree-type app") More complex apps, consisting of an entity type hierarchy, can be created by choosing the `tree` app type. ### Recommended folder structure[​](/docs/getting-started/fundamentals/app-types/.md#recommended-folder-structure "Direct link to Recommended folder structure") The `app.py` file can quickly become cluttered with a lot of code if your app grows in size. For tree-type apps we recommend to separate the code in sub-folders. This can be done by replacing the `app.py` file with a file called `__init__.py` within a folder named `app` and add sub-folders per entity type. Furthermore, it might be desirable to also split the controller and parametrization classes into separate files. For a hypothetical app with entity types `BlueType` and `GreenType` this looks as follows: ``` my-folder ├── app │ ├── blue_type │ │ ├── __init__.py │ │ ├── controller.py │ │ └── parametrization.py │ ├── green_type │ │ ├── __init__.py │ │ ├── controller.py │ │ └── parametrization.py │ └── __init__.py <- this is the new entry point of your app, replacing app.py ├── requirements.txt └── viktor.config.toml ``` note The `__init__.py` files in the entity type sub-folders are required to make Python treat directories containing the file as [packages](https://docs.python.org/3/tutorial/modules.html#packages) and can be left empty. ### Importing controllers[​](/docs/getting-started/fundamentals/app-types/.md#importing-controllers "Direct link to Importing controllers") If the controller class is in a separate file, it can be imported in the app's `__init__.py` file using Python's `import` command. For example, a controller class named `BlueType` in a file `blue_type/controller.py` can be imported in `__init__.py` as follows: ``` from .blue_type.controller import BlueType # defines entity type 'BlueType' ``` If the class name itself does not equal the entity type name, you can import as an alias. For example, a class named `Controller` in a file `blue_type/controller.py` can be imported in the app's `__init__.py` file to act as the controller for the `BlueType` entity type as follows: ``` from .blue_type.controller import Controller as BlueType # defines entity type 'BlueType' ``` ### Initial entities[​](/docs/getting-started/fundamentals/app-types/.md#initial-entities "Direct link to Initial entities") For a `tree` app type, it's required to define initial entities in code, since the top layer is not editable by the user. Initial entities can be set by means of the `initial_entities` variable in `app.py`, which is a list of [`InitialEntity`](/sdk/api/core/.md#_InitialEntity) objects. For example, adding an entity with name "An example entity" of type "ExampleType" would look like: ``` import viktor as vkt class ExampleType(vkt.Controller): ... initial_entities = [ vkt.InitialEntity("ExampleType", name="An example entity", params=...) ] ``` note On your development workspace, the initial entities **including their children** are applied **on every start**. On a production workspace, however, **only the top level entities** are applied the **first time the workspace is created**. Click to see all available InitialEntity arguments `InitialEntity` has the following arguments: * **entity\_type\_name** (obligatory): Refers to the class name of the entity-type's controller (or its [alias](/docs/getting-started/fundamentals/app-types/.md#importing-controllers)). * **name** (obligatory): Name of the entity which is shown in the interface. * **params**: params of the initial entity. If not defined, the default params will be set. Assume we have a parametrization with inputs `width` and `length`, the initial values can be set using a dictionary notation: ``` vkt.InitialEntity(..., params={"width": 300, "length": 500}) ``` or by pointing to a .json file located relative to the app file: ``` vkt.InitialEntity(..., params='initial_dimensions.json') ``` with `initial_dimensions.json`: ``` { "width": 300, "length": 500 } ``` * **children** info * [tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app) only List of children defined as `InitialEntity` objects. If not defined, no children will be added. Each child must be a valid child-type of its parent (i.e. the child-type must be defined as one of the `children` on the parent controller). ``` vkt.InitialEntity("ParentType", ..., children=[ vkt.InitialEntity("ChildType", ...), ... ]) ``` * **show\_on\_dashboard** (New in v13.7.0) info * [tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app) only * Top-level entities only This flag controls which top-level entities are shown as cards on the dashboard (default=`True`) * **use\_as\_start\_page** (New in v14.18.0) info * Not available for [editor-type app](/docs/getting-started/fundamentals/app-types/.md#editor-type-app) * Single, top-level entity only This flag can be set on a single top-level entity to appoint it as starting page for the user, instead of the dashboard (default) --- # Basic app structure Terminology On this page you will encounter terms that are highlighted. These terms are core concepts and are used throughout our entire documentation. If you ever need a quick refresher, you can click on the section below to get a nice overview! Remind me! In alphabetical order: App files: * app.py: this file contains the **controller**, and additional logic of your application. * requirements.txt: all Python dependencies of your project are listed in this file. It should **at least** specify which version of the VIKTOR SDK your app should be using. * viktor.config.toml: additional configuration settings are listed in this file. Core: * controller: contains the code that defines the **parametrization** and one or multiple **views**. * editor: the place where users can create and adjust their designs, perform calculations, and inspect results. * parametrization: the parametrization consists of the **input fields**, **sliders**, and **buttons** a user can interact with. These fields are available on the left-hand side of the editor. * params: the Python object that can be used to access the **user input** in your app code. * view: a view is a visualization shown on the right-hand side of an editor. You can show **3D models**, **maps**, **graphs**, **reports**, **pictures** and much more. You can define **multiple views**. ***Not a reader?** feel free to follow this video* The core of a VIKTOR app is the editor. This is the place where users can create and adjust their designs, perform calculations, and inspect results. The image below shows the editor of a VIKTOR app: ![](/assets/images/viktor-app-5701f40445ec2c0461fa80a2f034f1ff.svg) An editor can be created by defining a so-called controller, which holds the code for: 1. Parametrization: the parametrization consists of the **input fields**, **sliders**, and **buttons** a user can interact with. These fields are available on the left-hand side of the editor. 2. View: a view is a visualization shown on the right-hand side of an editor. You can show **3D models**, **maps**, **graphs**, **reports**, **pictures** and much more. While each editor consists of a single parametrization, **multiple views** can be present. Before diving into these concepts more, let's have a look at what files you will need to build a VIKTOR app. ## App files[​](/docs/getting-started/fundamentals/basic-app-structure/.md#app-files "Direct link to App files") The minimum file structure of a VIKTOR app looks as follows: ``` my-app ├── app.py ├── requirements.txt └── viktor.config.toml ``` * app.py: this file contains the **controller**, and additional logic of your application. * requirements.txt: all Python dependencies of your project are listed in this file. It should **at least** specify which version of the VIKTOR SDK your app should be using. * viktor.config.toml: additional configuration settings are listed in this file. ## The controller[​](/docs/getting-started/fundamentals/basic-app-structure/.md#the-controller "Direct link to The controller") To define a controller you will need to inherit from the `ViktorController` class: ``` import viktor as vkt class Controller(vkt.Controller): ... ``` info You can specify controller attributes if desired. Click to see all available controller attributes * `parametrization`: defines the editor's [parametrization](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-parametrization). * `summary`: to [show a summary](/docs/create-apps/results-and-visualizations/show-summary/.md). * `label` : name of the entity type as shown in the interface. * `children`: ([tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app) only) define this entity-type's children. Not providing the key is equal to having no children. * `show_children_as`: ([tree-type app](/docs/getting-started/fundamentals/app-types/.md#tree-type-app) only) defines how to visualize the children ('Table' | 'Cards'). * `allow_saving`: Specify whether user is allowed to save entities of this entity-type. May only be set for root entity types in tree-type app. * When this value is set as `False` more than one user can run calculations on same editor, and the entities of this entity type becomes read-only. This value defaults to `True`. * methods for [views](/docs/create-apps/results-and-visualizations/.md). * methods for [action buttons](/docs/create-apps/user-input/action-buttons/.md). * method for processing of a [file upload](/docs/create-apps/managing-files/uploading-files/.md#upload-using-file-like-entity-type). ### Defining a parametrization[​](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-parametrization "Direct link to Defining a parametrization") To create the editor's parametrization, you need to define a class that inherits from `ViktorParametrization` and assign it to the controller class using the `parametrization` attribute. [Input fields and action buttons](/docs/create-apps/user-input/.md) can be added to the editor by adding them as attributes on the parametrization class: ``` import viktor as vkt class Parametrization(vkt.Parametrization): input_1 = vkt.TextField('This is a text field') # add a field for textual input input_2 = vkt.NumberField('This is a number field') # add a field for numeric input class Controller(vkt.Controller): parametrization = Parametrization # assign the parametrization class to the controller class ``` The above editor will look as follows in the interface: ![](data:image/png;base64,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) *Example parametrization* ### Defining a view[​](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-view "Direct link to Defining a view") Views can be added to the editor by defining a method on the controller class and [decorate](https://docs.python.org/3/glossary.html#term-decorator) it with one of our [available views](/docs/create-apps/results-and-visualizations/.md). The `label` argument is obligatory and defines the name of the view as shown in the interface. The view method should return the view result that corresponds to the chosen view type (e.g. `TableResult` for a `TableView`): ``` import viktor as vkt class Controller(vkt.Controller): @vkt.TableView("Results") def results(self, params, **kwargs): data = [ [1, 2], [3, 4], ] row_headers = ["Row 1", "Row 2"] col_headers = ["Col 1", "Col 2"] return vkt.TableResult(data, row_headers=row_headers, column_headers=col_headers) ``` info The view `label` is required, however more arguments can be specified if desired. Click to see all available view arguments * `label` (obligatory): name of the view as shown in the interface. * `duration_guess`: tells the platform whether the view should be rendered as a quick or slow visualization: * <= 3: Quick visualization, which updates with every change in the editor. * \> 3: Slow visualization, which can be refreshed manually by means of an update button. * `description`: provide more information to the user through a tooltip (supports [Markdown](/docs/create-apps/layout-and-styling/style-text/.md)). * `update_label`: change the default text presented on the update button. * `visible` (>= v14.22.0): set the view's visibility based on other input fields. See ['Hide a view'](/docs/create-apps/results-and-visualizations/hide-view/.md). The above editor will look as follows in the interface: ![](/assets/images/fundamentals-view-1b412298dd7ed354831a6055321a209b.png) *Example view* ### `params` - connecting input to output[​](/docs/getting-started/fundamentals/basic-app-structure/.md#params---connecting-input-to-output "Direct link to params---connecting-input-to-output") In the sections above we have seen how to define the **parametrization** and the **views**. You may have noticed that the example mentioned *params* in the signature of the view method: ``` def results(self, params, **kwargs): ``` which is not used elsewhere in the code.. This params argument is used by the VIKTOR platform to inject the **user input** into your application logic. Let's combine the examples we saw earlier into a single controller. The input value can be obtained by referencing the attribute names, for example `params.input_1`: ``` import viktor as vkt class Parametrization(vkt.Parametrization): input_1 = vkt.TextField('This is a text field') input_2 = vkt.NumberField('This is a number field') class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Results") def results(self, params, **kwargs): data = [ [params.input_1, 2], # retrieving the user input value of the TextField [3, params.input_2], # retrieving the user input value of the NumberField ] row_headers = ["Row 1", "Row 2"] col_headers = ["Col 1", "Col 2"] return vkt.TableResult(data, row_headers=row_headers, column_headers=col_headers) ``` The above editor will look as follows in the interface: ![](/assets/images/fundamentals-params-c84cf50222e542c001e1f4955fcca1ae.png) *Example editor* --- # App code execution flow As a developer it is important that you fully understand how the VIKTOR platform triggers code when a user interacts with an application within the browser, in order to write effective code and prevent unexpected bugs. The app code execution flow is referred to as a job, and VIKTOR's execution flow might be different from the approach you are familiar with, especially if you are used to writing standalone (Python) scripts. ## Triggering actions[​](/docs/getting-started/fundamentals/call-flow/.md#triggering-actions "Direct link to Triggering actions") A job is triggered if (and only if) one of the following actions take place: * **Modifying input** Probably the most occurring trigger of the app's code is by changing the value of an input field. The entry point in the code is the currently active view-method. note If the current view is 'slow' (i.e. `duration_guess>3`), the method is **not** triggered automatically. * **Refreshing a view** Similar to modifying the input, the currently active view-method is triggered if the user refreshes the view. This takes place when: * entering the editor * switching to another view tab * clicking the view update button (in case of a 'slow' view) * **Clicking an action button** The third way of triggering the code is by clicking an action button (e.g. `DownloadButton`). The entry point in the code is the method linked to the button that is clicked. * **Clicking a next step button** In case of a [stepwise editor](/docs/create-apps/layout-and-styling/steps/.md), the 'on-next' function is triggered when a user navigates to the next step. * **Pre-process upload file** A less typical case occurs when [defining an entity type as file](/docs/create-apps/managing-files/uploading-files/.md#upload-using-file-like-entity-type). During the uploading of the file, the method decorated with the `ParamsFromFile` is triggered. In all cases, a method on the corresponding controller class is called, which ends with returning the required result to the platform. A job is completed after this return and code execution is terminated, waiting for a next trigger (which might already be present in the queue). The next trigger follows the same procedure (and if it is the same action it actually runs the same piece of code again!). ## Stateless code[​](/docs/getting-started/fundamentals/call-flow/.md#stateless-code "Direct link to Stateless code") A consequence of above-mentioned repetitive call flow is that the app's Python code is **stateless** (though within a call-cycle the code can still be stateful). This means that data is **not** stored within the code (e.g. on a global variable) for using it in the next call cycle. Instead, the data is recalculated each time it is requested. The only data that **is** stored (and thus can be used for the next call cycle) are the parameters (`params`) on each of the entities within the app. VIKTOR's stateless design is clarified in the following example. Imagine a cube defined by its length, width, and height, that can be set by the user. We want to show results based on these inputs to the user, by creating a `TableView`: ``` import viktor as vkt class Parametrization(vkt.Parametrization): length = vkt.NumberField("Length", default=1) width = vkt.NumberField("Width", default=1) height = vkt.NumberField("Height", default=1) class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Results") def results(self, params, **kwargs): volume = params.length * params.width * params.height surface = 2 * (params.length * params.width + params.length * params.height + params.width * params.height) data = [ [volume, "m³"], [surface, "m²"], ] row_headers = ["Volume", "Surface"] column_headers = ["Value", "Unit"] return vkt.TableResult(data, row_headers=row_headers, column_headers=column_headers) ``` Note that even though we calculate the surface area and volume of the cube, we never store this data. Each time the result is requested (e.g. when updating one of the dimensions in the editor), the above code is rerun. Similarly: * A report is generated and returned as download each time the user clicks the `DownloadButton` (the report is never stored). * A 3D-model is created and visualized in a `GeometryView` each time the user refreshes the corresponding view tab or modifies the input within the editor (the 3D-model is never stored). * A plot of the results is drawn and visualized in an `ImageView` each time the user refreshes the corresponding view tab or modifies the input within the editor (the figure is never stored). * etc. ## Single source[​](/docs/getting-started/fundamentals/call-flow/.md#single-source "Direct link to Single source") The examples of output above (report, 3D-model, plot) can be seen as representations of one and the same model (defined solely by its parametrization). Besides it is not possible to store these alternative representations, it is also not desired. What would happen if we would store the 3D-model of the cube and subsequently modify its length? Exactly, the visualization would be outdated, possibly without the user even noticing. The concept of defining a 'model' by its minimal set of independent parameters is called **single source** modelling. ## Long-running results[​](/docs/getting-started/fundamentals/call-flow/.md#long-running-results "Direct link to Long-running results") Sometimes, recalculating the results each time the information is requested is too time-consuming (e.g. if doing some long-running analysis to calculate results) and therefore not an option. We call such type of output **long-running results**. Below are solutions to two of the most common cases. ### Slow views[​](/docs/getting-started/fundamentals/call-flow/.md#slow-views "Direct link to Slow views") For example, a user would not expect (nor desire) a plot of the results of a long calculation (e.g. a structural analysis with third-party software) to be cleared if he or she (accidentally) changes the value in a `NumberField`. Here **slow views** come in handy. A slow view is a `View` that is refreshed by clicking its 'update' button. It is triggered by [setting a high `duration_guess`](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-view). The user is notified by means of a warning if the result has become outdated, but the figure would remain visible. ### Memoize[​](/docs/getting-started/fundamentals/call-flow/.md#memoize "Direct link to Memoize") Another common example is the implementation of a `DownloadButton` (e.g. generating a result report) and a `View` (e.g. for showing the results in a plot) calling the same analysis. If a user wants to visualize the results within the view **and** download the report to its local hard disk, running the analysis twice would be undesirable. Preferably, the result is stored internally, so that it will return instantly on the second (or third) call. The [`memoize`](/sdk/api/utils/.md#_memoize) function can be used to cache a calculation and achieve exactly this. ### Persistent storage[​](/docs/getting-started/fundamentals/call-flow/.md#persistent-storage "Direct link to Persistent storage") VIKTOR offers storage which can be used to store and retrieve files within an app workspace. The storage is persistent, meaning that the data will remain available with no time limit. This can be very helpful in cases where (intermediate) results need to be shared between jobs. For example, a long-running task is performed in job A, of which the results can be accessed in job B without the need to rerun the task. Read our [guide](/docs/create-apps/results-and-visualizations/storing-results/.md#persistent-storage) for more detail! ## Local files persistence between jobs[​](/docs/getting-started/fundamentals/call-flow/.md#local-files-persistence-between-jobs "Direct link to Local files persistence between jobs") When writing data to a file in the filesystem of your development environment, this file will be available between different jobs because it is actually saved on disk. However, the production environment works in a different way. An application is running in production in multiple processes, to support executing multiple jobs by multiple users working in parallel. Each of those processes has its own disk space. This means that the files stored in the disk of a specific process will be available to all jobs executed by that process, but not to other jobs executed by other processes. You as developer cannot control these processes or in which one a job will run, which could result in unpredictable behavior. Therefore we advise against working with local files! You can instead use the Persistant Storage. Read our [guide](/docs/create-apps/results-and-visualizations/storing-results/.md#persistent-storage) for more detail! --- # Entity vs. entity type A common source of confusion is the distinction between the terms 'entity' and 'entity type'. It is important to fully understand this terminology before diving deeper into VIKTOR's [call-flow](/docs/getting-started/fundamentals/call-flow/.md). In short, an 'entity type' is the **definition** of a certain object, it's attributes and behavior (logic) specified in (Python) code. An 'entity' is a single **instance** of an entity type. An entity always has a certain entity type and multiple entities can be created with the same type. For example, an entity-**type** 'Cube' might be defined by its width, length and height. A 3 x 3 x 3 cube would be an **entity** of the type Cube, just as a 4 x 4 x 4 cube would be an(other) **entity** of the same type. As a metaphor (thinking in terms of the Python language): the entity type would be a 'class', whereas an entity would be an 'instance' of the class. ## Developer vs. User[​](/docs/getting-started/fundamentals/entities-and-entity-types/.md#developer-vs-user "Direct link to Developer vs. User") Entity **types** are created by the app **developer**. The entity-type's definition and logic are defined in a [controller class](/docs/getting-started/fundamentals/basic-app-structure/.md#the-controller). Entity types are created during development. On the other hand, **entities** (of the predefined types) are typically created by the **user** within the app, they are created and modified at run-time. Two entities of the same type share the same behavior and the same set of attributes (since they share the same underlying code), but do not necessarily have the same attribute **values**. For example, the user might create a new cube entity (with different width, length and height values) that resides next to the already existing two, or modify the 4 x 4 x 4 cube mentioned above to a 4 x 4 x 5 cube by updating the corresponding height field within the entity's editor in the app. ![](/assets/images/cube-entity-vs-entity-type-50cf052b9e55d15a994a2b88198e7d3b.png) *Entity vs. entity type* note It is also possible for the developer to [create initial **entities**](/docs/getting-started/fundamentals/app-types/.md#initial-entities) at development time. In contrast, it is not possible for the user to create entity **types** (as he/she is not able to modify the underlying app-code). ## Example[​](/docs/getting-started/fundamentals/entities-and-entity-types/.md#example "Direct link to Example") Below are two example controllers (partly defined), in which the developer has defined 2 entity types: 'Project' and 'Design' (the latter being a child-type of the former). ``` import viktor as vkt class Project(vkt.Controller): label = 'Project' children = ['Design'] show_children_as = 'Cards' class Design(vkt.Controller): label = 'Design' ``` The figure below shows a snapshot of the current live application, as seen by the user. We can see that the user created an entity of type 'Project' (and named it 'My Project'). Within the created project, the user created 3 entities of type 'Design' (notice that 'Design' is its label seen by the user) and named them 'Design A', 'Design B', and 'Design C' respectively. ![](/assets/images/entity-vs-entity-type-7a5f8281df12d60584a0839de04b26b6.png) *Entity vs. entity type in VIKTOR* Since the designs are of the same entity type, opening their corresponding editor shows the same parametrization (after all, their logic is defined in the [parametrization class](/docs/getting-started/fundamentals/basic-app-structure/.md#defining-a-parametrization) of the entity type). Nevertheless, the attribute values assigned by the user make them unique: ![](/assets/images/design-a-vs-design-b-a2fb141a5192a2f2f3e6f315452002ad.png) *Entities 'Design A' (top) and 'Design B' (bottom) have equal parametrization but differ by value* --- # Install VIKTOR Start building apps by creating an account, installing VIKTOR and activating your account. ## Installation[​](/docs/getting-started/installation/.md#installation "Direct link to Installation") You can choose for cloud-based or local development. The different options are listed below in order of setup difficulty: * **Cloud-based** development using GitHub Codespaces / GitPod [Learn more](/docs/getting-started/installation/cloud-based-development/.md) [ ](/docs/getting-started/installation/cloud-based-development/.md) * **Local** development using a virtual environment [Learn more](/docs/getting-started/installation/local-development-venv/.md) [ ](/docs/getting-started/installation/local-development-venv/.md) * **Local** development using Docker [Learn more](/docs/getting-started/installation/installation-using-docker/.md) [ ](/docs/getting-started/installation/installation-using-docker/.md) ## Restart the installation[​](/docs/getting-started/installation/.md#restart-the-installation "Direct link to Restart the installation") If you happen to close the pop-up by accident, or you need to reinstall VIKTOR on an already activated account, you can go to the guide on how to [restart the installation workflow](/docs/getting-started/installation/restart-install-workflow/.md). Need help? Please consult the [FAQ](/docs/faq/.md) if you encounter any problems during installation. Couldn't find an answer to your problem? Our developers are ready to help you on the [Community Forum](https://community.viktor.ai/) --- # Cloud-based development If your local machine does not meet all requirements for development with the VIKTOR platform you can choose to use a remote development environment. A remote development environment is an environment that is hosted in the cloud and can often be used together with a code editor in the browser. Examples of remote development environments are GitHub Codespaces, GitPod, and Replit. ## Create an account[​](/docs/getting-started/installation/cloud-based-development/.md#create-an-account "Direct link to Create an account") Create a VIKTOR account if you haven't done so yet. * **Company account:** please contact your local administrator to create an account for you * **Free account:** create a free VIKTOR account by registering on the [VIKTOR website](https://www.viktor.ai/start-building-apps) ## Setup instructions[​](/docs/getting-started/installation/cloud-based-development/.md#setup-instructions "Direct link to Setup instructions") * GitHub Codespaces * GitPod Follow the steps below to set up a GitPod workspace and get started with developing on the VIKTOR platform: 1. Create a repository on GitHub, GitLab or Bitbucket for your VIKTOR app (if you don't have one already). 2. Add a GitPod configuration file called `.gitpod.yml` to your project's root directory with the content shown below. Do not forget to commit the changes. This configuration file instructs GitPod to download the VIKTOR CLI upon initialization of the workspace. More information on the GitPod configuration file can be found [here](https://www.gitpod.io/docs/config-gitpod-file). ``` tasks: - name: VIKTOR init: | curl -Lo viktor-cli 'https://sys.viktor.ai/api/v1/get-cli/?platform=linux&format=binary' chmod +x viktor-cli mv viktor-cli /workspace/viktor-cli command: | echo "export PATH=\$PATH:/workspace" >> ~/.bashrc source ~/.bashrc ``` 3. Log in to [GitPod](https://gitpod.io) with your GitLab, GitHub or Bitbucket account. 4. Click on Settings > Variables to configure several environment variables required to authenticate with the VIKTOR platform. Click the `New Variable` button to add a new environment variable. The following variables should be added: * `VIKTOR_ENV`: * **Free users:** `cloud.viktor.ai` * **Paid users:** `{company}.viktor.ai` (substitute `{company}` with the name of your company) * `VIKTOR_DEV`: the email address that your VIKTOR account is registered on. * `VIKTOR_TOKEN`: your development token.
How do I obtain a token? You can generate a token by logging in to your development environment. If you are logging in for the first time, use the link from the activation mail to generate a password to log in to the development environment. Alternatively, you can click "Forgot Password" to receive a mail to (re)set your password. After logging in close the first-time user modal (this modal is shown when you have not activated your account yet) and go to the settings page by clicking the three dots next to your name in the top-right corner and after that clicking 'Settings'. Select the 'Developer Account' tab and click the 'Generate new token' button. ![](/assets/images/generate-token-6324916ce9c4cafb13a000f0c633bcb7.png) *How to generate a new token*
Scope You can scope these variables to only be available for the repository you created in step 1 by inserting the owner of the repository (i.e. your GitLab, GitHub or Bitbucket username) and the name of the repository separated by a `/`. 5. Click the button 'New Workspace' to initialize your GitPod workspace. You will be asked to select a repository. Select the repository created in step 1 from the list. You will now land in a browser-based version of Visual Studio Code. 6. Run the following command to verify the configuration: ``` viktor-cli check-system ``` This should print: `V Your system is ready to use VIKTOR with isolation mode 'venv'`. You can find all your workspaces in the dashboard: .
***Not a reader?** feel free to follow this tutorial as a video* Follow the steps below to set up a GitHub codespace and get started with developing on the VIKTOR platform: 1. Create a new repository: * Navigate to the following url to create a repository from our template: * Under "Repository name" choose your desired app name * Click "Create repository" 2. Create a codespace: * In the repository created in step 1 click "Code" -> "Codespaces" -> click the three dots -> "New with options..." ![](/assets/images/codespaces-setup-f7474a603a7394e3f5c324e20710af46.gif) * Under "Recommended secrets" paste the value for `VIKTOR_CREDENTIALS` obtained during the onboarding flow * Click "Create codespace" VIKTOR\_CREDENTIALS Your VIKTOR Credentials can be used to **access or alter your sensitive data**. You should therefore make sure to **securely store these** and never store it directly in source-code or other plain text formats. You can always revoke and regenerate the credentials by [restarting the onboarding flow](/docs/getting-started/installation/restart-install-workflow/.md), and replacing the old value stored under "Codespaces secrets" in your [GitHub settings](https://github.com/settings/codespaces). You can find all your codespaces, grouped by repository, in the dashboard: . For more info about codespaces please refer to the official [codespaces docs](https://docs.github.com/en/codespaces). Congratulations, you are now ready to start coding your first VIKTOR app! 🚀 --- # Install VIKTOR with Docker caution The installation procedure to run VIKTOR using Docker is **not recommended** for first-time users. By using Docker, running the code in development will more closely resemble production, so the chance of encountering differences between development and production is smaller. We recommend Docker only for experienced developers, as setting up Docker for Windows is not always convenient and, depending on your company size, may require a paid subscription. ## Prerequisites[​](/docs/getting-started/installation/installation-using-docker/.md#prerequisites "Direct link to Prerequisites") Enterprise IT If you want to use VIKTOR within an enterprise IT-environment, please contact your IT-department to verify that your machine meets all [requirements](/docs/manage-apps/enterprise-it/.md). Alternatively, you can consider using a [cloud-based development environment](/docs/getting-started/installation/cloud-based-development/.md). Before you start the installation procedure, you can go through the following checklist to make sure your setup is ready for installation: * Machine should run on Windows 10 Home/Pro/Enterprise or Linux. * Python (64-bit); the programming language used by VIKTOR. * You will need personal VIKTOR credentials ([try for free!](https://www.viktor.ai/try-for-free)). * Virtualization needs to be turned on on your machine.
Go to `Task manager → Performance` and see if "Virtualization" is enabled. ![docker-bios-virtualization](/assets/images/docker-bios-virtualization-218246bb1b85fcfd75220b2102497e4d.png) caution If enabling of "Virtualization" is not allowed, it must be enabled in the BIOS of the machine first. In the BIOS, enable “Virtualization Technology (VTx)” (location and name may vary per machine) to do so. Please contact your IT department if you don't have the necessary permissions to make adjustments in your BIOS. ## What will I install?[​](/docs/getting-started/installation/installation-using-docker/.md#what-will-i-install "Direct link to What will I install?") In order to use the VIKTOR platform, you need to install the following tools: * [Docker](/docs/getting-started/installation/installation-using-docker/.md#installing-docker): software used by the CLI to run your app code in an isolated 'container' in the background. * [CLI](/docs/getting-started/installation/installation-using-docker/.md#installing-the-cli): VIKTOR's command-line interface (CLI) is required to interact with your app. ## Installing Docker[​](/docs/getting-started/installation/installation-using-docker/.md#installing-docker "Direct link to Installing Docker") Linux If you are using Linux, Docker can be installed using the package manager. There are two ways to install / use Docker on Windows: * Hyper-V virtualization (default): [system requirements](https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/hyper-v-requirements) * Windows Subsystem for Linux 2 (WSL2): [system requirements](https://docs.microsoft.com/en-us/windows/wsl/install-win10#step-2---check-requirements-for-running-wsl-2) The benefits and drawbacks of running on WSL2 are listed below: `+` installation and starting an app is fast
`+` installation of an app does not fail when deep dependency trees are present
`+` WSL2 is available for Windows Home, whereas Hyper-V is not
`-` WSL2 is not supported on all Windows versions
`-` conceptually more complex due to the separate Linux filesystem and command-line interface
`-` setting up requires more time We recommend to choose the default Hyper-V method and only choose WSL2 if you use Windows Home or you are experiencing issues during app development. * Hyper-V * WSL2 Estimated time: 1 hour 1. Install [Docker](https://docs.docker.com/docker-for-windows/install/) on your machine. When prompted, ensure "Enable Hyper-V Windows Features" is **selected** or "Install required Windows components for WSL 2" is **deselected** (options differ per installation version). 2. Open the Docker settings and **disable** the checkbox to use the WSL2 based engine in the "General" section, if this isn't the case yet: ![docker-hyper-v-backend](/assets/images/docker-hyper-v-backend-1f891168655e0ef6b197c48f6d574020.png) 3. Make sure that you share your user folder (`C:\Users\`). Allowing sharing of drives or folders (shared drives) is necessary when using Linux containers. If this was not done during the installation, you can set it in `Docker → Settings → Resources → File Sharing`. 4. In the start menu, type “Turn Windows features on or off” (“Turn windows features on or off”) and make sure that Hyper-V is checked: ![docker-windows-features-hyper-v](/assets/images/docker-windows-features-hyper-v-d640af4ba0d841951cf8b9e95094bf72.png) 5. You can check all required Hyper-V features by running the `systeminfo` command in `cmd.exe`. All requirements should have a value "yes". If this is not the case, please visit the [website of Microsoft](https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/hyper-v-requirements) for more information. Estimated time: 1 to 1.5 hours An alternative method of running VIKTOR is by using Windows Subsystem for Linux 2 (WSL2). WSL2 is a dedicated part of Windows which can be used to run Linux processes, providing an alternative to Hyper-V virtualization. In order to run Docker with WSL2, you will need to meet the stated [requirements](https://docs.microsoft.com/en-us/windows/wsl/install-win10#step-2---check-requirements-for-running-wsl-2). 1. Install [Docker](https://docs.docker.com/docker-for-windows/install/) on your machine. When prompted, ensure "Enable Hyper-V Windows Features" is **deselected** or "Install required Windows components for WSL 2" is **selected** (options differ per installation version). 2. Install [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-manual). * When asked for a Linux distribution, we recommend choosing the latest Ubuntu LTS version. * It is NOT necessary to create an account for the distribution. In case you do not have access to the Microsoft store, a manual download of a Linux distribution can be found [here](https://docs.microsoft.com/en-us/windows/wsl/install-manual#downloading-distributions). 3. Start Ubuntu from the start menu. This action will open a command-line shell and ask you to create a user account. 4. Open the Docker settings and configure the following: * General: enable the checkbox to use the WSL2 based engine * Resource → WSL integration: enable the checkbox "Enable integration ..." and manually select the correct Ubuntu distro ![docker-wsl2-backend](/assets/images/docker-wsl2-backend-c90a7dc5b1b0180183111f48ea52fb25.png) 5. Reboot your machine. 6. Start Ubuntu and type the following path in the file explorer address bar: `\\wsl$\Ubuntu-20.04` (replace "Ubuntu-20.04" with your distribution name) to get started. ## Installing the CLI[​](/docs/getting-started/installation/installation-using-docker/.md#installing-the-cli "Direct link to Installing the CLI") Estimated time: 15 min The VIKTOR command-line interface (CLI) is required to interact with your app code (installing dependencies, starting the app, etc.). Choose the CLI for your specific operating system and installation method below: * Hyper-V * WSL2 * Linux \[ ]I accept the [terms and conditions](https://www.viktor.ai/terms) and [privacy policy](https://www.viktor.ai/privacy).[Download for Windows](<> "Accept the terms & conditions and privacy policy first")
\[ ]I accept the [terms and conditions](https://www.viktor.ai/terms) and [privacy policy](https://www.viktor.ai/privacy).[Download for Linux (or WSL2)](<> "Accept the terms & conditions and privacy policy first")
The CLI can be made available in the Linux Subsystem by moving the executable from the 'Downloads' folder (or any other location you extracted the executable in) to the Linux home folder (`~`): ``` mv /mnt/c/Users//Downloads/viktor-cli ~ ``` \[ ]I accept the [terms and conditions](https://www.viktor.ai/terms) and [privacy policy](https://www.viktor.ai/privacy).[Download for Linux (or WSL2)](<> "Accept the terms & conditions and privacy policy first")
### Using the CLI from any folder[​](/docs/getting-started/installation/installation-using-docker/.md#using-the-cli-from-any-folder "Direct link to Using the CLI from any folder") If you want to use the CLI from any folder, the directory where the CLI resides must be added to the `PATH` environment variable (a variable that specifies the directories to be searched to find a command). Follow the instructions below to make the CLI available from any folder for your operating system. * Hyper-V * WSL2 / Linux The `PATH` variable is automatically set when using the Windows installer. tip We recommend to create a single folder on your hard disk in which all your individual applications will be created, and give it an appropriate name (e.g. `C:\Users\\viktor-apps`). Right click on the created folder and pin to "Quick Access" to enable easy navigation to this folder. You can (permanently) add a directory to the `PATH` environment variable by adding it to the `~/.bashrc` file. The easiest way to do this, is to open the bash shell **in the directory of the CLI** and extend the existing `PATH` variable with the current working directory (PWD). Use the `source` command to refresh the `PATH` variable within the current session without having to restart the shell: ``` echo "export PATH=\$PATH:'$PWD'" >> ~/.bashrc source ~/.bashrc ``` info "Bash" is the default command-line shell for most Linux distributions (including WSL2) that uses a start-up script called `.bashrc` located in the user's home directory (`~`). If you work with a different shell, you have to replace `~/.bashrc` in the above commands with the shell's corresponding start-up script (e.g. `~/.zshrc` for Zsh). Make sure the CLI is executable by using the `chmod` command: ``` chmod +x viktor-cli ``` If everything has been configured correctly, executing the command below in any folder should open the CLI's help-menu: ``` viktor-cli --help ``` tip We recommend to create a single folder on your hard disk in which all your individual applications will be created, and give it an appropriate name (e.g. `~/viktor-apps`). Make sure the CLI has full rights in the your apps directories, by changing its permissions with: ``` sudo chmod -R 777 ~/viktor-apps ``` ### CLI configuration[​](/docs/getting-started/installation/installation-using-docker/.md#cli-configuration "Direct link to CLI configuration") Next you'll need to set up the CLI. Open your command-line shell (Command Prompt in Windows) and enter the following command: ``` viktor-cli configure ``` The configure command opens a prompt that guides you through the configuration process. You can copy-paste in the command-line shell using a right-click of your mouse. You will need to enter the following information: 1. Development environment. This is the environment that you will use while developing VIKTOR apps. The correct development environment is also stated in the invitation email you received when your account was created. * **Free users:** `cloud.viktor.ai` * **Paid users:** `{company}.viktor.ai` (substitute `{company}` with the name of your company) 2. Email address used to create your VIKTOR account. 3. Personal token. You can generate a token by logging in to your development environment. If you are logging in for the first time, use the link from the activation mail to generate a password to log in to the development environment. Alternatively, you can click "Forgot Password" to receive a mail to (re)set your password. Go to the settings page by clicking the three dots next to your name in the top-right corner and after that clicking 'Settings'. Select the 'Developer Account' tab and click the 'Generate new token' button. You can copy the token and paste it in the command-line shell with a right-click of your mouse and clicking 'Paste'. 4. Select the isolation mode `docker` and press enter. 5. Enter the path to your Python installation. If Python has been added to the `PATH` environment variable it will be inserted as a suggestion, select it by pressing enter. ## System check[​](/docs/getting-started/installation/installation-using-docker/.md#system-check "Direct link to System check") Run the following command to verify the installation: ``` viktor-cli check-system --docker ``` The check system command performs several checks. The conclusion of the checks are printed at the end of the message: ``` Starting VIKTOR system check... V Operating system internet access V Docker runs V Docker using correct container V Docker access to user directory V Docker internet access V Docker access to PyPI V Docker access to VIKTOR domains The system check has been completed with the following conclusions: V Your system is ready to use VIKTOR with isolation mode 'docker' ``` If all checks succeeded, a "V" will be printed in front of *Your system is ready to use VIKTOR with isolation mode 'docker'*. If any of the system checks fails, additional information can be printed to the command-line by using the `--verbose` flag as follows: ``` viktor-cli check-system --docker --verbose ``` --- # Install VIKTOR [YouTube video player](https://www.youtube.com/embed/pqsuF2nOo5w?rel=0\&showinfo=0\&modestbranding=1) ## Prerequisites[​](/docs/getting-started/installation/local-development-venv/.md#prerequisites "Direct link to Prerequisites") For installing VIKTOR, you're going to need a few things: Python 3.10 - 3.13 (**64-bit**) Python is the programming language used by VIKTOR to write apps. VIKTOR supports Python 3.10 - 3.13 (**64-bit**). * Windows * Linux Python can be downloaded from the [official website](https://www.python.org/downloads/windows/): ![](/img/docs/python-download.png) Python can be installed using the local package manager. Code editor Most popular editors recommended by VIKTOR are [**PyCharm**](https://www.jetbrains.com/pycharm/download/#section=windows) and [**VS Code**](https://code.visualstudio.com/download), but you are free to choose any editor! Enterprise IT If you want to use VIKTOR within an enterprise IT-environment, please contact your IT-department to verify that your machine meets all [requirements](/docs/manage-apps/enterprise-it/.md). Alternatively, you can consider using a [cloud-based development environment](/docs/getting-started/installation/cloud-based-development/.md). ## Create an account[​](/docs/getting-started/installation/local-development-venv/.md#create-an-account "Direct link to Create an account") Create a VIKTOR account if you haven't done so yet. * **Company account:** please contact your local administrator or request access to your company's environment on the login page * **Free account:** create a free VIKTOR account by registering on the [VIKTOR website](https://www.viktor.ai/start-building-apps) ## Install & activate your account[​](/docs/getting-started/installation/local-development-venv/.md#install--activate-your-account "Direct link to Install & activate your account") After your account has been created, you will receive an email with a link to set your password and activate your account. Click the link and log in to VIKTOR. As a first-time user, you will be guided through the process of installing VIKTOR and activating your account. Follow the instructions in your browser to complete. If everything went well, the installation is concluded with the demo app running in your browser. Need help? Please consult the [FAQ](/docs/faq/.md) if you encounter any problems during installation. Couldn't find an answer to your problem? Our developers are ready to help you on the [Community Forum](https://community.viktor.ai/) --- # Restart installation At some point in your VIKTOR journey you may need to restart your installation workflow and follow it's steps to set-up your VIKTOR account. This may be because you have a new device or you just need to re-install VIKTOR. If you do not see the yellow ribbon at the top of your environment, you will need to follow the steps below. Otherwise you can click `start` and continue following the steps of the installation and activation of your account. ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnEAAABACAYAAAB1NCEZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABfaVRYdFNuaXBNZXRhZGF0YQAAAAAAeyJjbGlwUG9pbnRzIjpbeyJ4IjowLCJ5IjowfSx7IngiOjYyNSwieSI6MH0seyJ4Ijo2MjUsInkiOjY0fSx7IngiOjAsInkiOjY0fV19lA162QAAGXxJREFUeF7t3QtcVGXeB/CfCogXsBJNFi+rW4ZpCJhoAi4Kuir7pmyuSluw3oJyrBUylFIhN4hIrJgMFNdlshDXQtxF3QSXN6C1ceOipHiDXY2XEqzEFblp7/OccwYGmCsMOIP/7+czcG5zzpnnPOec//M859LnJwaEEEIIIcSi9JX+E0IIIYQQC0JBHCGEEEKIBaIgjhBCCCHEAlEQRwghhBBigSiII4QQQgixQBTEEUIIIYRYIAriCCGEEEIsEAVxhBBCCCEWiII4QgghhBALZOQbG9ikTXXAnUbWeUcaRgghhJC7rk9foK8NYD2Q94jDSK9mRBDHJmusZQFcs9RPCCGEELPT1wqwsWcdFMj1doY3pwo1cBTAEUIIIWaNn6v5OZv0eoYHcbwJlRBCCCHmj87Z9wTDgzi6Bo4QQgixDHTOvifQ3amEEEIIIRbI8Bsb6q9JHYQQQggxe7ZDpQ7zwMONW7fq0djYhDt3qKZQm759+8LGxhoDBtiiTx/dN6dQEEcIIYT0RmYUxPFQ48aN/8LKygq2tv2FQIVoxgPc+voGNDc3w85usM5AjlKREEIIId2K18DxAG7gwAEUwOnB04enE08vnm66UEoSQgghpFvxJlReA0cMx9OLp5suFMQRQgghpFvxJkKqgTMOTy991w5SihJCCCGEWCAK4gghhBBCLJD5BnE/lgH/zpB6CCGEEEKIOvMN4r6KBkoSgNu678wghBBCSO/GH7lx6tQZXLhYgebm29JQYp5B3OUjwLVTQMP3wNc7pIGEEEIIuVfwYO2jjz/BooBgPPzIdCz49dOYNTsA452fwPIVLyE753NpynuX+T3s93YjcHgucKta7O9rBSw4Cgx0FPsJIYQQop8ZPez3++9/xAMP3Cf16VdWdgGrQ8JRUXEZ3l7T4O7uAheXibhx4wbOnDmP//38nzh37iJmzfLC+4mxsLe3k77Zu+hLN/ML4s58AJTKgfucgfsnABUZwMg5wIx3pAkIIYSQTrh2CmnJO1FQnI+mJgdYj/aFzyoZFj/WGgAUJbsi6agMoRmr4CYN6yxTzqtTLDSI482mi5esFJ6T9t47b8DHx1Ma04o/euODpD8j7i05fjFuDP72148waNBAaexdUJWB1dOigcRs7FroIA3sOn3pZl7NqfXVwNmdYvfjWwCXMMDKFvjmGFD9L3F4r3MKSQHhOHxV6u0pV48gKiAFRVJvV9RUVKK2hy9RqMoKR0jyKbGni7+lW9a/JAUhEUdQJfUaq+5sOqKC/RBiom1Euhc/WUdl1Uh9xmm6WoErtVKPzrxcg8MRLCgokXprK1He08cNS1Zfht0RQcgtHwbPkJ1YGbkRnkPKcGyzDLtPN0gTkbvt+vVaLF/5kvC6qb8fSRcCuP/+9yY2bYmDi6uP0KwasWGrEMSteWEF9vzpXeE6uRdfipTmYIxTeG+0K0a+K51LWtTg4PNs+OgEfCUNMVfmFcQVvyU2p46aBzzgAvR/AJgQKo776nX2x7BKQ4OwEpliczBkAa7sROmP9TEZKFUdSM1VV4IVEwZtbdzMx4cR0fjsstTfae1OUN2lfTqYbP1NqQwH3szACFkGku9WCb5XMUHe6q79Bw1Qpq7Ge0crpH7DlR+NRlxqPuqkfqLHuXworwGTVmxAoK8HPKb6InBLONu/SqA8VoImoUDNa874xHKxW8ozdRdzkBQZwM4V7HwRGIw/ppWpFfzE/BUSJoci/jk2jRzK29rnRXTjNWvffVeNpA/i4ej4oPDO1eDlLyIt7VMsW7oIo0Y5CdfJRb4WI0zvO9tbCOb+/lkuco7nCcPuJeYTxH3PIuHLh4F+NoDbBmkgMz5YvB6u9hJwab80sItush0sYhuu/TIG2w8UI/nAPqx8SInETRm4Ik1CDDTIC+v278TisVK/pTHL9W9EXa0TRo/pndd4EHX94bk+G/FLjM+A45bsRPJ6L9zFBiTL4jAUvJGr9G+HUaYqsPdzQWgGOweEecAaLghKzUOQDx+xSuyexDrrldgdGc4C+GUIlWdjXaAzru2X4YO8G3zCVhUpUF51hoe/KxzZfDXOi+jE70D9y4FDQmA29XFXYVhR0Wl8+eVXCFv3PCI3/gFHD6dhwoTxSE8/iB9/vC5Ms1a2EjY2Nkjb172PJas9mYL1i7wxcrQrZgTH4uAlHTW4hQlsOn+89bECsjnTWLc3gmIycOGmNN5EzCeI+1e0+P+RFYDtMODQTGD/RKCJbSTX9eK40+8AzV1PgarcVBQ9vBohvk6w7scG9LOD81OBcKtKxz/Oi9Pg9g0o92yEbAkrYS0JwKsJObiiKnnxprIwBTJV4wNlSMytQFlWAtYHitNHsZKaqoTMm1pelSuQKPMXSnIyWQoKtF5i2IBy1Xx4DWFCPqrYcoXmw5CNqGpfquM1iqoSYvBGpJ3tmKm0fhf1uJyreZ21rUdH6s3BUo3HoXzpt/pBFpmO0pZNpj5PtXFCLYcfMlnaF0Wxcapm0psVOJwgE2tLO6yfDlq+pzkd2jVn69ruwnrKkak1zdppqm6dl5BHKqURTLvltMxHWEYQO2HkIDOEjVOlhd78qKoFkGqLtM2/DXF7xeW2nozK97N5GLrMNs3F7dKxHd48/MflqvyfgGNqSVFTqJCajsVxuaqZGpXepstbqv11ewhbJza99v2nraaqky37YsffoV6L17ZmUFdTbN3FDMQJacP3wYO4pBY3dLykQEdaCdsyXPy9PC+myvGqtppFXfudKq+pxrN5JX2hWinxd23fo7oUgG2HrRko17f/9xSnAMhCAmB9Nhrbg/2xbnMCDuS1vZRioL0dBtryLluxm58fMAGBKXnYHr0Ubk4OcH7SH4+w31p+rl3tqeNGhL0ZhpWrvDCK9WqeF9GluLhUeOH7bBbEqUyePAl/SU/BiuWBQj8P1jxnTMXt23fQ0NAoDBs8eBCemD4F+flfCv3d4usUPPvULnw3JxLp++RY+3MlOzZG4fj30niNKpF2qAKekYlQvO2H60nRWJtyiu0JpmMeQRx/qC9/uO8AFrxNWC0OU91vwf+P/BUw1AVoZMUnftNDF337TQ4cJzm3LcHyEtn+fQgaL/aW7ZVh94WZiPiIldLSdmFBPwUSWOK3vIq2ogR13pGQ7y9GfJgzyt8NwL6mpYjZWwz5znAMzUjAYbUmupor/TEnJgvJB1iJ7LE8KBJzoKn1tpYdhOMy7PHbZF5DmIq59VGQ/7USjv7bkJwcC0fwi2SLETqZTXy7DIqIMFyeLoecDYt/eQJKt+yCst2j9TR+V3AQp68GYBNf5+1BLGjehVzpJKxtPQxRdKJa+q2pmHM7FgdypRPU+XQk7reR5pmBoDGHkZiiRNPw+YjKyMZClvZuUWxcCNvWLJsrU1bj2KDnEMNrS1M2YsRRGRRaTqCttH9Pezq00rvddaRZBxU5qJos5ZGt3rj2LssT0rQty0nj6xiLcSdY/wm2awtpoYAbfLGQp5OQFobkx5O4Pn0L4lOfBS/wa51/Gw7wmhuA8rwSKS9WorCgHG7TDVymoa7mIOH1Yji/ug/JLN1jgu1xOFKBUn7yrMzA9jfPwi0mWxgX4ccOeu+oB4cGpreJ81ZNcS08NmcgPtjFoHzD1ZyohPOGDLb8PMg82/+OTqhnBbSt6Ri4fB/bv7MQs9gJ13Vedqd7f95dPBmhqez37o3FtPqTLAzRxID9rqIC1k/Gisec9a44F8+C8h+lcczlH5wg+xPbnnz/v/U+2y7s2M5p20bi2B7hOG8L5KlZCHrGF0Ov5OBYAguOX2DBrK5g0tYONv/JRuLLUmFZKGRpYGePARSodckPP4gZafiw1hsy+vXriyeeeLzl5flHjx5HqmI/Fizww4MPsphBMm7cGOHaOVXtnFG2BQm1a60fVsjIksYJGlCQKcdX3mH445r5LIj0QmBoEOZXH8Gn/9R9LWxg+BYEzvLA7CUb8EooC2EU2SiVxpnC3Q/i+MN8+UN9ucfC2BYTii4dTdnC/vQBLnwE3OjKBUw1qCqXOrUqQ0EWC7pC52OUNevt5wDP4CAMPZrdGiCN94PPQ2Jzl737TFYy84XHDLFmz/o+Z/xirBI1PwijBY4zfeFszzr62cEjeA0mlShR2CGKq0H+Z+mYtOJZeAjTOmCO/zLU/POU5pPBmXwU2KzB00+y5bJe+8cWwHNsCgrPiaP1Wwb/JWNhz9fZyRse43NwWViQkevRjtvSAOm3OsGD/e6qb/5PHDGIlUZvVeJSRSUr2bN0WLUT8asmC+veUX+4rcrAG6tchPWDvQfcp9awAFz3DtP573EGbHetaabB+GVY6C7lkYcWYY53DgoL+XqoLUdYR2fMmTsZpSXaNpwB6zV2GRZ7O8Hevj9LT8Pnbz/FC6MKlTjN53P1FEqrlmGa0OxjSFoYpqYwG1c8A7FYtb9MXYq1Mg8M5WfvEQsQsScKC52EURg1zQ8O5yvxrdjLGJjeJs5bDk8GwNPJDvZaDkeaOAYskvYXOzgHLMWk85+jqCs39V9QomjQUvj7OAi/w3r0VLjrbHXVsT/nZGBcQAAmqY5B01trOtoyYP9pc+x7luW7DBQWt1YRPuLrBQf+Xbb/LwxdA6tcJctNjFHbqBvZO8HzqTC8ticL8ZtkGHhVDsUBKdDU5OoRJGyOxrePbsQbrECWLBSySHewsrYS/jc1Nwv/2zt+PB+rnguDi8sEJLwttd5JrKx0f1enp8OQvm+n2icWL7bZRSpQmsf+5cVihirQmxaNI2xQg57F2fJ9QdAf4yd6AdXluGLIidRAdz+I4w/z5Q/15Y8U+fmT0kAN+PhxAcBPrPheJF7Q2DkOcBwndWrViKYmVVW45L5h7JuVuK6p+qxlIxnI1pYduGpQp+lkyH5eafw0qcTHPlFyln8qofFccId9qqIRp5pWajaqqTIkYNHDmPUwlFMAImL8cP2TaLwSyEo6m9JRVi+WrjSxrq/AgWjVzSeu2J0jjdCjs98zersbpT8GDgLEB43z5Shx7CUpbdknKoWt5H+qWa7QxID1anMmNGL+93lg2mQFCy4bUHumGFW+HnAT8rPp0uLbqlPt1s8O46Y6w5HPmy2rJvd9vCo1p4a8sFFLGuhh4rxl3U/7dw0i7OONwn7UaXz/trPFALGva9h6DLlfDLz0MW7/EfP1rZtaGohYOgyqbcQt3m3kNjK1stRl7Pe0bfK3d/dgBXCg7nKNxpYRQVWlUHh9ZLoHHHg+7so2JToNHyY+muPiRc03+ry9bQeGDLHHx3uThCZUdecvlAuB3NAH7peGGMHRFZ4zPNQ+UzGeF3haNKKB55vfbMEXLJo7o/bZNs90jxPpjLsbxNWxXeN8qtjNHymibmEesORrYMBwaQDz2DrxkSPfsnHffSENNJ7Dg16oKm13bQ2/m2jJMiiEa+JsYG19o22Q9SM/ATq0Pal1Vn09mrTNi53U3Dbx0p7aZ/8qoYmsA771xsYiSn1a9nnNFJnKmPUwVBMrrY/0RejrOyFPy0KERwl2b8vRctKuxIHXw1DlvU28+YQtP3SeNEqnzn6P687t3oC6myz7CgESX44vFuxQS1v+ifFlS9LE2PUyZv52mOazFKUnjiM/L6elKdWUaTHCkc2zXZtZXe0NNLGTYdOJXYj7zAGL3xWbU8Vmy07okbxlBGEftzG+gKeO79836sUAqEtYoDWYJZG2QKsNY9NGzNcDBmkJxlg63LS3EQNRo7aR6TnPDcYo6xxkbopGWo4SypP5OBAvRxHL06NYoUJ1zrbux/eSszidp0Q5b93jNYjs37mjGSjg33l7m+bmVA06zIvoNHHiI7BjwdnhI5pLDtHRr2D/vl0dngfHn6VWUKDEjCceR9++3RHWjMUkvh/kleFKfzvhwcL8w3O9vZ5ySH1L0N+A81/nA8PGYZQJ311wd4O4olhW2mwGRi8QHymij/ojRwq3Aj/xoqrxRs15Dm4XdmF3Xo1wIuEX/ZZ9koaiscGYI1wT5wxP/wYcSzqCK/zkwy8KTlfgio8vPNtE54arKsgT74ji80p9H6Xu3nDvMC8HuM2cj9K9ChRJO3xtSTqSsirVzoHVwkFT8LAXPGr3YV8OG89/R1Mlju1QQKm1SKn2XZ0MWQ/jNX2VivURCvFRLlpqOm7Vqk40LID40QFD7Nh07ETYVJWP/JPSKJ0M+Z62dDDxdj+/D5knWbDCOmsvHsSxPF+4u/OD+lhMm1uDXEWOtJwGXMlJgYJNq5mx62Xc/O2n+2LSiW3IPK1qSuX0LNPRCY7ns6HkVRRs/lW52dDWGOzg7odRBWnIvCxu29rCFLwalo5zbL636tk62drBgReq2TLKcj/v1HVkPZO3dO8/VRkHoeT7C/8dGekoHT8TbvzSnqFOGGGdjS8Lpd9/PgdK1Q1UujzsAbeb6cjKZccp1tt0+SQKjX8SCWMHd28WqKezdVIdg06wgrBGBqRNxecouCjmpdrCD3HgxFJMc22t5TuXm48a4bhaicyk99E824PlJsO2UbdynI8I+U74jKlGQfJz2B0jQ+4ZJ7jJdiFMreA7yX8jxtmXoCAhGvk8Mz60FK+8FASr4mgo4rehdHQQfHizdrlYQ6dLh3kRnXhN2pIli4S3NfA3MrS3Y8ceHMw8LPW12rnrQzQ3NyPo2SXSEFOzg+fSVZhSnY71f0jBkS+UOL4/GkGzViP5a92Fo7QP5NL0b+KtJGDK8wswRRpnCncviLuqZIU+Fm33tQYmvywNVFPwIvCP37PgtV3xhT9yZNDP2LHmMnDxI2mgkQa5IDQuHEOOhWPdYleEBAbhw29mImLz/JZaAOdn5Fj58OeI+504PvNmEF6T8dvQO8fhZzdwLNIfIYu9objoi5UveLWU/NQ5zotCmG8NPn6eN2X4ITK9Ae7TxWveMHwqPN2VUDzjh92nWb+tM1ay3zE0RwYZ/x1BsSgb4y1e99Je++/qoXM9Osl6+mqsnVmJVH7XJZtnnHICgtaqaodY4OgXgEuJ0xCSwq9PccbiDQH49oMAyNi061Kq4fioA27qrU3Q8z096WDS7T7WF46lMVi3xBXrN+VhxPooLBAqlvtj0nI5Aodni8tZ/Bu8V+IEr0e1N3cZt15Gzt92Mtu2NUBLU6pI5zKHz0bQcnuxyTZwGZKrHDBa+JYGw30RttkVp7f8RsxLqbVYuHUVJtmyANI7CIEP5iCO3wH7zEbk2kxg+2Ct5ksNdOj2vGXA/uPA9o+ytwKEfVxewJb/inQ86eeCp8P8cEm4PMEfW//WgBGGPFHE1gVBm4LRnLZMXM/Uevyik0d/e28Z1k4/i6RVYjp/yQI1zQxIm5FOqDu0kY1n+Tr+LNw2yOCj9kD50faVkK/wY+kQjPz7w7F2MQ/h9G2jnmE93AOBkXLhZiNeyyjfswWhvmPb3uTm6IuIVF4znIWgCdIgnzDE85uE9mcgKtAXgQmsO051vnDAgjj1fjUa5kV0W//yC8Lz4cJf3oKrV/XX0/Jg7/0df8Ls2V6YN2+2NNT0+rvI8OEnMnhWpWL1sucQvqsanm/E4vcTdRdI/D3skbVlLYJezsaQ0Fgk/l7cH0zl7rx2i9eg/X0RK8ZdAia+wD5rpBFqMr3Fa+X+5x9tm1S5bz4DvuBNq6z4/utswKYz1SQ9hz9CIHNkNqL8e/JwRYihGlCQ4I/Tvtla77wkvQCvHVMF6fxRIalOiErQEHjowr/3MfuepoAF/BEjfrj8tPY7eEkPs9TXbp0+g8W/FV+7tfX1Dfi1/1zhLlV1/C7UXSl7kSjfLbx261Dmh8JbHswGf07cIgVeOViMF92lYZ1gnq/dKv+LGMANeJAV/FZKA9vxSgR8/szCXw0XKY6cCwxjRVL+zLjS96SBhJDOaLp8GMdKguDVpQseiTmr+yIB6+VqzZzp+zBw8ljjAjhCeojLY4/i4KepGDx4MNbINuDxqXPwRsx2JGxPEj5h4ZvhNsUP7763C7N8PHHo0F7zCuB6UM/XxPHAK+tXrPD/gxjEDdbaCKMbf8/qjX+L3b86CAx5WOw2Q1QTR8xVaYofEnMmw2dzDAIn3IXrlEjP4NfBKWKgOHIETRgLh+nhkL3kBUe15nODUE2cZbHQmjgVfp3bRx9/igOf/FV4c4MKr6Hz+eUM/O7ppzBrlpc01Mz0UE1czwdx/GaGC3ulHhMZ9jgwS7rLlRBCCCEWH8Sp429yuHChHAMHDcDPx4yGlXirf69nfkFcTZF4R6qpObiKN0kQQgghpFcFcfcq8wviCCGEENL9KIizePrS7e4+J44QQgghhHQKBXGEEEIIIRaIgjhCCCGEdCv+Oqw7dzr3lqV7FU8vfa8RoyCOEEIIId3KxsYa9fX63rhD1PH04ummCwVxhBBCCOlWAwbYCs99q6u7RTVyevD04enE04unmy50dyohhBDSG5nR3akcDzf4894aG5sokNOBN6HyGjgewPXp00caqhkFcYQQQkhvZGZBHDE9ak4lhBBCCLFAhgdxfSjeI4QQQiwCnbPvCYZv5b42UgchhBBCzBqds+8Jhgdx1gPZ1FZSDyGEEELMEj9X83M26fUMv7FBwCZtqgPuNLJOurOEEEIIMRu8CZXXwAkBnO67GknvYGQQRwghhBBCzAFd+UgIIYQQYoEoiCOEEEIIsUAUxBFCCCGEWCAK4gghhBBCLBAFcYQQQgghFoiCOEIIIYQQC0RBHCGEEEKIxQH+Hz20ZmpmRuMDAAAAAElFTkSuQmCC) There are three easy steps you need to complete to do this but first you will need to navigate to the web environment, for example `cloud.viktor.ai`. 1. Navigate to your user profile by clicking the three dots on the top right of the browser tab and go into the `Settings`. 2. Go into `Developer account`. 3. Click on `Reset Developer Account`, this will trigger the installation pop-up. ![](/assets/images/restart-install-workflow-3-2ce9b7e29fd953fa87643266386918b6.png) From here, follow the steps to installing and activating your account. If you were to close the pop-up now, the yellow ribbon will appear at the top of your environment and you can always resume it from there. --- # Starter guide Great to see you are ready to learn how to use VIKTOR! Here you will learn the basics of creating VIKTOR apps! Before you continue, please make sure you completed the [installation / activation instructions](/docs/getting-started/installation/.md) which include: * Installing Python on your computer * Installing a code editor on your computer (e.g. [PyCharm](https://www.jetbrains.com/pycharm/download/) or [VS Code](https://code.visualstudio.com/Download)) * Activating your VIKTOR development account New to Python? Writing VIKTOR apps requires basic Python knowledge. If you are entirely new to this programming language, we advise to check out ["Python for Non-Programmers"](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) which lists learning resources including some nice interactive courses. ## Set up the app[​](/docs/getting-started/starter-guide/.md#set-up-the-app "Direct link to Set up the app") Every new app setup starts by running the `quickstart` command, which will: * Download and extract a template app to your machine * Install the app's Python dependencies * Prompt to open the app in your code editor of choice Before you continue Make sure that you **have a code editor installed on your computer.** We recommend using [**VS Code**](https://code.visualstudio.com/Download) or [**PyCharm**](https://www.jetbrains.com/pycharm/download/). If you use GitHub Codespaces make sure that you have a Codespace open, which you probably have if you followed the installation process. Open Windows PowerShell using Start (or a terminal if you use Linux) and start by running the command below. If you use GitHub Codespaces simply run the command in the terminal of your Codespace. ``` viktor-cli quickstart hello-viktor ``` and select your code editor of choice (GitHub Codespaces users don't need to make this choice): ``` Your app is ready and located at: C:\Users\\viktor-apps\hello-viktor ? Do you want to open the app code in your code editor? [Use arrows to move, type to filter] > Open with `VS Code` Open with `PyCharm Community Edition 20XX.X.X` Skip ``` After pressing enter, the code editor will open the folder where the app is extracted to and automatically start the app as shown in the code editor's terminal. **Do not close the terminal** as this will break the connection with your app. tip Continuing development of an already existing app does not require you to run the `quickstart` command again. Simply open the project folder in your code editor and the app will automatically start! Need help? **When I try to open the app code I see a warning message regarding trusting the project** You may first see a security warning about trusting projects located in the `viktor-apps` directory. * PyCharm * VS Code Go ahead and tick the checkbox, followed by clicking the "Trust Project" button: ![](/assets/images/starter-guide-pycharm-trust-3d2323d3b9ecf4ba4dfe96d3e5daacb5.png) PyCharm should now open and look similar as shown below: ![](/img/docs/starter-guide-pycharm.png) Go ahead and click the "Trust Folder & Continue"" button: ![](/assets/images/starter-guide-vscode-trust1-8ba0ce9af63d704f9958b38bdb765fa7.png) Subsequently you can click the checkbox to automatically trust all your future apps, and click "Yes, I trust the authors": ![](/assets/images/starter-guide-vscode-trust2-230654bcc4f9c7fbc7bdd0d461b2ccae.png) VS Code should now open and look similar as shown below: ![](/img/docs/starter-guide-vscode.png) **I get the following error message 'viktor-cli not recognized'** If you activated your account, continued with the starter guide and installed a code editor in the same session you might encounter the following error: ``` viktor-cli : The term 'viktor-cli' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:1 + viktor-cli + ~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (viktor-cli:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException ``` You can solve this error by closing and restarting your code editor. After doing so you can run the command without any problems. The problem is caused because your code editor inherits the environment variables of the process that launched it and because you installed the VIKTOR CLI in the same session it requires a restart to be recognized properly. **I cannot find my code editor's terminal** You can find the terminal as shown below: * PyCharm * VS Code ![](/img/docs/new-terminal-pycharm.png) ![](/img/docs/new-terminal-vscode.png) **Where is the app located on my computer?** When you run the `quickstart` command the app gets downloaded to a folder on your computer. You can find the app in the following directory: `C:\Users\\viktor-apps\hello-viktor`. **My app started in Powershell, how can I continue with this starter guide?** If the app starts in Powershell after running the `quickstart` command this means that you don't have a code editor installed. Please download a code editor as you will need this to add or modify code of your app. We recommend using [**VS Code**](https://code.visualstudio.com/Download) or [**PyCharm**](https://www.jetbrains.com/pycharm/download/). After installation you can open the folder `C:\Users\\viktor-apps\hello-viktor` in the code editor manually. ### Development workspace[​](/docs/getting-started/starter-guide/.md#development-workspace "Direct link to Development workspace") After creating the app and running the `quickstart` command to download the app code you are ready to start building. To do so, each app has its own development workspace. This is the place where you can see what your app looks like and try out the functionalities of the app. You can enter the development workspace in two different ways: 1. By clicking the 'Develop' button on the app card. The 3 latest apps you created are shown on the 'Develop' page. Alternatively, you can find all your apps by visiting the App store and selecting 'My apps'. ![](/img/docs/development-workspace-app-card.png) 2. By following the URL that is shown in the terminal when your app code connects to the VIKTOR platform. This is a direct link to the corresponding development workspace. ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` After you have entered the development workspace you should see your app. The app you are creating in this starter guide looks like this: ![](/img/docs/starter-guide-welcome.png) ## Create your first input fields[​](/docs/getting-started/starter-guide/.md#create-your-first-input-fields "Direct link to Create your first input fields") Open the `app.py` file in your code editor. This is where you will write the code of your app. The content should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") class Controller(vkt.Controller): parametrization = Parametrization ``` The `app.py` file consists of 3 parts: * **(line 1) imports**: this is where you import Python modules you use in your app * **(lines 4-5) Parametrization class**: this is where you define the inputs of your app * **(lines 8-9) Controller class**: this is where you define the outputs (such as visualizations) of your app A detailed explanation of the folder structure and above concepts can be found [here](/docs/getting-started/fundamentals/basic-app-structure/.md). App connection * The app will update automatically after adjusting and saving the `app.py` file (as long as you don't close the terminal!) * Closed your code editor or the terminal inside your editor? Use `viktor-cli start` to reconnect the app. Let's add a `NumberField` by copying the **highlighted** line of code. Your `app.py` file should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") length = vkt.NumberField("Length") class Controller(vkt.Controller): parametrization = Parametrization ``` Save the `app.py` file. This action triggers a reload of your app. This reload is shown in the terminal. If you made a coding mistake, errors will also be printed in the terminal. ``` INFO : Reloading app... INFO : App code loaded, waiting for jobs... ``` Refresh your webpage in the browser to see the "Length" input we just added: ![](/img/docs/starter-guide-inputs-1.png) Go ahead and click in the box just beneath "Length" to start typing. In many cases it is helpful to guide the user by providing a default value for the input fields. You can add a default value of 1 like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") length = vkt.NumberField("Length", default=1) class Controller(vkt.Controller): parametrization = Parametrization ``` Save the `app.py` file and refresh your webpage in the browser. Any pop-up regarding unsaved changes may be ignored. After reloading, your app will show the default value: ![](/img/docs/starter-guide-inputs-2.png) To conclude the parametrization of our design, we will add 2 more number fields representing the "Width" and "Height" respectively. Copy the **highlighted** lines of code below such that your `app.py` file looks similar: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") length = vkt.NumberField("Length", default=1) width = vkt.NumberField("Width", default=1) height = vkt.NumberField("Height", default=1) class Controller(vkt.Controller): parametrization = Parametrization ``` Save the `app.py` file and refresh your webpage in the browser: ![](/img/docs/starter-guide-inputs-3.png) ## Create your first visualization[​](/docs/getting-started/starter-guide/.md#create-your-first-visualization "Direct link to Create your first visualization") Now let's see how we can use these input fields in a result! In this example we will use the length, width, and height defined in the parametrization as dimensions of a cube. The cube's volume and outer surface area are the results we will show in a table view. Copy the **highlighted** lines of code below, such that your `app.py` file looks like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") length = vkt.NumberField("Length", default=1) width = vkt.NumberField("Width", default=1) height = vkt.NumberField("Height", default=1) class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Results") def results(self, params, **kwargs): data = [ [1, 2], [3, 4], ] row_headers = ["Row 1", "Row 2"] column_headers = ["Col 1", "Col 2"] return vkt.TableResult(data, row_headers=row_headers, column_headers=column_headers) ``` Save the `app.py` file and refresh your webpage in the browser: ![](/img/docs/starter-guide-view-1.png) Great, now let's connect the input values (obtained using the **params** argument) to the output. We will also rename the row and column headers to be more specific for our app: ``` import viktor as vkt class Parametrization(vkt.Parametrization): welcome = vkt.Text("# 👋 Welcome to your first VIKTOR app! 👋\n## Let's start with the basics") length = vkt.NumberField("Length", default=1) width = vkt.NumberField("Width", default=1) height = vkt.NumberField("Height", default=1) class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Results") def results(self, params, **kwargs): volume = params.length * params.width * params.height surface = 2 * (params.length * params.width + params.length * params.height + params.width * params.height) data = [ [volume, "m³"], [surface, "m²"], ] row_headers = ["Volume", "Surface"] column_headers = ["Value", "Unit"] return vkt.TableResult(data, row_headers=row_headers, column_headers=column_headers) ``` Save the `app.py` file and refresh your webpage in the browser: ![](/img/docs/starter-guide-view-2.png) Well done! You can now adjust the dimensions of the cube and directly see its effect on the volume and outer surface area. ## Automate the boring\![​](/docs/getting-started/starter-guide/.md#automate-the-boring "Direct link to Automate the boring!") With these basic instructions you now have the skills to build your very own apps! This is just the tip of the iceberg however. With VIKTOR you can also create 3D models, interactive data visualizations, automated reports, geographic maps and much more... Click the button below to continue your journey! * What's next [Learn more](/docs/getting-started/whats-next/.md) --- # What's next? Congratulations, you have successfully installed VIKTOR and built your first app! Now you are ready to follow your own path. What is the next step? Well, that all depends on your interests. * Do some concepts still raise questions for you? Don't worry, we advise you to check out the following pages: Basic app structure - get familiar with the app files, and building blocks required to create a basic app. [Learn more](/docs/getting-started/fundamentals/basic-app-structure/.md) * App code execution flow - learn how and when the VIKTOR platform triggers your application code, and the stateless behavior when running calculations. [Learn more](/docs/getting-started/fundamentals/call-flow/.md) - Explore all VIKTOR features and learn by following code examples: Tutorials - ramp up your VIKTOR skill by following one of the instructive tutorials [Learn more](/docs/tutorials/.md) - Guides - get an overview of all features in our documentation. Many input fields, results & visualization, layout options and more are available [Learn more](/docs/create-apps/.md) * Gain inspiration by checking out example applications: Example apps - we have many example apps you can use as inspiration to create your own apps. Source code included! [Learn more](https://www.viktor.ai/apps-gallery) Happy coding! And remember... **Automate the boring. Engineer the awesome!** ## Community VIKTOR is not only a platform for quickly creating apps; we are also a community of enthusiastic and ambitious developers searching for new ways to engineer the awesome. Join our community and ask for support, share ideas and learn about the latest features. [Community Page](https://community.viktor.ai/) ![](/img/illustrations/illustration-community.svg) --- # Manage apps With the VIKTOR platform you can build and distribute web applications, writing only Python. Next to facilitating a web-application environment with easily customizable elements, the VIKTOR platform has several extra features that help quickly create a user-friendly web-application. This section will cover these extra features. ## Architecture schematic[​](/docs/manage-apps/.md#architecture-schematic "Direct link to Architecture schematic") The following architecture schematic shows how the different workspaces, apps and workers relate to each other. ![](/assets/images/simplified-architecture-1ddbaf5d22fc52bf3a19b2de33445c69.png) --- # Access Management This page explains the controls that VIKTOR has to manage access to data and logic. These are divided in three categories: environment, workspace and app. The difference between workspaces and apps is explained [here](/docs/manage-apps/workspaces-and-apps/.md). ## Environment access[​](/docs/manage-apps/access-management/.md#environment-access "Direct link to Environment access") Access to the environment can be setup in two ways: * login with username and password * Single Sign-On (for more info see [this page](/docs/manage-apps/single-sign-on/.md)) ## Environment rights[​](/docs/manage-apps/access-management/.md#environment-rights "Direct link to Environment rights") Each user has two access attributes that determine the role they have. The possible combinations, together with their name are listed below. The matrix with their permissions is shown below. | Access level | Developer access | Role | | ------------- | ---------------- | ------------------ | | User | | Internal user | | User | ✓ | Internal developer | | Admin | | Admin user | | Admin | ✓ | Admin developer | | External user | | External user | | External user | ✓ | External developer | | | external user | external developer | internal user | internal developer | admin user | admin developer | | ---------------------------------- | ------------------ | ------------------ | ------------------ | ------------------ | ---------- | --------------- | | invite users to organization | n | n | n | n | y | y | | edit users on organization | n | n | n | n | y | y | | remove users | n | n | n | n | y | y | | | | | | | | | | create workspace | n | y\* | n | y\* | y | y | | edit workspace | if workspace admin | if workspace admin | if workspace admin | if workspace admin | y | y | | set workspace visibility to public | n | n | n | n | y | y | | archive workspace | if workspace admin | if workspace admin | if workspace admin | if workspace admin | y | y | | manage users in workspace | if workspace admin | if workspace admin | if workspace admin | if workspace admin | y | y | | | | | | | | | | access private workspace | when invited | when invited | when invited | when invited | y | y | | access internal workspace | n | n | y | y | y | y | | access public workspace | y | y | y | y | y | y | | | | | | | | | | view activity dashboard | n | n | n | n | y | y | | | | | | | | | | list and modify workers | n | n | n | n | y | y | | | | | | | | | | see appstore | n | n | y | y | y | y | | create app | n | n | n | y | y | y | | publish app version | n | y\* | n | y\* | n | y | \* Only for apps they maintain Besides rights on the environment, there are more granular controls on workspaces and apps. ## Workspace access[​](/docs/manage-apps/access-management/.md#workspace-access "Direct link to Workspace access") Access to the workspace is managed by setting the visibility of the workspace: * `private`: invited users see the workspace and have access * `internal`: everyone inside the company (excluding external users) can see and access the workspace * `public`: everyone can access the workspace using the URL (also people not logged in) ## Workspace rights[​](/docs/manage-apps/access-management/.md#workspace-rights "Direct link to Workspace rights") Workspace rights (what can a user do when they enter the workspace) are configured using usergroups. You define what this usergroup is allowed to do and assign users to this group. The possibible permissions per object type are: | category | detail | explanation | | -------- | -------- | ------------------------------------------------------------------------------------------ | | Read | Navigate | Minimum (navigation) access, excluding summary info and excluding editor access | | Read | Basic | Makes an object and its summary information accessible to a user, not including the editor | | Read | All | Gives access to all object information including the editor | | | | | | Write | Create | Allows the user to create an object | | Write | Update | Allows the user to update an object | | Write | Rename | Allows the user to rename an object | | | | | | Delete | | Allows the user to delete an object | Usergroup assignment differs between internal and private workspaces: * `private` workspaces: users are explicitly invited to get access. During invitation, the appropriate usergroup (and thus access level) is selected * `internal` workspaces: users automatically get access when they are invited to the environment. They are added to the default user group of each internal workspace. This default can be configured per workspace. ## Workspace admin[​](/docs/manage-apps/access-management/.md#workspace-admin "Direct link to Workspace admin") The administration of a workspace can be delegated to a specified "Workspace admin", which is assigned from the users on the workspace. This workspace admin can: * invite users (in the case of private workspace) * set access levels for the users * assign other workspace admins * archive the workspace ## App accesss[​](/docs/manage-apps/access-management/.md#app-accesss "Direct link to App accesss") All users (except for external users/developers) can access the app store and find the applications that have been created. Here they can checkout app details and learn about the application and which developers maintain the app. Apps are not used by users directly, these are workspaces (see [this explanation](/docs/manage-apps/workspaces-and-apps/.md)). The apps only contain the logic, without data and no users. Users can contact (one of) the maintainers, to get access. Internal developers and admin users can create apps. Developers are automatically assigned as the first maintainer on the app. ## App rights[​](/docs/manage-apps/access-management/.md#app-rights "Direct link to App rights") Only app maintainers can publish new versions of an app. They are treated as being allowed to have access to the code. This means that error reports (with tracebacks containing code) are available to them. App maintainers are not allowed to create workspaces. They can use their development workspace when developing, but need explicit access to relevant workspaces to get access to production data. --- # Activity Dashboard Administrators can inspect the activity within their organization using the activity dashboard in the Administator menu. Several different views, each with their own level of detail are available. The different options are described in the sections below. ![](/assets/images/user-activity-ae752fbcf994766a68a189f18e1a9076.png) ## Users[​](/docs/manage-apps/activity-dashboard/.md#users "Direct link to Users") A summary of the activity of all users is available on the Users tab. The activity data is presented as time series graphs and is split into three key metrics: 1. Total users (all users within the organization including developers) 2. Monthly active users (unique users that logged in to the environment at least once during a month) 3. Daily logins (a daily login is defined as a user that uses a workspace on a single day, excluding development and public workspaces) ## Developers[​](/docs/manage-apps/activity-dashboard/.md#developers "Direct link to Developers") The Developers tab provides a summary of the activity of Developers in the organization. The Developer activity is presented as time series graphs and is split into three key metrics: 1. Total developers (all users within the organization that have developer access) 2. Monthly active developers (unique users with developer access that logged in to the environment at least once during a month) 3. Daily developer logins (a daily developer login is defined as a user that uses his/her development workspace(s) on a single day) ## Workspaces[​](/docs/manage-apps/activity-dashboard/.md#workspaces "Direct link to Workspaces") The Workspaces tab provides an overview of the user activity within the different workspaces within the organization. The Workspaces activity is presented as time series graphs and is split into three key metrics: 1. Total users per workspace 2. Monthly active users per workspace 3. Daily logins per workspace ## Audit logs[​](/docs/manage-apps/activity-dashboard/.md#audit-logs "Direct link to Audit logs") ![](/assets/images/audit-logs-925cf4cde9014505e47c46d7f830666a.png) Historical data The bulk of the user events have been introduced in the platform release of April 2023. Before this time only a limited number of events are available. While the Users, Developers and Workspaces tabs give insights into the activity of your organization over time, it does not give insights into who was active and what activities were performed. The Audit log enables administrators to generate detailed activity overviews. These overviews are presented in tabular form and can be exported in CSV format. It is possible to generate an overview of daily user logins, daily developer logins, monthly user activity and monthly developer activity by selecting the corresponding activity type from the dropdown. The results can be filtered on users, workspaces (daily user logins only), start and end date. Furthermore, a detailed audit log is available by selecting 'Event' from the activity type dropdown. Events are recorded for specific actions performed by users within your organization. Each event entry shows the relevant information for that event, such as: * The user that performed the action * The type of action that was performed * (if applicable) The workspace that was affected by the event or the event occurred in * (if applicable) The app that was affected by the event * (if applicable) The entity that was affected by the event * The date and time of the event * Event specific information ### Event types[​](/docs/manage-apps/activity-dashboard/.md#event-types "Direct link to Event types") The table below gives an overview of the events that are currently available: | Event type | Description | | ----------------------------- | --------------------------------------------------------------------------------------------- | | `APP.ARCHIVE` | The user archived an app | | `APP.CREATE` | The user created an app | | `APP.PUBLISH` | The user published a new app version | | `APP.PUBLISH_FAIL` | The user published a new app version with errors | | `APP.UNARCHIVE` | The user unarchived an app | | `APP.UPDATE` | The user updated the app information | | `EDITOR.COMPUTE` | The user performed a calculation within the editor | | `EDITOR.ENTER` | The user entered the editor | | `EDITOR.EXIT` | The user exited the editor | | `ENTITY.COPY` | The user copied the entity | | `ENTITY.COPY_RECURSIVE` | The user copied the entity recursively | | `ENTITY.CREATE` | The user created the entity | | `ENTITY.DELETE` | The user deleted the entity | | `ENTITY.RENAME` | The user renamed the entity | | `ENTITY.REVISE` | The user restored a previous revision of the entity | | `ENTITY.SAVE` | The user saved the entity | | `ORG.DELETE_USERS` | The user deleted users from the organization | | `ORG.INVITE_USERS` | The user invited users to the organization | | `USER.CLI_DOWNLOAD` | The user downloaded the CLI in the onboarding process | | `USER.DEV_PAIRING_ACTIVATE` | The user activated their development account in the onboarding process | | `USER.DEV_PAIRING_RETRIEVE` | The user retrieved an activation code for their development account in the onboarding process | | `USER.DEV_PAIRING_VERIFY` | The token / username combination was verified in the onboarding process | | `USER.LOCK` | The user account was locked | | `USER.LOGIN` | The user logged in to the environment | | `USER.LOGIN_FAIL` | The login for the user account failed | | `USER.LOGOUT` | The user logged out of the environment | | `WORKSPACE.ARCHIVE` | The user archived the workspace | | `WORKSPACE.CHANGE_VISIBILITY` | The user changed the workspace visibility | | `WORKSPACE.CREATE` | The user created the workspace | | `WORKSPACE.DELETE_USERS` | The user deleted users from the workspace | | `WORKSPACE.ENTER` | The user entered the workspace | | `WORKSPACE.INVITE_USERS` | The user invited users to the workspace | | `WORKSPACE.UNARCHIVE` | The user unarchived the workspace | Below an overview of the available columns per event type and corresponding value types are shown: | Event type | Column | Example value | | ---------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------ | | All event types | Name | John Doe | | All event types | Email | JohnDoe\@viktor.ai | | All event types | Event | USER.LOGIN | | All event types | Date | January 23, 2023, 09:44 | | `APP.` events | App | my-first-app | | `WORKSPACE.`, `ENTITY.`, `EDITOR.` events | Workspace | My First Workspace | | `ENTITY.`, `EDITOR.` events | Entity | My First Entity | | `ORG.INVITE_USERS`, `ORG.DELETE_USERS`, `WORKSPACE.INVITE_USERS` | Users | Jane Doe, Jess Doe | | `WORKSPACE.CHANGE_VISIBILITY` | Old | INTERNAL (one of INTERNAL, PRIVATE, PUBLIC) | | `WORKSPACE.CHANGE_VISIBILITY` | New | PRIVATE (one of INTERNAL, PRIVATE, PUBLIC) | | `EDITOR.COMPUTE` | Type | view (one of view, parametrization, step, button, preprocess) | | `EDITOR.COMPUTE` | Result | result (one of created, error, error\_user, result, started, stopped, expired) | | `EDITOR.COMPUTE` | Duration (s) | 2.38 | | `EDITOR.COMPUTE` | Method Name | get\_geometry\_view | | `EDITOR.COMPUTE` | Method Label | 3D Model | --- # Enterprise IT VIKTOR is a low-code application development platform based on Python. This guide outlines the prerequisites to use VIKTOR within an enterprise IT environment. ## Device settings[​](/docs/manage-apps/enterprise-it/.md#device-settings "Direct link to Device settings") In order to develop applications on the VIKTOR platform the machine of a developer needs to meet the following requirements: * The machine runs a Windows or Linux operating system. * Python 3.10 - 3.13 (**64-bit**) is available or can be installed by the developer. * A code editor is available or can be installed by the developer. * The machine has internet access (TCP over port 443, TLS >= v1.2). ## Network / proxy settings[​](/docs/manage-apps/enterprise-it/.md#network--proxy-settings "Direct link to Network / proxy settings") The CLI is used to connect local application code (hosted on the machine of the developer) to a cloud-based development workspace. This requires an internet connection with network settings specified below. ### Domains[​](/docs/manage-apps/enterprise-it/.md#domains "Direct link to Domains") The following domains should be accessible on the machine of the developer in order to be able to use VIKTOR. * `*.viktor.ai` (`viktor.ai` and all of its subdomains) * `*.amazonaws.com` (all subdomains of `amazonaws.com`) If you want to be more restrictive, it is possible be more selective on the allowed urls, note these domains are subject to change, so we strongly recommend to whitelist all subdomains of `viktor.ai` & `amazonaws.com` Do replace `` with one of `eu1` for Frankfurt, `ap1` for Australia, `eu2` for London, `us1` for the US. Also do `` with your viktor subdomain (e.g. `acme` for `acme.viktor.ai`). * `addons.viktor.ai` (used in environments in Frankfurt) * `addons..viktor.ai` (for the other regions) * `api-.viktor.ai` (still used but deprecated, for environments in Frankfurt) * `api-..viktor.ai` (still used but deprecated, for environments in other regions) * `cloud.viktor.ai` * `community.viktor.ai` * `.viktor.ai` (for environments in Frankfurt, for example acme.viktor.ai) * `..viktor.ai` (for environments in other regions, for example acme.eu2.viktor.ai) * `connect.viktor.ai` (deprecated, used in some environments in Frankfurt) * `connect..viktor.ai` * `developers.viktor.ai` (for environments in Frankfurt) * `developers..viktor.ai` (for environments in other regions) * `docs.viktor.ai` * `errors.viktor.ai` * `sys.viktor.ai` (for environments in Frankfurt) * `sys..viktor.ai` (for environments in other regions) * `viktor.ai` * `viktor-storage.s3.amazonaws.com` (still used but deprecated, for environments in Frankfurt) * `viktor-storage-.s3.amazonaws.com` * `viktor-system.s3.amazonaws.com` Furthermore, installation of third-party Python packages requires access to: * `files.pythonhosted.org` * `pypi.org` * `pypi.python.org` ### SSL certificates[​](/docs/manage-apps/enterprise-it/.md#ssl-certificates "Direct link to SSL certificates") If a proxy is configured in such a way that the SSL certification chain is modified by replacing the root CA's certificate by a self-signed certificate, the developer may run into SSL cert verification errors while either installing or running an app locally: **errors while installing the app** Pip (the Python package manager) has introduced the [`truststore` feature](https://pip.pypa.io/en/stable/topics/https-certificates/) to use the system certificate store for Python versions 3.10 and higher. The VIKTOR CLI uses this feature automatically when you use a Python version that supports it. Therefore, the easiest solution is to use Python 3.10 or higher which can be configured depending on the selected isolation mode: * Virtual environment (venv) * Docker Install Python 3.10 or higher and configure this version for developing apps with the command `viktor-cli configure`. Change the Python version to 3.10 or higher in the `viktor.config.toml` file. **errors while running the app** By default Python's `requests` package does not use the system certificate store, but uses a bundled CA certificate store to establish secure connections. Because the certificate of the proxy is not present in the bundled CA certificate store an error will occur. VIKTOR automatically mounts the system certificates when making requests since SDK version `v14.15.2`. Therefore, the easiest solution is to develop apps using this version or higher. --- # Organization Settings The settings for the entire environment can be set under the `Settings` menu (administrators only). ## Customized appearance[​](/docs/manage-apps/organization-setting/.md#customized-appearance "Direct link to Customized appearance") Opening `Settings > Appearance` leads to a configuration page on which the admin can adjust the global theme of the company environment. This includes customization of the following elements: * logo's * login image * button colors ![](/assets/images/org_settings_appearance-85b42db02c3a4abe4849d86643b88e37.png) --- # Regional hosting VIKTOR allows customers to specify the precise geographic location for storing their customer data. This may be necessary for handling sensitive projects or complying with government legislation. ![](/assets/images/hosting-regions-6a6191f0f0ac83d97034814775c8cb9e.svg) ## Regions[​](/docs/manage-apps/regional-hosting/.md#regions "Direct link to Regions") VIKTOR is currently is available in the following regions: | region | abbreviation | status | | ----------------------- | ----------------- | ------------------- | | EU (Frankfurt) | `*.viktor.ai` | available (default) | | United Kingdom (London) | `*.eu2.viktor.ai` | available | | Australia (Sydney) | `*.ap1.viktor.ai` | available | | United States (Oregon) | `*.us1.viktor.ai` | available | We consider additional regions on a customer request basis. Please contact us at `support@viktor.ai` if you have specific requirements. ## Multi regional setup[​](/docs/manage-apps/regional-hosting/.md#multi-regional-setup "Direct link to Multi regional setup") In addition to hosting in a single region, VIKTOR also offers the capability of storing data in multiple regions and sync apps and users. This brings about several benefits: * User synchronization: Users are provisioned only once and enjoy a unified login experience across all regions. * App synchronization: Apps published in one region become automatically available in other regions, promoting consistency and accessibility. * Workspace data stored in specified regions: VIKTOR ensures compliance with regulations by storing workspace data in designated regions. --- # Single Sign On (SSO) The VIKTOR platform supports Single Sign On using the OpenID Connect protocol. In this guide the configuration on Microsoft Entra ID is laid out. This guide will walk you through all the required steps to configure your VIKTOR application, so that it uses OpenID Connect to authenticate to your Microsoft Entra ID, forcing your users to access it using their Entra ID account. Once you have completed this configuration you can enable an OpenID Connect "Log in with Microsoft Entra ID" button for your VIKTOR application. ![](/assets/images/login_screen_entra_id-8fb9a56b7089be03fd26043a2551223b.png) Upon request, we can customize the provider name "Microsoft Entra ID" in your login button label, with the label of your choosing. Additionally, to this guide you can see [Microsoft Entra ID - Register An App Quickstart Guide](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) as a reference. If Single Sign On is enabled, users will sign in using your Microsoft Entra ID, but there is no active synchronization between the Microsoft Entra ID and the VIKTOR environment. When you remove a user from your Microsoft Entra ID, this user will be blocked when trying to sign in through SSO, but the user will still be present in the users-list in the VIKTOR environment. note Users with a developer account have a second method of authentication, which is used when commands are executed from the [CLI](/docs/create-apps/references/cli/.md) (such as listing apps or publishing apps). The developer token expires 1 month after the last login, meaning that in case you revoke access (in Entra ID) for a developer user, he/she will automatically lose developer access after this month. Alternatively, you can revoke developer access immediately by manually deleting the developer user in the VIKTOR environment. ## Create a new Microsoft Entra ID Application[​](/docs/manage-apps/single-sign-on/.md#create-a-new-microsoft-entra-id-application "Direct link to Create a new Microsoft Entra ID Application") First, you need to open your Microsoft Entra ID portal, either by logging in to your Microsoft Entra admin center and then selecting the Microsoft Entra ID service, or by directly visiting [entra.microsoft.com](https://entra.microsoft.com). To create a new application, go to `App Registrations > New Registration`, as shown in the screenshots below. ![](/assets/images/sso1-83b1ae36d574f1958cd2ad7a2e19f0a5.png) ![](/assets/images/sso2-c7d8dab7386f01ff812f37a496c64f35.png) ![](/assets/images/sso3-ca7f44b9b2b6cdffdf755b42ecefeebc.png) Here we have configured our application’s Redirect URI. If your VIKTOR application is running at `https://{subdomain}.viktor.ai`, this value should be `https://{subdomain}.viktor.ai/api/oidc/callback/`. To avoid naming inconsistencies and to make it easier for your admins and users to discover the application, you can standardize the name of your VIKTOR applications as "VIKTOR {subdomain}". ## Set up the Microsoft Entra ID Application[​](/docs/manage-apps/single-sign-on/.md#set-up-the-microsoft-entra-id-application "Direct link to Set up the Microsoft Entra ID Application") 1. Application IDs After you have created the new application, you can find its IDs in the "Overview" page, as shown below. The Application (client) ID and Directory (tenant) ID will be used later to setup your VIKTOR application. ![](/assets/images/sso4-663ad90f26fb3dc4d7af69b9959201a0.png) 2. Configure permissions Next, you need to enable the required permissions for VIKTOR to be able to read the logged-in user’s basic information and register them to your VIKTOR application, after they have successfully logged in. Go to "API Permissions" and clear existing permissions. Add the required permissions by navigating to: Add a permission > Microsoft Graph > Delegated permissions. Select email, offline\_access, openid and profile, and click "Add permissions". Click "Grant admin consent for {tenant}". ![](/assets/images/sso5-31c5be96c949d51a0b5b3169c3401728.png) ![](/assets/images/sso6-d077e137756b489182d5465f30bb0639.png) ![](/assets/images/sso7-208988fae2c2214966eafa011f2f6123.png) ![](/assets/images/sso8-5ad5506786bd703b827db7722730fe86.png) 3. Setup for Single Logout To enable your VIKTOR application to log out a user when they log out from Microsoft Entra ID, you need to specify your application’s Logout URL, in the "Authentication" page. If your VIKTOR application is running at `https://{subdomain}.viktor.ai`, this value should be `https://{subdomain}.viktor.ai/api/oidc/logout/`. ![](/assets/images/sso9-644d8dd9559197dbb8f5e03e68af2b71.png) 4. Create a client secret Last, you need to create a client secret for your VIKTOR application to prove its identity when authenticating the user. Go to "Certificates & secrets" and add a client secret. Use description "Default" and expiration "Never". Copy the value of the secret for later use. If you have other requirements concerning the expiration of this secret you are free to choose so. Please remember that when changing this secret you will have to relay the new value with us. ![](/assets/images/sso10-0005c6045770dbb500072a99b40a1463.png) ![](/assets/images/sso11-949faee07c61694546045c73884fa11a.png) ![](/assets/images/sso12-bc4b5facdea1324bd5c4b3e2368d18f2.png) 5. Configure the application URL and logo If you decide to make this application discoverable to your user via their Access Panel or the O365 app launcher, then you may want to set up your application’s home page URL, to allow redirecting to the app, and logo. To do so go to "Branding". Here we have configured our application’s Home page URL. This value should be your VIKTOR application address `https://{subdomain}.viktor.ai`. Should you choose to use the VIKTOR logo, you can save and upload our official logo. ![](/assets/images/sso13-5141ba30efb0fc56dbf0a827e2be87f6.png) ### (Optional) Provision 'Guest' users with reduced access rights[​](/docs/manage-apps/single-sign-on/.md#optional-provision-guest-users-with-reduced-access-rights "Direct link to (Optional) Provision 'Guest' users with reduced access rights") It is possible to have new 'guest' users in Microsoft Entra ID added as [external user](/docs/manage-apps/access-management/.md#environment-rights) to the VIKTOR environment. In order to do so, Microsoft Entra ID needs to include the user's account status in the claims. Navigate to "Token Configuration", and click the "+ Add Optional Claim" button. For the Token type, select "ID", then under 'Claim' tick the "acct" option. Confirm your choices by clicking the "Add" button. ![](/assets/images/sso22-43ac1ac6d7e09e2626e6158af9b90fa5.png) info The guest role is set in VIKTOR when the user logs in for the first time. Updating the user role in VIKTOR at a later stage will permanently overwrite the setting. Modifying the account status in Microsoft Entra ID after the user has logged in to VIKTOR has no effect. ## Set up the VIKTOR Application[​](/docs/manage-apps/single-sign-on/.md#set-up-the-viktor-application "Direct link to Set up the VIKTOR Application") Now that your application is ready on Microsoft Entra ID, we will need the information below to setup your VIKTOR application: * Application (client) ID * Directory (tenant) ID * Client secret * (Optional) Custom provider name label to be shown in the login button, instead of "Microsoft Entra ID" in "Log in with Microsoft Entra ID". You can send this information via email to your contact person. \*\* Note: make sure to place the client secret in a file and lock it with password before sharing. Send the password separately, via SMS or phone call. \*\* If you have different policies for sharing password or secrets, feel free to follow them. In any case, do not send the secret as plain text. ## Provision the Application[​](/docs/manage-apps/single-sign-on/.md#provision-the-application "Direct link to Provision the Application") At this point the VIKTOR App is registered in your Microsoft Entra ID and can be used. To manage operational settings go to "Enterprise Applications" from the Microsoft Entra ID main page and search for "VIKTOR". Below you can find some settings you might want to consider. ### Assign application owners[​](/docs/manage-apps/single-sign-on/.md#assign-application-owners "Direct link to Assign application owners") To allow other users to configure and maintain the application, you can assign them as Owners. Go to Owners > Add and select the desired users. ![](/assets/images/sso14-7738a37e6a2385fb6465a8599de65a33.png) ### Assign users to the application[​](/docs/manage-apps/single-sign-on/.md#assign-users-to-the-application "Direct link to Assign users to the application") By default, your Microsoft Entra ID application will be configured to allow all your users to sign in. To allow only selected users to sign in, navigate to "Properties" and enable "User assignment required". If you want the application to be visible to the assigned users in their Access Panel and the O365 app launcher, also enable "Visible to users". ![](/assets/images/sso15-faff4f161b5346ebad56fcf5aad7f51b.png) To assign users to your application, go to Users and groups > Add user and select the desired users. ![](/assets/images/sso16-39a47d44c0c68cd1a4a40076b56d5355.png) For further information on how to set up user access follow [this guide](https://learn.microsoft.com/en-us/entra/identity-platform/howto-restrict-your-app-to-a-set-of-users). ## Enable self-service access[​](/docs/manage-apps/single-sign-on/.md#enable-self-service-access "Direct link to Enable self-service access") Self-service application access is a great way to allow users to self-discover your VIKTOR application from the [My Apps](https://myapps.microsoft.com/) portal. To allow your users to self-discover your VIKTOR application, you need to enable self-service application access first. A user who has requested access will be able to log in to the app only after his/her request has been approved. note Self-service application access is not available for guest users, only for members of your organization with a P1 or P2 license. ### Setup your application[​](/docs/manage-apps/single-sign-on/.md#setup-your-application "Direct link to Setup your application") To enable self-service you first need to create a group and assign it to your application. All user that will be approved to use the application via self-service will land in this group, thus acquiring access for your application. First go to "Groups" from the Microsoft Entra ID main page and create a "New group". In our case, we created a group called "Test group". Then go back to the Microsoft Entra ID main page, select "Enterprise applications", find your "VIKTOR" application and open "Users and groups". From this screen, assign the group you just created to your application, as shown below. ![](/assets/images/sso17-339ec1feedd6d347b7b0792725208695.png) Next, go to "Self-service". From here you can: * enable the self-service for your application * select the group where the users will land once they get access * select whether approval will be required before the user is able to login * select the users responsible for approving self-service requests ![](/assets/images/sso18-b2dd018a581c8a1b52ecaae926876cf4.png) To allow a member of your organization to self-service you need to assign a P1 or P2 license to them. From the Microsoft Entra ID main page, go to Licenses –> All products, select your "Microsoft Entra ID Premium P1" or "Microsoft Entra ID Premium P2" license, click "Assign" and select your users. ![](/assets/images/sso19-84e93491ce1142c9150460bc89c917ea.png) Alternatively, you can assign the licenses via your [Microsoft 365 admin center](https://admin.microsoft.com/#/licenses). ### The self-service flow in action[​](/docs/manage-apps/single-sign-on/.md#the-self-service-flow-in-action "Direct link to The self-service flow in action") After setting up self-service in your application, you have now enabled your users to request for application access via their [My Apps](https://myapplications.microsoft.com/) page. By clicking on "Add self-service apps", they will see a list of application they can request access for, like shown below. ![](/assets/images/sso20-b15891859d43eb4dc0e85cf784c7eda2.png) The user assigned to approve the self-service request will get an email for the application access requested by the user, like the one shown below. Approving the request will allow the user to login to the application. ![](/assets/images/sso21-8d9946d3f707c6d7d70c3b2ae3e60fd9.png) --- # Software integrations There are different ways to connect to third-party software from a VIKTOR app. Some external programs run locally, while others are accessed online. Summarizing the different methods to integrate with third-party software: | Integration | Installation | Usage | Admin required | | ------------------- | ------------ | -------- | -------------- | | Personal worker | local | personal | no | | Organization worker | local | shared | yes | | API tokens | cloud | shared | no | | OAuth 2.0 | cloud | personal | yes | More information can be found inside the [Develop apps](/docs/create-apps/software-integrations/.md) page. ## Workers[​](/docs/manage-apps/software-integrations/.md#workers "Direct link to Workers") A **worker** is a program created by VIKTOR that can be used to establish a connection between the VIKTOR platform and third-party software that runs outside the platform. With a worker a user is able to execute tasks using the third-party software and retrieve the results through the VIKTOR application. ### Architecture[​](/docs/manage-apps/software-integrations/.md#architecture "Direct link to Architecture") The component diagram below shows how the VIKTOR worker communicates with the VIKTOR cloud. There is a slight difference between production and development environments as shown in Figure 1. Communication between the worker and the VIKTOR cloud is established by a TCP connection encrypted using TLS 1.2. This connection originates from the worker to the VIKTOR cloud. In this manner it is not required to open ports to the public internet on the machine or company network. ![](/assets/images/simplified-architecture-1ddbaf5d22fc52bf3a19b2de33445c69.png) *Simplified component diagram for VIKTOR platform* ### Requirements[​](/docs/manage-apps/software-integrations/.md#requirements "Direct link to Requirements") This section outlines the requirements of the VIKTOR worker. The VIKTOR worker can be installed on any machine that is used to run the third-party software to be integrated with. #### Minimum requirements[​](/docs/manage-apps/software-integrations/.md#minimum-requirements "Direct link to Minimum requirements") * Processor: 64-bit AMD or Intel * Operating system: Windows * The third-party software that is to be integrated is installed and licenses are available * The VIKTOR worker requires outgoing TCP access to the internet over port 443. This is same port that is used for internet using HTTPS. #### Recommended requirements[​](/docs/manage-apps/software-integrations/.md#recommended-requirements "Direct link to Recommended requirements") * Processor: 64-bit AMD or Intel * Operating system: Windows Server * The third-party software that is to be integrated is installed and licenses are available * The VIKTOR worker requires outgoing TCP access to the internet access over port 443. This is same port that is used for internet using HTTPS. #### Considerations for server requirements[​](/docs/manage-apps/software-integrations/.md#considerations-for-server-requirements "Direct link to Considerations for server requirements") The requirements posed by the VIKTOR worker are negligible. the system requirements of the third-party software that is integrated with are leading. The recommended requirements for these software packages should provide you with a good starting point. Often performance bottlenecks can be traced back to the following causes: * The machine is not running an operating system that is tailored to servers (for example Windows Server). This will often lead to a lower uptime because of unexpected updates or reboots. * Engineering software often does not use parallelization to write results, the only thing that you can facilitate in this good read and write speed. We therefore recommend equipping the server with SSDs. * Not all engineering software uses multiple cores and some programs have been built for 32-bit processors instead of 64-bit processors. In this case the maximum amount of RAM that can be used is 4GB. In conclusion more cores and more RAM does always improve performance. * Most engineering software only use graphics cards (GPU) for the the user interface and not to solve models, which is restricted to the central processing unit (CPU). Therefore, it might not be required to equip the server with high- performance GPUs. * If hardware is no longer a bottleneck the amount of available licenses might be the bottleneck. This can happen when all licenses are in use by other users. Some software allows pinning the license to make sure it is always available. * VIKTOR applications allow for parallelization of external analysis tasks with the worker. If enough licenses are available and the machine has enough capacity the worker can be configured to execute tasks in parallel. ### Installation[​](/docs/manage-apps/software-integrations/.md#installation "Direct link to Installation") Environment administrators can set up integrations for the entire organization, while developers and users (if enabled\*) can create and set up integrations for personal use only. Select the correct tab below and follow the steps. \* The use of personal workers in **production workspaces** is disabled by default. Developers can enable it for their maintained apps in the [app edit dialog](/docs/manage-apps/workspaces-and-apps/.md#editing-an-existing-app). * Personal use * Organizational use 1. Navigate to the "My Integrations" tab in your personal settings 2. Select the 'Workers" tab 3. Click "Add worker" 4. Follow the steps provided in the modal ![](/assets/images/create-worker-integration-user-ec6fdf657bc9641d78e869c99f2bd81a.png) ![](/assets/images/create-worker-integration-user-dialog-a81fae0d69f14c170f99389d1a60c83f.png) 4.1. Select the software of choice 4.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 4.3. Copy the generated **connection key** and paste it when the installer asks for it caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Select the "Workers" tab 3. Click "Add worker" 4. Follow the steps provided in the modal ![](/assets/images/create-worker-integration-admin-4ccfb74c49d984e1f19a9fa6d3d67806.png) 4.1. Select the software of choice 4.2. Select the workspace(s) the integration should be available to 4.3. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 4.4. Copy the generated **connection key** and paste it when the installer asks for it Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. ### Operation[​](/docs/manage-apps/software-integrations/.md#operation "Direct link to Operation") After installation the worker can be operated in two ways, namely: * Starting the worker manually via the desktop shortcut. During installation a shortcut to the VIKTOR worker is created on the desktop. You can start the worker by double-clicking the shortcut. * (requires Administrator privileges) As scheduled task. During installation, you are asked to create a scheduled task for the worker. If this option has been selected the worker will automatically start after (re)boot of the server. We advise to run the worker as a scheduled task to make sure it is always connected to the platform. #### Creating a scheduled task manually[​](/docs/manage-apps/software-integrations/.md#creating-a-scheduled-task-manually "Direct link to Creating a scheduled task manually") note Creating a scheduled task requires Administrator privileges on your machine. When you have selected the option ‘Create scheduled task’ during installation of the worker, the worker will launch upon (re)boot of the server. You can check if a scheduled task has been created using the Windows Task Scheduler. You will need to start the Task Scheduler with administrator rights. The program can be started using the 'Start Menu' or through 'Start' > 'Windows Administrative Tools' > 'Windows Task Scheduler'. If the scheduled task for the VIKTOR worker is not present you can create a task as follows: 1. Select 'Create task' in the side menu . This action will open a new window. 2. Supply a name for the task in the tab 'General', for example `Viktor for ` 3. Under 'Security options' : 1. Select a user with the appropriate execution rights in the field 'When running the task, use the following user account' 2. Check 'Run whether user is logged on or not' * To use this option the user account requires 'Log on as a batch job' rights 4. Add a new trigger on the tab 'Triggers' using the 'New…' button. 1. Begin the task: At startup 5. Add a new action on the tab 'Actions' using the 'New…' button. 1. Action: Start a program. 2. Program/script: `C:\Program Files\Viktor for ``\viktor-worker-...-.exe` 3. Start in (optional): `C:\Program Files\Viktor for \` 6. Uncheck 'Stop the task if it runs longer than' in the tab 'Settings' 7. Save and start the task. #### Activity monitoring[​](/docs/manage-apps/software-integrations/.md#activity-monitoring "Direct link to Activity monitoring") A log is kept displaying all activity of the worker. This log shows at what time tasks have been started and completed. The location of the log file depends on the environment variables of the server. The logs are written to the `C:\ProgramData` folder or the first of the following variables `%TMP%`, `%TEMP%` en `%USERPROFILE%`. In the exceptional case that none of these variables are set the worker stores the log files in the Windows folder. #### Shared licenses[​](/docs/manage-apps/software-integrations/.md#shared-licenses "Direct link to Shared licenses") The VIKTOR worker only uses a license during execution of a task (e.g. running a simulation using the software package). If the program uses floating licenses this means that a licenses will only be taken from the license pool during the task. The license will be released upon completion of the task. ### Upgrading / Revoking[​](/docs/manage-apps/software-integrations/.md#upgrading--revoking "Direct link to Upgrading / Revoking") An update of the VIKTOR worker might become available. In that case you can install the new version as follows: 1. Uninstall the old version of the VIKTOR worker using the 'Add or remove programs' feature of Windows. 2. Install the new version of the worker by running the Windows Installer and completing the installation wizard. If the worker is no longer used or needed, please contact your environment administrator to revoke the worker through the administration panel or remove personal workers through the "My integrations" tab. Subsequently, the worker can be uninstalled from the machine. ### Security[​](/docs/manage-apps/software-integrations/.md#security "Direct link to Security") In this section we highlight the measures taken to incorporate security in the design of the VIKTOR worker. First of all, the worker only requires an outgoing connection to connect to the platform. Therefore, there is no need to open ports for incoming traffic or port-forwarding of incoming traffic to the machine from the outer network perimeter. Furthermore, a VIKTOR worker is built for a specific software package, so a worker is only able to perform one specific task. The exception to this is the generic worker, which we have developed to allow for integrations with software we do not have a specific integration with (yet). The following paragraph describes the way the generic worker can be used in more detail. The generic worker can be used to execute executables on the machine. In order to prevent abuse, the executables that can be called using the worker are defined in the worker configuration file and thus are controlled by the administrator of the server. The configuration file can be found in `C:\Program Files\Viktor\Viktor for \config.yaml`, unless you have chosen a different installation location. The worker is not allowed to call any other executables than the ones defined in the configuration file. Furthermore, any additional arguments that are used to call the executable with are fixed. These arguments are defined in the configuration file as well. In conclusion the administrator of the server is in full control of the executables that can be called using the generic worker and can be limited to only those that are required to run the analyses required by the application. ### Troubleshooting[​](/docs/manage-apps/software-integrations/.md#troubleshooting "Direct link to Troubleshooting") If the worker is not able to connect to the platform or successfully complete tasks the following checks can be performed to fix the problem yourself: 1. Inspect the log file. You can find this file in `C:\ProgramData\Viktor\Viktor for ``\logs\worker.log`. All errors that the worker encounters are logged in this file. In the exceptional case that `%ProgramData%` is not defined as an environment variable the log files are written to a different directory. In that case you can find the log in one of the following: `[ %TMP% | %TEMP% | %USERPROFILE% | C:\Windows ]` `\Viktor\Viktor for \logs\worker.log`. 2. Inspect the configuration file of the worker. You can find this file in `C:\Program Files\Viktor\Viktor for \config.yaml`, unless you have chosen a different installation directory during installation of the worker. 3. Inspect the availability of the licenses of the third-party software that is to be integrated with. In most cases this can simply be done by manually launching the program via the start menu. ### Known issues[​](/docs/manage-apps/software-integrations/.md#known-issues "Direct link to Known issues") #### SCIA Engineer[​](/docs/manage-apps/software-integrations/.md#scia-engineer "Direct link to SCIA Engineer") The solver of SCIA Engineer cannot be executed from a Windows service or scheduled task, due to ‘session 0 isolation’. Therefore, it is required that the VIKTOR worker integration with SCIA Engineer run in a user environment. This implies that a user account should always be logged on to make sure that tasks can be completed successfully. The vendor of the software is aware of this problem and looking into ways to fix this. In order to do this it is convenient to set up an account that logs on automatically upon (re)boot of the server. This account should have access to a SCIA Engineer license. To set up a VIKTOR worker to integrate with SCIA Engineer please proceed as follows: 1. Create a new user account with appropriate access rights. 2. Enable automatic logon for the account created in step 1, as described in [this article](https://support.microsoft.com/en-us/help/324737/how-to-turn-on-automatic-logon-in-windows). We want to stress that this logon procedure is “only advised when the computer has been physically protected and steps have been taken to prevent unauthorized users remotely accessing the register”. 3. The VIKTOR worker is supplied as a Windows Installer (.msi file). You can configure the worker by completing the installation wizard. 4. After installation a shortcut for the VIKTOR worker can be found on the Desktop and in the Start menu as `Viktor for `. By starting the application you enable the connection between the VIKTOR platform and the worker. 5. It is also possible to create a scheduled task that runs the VIKTOR worker. The task should be run by the account created in step 1. Furthermore, make sure to check the box ‘Run only when the user is logged on’. #### COM permissions[​](/docs/manage-apps/software-integrations/.md#com-permissions "Direct link to COM permissions") Several workers communicate using Windows COM. The following integrations use COM: * Excel * AxisVM * RFEM The user account running the workers needs to have the correct permissions. Although the permissions might be already correct for operating the worker from the desktop, running the worker as a scheduled task might require additional configuration. When you encounter problems it is helpful to inspect the 'Windows Logs' to see if any errors were raised during execution of the worker. The logs can be accessed using the following steps: 1. Open 'Component Services' (Start > Component Services). 2. Select 'Event Viewer (Local)'. 3. Select 'Windows Logs'. 4. Select 'System', this will open a list of logs of your system. 5. Inspect these logs for any errors related to the usage of Windows COM, this can be done by looking at the source of the log, which will be labeled 'DistributedCOM'. An error related to a lack of permissions might look like the example below: ![](/assets/images/com_error_log-610e0de6cf563965193e79f275adf977.png) *Example of Windows error log* The information from this log can be used to correctly configure permissions. First of all, the permissions for the CLSID and APPID should be set in the registry. Please follow the steps below: 1. Open the 'Registry Editor' as administrator. 2. Go to `Computer\HKEY_CLASSES_ROOT\CLSID\{INSERT_CLSID_FROM_LOG}`. Use the right mouse button to select 'Permissions'. 3. Add or select the user account you use to run the worker and select 'Full Control'. Click 'Apply' to store the new permissions. 4. Go to `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{INSERT_APPID_FROM_LOG}`. Use the right mouse button to select 'Permissions'. 5. Add or select the user account you use to run the worker and select 'Full Control'. Click 'Apply' to store the new permissions. Now the right permissions should be set in the DCOM config. Please follow the steps below to set the correct permissions: 1. Open 'Component Services' as administrator and select DCOM Config (Console Root > Computer > My Computer > DCOM Config). 2. To be able to see the corresponding AppIDs click 'View' and subsequently 'Detail', subsequently find the corresponding AppID from the event log. 3. Click the entry with the right-mouse button and open 'Properties', select the 'Security' tab. 4. Now select the option 'Customize' in 'Launch and Activation Permissions' and press 'Edit'. 5. Add or select the user account you use to run the worker and select 'Local Activation' and close the window by clicking 'Ok'. Finally close the 'Properties' window by pressing 'Apply'. Now the permissions should be configured correctly to run the worker from a local user account. #### Microsoft Excel UI elements[​](/docs/manage-apps/software-integrations/.md#microsoft-excel-ui-elements "Direct link to Microsoft Excel UI elements") The scheduled task that is created by the installer to run analyses with Microsoft Excel is able to run without problems in most cases. However, when the scheduled task is run from the SYSTEM account with the setting 'Run whether user is logged on or not' it is not possible for Excel to load any UI elements. This will cause any macro that uses 'User forms' to hang. These forms are sometimes used for progress bars during macro calculations. We advise that any user forms are stripped from Excel workbooks that are used for analyses using the VIKTOR worker. Microsoft has published an article with some considerations for server-side automation of Office programs, please read [this article](https://support.microsoft.com/en-us/topic/considerations-for-server-side-automation-of-office-48bcfe93-8a89-47f1-0bce-017433ad79e2). #### Microsoft Excel cells not updating[​](/docs/manage-apps/software-integrations/.md#microsoft-excel-cells-not-updating "Direct link to Microsoft Excel cells not updating") There can be differences in the behaviour of a macro when running Excel headless as compared to using the GUI. Notably, if your macro changes the value of a given cell, the values of the cells that are dependent on that value will not be updated automatically if the GUI is not open. This can be fixed by using the `Worksheet.Calculate` function in your marco to make sure the cells are updated as needed. More information on how to use `Worksheet.Calculate` function can be found in [this article](https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet.calculate\(method\)) ## OAuth 2.0 integrations[​](/docs/manage-apps/software-integrations/.md#oauth-20-integrations "Direct link to OAuth 2.0 integrations") **OAuth 2.0** (Open Authorization) is an industry-standard protocol that allows secure authorization to third-party software, without sharing their credentials. This enables users to access their third-party data from within a VIKTOR application, without exposing their login password. ### How it works (on a high level)[​](/docs/manage-apps/software-integrations/.md#how-it-works-on-a-high-level "Direct link to How it works (on a high level)") Once the integration is set up by an organization admin and added to an application by a developer, the end user will be able to log in to the third-party software. Here is how it will work for an end user on a high level. 1. **User initiates connection:** In an application, VIKTOR will redirect the user to the third-party software to request access. 2. **User grants permission:** The user logs in (if not already), reviews the access request, and approves or denies it. 3. **Temporary authorization code issued:** If approved, the third-party software sends a short-lived code to VIKTOR. 4. **Token exchange:** VIKTOR exchanges that code for an access token — a credential we can use to access specific data or perform limited actions on behalf of the user. ### Architecture[​](/docs/manage-apps/software-integrations/.md#architecture-1 "Direct link to Architecture") OAuth 2.0 enables secure, token-based access to third-party services without exposing user credentials. When a VIKTOR application needs to access external data, OAuth 2.0 facilitates a secure handshake between VIKTOR, the third-party service, and the end user. The process uses industry-standard security measures including encrypted communication, time-limited tokens, and scope-limited permissions to ensure that access is both secure and controllable. The diagram below shows how the protocol communicates with VIKTOR. ![](/assets/images/oauth-2-integration-protocol-10df4374587e3a6f0aba7ed32d29b1dd.png) *Diagram of OAuth 2.0 integration protocol* ### Requirements[​](/docs/manage-apps/software-integrations/.md#requirements-1 "Direct link to Requirements") * The third-party software to integrate with should support OAuth 2.0 in accordance with [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749). * OAuth 2.0 URLs should use **HTTPS** encryption. * Support for **PKCE** (Proof Key for Code Exchange) is recommended for enhanced security. * **Refresh tokens** should be supported for long-lived integrations without requiring frequent re-authentication, so it is highly recommended to add `offline-access` scope whenever possible. * **Scope-based permissions** can be set to limit access to only specific data and operations required by the VIKTOR application. ### Creating an OAuth 2.0 integration[​](/docs/manage-apps/software-integrations/.md#creating-an-oauth-20-integration "Direct link to Creating an OAuth 2.0 integration") caution You need to be an environment administrator in order to set up an OAuth 2.0 integration. **Environment administrators** are able to set up the OAuth 2.0 integration for all applications. **Developers** are able to use existing integrations in their applications. The diagram below outlines how administrators, users, and developers engage with OAuth 2.0 integrations at different stages. ![](/assets/images/oauth-2-sequence-flow-ebb1ad6b393db243726146c960c4bd70.png) *Diagram of OAuth 2.0 flow* Go to our list of [supported software](/docs/create-apps/software-integrations/.md#supported-software) and choose the software that you would like to integrate with for the installation guide. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Select the "OAuth 2.0 integrations" tab 3. Click "Add OAuth 2.0 integration" 4. Follow the steps provided in the modal ![](/assets/images/create-oauth-integration-admin-6294dcc35560eaff3a66c2546dd37259.png) 1. Select the software of choice 2. Fill in the basic information of the integration, including the app that the integration should be available to 3. Fill in the credentials needed to establish a connection. These credentials can found in your third-party software app. ![](/assets/images/create-oauth-integration-admin-configuration-details-7ced0828b6c88d9e12e5bb50d011c85e.png) *Credentials required for an OAuth 2.0 integration* Client secret For security reasons, the client secret will not be retrievable from within VIKTOR once the integration is created. --- # Workspaces and apps This page explains the concepts of workspaces and apps, shows their location in the interface and explains what can be configured. ## Workspace vs. app[​](/docs/manage-apps/workspaces-and-apps/.md#workspace-vs-app "Direct link to Workspace vs. app") A normal user mainly interacts with workspaces: this is where calculations can be performed. Inside the app store, the user can also find "apps", which are produced by developers. This section explains the difference between them. What makes this a bit difficult is that the term "app" is also used for fully functional applications on your phone. Within VIKTOR an app itself is not yet usable for an end-user as will be explained below (this is a workspace). **App** An app contains your logic and all the code that the programmer wrote: how the app is structured, how the input is organized, what the output looks like and what calculations should be performed (the entity types and their structure). As an example, you could have an app for calculating the volume of a beam. The app defines: * input: `length`, `width`, `height` * output: 3d model of beam, calculated volume * calculation: `vol = length * width * height` This app cannot yet be used by users. It misses the data: which users have access and the actual values that they inserted and stored. **Workspace** A workspace is the actual place where a user can perform calculations. In short, it's an app + data: both user and calculation data. If the app is a .exe, the workspace corresponds to the fully installed version of the simulation software on a particular computer. ![](/assets/images/workspace_app-7594a977430f12154ee03177c0f3cd76.png) You can have multiple workspaces of the same app with different data. For instance, you can create workspaces for different projects or split users between two different workspaces to separate the data and make sure that they cannot see each other's work: ![](/assets/images/two_workspaces_one_app-00011c23cdf960a07c479ca4e5c8ea68.png) ## Managing apps[​](/docs/manage-apps/workspaces-and-apps/.md#managing-apps "Direct link to Managing apps") Apps can be found in the app store page of the environment. All users (except for external users/developers) have access to this page, allowing easy discovery and seeing what's available. On the details page of the app the user can find images, a description and more information about the app. ![overview of apps](/assets/images/appstore_resized-8a988687f20d11d210d14578937df85b.gif) ### Creating a new app[​](/docs/manage-apps/workspaces-and-apps/.md#creating-a-new-app "Direct link to Creating a new app") Apps can be created by administrators and developers. Developers are automatically assigned as the first maintainer on the app they create. In the "App Store" menu, click on the "Create app" button in the top-right corner to create a new app. Select whether you want to: * Create an app from scratch * Create an app from an existing excel spreadsheet * Create an app from one of the many templates in our library ![App Creation options](/assets/images/create-new-app-options-f8f047dbe5e44922a98535bbd4aff234.png) ### Editing an existing app[​](/docs/manage-apps/workspaces-and-apps/.md#editing-an-existing-app "Direct link to Editing an existing app") The details of an existing app can be updated by navigating to the "App Store" menu, followed by clicking on the "Manage" button on the app card. On the details page, click the button "Edit App" in the top-right corner to go through the same steps as when you first created the app. ### Version history[​](/docs/manage-apps/workspaces-and-apps/.md#version-history "Direct link to Version history") All the versions of the app can be seen on a separate tab, accompanied by the publication date and developer that published this version: ![app versions page](/assets/images/app_versions-43d1026d05789e0d366458c1278cbc7f.png) ### Environment variables[​](/docs/manage-apps/workspaces-and-apps/.md#environment-variables "Direct link to Environment variables") ADMIN & MAINTAINERS ONLY Administrators and app maintainers can access the variables tab on the app. On this tab, environment variables can be created, adjusted, or deleted. For more information please refer to [using environment variables](/docs/create-apps/development-tools-and-tips/environment-variables/.md). ![app variables page](/assets/images/app_details_variables-d64e0def95e4d027d3ba9c6a408080b1.png) ### Apps archive[​](/docs/manage-apps/workspaces-and-apps/.md#apps-archive "Direct link to Apps archive") ADMIN & MAINTAINERS ONLY To archive apps that are no longer being used, administrators and app maintainers can click the three dots on the app card and then select the "Archive" option from the menu that appears. Archived apps can be inspected by clicking the "Archive" button in the top-right corner in the "App Store" menu. Apps can be unarchived by clicking the "Unarchive" button. Note that an app **cannot be archived** when: * the app has active workspaces accociated to it Solution: [Archive active workspaces first](/docs/manage-apps/workspaces-and-apps/.md#workspaces-archive) Note that an app **cannot be unarchived** when: * the apps limit has been reached Solution: [Contact VIKTOR](https://www.viktor.ai/contact) ## Managing workspaces[​](/docs/manage-apps/workspaces-and-apps/.md#managing-workspaces "Direct link to Managing workspaces") A VIKTOR environment may consist of multiple workspaces which are shown on the landing page when logging in. Each card represents a workspace and consists of a brief description of the functionalities. ![](/assets/images/workspaces-6abdf84241d5c27585f2660e657d1fba.png) ### Creating a new workspace[​](/docs/manage-apps/workspaces-and-apps/.md#creating-a-new-workspace "Direct link to Creating a new workspace") ADMIN & MAINTAINERS ONLY An administrator or app maintainer can either click "Create workspace" on an existing app card, or navigate to the "Workspaces" menu and click on the "Create workspace" button in the top-right corner to create a new workspace. note App maintainers are only allowed to create [private](/docs/manage-apps/access-management/.md#workspace-access) workspaces of an app they maintain. Upon creation, the app maintainer will be admin of the newly created workspace. ### Editing an existing workspace[​](/docs/manage-apps/workspaces-and-apps/.md#editing-an-existing-workspace "Direct link to Editing an existing workspace") ADMIN ONLY An administrator can edit a workspace by clicking on the three dots on the corresponding card in the workspaces panel. A modal opens in which you will be guided through the same steps as during the creation process. ### Workspaces archive[​](/docs/manage-apps/workspaces-and-apps/.md#workspaces-archive "Direct link to Workspaces archive") ADMIN ONLY To archive workspaces that are no longer being used, administrators can click the three dots on the workspace card and then select the "Archive" option from the menu that appears. Archived workspaces can be inspected by clicking the "Archive" button in the top-right corner in the "Workspaces" menu. Clicking the three dots on an archived workspace card allows you to unarchive the workspace. Note that a workspace **cannot be unarchived** when: * the latest published app version is running an unsupported version of the VIKTOR SDK Solution: [Upgrade the SDK version](/docs/publish-apps/upgrade-viktor-version/.md) * the workspaces limit has been reached Solution: [Contact VIKTOR](https://www.viktor.ai/contact) * the app is archived Solution: [Unarchive the app first](/docs/manage-apps/workspaces-and-apps/.md#apps-archive) ## Labels[​](/docs/manage-apps/workspaces-and-apps/.md#labels "Direct link to Labels") An admin can add labels to workspaces and apps. This enables users to filter and quickly find the tools relevant for them. For instance the labels can be used to distinguish between industry disciplines, such that a newly registered GIS user can quickly find the relevant workspaces for him/her. Besides filtering on labels, a user can also filter on workspace visibility and app name. ![workspaces with GIS label](/assets/images/labels_gis-7163adaf2837620fddf816a488666419.png) ### Labels on apps[​](/docs/manage-apps/workspaces-and-apps/.md#labels-on-apps "Direct link to Labels on apps") Besides labels on workspaces, labels can also be added to apps. These labels are pre-selected when a new workspace is created from this app. Besides filtering on these labels, users can also filter on the maintainer(s) of the app. ### Label admin[​](/docs/manage-apps/workspaces-and-apps/.md#label-admin "Direct link to Label admin") Admins can manage the labels by visiting a dedicated page in the interface. The environment will be filled with a starting list. In the enterprise tier these labels can be edited, removed and new labels can be created. ![managing labels page](/assets/images/labels_manage-dd13e251a16a96139017328eb071f568.png) ### Label inspiration[​](/docs/manage-apps/workspaces-and-apps/.md#label-inspiration "Direct link to Label inspiration") In the enterprise tier, labels can freely be generated and changed to meet specific needs of your company. To give some inspiration on potential use cases: * industry (in the starting list) * discipline (in the starting list) * integration/software package (in the starting list) * project name (on workspace) * development status (on app) --- # Publishing an app Publishing (also called "releasing" or "deploying") means that the application is uploaded to the VIKTOR platform, making the app available in the organization environment. Note that the source code is secure and **cannot** be inspected by users that have access to the online VIKTOR environment. Watch the video below to get a quick overview of how to publish an app. The steps described in the video are: 1. Creating a new application 2. Publish the application source code 3. Creating a new workspace note Free-tier VIKTOR developers (`cloud.viktor.ai`) can only publish [editor-type apps](/docs/getting-started/fundamentals/app-types/.md#editor-type-app) with a [public visibility](/docs/manage-apps/access-management/.md#workspace-access) on the workspace. ## Publish a new app[​](/docs/publish-apps/.md#publish-a-new-app "Direct link to Publish a new app") Publishing an app requires a handshake between environment admin and the developer (which may be the same person): 1. Creating a new application (developer) 2. Publish the application source code (developer) 3. Creating a new workspace (environment admin) These steps are outlined in the sections below. ### 1. Creating a new application[​](/docs/publish-apps/.md#1-creating-a-new-application "Direct link to 1. Creating a new application") Navigate to your VIKTOR environment and click **App Store** in the main menu. ![](/assets/images/create-app-8cdea338ce33a1ab9b443a95208b7e2a.png) Click on the **Create app** button and follow the steps: ![](/assets/images/create-app-step1-b2ba55ee90a992ca27f1fcffef3e182d.png) *Basic information* ![](/assets/images/create-app-step2-2f91ae4f18303fda6712c42a0ce27562.png) *Labels* ![](/assets/images/create-app-step3-e390d683fca13a229bf312094ec6a555.png) *Images* ![](/assets/images/create-app-step4-d70ee1645be445875ac3b4f407e27fa2.png) *Maintainers* ![](/assets/images/create-app-step5-f263429a60da771180057e84e462df3d.png) *Review* Please refer to the [Managing apps](/docs/manage-apps/workspaces-and-apps/.md#managing-apps) documentation for more information on apps. ### 2. Publish the application source code[​](/docs/publish-apps/.md#2-publish-the-application-source-code "Direct link to 2. Publish the application source code") note Free VIKTOR developers (`cloud.viktor.ai`) automatically have environment admin rights. After preparing the app in the online VIKTOR environment, the developer can publish the source code by using the [`publish`](/docs/create-apps/references/cli/.md#publish) command of the CLI: ``` viktor-cli publish ``` You can also override the tag and app name of your new published version by running the CLI command such below: ``` viktor-cli publish --registered-name --tag v0.1.0 ``` note * Although we use the term 'tag' as a variable for the publish command, this is not linked to the git tag. The CLI will not check out the tag you specify in the publish command, you will have to do this **manually** first (e.g. `git checkout `). * If you are using git the CLI respects the .gitignore file and uses git to gather the files for uploading to VIKTOR. * You can force the CLI to upload all files in the app folder by using the `--use-filesystem` flag. * If you have any uncommitted changes or unstaged files, the `publish` command will fail as a safety mechanism. The `registered-name` is specified in step 1 by the developer and can be inspected using the [`apps`](/docs/create-apps/references/cli/.md#publish) command of the CLI: ``` >>> viktor-cli apps The following apps are connected to your account: Name | Full name | Latest tag | SDK version | Status crane-demo | crane-demo.viktor.demo | v2.1 | 13.6.2 | published monitoring-demo | monitoring-demo.viktor.demo | v1.1 | 13.6.1 | published ... ``` or in the interface in the "App Store" menu: ![](/assets/images/appstore_app_names-b9cac3e5f11bf76aaa3758ad8a64170b.png) After pressing enter you will see a spinner which you can use to monitor the publication. Once you see the spinner it is not possible to cancel the process. It is not a problem if you accidentally close the CLI at this point, publishing will continue in the background. During publication several checks will be performed. If any problems occur you will be presented with the reason for failure. Please contact VIKTOR in case you are stuck. ### 3 Create / request a new workspace[​](/docs/publish-apps/.md#3-create--request-a-new-workspace "Direct link to 3 Create / request a new workspace") You need to create a workspace for your app to make it available for other users. If you are an organization admin, you can directly create a new workspace and add users by clicking the **Create workspace** button: ![](/assets/images/app-card-create-workspace-633dc189d4f2366b23df05484437b799.png) In case you do not have administrator rights, click on the **Details** button: ![](/assets/images/app-card-details-09f6de1ff3506f895b634a01b5375121.png) and request a new workspace by clicking **Request new**: ![](/assets/images/request-workspace-39d70b8b18f0cdb59804527bacfd5afa.png) Please refer to the [Managing workspaces](/docs/manage-apps/workspaces-and-apps/.md#managing-workspaces) documentation for more detail. ## Publish a new version of an existing app[​](/docs/publish-apps/.md#publish-a-new-version-of-an-existing-app "Direct link to Publish a new version of an existing app") Every new addition or change to the application source code requires a new release, which is done by directly publishing the source code as described in step 3 in the section above. Publishing a new version can be automated using [Continuous Deployment](/docs/create-apps/development-tools-and-tips/ci/.md#continuous-deployment) (CD) tools. Make sure to keep [backward compatibility](/docs/publish-apps/backward-compatibility/.md) in mind when creating new releases. caution In case of an entity type incompatible publish, follow these steps: 1. Use the `publish` command with the new app code 2. Wait for it to fail due to the incompatible change 3. Notify your contact person at VIKTOR (or send a message to ) and mention the incompatible change(s) 4. Await VIKTOR to republish with necessary adjustments in the database ## Limitations[​](/docs/publish-apps/.md#limitations "Direct link to Limitations") The following cases cannot be handled without intervention from VIKTOR. If you want to publish an app and encounter one of these limitations, please reach out to your contact person at VIKTOR to publish the application. * It is not possible to clear the database of an app before publishing. * It is not possible to publish an app that has incompatible entity type changes, e.g: * Removal / renaming of entity types that are already present in the database * Changing names of top-level entities --- # Backward compatibility In a VIKTOR application, a lot of valuable data and knowledge is gathered over time. It is very important that, even after numerous updated to the application logic, data that is saved years ago can still successfully be processed by the application logic today, and that it results in the same output. This ensurance is called backward compatibility. ## Backward incompatible changes[​](/docs/publish-apps/backward-compatibility/.md#backward-incompatible-changes "Direct link to Backward incompatible changes") The five most common cases for applications to become backward incompatible are: * An entity type is removed or the entity type has been renamed * An entity type is moved to a different parent entity type (i.e. the hierarchy is changed) * A parameter in the parametrization has been moved to a different path (e.g. `tab1.parameter` -> `tab2.parameter`) * A parameter in the parametrization has been renamed (e.g. `tab.section.parameter1` -> `tab.section.parameter2`) * A parameter is used in a different way (e.g. units are now in "m" instead of "mm") ## Testing backward compatibility[​](/docs/publish-apps/backward-compatibility/.md#testing-backward-compatibility "Direct link to Testing backward compatibility") The following manual steps can be performed to test compatibility of your code changes: 1. Install and start the app on the current deployed version 2. Start the app, create a few entities and make sure to save the input data 3. Stop the app and switch to the to-be-deployed version 4. Start the app (do not clear the database!) 5. Check if there are no unexpected errors or incorrect calculation results ## Best practices to avoid compatibility issues[​](/docs/publish-apps/backward-compatibility/.md#best-practices-to-avoid-compatibility-issues "Direct link to Best practices to avoid compatibility issues") Most of the backward compatibility issues can be avoided with some careful planning. Always keep backward compatibility in mind when setting up a new architecture or updating your current architecture: * When adding a new entity type, take some extra time to think about a proper name * When adding a new parameter to the Parametrization, take some extra time to think about a proper name * When defining a unit for a parameter, try to be consistent with the rest of the parameters in the app --- # Continuous Deployment (CD) Please refer to the [CI/CD](/docs/create-apps/development-tools-and-tips/ci/.md#continuous-deployment) guide for more information on continuous integration/deployment, and for example files for frequently used CI/CD platforms. --- # Platform limits Here you can find explanations on certain limits that are applied when developing VIKTOR apps and when they are running on production environments. ## Disk storage limit of 5 GB[​](/docs/publish-apps/limits/.md#disk-storage-limit-of-5-gb "Direct link to Disk storage limit of 5 GB") If your use case requires writing files to disk, keep in mind that we enforce a limit of 5 GB of available disk space. If this limit is exceeded, the job will fail. If your app requires more than that limit, please contact us. caution Note that writing files to disk can be unpredictable on production environments and it is usually advised against. For more details check how [files are persisted between jobs](/docs/getting-started/fundamentals/call-flow/.md#local-files-persistence-between-jobs). You can instead use the Persistant Storage, where also this limit does not apply. Read our [guide](/docs/create-apps/results-and-visualizations/storing-results/.md#persistent-storage) for more detail! --- # Upgrade VIKTOR version To upgrade the version of the VIKTOR [SDK](/sdk/api/.md) used in your app, modify your `requirements.txt` with the desired version: ``` viktor==14.24.0 ``` The latest SDK version and a list of all notable changes can be found in the [changelog](/sdk/changelog/.md). Don't forget to (re)[install](/docs/create-apps/references/cli/.md#install) your app after modifying the VIKTOR version (or any of the other Python dependencies), using: ``` viktor-cli install ``` note When [creating an empty app using the CLI](/docs/create-apps/references/cli/.md#create-app), the latest VIKTOR version (at that time) is automatically set in `requirements.txt`. ## Versioning[​](/docs/publish-apps/upgrade-viktor-version/.md#versioning "Direct link to Versioning") VIKTOR uses [semantic versioning](https://semver.org/) to denote different versions of the SDK. The convention that is used for the version number has format v**X**.**Y**.**Z**, where: * **X** is the major: increments when a backwards incompatible change is introduced. * **Y** is the minor: increments when a new functionality is added, without breaking compatibility with older versions. * **Z** is the patch: increments when the code can drop-in replace the previous code, or when documentation is added/changed. ## Release cycle[​](/docs/publish-apps/upgrade-viktor-version/.md#release-cycle "Direct link to Release cycle") Currently, we expect to release a **major** version of the SDK once a year. Support for the previous major version of the SDK will be dropped 15 months after the release of a new version. **Minor** versions of the SDK are released more frequently and can be expected to be released every month. **Patches** might be released in between minor versions containing bug fixes or changes to the docstring. ![Release schedule](/assets/images/sdk_release_cycle-0fad45d229f2ab5324fce62a6d7fead5.svg) *Release schedule* Workspaces with an app version that uses an unsupported version of the SDK can still be accessed after the support period ends. However, archived workspaces cannot be unarchived in this case. We will notify developers of upcoming end-of-life dates well in advance so there is enough time to upgrade apps to a newer version of the SDK. ## Upgrades & deprecations[​](/docs/publish-apps/upgrade-viktor-version/.md#upgrades--deprecations "Direct link to Upgrades & deprecations") ### Patch (`v1.2.3` -> `v1.2.4`)[​](/docs/publish-apps/upgrade-viktor-version/.md#patch-v123---v124 "Direct link to patch-v123---v124") Patch versions of the SDK are backwards compatible and, therefore, these releases can be used without modifying the code of your application. ### Minor (`v1.2.3` -> `v1.3.0`)[​](/docs/publish-apps/upgrade-viktor-version/.md#minor-v123---v130 "Direct link to minor-v123---v130") Minor versions of the SDK are backwards compatible and, therefore, these releases can be used without modifying the code of your application. Minor versions include deprecation warnings, that inform the developer on upcoming breaking changes that need to be addressed in order to use the next major release. Deprecation warnings are logged by the CLI if the code of your application requires modification. It is not mandatory to fix deprecation warnings when updating to a minor version. To make addressing deprecations easier we have started shipping automated code fixes. These automated fixes can be applied using the CLI [`fix`](/docs/create-apps/references/cli/.md#fix) command. ### Major (`v1.2.3` -> `v2.0.0`)[​](/docs/publish-apps/upgrade-viktor-version/.md#major-v123---v200 "Direct link to major-v123---v200") Migration guide v13->v14 A guide on how to migrate your app from v13 to v14 is available [here](/sdk/v13-to-v14/.md). A new major release introduces backwards incompatible changes. This means that the code of your application should be updated in order to use the new major version of the SDK. To make this process as easy as possible we provide you with [upgrade instructions](/sdk/upgrades/.md) for each change. To speed up the process of updating your app we have started shipping automated code fixes. These automated fixes can be applied using the CLI [`fix`](/docs/create-apps/references/cli/.md#fix) command. note From experience, upgrading your application to the next major version can be done in the order of a day development time. If you are having difficulty updating your application to new version of the SDK please do not hesitate to contact us. --- # Tutorials To see some more examples and improve your skills, pick one of our tutorials and learn more about creating awesome VIKTOR apps! ## Beginner level[​](/docs/tutorials/.md#beginner-level "Direct link to Beginner level") ![](/img/docs/cards/basic-three-d-tutorial.svg) ## [Basic 3D Models](/docs/tutorials/basic-3d-model/.md) Learn how to generate and visualise 3D models in a VIKTOR app ![](/img/docs/cards/map-tutorial.png) ## [Maps](/docs/tutorials/interactive-maps/.md) Learn how to display data on an interactive map in a VIKTOR app ![](/img/docs/cards/data-graph-tutorial.png) ## [Graphs & Data](/docs/tutorials/plots-and-data/.md) Process data with Pandas and show it on a Plotly graph in a VIKTOR app ![](/img/docs/cards/reporting-tutorial.svg) ## [Automatic reporting](/docs/tutorials/automatic-reporting/.md) Learn how to generate parametric reports in a VIKTOR app ![](/img/docs/cards/calculationspreadsheet-tutorial.svg) ## [Spreadsheet calculation](/docs/tutorials/spreadsheet-calculator/.md) Learn how to execute a spreadsheet calculation in a VIKTOR app ![](/img/docs/cards/script-to-app-tutorial.svg) ## [Python script to app](/docs/tutorials/python-script-to-app/.md) Convert your Python project to a VIKTOR app ![](/img/docs/cards/post-process-etabs-data-card.svg) ## [Process ETABS data](/docs/tutorials/process-etabs-data/.md) Post-process ETABS base reactions data into a heatmap ![](/img/docs/cards/staadpro-tutorial-card.png) ## [Process STAAD.Pro data](/docs/tutorials/process-staad-data/.md) Post-process STAAD.Pro Analysis results ## Intermediate level[​](/docs/tutorials/.md#intermediate-level "Direct link to Intermediate level") ![](/img/docs/cards/three-d-tutorial.jpg) ## [Advanced 3D Models](/docs/tutorials/intermediate-3d-model/.md) Learn how to generate and visualise advanced 3D models in a VIKTOR app ![](/img/docs/cards/scia-tutorial.jpg) ## [SCIA Engineer](/docs/tutorials/integrate-scia/.md) Learn how to create and analyse a SCIA Engineer model in a VIKTOR app ![](/img/docs/cards/dynamo-tutorial.png) ## [Dynamo integration](/docs/tutorials/integrate-dynamo/.md) Learn how to parametrically influence a Dynamo model in a VIKTOR app ![](/img/docs/cards/grasshopper-tutorial.svg) ## [Rhino/Grasshopper](/docs/tutorials/integrate-grasshopper/.md) Learn how to parametrically influence a Grasshopper model in a VIKTOR app ![](/img/docs/cards/etabs-sap2000-tutorial.png) ## [ETABS/SAP2000](/docs/tutorials/integrate-etabs-sap2000/.md) Learn how to parametrically influence an ETABS or SAP2000 model in a VIKTOR app ![](/img/docs/cards/staadpro-tutorial-card.png) ## [Bentley STAAD.Pro](/docs/tutorials/integrate-staadpro/.md) Learn how to integrate STAAD.Pro and parametrically design & analyse a frame in a VIKTOR app --- # Creating an editor-type app In this tutorial we will create an editor-only application, that can be used to visualize world population and life expectancy data in a few different ways: 1. bar chart of the Netherlands 2. animated scatter plot per continent 3. world map surface plot The end result can be downloaded [here](/files/docs/editor-tutorial-complete.zip). tip For more examples of applications, please visit the [sample apps](https://www.viktor.ai/apps-gallery) ## Creating an empty app[​](/docs/tutorials/app-type-editor/.md#creating-an-empty-app "Direct link to Creating an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ## Folder structure[​](/docs/tutorials/app-type-editor/.md#folder-structure "Direct link to Folder structure") The app has the following folder structure: ``` editor-tutorial ├── app.py ├── CHANGELOG.md ├── README.md ├── requirements.txt ├── tests │ └── __init__.py └── viktor.config.toml ``` Note that the app type ('editor') has been defined in `viktor.config.toml`: ## Dependencies[​](/docs/tutorials/app-type-editor/.md#dependencies "Direct link to Dependencies") Navigate to the newly created folder and open `requirements.txt` and add `plotly` as additional requirement. We will use this package to create the (interactive) visualizations. ``` viktor==X.X.X plotly ``` ## Installation[​](/docs/tutorials/app-type-editor/.md#installation "Direct link to Installation") After adding the additional requirement the app needs to be installed again. Navigate to your terminal in the code editor, close the connection using Ctrl+C and enter the following command: ``` viktor-cli install ``` And afterwards: ``` viktor-cli start ``` Go to your browser and refresh the page to verify that the app is installed and running as expected. You should see the app's editor, which is currently a blank page. note If you see the "Workspaces" menu upon logging in, click the "Open" button on the "Development" workspace. After opening, you will be redirected to the app's editor. ## Defining the editor (input / output)[​](/docs/tutorials/app-type-editor/.md#defining-the-editor-input--output "Direct link to Defining the editor (input / output)") Open `app.py` and replace it with the following code: ``` import viktor as vkt import plotly.express as px class Parametrization(vkt.Parametrization): graph = vkt.OptionField( "Life expectancy:", options=["The Netherlands", "Continents", "Global"], default="Continents", variant="radio", flex=100 ) class Controller(vkt.Controller): parametrization = Parametrization(width=20) @vkt.PlotlyView("Life Expectancy") def plotly_view(self, params, **kwargs): df = px.data.gapminder() if params.graph == 'The Netherlands': data = df.query("country == 'Netherlands' ") fig = px.bar(data, x='year', y='pop', color='lifeExp') elif params.graph == 'Continents': fig = px.scatter( df, x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country", size="pop", color="continent", hover_name="country", facet_col="continent", log_x=True, size_max=75, range_x=[100, 100000], range_y=[25, 90] ) elif params.graph == 'Global': fig = px.choropleth( df, locations='iso_alpha', color='lifeExp', hover_name='country', animation_frame='year', color_continuous_scale=px.colors.sequential.Plasma, projection='natural earth' ) else: raise NotImplementedError return vkt.PlotlyResult(fig) ``` In your browser, refresh the page to reload the editor. On the left side, you will now see radio buttons with the defined options. Go ahead and select another option and see how it influences the results on the right-hand side. ![](/assets/images/tutorial-editor-a56b0f7883dce450c93a5c59434320a1.png) --- # Creating a simple-type app In this tutorial we will create a simple-type application; an app that consists of only one single [entity type](/docs/getting-started/fundamentals/entities-and-entity-types/.md). note The main difference with the [editor-type app](/docs/tutorials/app-type-editor/.md) is that with the simple-type app you can create as many objects (entities) as you want. Each object editor stores its own (unique) data. The app visualizes world population and life expectancy data in a few different ways: 1. bar chart of the Netherlands 2. animated scatter plot per continent 3. world map surface plot The end result can be downloaded [here](/files/docs/simple-tutorial-complete.zip). tip For more examples of applications, please visit the [sample apps](https://www.viktor.ai/apps-gallery) ## Creating an empty app[​](/docs/tutorials/app-type-simple/.md#creating-an-empty-app "Direct link to Creating an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Simple' as app type when asked to make this choice and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ## Folder structure[​](/docs/tutorials/app-type-simple/.md#folder-structure "Direct link to Folder structure") The app has the following folder structure: ``` simple-tutorial ├── app.py ├── CHANGELOG.md ├── README.md ├── requirements.txt ├── tests │ └── __init__.py └── viktor.config.toml ``` Note that the app type ('simple') has been defined in `viktor.config.toml`: ## Dependencies[​](/docs/tutorials/app-type-simple/.md#dependencies "Direct link to Dependencies") Navigate to the newly created folder and open `requirements.txt` and add `plotly` as additional requirement. We will use this package to create the (interactive) visualizations. ``` viktor==X.X.X plotly ``` ## Installation[​](/docs/tutorials/app-type-simple/.md#installation "Direct link to Installation") After adding the additional requirement the app needs to be installed again. Navigate to your terminal in the code editor, close the connection using Ctrl+C and enter the following command: ``` viktor-cli install ``` And afterwards: ``` viktor-cli start ``` Go to your browser and refresh the page to verify that the app is installed and running as expected. You should see the app's editor, which is currently a blank page. note If you see the "Workspaces" menu upon logging in, click the "Open" button on the "Development" workspace. After opening, you will be redirected to the app's editor. ## Defining the editor (input / output)[​](/docs/tutorials/app-type-simple/.md#defining-the-editor-input--output "Direct link to Defining the editor (input / output)") Open `app.py` and replace it with the following code: ``` import viktor as vkt import plotly.express as px class Parametrization(vkt.Parametrization): graph = vkt.OptionField( "Life expectancy:", options=["The Netherlands", "Continents", "Global"], default="Continents", variant="radio", flex=100 ) class Controller(vkt.Controller): parametrization = Parametrization(width=20) @vkt.PlotlyView("Life Expectancy") def plotly_view(self, params, **kwargs): df = px.data.gapminder() if params.graph == 'The Netherlands': data = df.query("country == 'Netherlands' ") fig = px.bar(data, x='year', y='pop', color='lifeExp') elif params.graph == 'Continents': fig = px.scatter( df, x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country", size="pop", color="continent", hover_name="country", facet_col="continent", log_x=True, size_max=75, range_x=[100, 100000], range_y=[25, 90] ) elif params.graph == 'Global': fig = px.choropleth( df, locations='iso_alpha', color='lifeExp', hover_name='country', animation_frame='year', color_continuous_scale=px.colors.sequential.Plasma, projection='natural earth' ) else: raise NotImplementedError return vkt.PlotlyResult(fig) ``` In your browser, click on "+ Create", as shown in the image below. ![](/assets/images/create-entity-dc7424d74c6322e4d62ba5c33b78f08f.png) Fill in a name in the pop-up, and click “Create and open”, to create the object (entity) and open its editor. On the left side, you will now see radio buttons with the defined options. Go ahead and select another option and see how it influences the results on the right-hand side. Save your changes by clicking the disk icon in the top-right corner of the screen (encircled in red in the image below). ![](/assets/images/tutorial-simple-279d67b1cd21c33288855438c52baa96.png) --- # Creating a tree-type app In this tutorial we will create an application that implements a 'tree' entity type hierarchy, consisting of two [entity types](/docs/getting-started/fundamentals/entities-and-entity-types/.md) (with parent-child relation). The child entity type allows the user to click on a map to define a `GeoPoint`. The parent entity type collects the locations on each child entity and shows them together on a single map, making use of the [API](/docs/api/sdk/.md). The end result can be downloaded [here](/files/docs/tree-tutorial-complete.zip). tip For more examples of applications, please visit the [sample apps](https://www.viktor.ai/apps-gallery) ## Creating an empty app[​](/docs/tutorials/app-type-tree/.md#creating-an-empty-app "Direct link to Creating an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Tree' as app type when asked to make this choice and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ## Folder structure[​](/docs/tutorials/app-type-tree/.md#folder-structure "Direct link to Folder structure") The app has the following folder structure: ``` tree-tutorial ├── app │ ├── my_entity_type │ │ ├── __init__.py │ │ └── controller.py │ ├── my_folder │ │ ├── __init__.py │ │ └── controller.py │ └── __init__.py ├── CHANGELOG.md ├── README.md ├── requirements.txt ├── tests │ └── __init__.py └── viktor.config.toml ``` Note that the app type ('tree') has been defined in `viktor.config.toml`: ``` app_type = 'tree' ``` To keep things simple, we will stick to the current entity type and corresponding folder names within this tutorial. ## Installation[​](/docs/tutorials/app-type-tree/.md#installation "Direct link to Installation") Login to the app in your browser to verify that the app is installed and running as expected. You will be redirected to the app's dashboard. note If you see the "Workspaces" menu upon logging in, click the "Open" button on the "Development" workspace. After opening, you will be redirected to the app's dashboard. The tree-type app generated by the CLI consists of a top folder, called "My Folder", shown in the sidebar on the left side of the screen. ![](/assets/images/tutorial-tree-dashboard-c6f5344657f5c2e2faa8cc0bcca65de2.png) Click "My Folder" to enter the folder. Now, let's add a new object by clicking the + (create new object) button on the right side of the screen. You'll now see a menu where you can add a new object: ![](/assets/images/tutorial-tree-create-object-8064bb45fa9ce960865664e6449bf393.png) *Create a new object of type "My Entity Type"* Provide a name for the new object and click "Create and open", to create the new object and automatically navigate to the object's editor (it should be empty). From here, you can navigate back to "My Folder" in a few different ways: * By clicking the back button in the top right side of the screen: ![](data:image/png;base64,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) * By clicking the menu button in the top left corner of the screen. This will extend (or collapse) the side menu. You can expand "My Folder" to see all containing objects, or click on it: ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAvCAYAAAB30kORAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV/TSqVUHMwgIhKkOlkQFXHUKhShQqgVWnUwH/2CJg1Jiouj4Fpw8GOx6uDirKuDqyAIfoA4OjkpukiJ/0sKLWI8OO7Hu3uPu3cA16gomhUaBzTdNtPJhJDNrQrhV4TAI4JhDEmKZcyJYgq+4+seAbbexVmW/7k/R4+atxQgIBDPKoZpE28QT2/aBuN9Yl4pSSrxOfGYSRckfmS67PEb46LLHMvkzUx6npgnFoodLHewUjI14inimKrplM9lPVYZbzHWKjWldU/2wmheX1lmOs1BJLGIJYgQIKOGMiqwEadVJ8VCmvYTPv4B1y+SSyZXGQo5FlCFBsn1g/3B726twuSElxRNAF0vjvMxAoR3gWbdcb6PHad5AgSfgSu97a82gJlP0uttLXYE9G4DF9dtTd4DLneA/idDMiVXCtLkCgXg/Yy+KQf03QKRNa+31j5OH4AMdZW6AQ4OgdEiZa/7vLu7s7d/z7T6+wFkC3KhWlFeuQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+YEFAolEN7hcWIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAB3UlEQVRo3u2Zv27bMBDGvztTlLUGSJ4gk7unY70VnQs/pZE5yOaMyQO0U18gBbrKIqVjpywGTFIUZUWJ7gGOP5y++ytyzjnMzBgztAV6gV6g34GpHE6cc+i6DiICEYFzDm+VlIhARGBmMDNWqxWIaNB7NKROiwjatkXbtv0ipRSUUmDmy0Jba2GtHRSxoihQFMX40CICYwxEJE9SMUNr3SvqvaBFBE3TIHfnJyKUZRkNzlMDvyVy0zTRXy8a2hiDMWcr5xyMMfmgrbXZNBz6mjHJzbkc5bKYAAWh+9bgHBZ6k0M6mwralz/eNt51ndf5fv+A+/1jEtjP3Xfsdj+8byul+kOHtHVzfYXN5jYJ+ub6Cqlve5vL8Xi8SNU41ynX63WapqeyZE2HoJ8OzzgcXpKgtts7fNt+zQ8dNTeALv4VvJqu63oyiRARqqrqr+mhG8ZQ6CR5MLO3eoypad+YGoT22evff/j9608S9ObLLVLf9mraOYe6rieRR1VVZyUS1PS5VjrqiUApr6Y5xsEU0INGU2ZO2piHbOihXOJcjnLNGzEBiibRWo9at4kIWuu8iy0zoyzLUcD7nhA+/rHmdAGdzVnsNOqzOkCeds7ZnHqnsuX3xQK9QC/Qnwj6PxL+Hu+v+sNlAAAAAElFTkSuQmCC) * By clicking the breadcrumbs at the top of the screen: ![](data:image/png;base64,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) Delete the created entity afterwards. ## Defining the GeoPoint (child)[​](/docs/tutorials/app-type-tree/.md#defining-the-geopoint-child "Direct link to Defining the GeoPoint (child)") Let's modify `MyEntityType` so that the user can define a `GeoPoint` on a map. Open `app/my_entity_type/controller.py` and replace it with the following code: ``` import viktor as vkt class Parametrization(vkt.Parametrization): geo_point = vkt.GeoPointField("Select point") class Controller(vkt.Controller): parametrization = Parametrization @vkt.MapView("Map") def map_view(self, params, **kwargs): features = [] if params.geo_point: features.append(vkt.MapPoint.from_geo_point(params.geo_point)) return vkt.MapResult(features) ``` In your browser, open "My Folder" and create a few entities of type "My geo-point". Don't forget to select a point on the map for each of them and save (including the entity created at the start of this tutorial, if you did not delete it before). ## Defining the Overview (parent)[​](/docs/tutorials/app-type-tree/.md#defining-the-overview-parent "Direct link to Defining the Overview (parent)") To show all the geo-points we just created, let's modify `MyFolder` to iterate over all its children and obtain the point from the params for each of them. Open `app/my_folder/controller.py` and replace it with the following code: ``` import viktor as vkt class Controller(vkt.Controller): label = 'Overview' children = ['MyEntityType'] show_children_as = 'Table' @vkt.MapView("Map") def map_view(self, params, entity_id, **kwargs): features = [] for child in vkt.api_v1.API().get_entity(entity_id).children(): point = child.last_saved_params.geo_point if point: features.append(vkt.MapPoint.from_geo_point(point)) return vkt.MapResult(features) ``` In your browser, open the editor of "My Folder". Within the "Map" view, click the 3 dots and select "Center map", to fit all objects within the view. You should now be able to see all your previously created geo-points. --- # Tutorial - Automatic reporting note Estimated time: 30 minutes
Difficulty level: Beginner * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/automatic-reporting/.md#introduction "Direct link to Introduction") Welcome to this tutorial on automatic reporting in VIKTOR with Python! As an engineer or data scientist, generating reports is an essential part of your work. Reporting not only helps you understand the insights from your data but also helps you communicate your findings/results to stakeholders. In this tutorial, we will explore how to automate the process of generating reports in VIKTOR with python. We will cover: 1. [Creating a basic report](/docs/tutorials/automatic-reporting/.md#1-basic-setup) 2. [Adding a table with dynamic rows to the report](/docs/tutorials/automatic-reporting/.md#2-table-with-dynamic-rows) 3. [Adding a table with dynamic columns to the report](/docs/tutorials/automatic-reporting/.md#3-table-with-dynamic-columns) 4. [Including a figure in the report](/docs/tutorials/automatic-reporting/.md#4-adding-a-figure) 5. [Downloading the report](/docs/tutorials/automatic-reporting/.md#5-download-the-word-report) By the end of this tutorial, you will have created a simple VIKTOR application that makes an invoice. See gif below: ![](/assets/images/tutorial_reporting_animation-108813f0e37d9746463a499966c49403.gif) *What the app looks like once you've completed this tutorial* tip You can find the complete code [below](/docs/tutorials/automatic-reporting/.md#6-all-code-together). ## Pre-requisites[​](/docs/tutorials/automatic-reporting/.md#pre-requisites "Direct link to Pre-requisites") Prerequisites * You have some experience with reading Python code During the tutorial, we added some links to additional information; but don't let them distract you too much. Stay focused on completing the tutorial. After this, you will know everything you need to create an app which includes automatic reporting functionalities. ## 1. Basic setup[​](/docs/tutorials/automatic-reporting/.md#1-basic-setup "Direct link to 1. Basic setup") In this chapter, we will go through the process of generating a report automatically as fast as possible. In the following chapters, we will add more elements to the report. First, we will create a Word template and then fill this template with data from our app. At the beginning, you may feel that you are not making a lot of progress because we have to set the basis first, but we promise that we will end up adding stuff to your app and report at lighting speed ⚡ Let’s get started! ### Create an empty app[​](/docs/tutorials/automatic-reporting/.md#create-an-empty-app "Direct link to Create an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Create your Word template[​](/docs/tutorials/automatic-reporting/.md#create-your-word-template "Direct link to Create your Word template") To make a report in this tutorial we will use a hypothetical example, we will create an invoice. Depending on your situation you may choose to format this more in terms of an engineering report or consultancy presentation. To start, we will have to make a Word template to fill with information later. We will keep it basic for now and only add the client’s name, company, and date. We will use `tags` enclosed by double curly braces like this `{{company}}` to place information in the Word template. The string inside the double curly braces is known as the identifier, and we use it to place the correct values in the right tags. 1. Open an empty Word file and fill it similarly to the example below. Alternatively, you can download the [pre-made template](/files/docs/reporting-tutorial/Template_part1.docx) ![](/img/docs/tutorial-reporting-1.jpg) 2. Now, save your template in a `files` folder. Navigate to your app directory (most likely located somewhere similar to `C:\Users\\viktor-apps\reporting-tutorial`) and create the new folder there. Once you've created the new folder, save the template in it with the filename `Template.docx`. Your app folder should now look something like this: ``` reporting-tutorial ├── files │ └── Template.docx ├── tests ├── app.py ├── CHANGELOG.md ├── README.md ├── requirements.txt └── viktor.config.toml ``` ### App input fields[​](/docs/tutorials/automatic-reporting/.md#app-input-fields "Direct link to App input fields") The next step is to have some information to fill the template with. In this case, we will add 3 input fields to our app: `client_name`, `company`, and `date`. We will use a [`TextField`](/sdk/api/parametrization/.md#_TextField) and [`DateField`](/sdk/api/parametrization/.md#_DateField) for this. 1. Open `app.py`, and add the relevant fields to your parametrization. If you like you could accompany the fields with some instructive text. In the end your `app.py` file should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# Invoice app 💰 \n This app makes an invoice based on your own Word template") client_name = vkt.TextField("Name of client") company = vkt.TextField("Company name") lb1 = vkt.LineBreak() # This is just to separate fields in the parametrization UI date = vkt.DateField("Date") class Controller(vkt.Controller): parametrization = Parametrization ``` 2. Refresh your app, and you should see the input fields there. ### Filling the template with data[​](/docs/tutorials/automatic-reporting/.md#filling-the-template-with-data "Direct link to Filling the template with data") We will now fill the word template from the input fields. 1. First, import `Path` from `pathlib` at the beginning of you `app.py` file: ``` from pathlib import Path ``` 2. Now create a method called `generate_word_document` in your controller class. The resulting controller class would look like below: ``` class Controller(vkt.Controller): parametrization = Parametrization def generate_word_document(self, params): # Create emtpy components list to be filled later components = [] # Fill components list with data components.append(vkt.word.WordFileTag("Client_name", params.client_name)) components.append(vkt.word.WordFileTag("company", params.company)) components.append(vkt.word.WordFileTag("date", str(params.date))) # Convert date to string format # Get path to template and render word file template_path = Path(__file__).parent / "files" / "Template.docx" with open(template_path, 'rb') as template: word_file = vkt.word.render_word_file(template, components) return word_file ``` #### How this works[​](/docs/tutorials/automatic-reporting/.md#how-this-works "Direct link to How this works") 1. **List with information:** Inside `generate_word_document` we made a list `components` with all the information we want to put in the report. The [`WordFileTag`](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#wordfiletag) function has two arguments, the first argument is the identifier. This is used to find the location in the word template. The second argument is the value that needs to be placed at the location of the identifier in the template 2. **Open and render template**: The last part opens the template and uses the function [`render_word_file`](/sdk/api/external/word/.md#_render_word_file) to insert the information from the `components` list into the template. Finally, we need to return the filled template. ### Generate a PDF report[​](/docs/tutorials/automatic-reporting/.md#generate-a-pdf-report "Direct link to Generate a PDF report") Now that we have a filled template invoice, we can work on visualising it. In VIKTOR it is possible to show a pdf using the [`PDFView`](/sdk/api/views/.md#_PDFView). Follow the next steps: 1. Create a `pdf_view` method inside the controller class, after the `generate_word_document` method we just created. 2. Generate the invoice using the `generate_word_document` method we built in the previous section. 3. Convert word to pdf, with the [`convert_word_to_pdf`](/sdk/api/utils/.md#_convert_word_to_pdf) function. 4. Return a [`PDFResult`](/sdk/api/views/.md#_PDFResult). See code below for the resulting `pdf_view` method: ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.PDFView("PDF viewer", duration_guess=5) def pdf_view(self, params, **kwargs): word_file = self.generate_word_document(params) with word_file.open_binary() as f1: pdf_file = vkt.convert_word_to_pdf(f1) return vkt.PDFResult(file=pdf_file) ``` ### All code so far, just in case.[​](/docs/tutorials/automatic-reporting/.md#all-code-so-far-just-in-case "Direct link to All code so far, just in case.") Just in case something went wrong, here you can find all code together so far: **Complete code** ``` import viktor as vkt from pathlib import Path class Parametrization(vkt.Parametrization): intro = vkt.Text("# Invoice app 💰 \n This app makes an invoice based on your own Word template") client_name = vkt.TextField("Name of client") company = vkt.TextField("Company name") lb1 = vkt.LineBreak() # This is just to separate fields in the parametrization UI date = vkt.DateField("Date") class Controller(vkt.Controller): parametrization = Parametrization def generate_word_document(self, params): # Create emtpy components list to be filled later components = [] # Fill components list with data components.append(vkt.word.WordFileTag("Client_name", params.client_name)) components.append(vkt.word.WordFileTag("company", params.company)) components.append(vkt.word.WordFileTag("date", str(params.date))) # Convert date to string format # Get path to template and render word file template_path = Path(__file__).parent / "files" / "Template.docx" with open(template_path, 'rb') as template: word_file = vkt.word.render_word_file(template, components) return word_file @vkt.PDFView("PDF viewer", duration_guess=5) def pdf_view(self, params, **kwargs): word_file = generate_word_document(params) with word_file.open_binary() as f1: pdf_file = vkt.convert_word_to_pdf(f1) return vkt.PDFResult(file=pdf_file) ``` Now that we have a basic functional version of our report, let's add some more complicated elements. In the next sections we are going to add: 1. A table, with dynamic rows 2. A table with dynamic columns 3. A figure we're going to make ourselves Finally we'll also include functionality to download the report. ## 2. Table with dynamic rows[​](/docs/tutorials/automatic-reporting/.md#2-table-with-dynamic-rows "Direct link to 2. Table with dynamic rows") The simple steps to adding a table with dynamic rows into our invoice are: * Update the template * Add input fields for the table * Process the user input * Fill the template with the processed input ### Update the template[​](/docs/tutorials/automatic-reporting/.md#update-the-template "Direct link to Update the template") The table has a variable amount of rows (dynamic rows), meaning that the number of rows will vary depending on the input. We will do this by writing a for loop inside our template. Follow the steps or just download the [updated template](/files/docs/reporting-tutorial/Template_part2.docx) 1. Open your Word template and create a table with the appropriate column headings and layout. 2. Add a row below and paste the following line of code in the first cell to start the for loop: ``` {% tr for r in table1 %} ``` 3. Add another row and, in each column, add the following line of code, where `var` is the key name of the value (desc, qty, price, total): ``` {{r[var]}} ``` 4. Insert a bottom row and add the following line of code to close the for loop: ``` {% tr endfor %} ``` 5. Under this table, lets add the following line to show the total price: ``` ${{total_price}} ``` By following the steps, you added the table to the template, which should make it look like this: ![](/img/docs/tutorial-reporting-template-page1.PNG) ### Add input fields[​](/docs/tutorials/automatic-reporting/.md#add-input-fields "Direct link to Add input fields") For the table, we will add some input fields. 1. In your `Parametrization` class, under the fields we added before, add: ``` # Table table_price = vkt.Table("Products") table_price.qty = vkt.NumberField("Quantity", suffix="-", min=0) table_price.desc = vkt.TextField("Description", suffix="-") table_price.price = vkt.NumberField("Price", suffix="€", min=0) ``` 2. Refresh your app. You should see a nice table! ### Process user input[​](/docs/tutorials/automatic-reporting/.md#process-user-input "Direct link to Process user input") In order to enter the table and the final total amount on the invoice, we will create two methods. One to calculate the total price and another to process the data in the table. #### Calculate the total price[​](/docs/tutorials/automatic-reporting/.md#calculate-the-total-price "Direct link to Calculate the total price") Inside your `Controller` class, under the `PDFview` we made in last section, create this method: ``` @staticmethod def calc_total_price(params): # Get user entry from params product_table = params.table_price # Calculate total price from quantities and unit price quantities = [row["qty"] for row in product_table] prices = [row["price"] for row in product_table] total_price = 0 for qty, price in zip(quantities, prices): total_price += qty * price return total_price ``` This method takes the table and for every entered item in the table, it calculates the total price for that specific item and adds it to the overall total. Which is then returned by the method. #### Processing the table[​](/docs/tutorials/automatic-reporting/.md#processing-the-table "Direct link to Processing the table") The user input currently in the table does not provide all information for the invoice we have set up in the template. For this table we will also require a total cost per product. Inside your `Controller` class, under the `calc_total_price` method we just made, create this method: ``` def process_table(self, params): product_table = params.table_price for row in product_table: row["total"] = row["qty"] * row["price"] return product_table ``` ### Fill template[​](/docs/tutorials/automatic-reporting/.md#fill-template "Direct link to Fill template") Remember that we created the method called `generate_word_document` to add the data to the word template? Well, now we will modify that method to add the table data. 1. Just below the method definition, add these two lines like this: ``` def generate_word_document(self, params): #<--- this is just for your reference total_price = self.calc_total_price(params) table = self.process_table(params) ``` 2. Just a few lines under, in the part where we append the data to the components list, add: ``` components.append(vkt.word.WordFileTag("total_price", str(total_price))) # Convert price float to string components.append(vkt.word.WordFileTag("table1", table)) ``` 3. Update your app, fill in the table and check this amazing table inside your invoice! tip If you get stuck, you can always try to have a quick peek at the [complete code](/docs/tutorials/automatic-reporting/.md#6-all-code-together) at the end of this tutorial ## 3. Table with dynamic columns[​](/docs/tutorials/automatic-reporting/.md#3-table-with-dynamic-columns "Direct link to 3. Table with dynamic columns") In the previous section, we added a table with a fixed column and a variable number of rows. This time we will turn things around and create a table with fixed rows and variable columns because this could apply better to your situation, and we want to show you both options. The steps are the same as before, so let’s jump into it. ### Update the template[​](/docs/tutorials/automatic-reporting/.md#update-the-template-1 "Direct link to Update the template") Open the template and add a second table to it that looks as follows and don't forget to save. Or just use the [updated template](/files/docs/reporting-tutorial/Template_part3.docx) ![](/img/docs/tutorial-reporting-3.jpg) You may notice that, this time, we are creating a for loop in each row that loops through the columns. ### Adjust the data processing[​](/docs/tutorials/automatic-reporting/.md#adjust-the-data-processing "Direct link to Adjust the data processing") For this second table we also have to calculate the percentage of the total costs every product constitutes. Therefore, we will adjust the `process_table` method we made earlier. It should now look like the following (notice we are employing the `calc_total_price()` method created earlier in the process as well): ``` def process_table(self, params): total_price = self.calc_total_price(params) product_table = params.table_price for row in product_table: row["total"] = row["qty"] * row["price"] row["perc"] = str(round((row["total"] / total_price) * 100, 2)) + "%" return product_table ``` ### Fill template[​](/docs/tutorials/automatic-reporting/.md#fill-template-1 "Direct link to Fill template") For the sake of time, we will use the same input fields and calculation methods we made before. 1. To add the data to the template, go to `generate_word_document` and add: ``` components.append(vkt.word.WordFileTag("table2", table)) ``` 2. Update your app and see the new table in the report. Wow, that went lightning fast! ## 4. Adding a figure[​](/docs/tutorials/automatic-reporting/.md#4-adding-a-figure "Direct link to 4. Adding a figure") Now we will add a figure, and we will choose a pie chart because we are engineers and we love charts 😉 ### Generating the figure[​](/docs/tutorials/automatic-reporting/.md#generating-the-figure "Direct link to Generating the figure") To generate the figure you can use multiple different python libraries. In this tutorial we will not go into depth on this subject. The method below can take in the params as we created them earlier, create a pie-chart of the total division of products in the customer's order, and save that figure to a data object using the `BytesIO` package. 1. At the end of you code, inside the `Controller` class add this code: ``` @staticmethod def create_figure(params): product_table = params.table_price # Create figure fig, ax = plt.subplots(figsize=(16, 8)) products = [row["desc"] for row in product_table] qty = [np.round(row["qty"], 2) for row in product_table] ax.pie(qty, labels=products, autopct="%1.1f%%") ax.set_title("Pie chart total sold products") png_data = BytesIO() fig.savefig(png_data, format='png') plt.close() return png_data ``` 2. Don't forget the imports ``` from io import BytesIO import numpy as np import matplotlib.pyplot as plt ``` ### Update the template[​](/docs/tutorials/automatic-reporting/.md#update-the-template-2 "Direct link to Update the template") Open your template and place the following tag at the location where you want to see the pie chart. This should complete the template. Again, you can also download the [full template](/files/docs/reporting-tutorial/Template.docx) here: ``` {{ figure_sales }} ``` ### Insert Image in report[​](/docs/tutorials/automatic-reporting/.md#insert-image-in-report "Direct link to Insert Image in report") An image can be inserted using the [`WordFileImage`](/docs/create-apps/documents-and-spreadsheets/word-file-templater/.md#wordfileimage) object which requires a binary file handle. The method `create_figure` stores a png image in the `BytesIO` object. This object can be directly placed in the Word document through the `WordFileImage`. 1. You can paste the code below in the `generate_word_document` method underneath the tables and above the actual rendering of the Word file: ``` # Place image figure = self.create_figure(params) word_file_figure = vkt.WordFileImage(figure, "figure_sales", width=500) components.append(word_file_figure) ``` 2. Update your app, and you will see the chart. ## 5. Download the Word report[​](/docs/tutorials/automatic-reporting/.md#5-download-the-word-report "Direct link to 5. Download the Word report") The last step is to add a download button, the download enables the user to download a file in any format. In this case we will use it to download the report in Word format, just in case you want to add something manually. note The `PDFView` used in the previous chapter already allows the user to download the PDF file from the view directly. The case we're tackling with this download button is the one where the user would require the actual Word format. ### Create a download method[​](/docs/tutorials/automatic-reporting/.md#create-a-download-method "Direct link to Create a download method") The button we will make in the next step requires a file in the form of a [`DownloadResult`](/sdk/api/result/.md#_DownloadResult), so first we will make a simple method. At the end of your `Controller` class add: ``` def download_word_file(self, params, **kwargs): word_file = self.generate_word_document(params) return vkt.DownloadResult(word_file, "Invoice.docx") ``` ### Add a download button.[​](/docs/tutorials/automatic-reporting/.md#add-a-download-button "Direct link to Add a download button.") A [`DownloadButton`](/sdk/api/parametrization/.md#_DownloadButton) is added to the parametrization to allow the user to download the file with a single click. This button requires a `method` argument. This method is the method we just added to the controller class. note Pay attention to the way the method is added to the DownloadButton. This has to be in the format of a `string` so if the method (as in the example below) is called `download_word_file` then it should be added to the DownloadButton as `method="download_word_file"` At the end of your `Parametrization` class add the button: ``` # Downloadbutton download_word_file = vkt.DownloadButton('Download report', method='download_word_file') ``` ## 6. All code together[​](/docs/tutorials/automatic-reporting/.md#6-all-code-together "Direct link to 6. All code together") **Complete code** ``` import viktor as vkt import matplotlib.pyplot as plt import numpy as np from io import BytesIO from pathlib import Path class Parametrization(vkt.Parametrization): intro = vkt.Text("# Invoice app 💰 \n This app makes an invoice based on your own Word template") client_name = vkt.TextField("Name of client") company = vkt.TextField("Company name") lb1 = vkt.LineBreak() # This is just to separate fields in the parametrization UI date = vkt.DateField("Date") # Table table_price = vkt.Table("Products") table_price.qty = vkt.NumberField("Quantity", suffix="-", min=0) table_price.desc = vkt.TextField("Description", suffix="-") table_price.price = vkt.NumberField("Price", suffix="€", min=0) # Downloadbutton download_word_file = vkt.DownloadButton('Download report', method='download_word_file') class Controller(vkt.Controller): parametrization = Parametrization def generate_word_document(self, params): total_price = self.calc_total_price(params) table = self.process_table(params) # Create emtpy components list to be filled later components = [] # Fill components list with data components.append(vkt.word.WordFileTag("Client_name", params.client_name)) components.append(vkt.word.WordFileTag("company", params.company)) components.append(vkt.word.WordFileTag("date", str(params.date))) # Convert date to string format components.append(vkt.word.WordFileTag("total_price", str(total_price))) # Convert price float to string components.append(vkt.word.WordFileTag("table1", table)) components.append(vkt.word.WordFileTag("table2", table)) # Place image figure = self.create_figure(params) word_file_figure = vkt.WordFileImage(figure, "figure_sales", width=500) components.append(word_file_figure) # Get path to template and render word file template_path = Path(__file__).parent / "files" / "Template.docx" with open(template_path, 'rb') as template: word_file = vkt.word.render_word_file(template, components) return word_file @vkt.PDFView("PDF viewer", duration_guess=5) def pdf_view(self, params, **kwargs): word_file = self.generate_word_document(params) with word_file.open_binary() as f1: pdf_file = vkt.convert_word_to_pdf(f1) return vkt.PDFResult(file=pdf_file) @staticmethod def calc_total_price(params): # Get user entry from params product_table = params.table_price # Calculate total price from quantities and unit price quantities = [row["qty"] for row in product_table] prices = [row["price"] for row in product_table] total_price = 0 for qty, price in zip(quantities, prices): total_price += qty * price return total_price def process_table(self, params): total_price = self.calc_total_price(params) product_table = params.table_price for row in product_table: row["total"] = row["qty"] * row["price"] row["perc"] = str(round((row["total"] / total_price) * 100, 2)) + "%" return product_table @staticmethod def create_figure(params): product_table = params.table_price # Create figure fig, ax = plt.subplots(figsize=(16, 8)) products = [row["desc"] for row in product_table] qty = [np.round(row["qty"], 2) for row in product_table] ax.pie(qty, labels=products, autopct="%1.1f%%") ax.set_title("Pie chart total sold products") png_data = BytesIO() fig.savefig(png_data, format='png') plt.close() return png_data def download_word_file(self, params, **kwargs): word_file = self.generate_word_document(params) return vkt.DownloadResult(word_file, "Invoice.docx") ``` ## To infinity and beyond\![​](/docs/tutorials/automatic-reporting/.md#to-infinity-and-beyond "Direct link to To infinity and beyond!") Well done! You are now able to create an app that takes in user input and processes this automatically into a report which is shown as a `PDFView` and can be downloaded as a Word file! Of course, the journey doesn't end here. Check out some of our other [tutorials](/docs/tutorials/.md) or go to the [Create apps](/docs/create-apps/.md) where you can see the different options you have to create apps. --- # Tutorial - Create an interactive 3D building info Level: **Beginners**
Time: **30 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps)
***Not a reader?** feel free to follow this tutorial as a video* ## Introduction[​](/docs/tutorials/basic-3d-model/.md#introduction "Direct link to Introduction") Welcome to this tutorial on how to create a web app that takes you from making simple 3D elements, to combining them into a parametric building, using VIKTOR and Python! As an engineer or architect, you may work with changing requirements for a project. In this tutorial we will take an office building as an example. We will explore how to visualize 3D elements and create patterns from our inputs to create an interactive building with VIKTOR and python. Like this we wont need to change any code when we need to change the requirements of the building. 1. [Create and Install the app](/docs/tutorials/basic-3d-model/.md#1-create-install-and-start-an-empty-app) 2. [Adding 3D geometry](/docs/tutorials/basic-3d-model/.md#2-adding-a-3d-geometry) 3. [Let's make it interactive](/docs/tutorials/basic-3d-model/.md#3-lets-make-it-interactive) 4. [Complete Code](/docs/tutorials/basic-3d-model/.md#4-complete-app-code) By the end of this tutorial you will be able to make 3D elements and use them in patterns in a VIKTOR app and have a basic understanding of how you can use built-in VIKTOR elements to upgrade your visuals! Try the app we'll be building below: Need help? Are you encountering an error? Take a look at the [**complete app code**](/docs/tutorials/basic-3d-model/.md#5-complete-app-code). Also know that you can always ask for help at our [**Community Forum**](https://community.viktor.ai/), where our developers are ready to help with any question related to the installation, coding and more. ## 1. Create, install and start an empty app[​](/docs/tutorials/basic-3d-model/.md#1-create-install-and-start-an-empty-app "Direct link to 1. Create, install and start an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. **Did you encounter any errors?** * Always make sure to check the spelling of everything you placed in the command-line, a small mistake and the command you are trying to run may not be recognised! * If you are encountering: ``` ERROR: Exiting because of an error: no requirements.txt file PS C:\Users\\viktor-apps> ``` Then you are not in the correct folder! check the command-line and navigate to the 3d-building-tutorial folder. * If you are encountering: ``` Error: App definition is not compatible with the data currently stored in the database. Use the command 'viktor-cli clear' to clear the database. PS C:\Users\\viktor-apps\3d-building-tutorial> ``` That means you have not cleared the database yet! Use the `viktor-cli clear` to clear and then you can use `viktor-cli start` to start the app. No need to install it again! Not seeing any of these errors? Head over to our community! There is a good chance another developer encountered it and solved it too! ## 2. Adding a 3D geometry[​](/docs/tutorials/basic-3d-model/.md#2-adding-a-3d-geometry "Direct link to 2. Adding a 3D geometry") Lets jump into our `app.py` file and start working on our VIKTOR application. The first thing we will do is make sure we can see all our progress in the 3D view. For now we will leave the `Parametrization` as is. In the `Controller`, let's change the label to something like "Parametric Building" and add the `GeometryView`. The geometry that we will display is the `SquareBeam`, for now, lets make it a 1-by-1-by-1 block. ``` class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): block = vkt.SquareBeam( length_x=1, length_y=1, length_z=1 ) return vkt.GeometryResult(block) ``` Save your `app.py`, if you closed the terminal enter `viktor-cli start` and go to your cloud environment (e.g. ) to see your cube. If all went well you should now see a simple cube in the middle of your screen similar to the image below. You can zoom and pan around it with your mouse. If you click the three dots on the top right you can see some options that come standard with VIKTOR's `GeometryView`. ![](/assets/images/tutorial-parametric-cube-ff85e04c59270444e94154022b5eaa5f.png) ## 3. Let's make it interactive[​](/docs/tutorials/basic-3d-model/.md#3-lets-make-it-interactive "Direct link to 3. Let's make it interactive") To go from a simple cube to a parametric building we will have to: * make the cube adjustable in size to become a slab (ceiling of a floor) * make windows (to represent the floor) * make a window-slab-window-slab-etc pattern to make a building * duplicate the pattern to make multiple floors ### Parametrize the cube into a slab[​](/docs/tutorials/basic-3d-model/.md#parametrize-the-cube-into-a-slab "Direct link to Parametrize the cube into a slab") In order to turn the cube into a slab, we will make the dimension in the vertical axis fixed. That way we have a fixed ceiling/floor thickness. Then we will make the dimensions in the x and y direction variable. Let's start by adding a `NumberField` to the parametrization. You may add a minimum and a default value to make sure you are presented with a model on start up. In this case, a building's dimensions cannot be negative so we choose zero as the minimum and let's say our hypothetical client's lot is currently about 30x30 meters so we will choose that as our default. ``` class Parametrization(vkt.Parametrization): width = vkt.NumberField('Width', min=0, default=30) length = vkt.NumberField('Width', min=0, default=30) ``` If you navigate to your browser again, you will see these two fields appear on the left side of the window but the cube is still the same. To get our cube to turn into a slab, lets change the code. Notice how we change the hard-coded values of `length_x` and `length_y` to `params.length` and `params.width`. ``` class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): block = vkt.SquareBeam( length_x=params.width, #<-- change this length_y=params.length, #<-- change this length_z=1 ) return vkt.GeometryResult(block) ``` If you go back to the browser, you should now see that changing the code results in a change in the size of the block. When you refresh the page, you should see that the default dimensions for the width and length are 30, just like we coded in the parametrization. If all went well it should look something like the image below: ![](/assets/images/tutorial-parametric-slab-6a5e92c4643330d080607e20efba336a.png) ### Make the windows of the floor[​](/docs/tutorials/basic-3d-model/.md#make-the-windows-of-the-floor "Direct link to Make the windows of the floor") To make the windows of the floor we will assign materials. Since we already have our slab, lets call the material for that "concrete" and for our windows "glass". We can easily add these materials and their properties to the `get_geometry` method by using the `Color` and `Material` objects. ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): #Materials: glass = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) #<-- add this facade = vkt.Material("Concrete") #<-- add this block = vkt.SquareBeam( length_x=params.width, length_y=params.length, length_z=1 ) return vkt.GeometryResult(block) ``` Now we have two materials and a block, but we need to have two blocks, one to represent the concrete facade and the other for the windows. So, we can simply rename the block that we have, duplicate it for the windows and assign the materials. By grouping together the facade and the window we can have a single object that represents an entire floor. Let's also display this in our `GeometryView` to see our floor. ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): #Materials: glass = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) facade = vkt.Material("Concrete") floor_glass = vkt.SquareBeam( length_x=params.width, length_y=params.length, length_z=1, material=glass #<-- add this ) floor_facade = vkt.SquareBeam( length_x=params.width, length_y=params.length, length_z=1, material=facade #<-- add this ) floor = vkt.Group([floor_glass, floor_facade]) #<-- add this return vkt.GeometryResult(floor) #<-- Make sure to change this ``` You may have noticed that you still see the slab like before, it does not look like an entire floor including windows. That is because our windows are now inside of the slab. Lets change the values so that we have a bit of overhang and a bit of offset, just like some real buildings have. ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): #Materials: glass = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) facade = vkt.Material("Concrete") floor_glass = vkt.SquareBeam( length_x=params.width, length_y=params.length, length_z=2, #<-- change this material=glass ) floor_facade = vkt.SquareBeam( length_x=params.width+1, #<-- change this length_y=params.length+2, #<-- change this length_z=1, material=facade ) floor_facade.translate((0, 0, 1.5)) #<-- add this floor = vkt.Group([floor_glass, floor_facade]) return vkt.GeometryResult(floor) ``` The floor you have made should look something like the image below: ![](/assets/images/tutorial-parametric-floor-9090d83503546c915d3778f79faccd15.png) ### Duplicating a 3D element[​](/docs/tutorials/basic-3d-model/.md#duplicating-a-3d-element "Direct link to Duplicating a 3D element") Now you should be able to see a single floor in your `GeometryView`. The next step is to duplicate the floor to a certain amount. For this we will use VIKTOR's `LinearPattern`. Let's make the building 16 floors high and because our floor's thickness is equal to three we will make that the spacing. ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): ... floor = vkt.Group([floor_glass, floor_facade]) #<-- Use this line as a reference! building = vkt.LinearPattern(floor, direction=[0, 0, 1], number_of_elements=16, spacing=3) return vkt.GeometryResult(building) ``` If all went well, you should now see a 16 storey building in your browser similar to the image below. You should also be able to change the values of the width and length of this building. ![](/assets/images/tutorial-parametric-flat-1ba4c0a17df487cd9e8ecb65c5a0991a.png) Let's make it a bit more interesting by adding the number of floors to the parametrization and allowing the user to choose a color for their building. For this we add a `ColorField` and another `NumberField`. Since we want the building to have a default of 16, a minimum of 10 and a maximum of 40 floors , let's improve the user experience and make this a slider. ``` ... class Parametrization(vkt.Parametrization): ... number_floors = vkt.NumberField("How many floors", variant='slider', min=10, max=40, default=16) #<-- add this field building_color = vkt.ColorField("Facade Color", default=vkt.Color(221, 221, 221)) #<-- add this field ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): ... facade = vkt.Material("Concrete", color=params.building_color) #<-- add color here ... building = vkt.LinearPattern(floor, direction=[0, 0, 1], number_of_elements=params.number_floors, spacing=3) #<-- change to parametric input here return vkt.GeometryResult(building) ``` ### Improve the user's experience[​](/docs/tutorials/basic-3d-model/.md#improve-the-users-experience "Direct link to Improve the user's experience") The best applications make it easy for the user to reach their goal. By adding text we can inform the user about the application. We may also choose to add a schematic drawing or image to inform them visually. This can all be done in the Parametrization so let's add a `Text` to our app. ``` ... class Parametrization(vkt.Parametrization): intro_text = vkt.Text( "# 3D Parametric Building App 🏢\n" "In this app, the user can change the dimensions of the building, choose the amount of floors and a color for the facade. The app will generate a 3D building for the user as output." ) ``` The final app should now look like this: ### Well done\![​](/docs/tutorials/basic-3d-model/.md#well-done "Direct link to Well done!") If your app now works you have successfully completed this tutorial! You just made some architects shiver with those programming skills there! ## 4. Complete app code[​](/docs/tutorials/basic-3d-model/.md#4-complete-app-code "Direct link to 4. Complete app code") Were you able to do everything in this tutorial without error? If not, you can always take a look at the full code: **Complete code** ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro_text = vkt.Text( "# 3D Parametric Building App 🏢\n" "In this app, the user can change the dimensions of the building, choose the amount of floors and a color for " "the facade. The app will generate a 3D building for the user as output." ) width = vkt.NumberField('Width', min=0, default=30) length = vkt.NumberField('Length', min=0, default=30) number_floors = vkt.NumberField("how many floors", variant='slider', min=10, max=40, default=25) building_color = vkt.ColorField("Building Color", default=vkt.Color(221, 221, 221)) class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D building", x_axis_to_right=True) def get_geometry(self, params, **kwargs): #Materials: glass = vkt.Material("Glass", color=vkt.Color(150, 150, 255)) facade = vkt.Material("Concrete", color=params.building_color) floor_glass = vkt.SquareBeam( length_x=params.width, length_y=params.length, length_z=2, material=glass ) floor_facade = vkt.SquareBeam( length_x=params.width+1, length_y=params.length+2, length_z=1, material=facade ) floor_facade.translate((0, 0, 1.5)) floor = vkt.Group([floor_glass, floor_facade]) building = vkt.LinearPattern(floor, direction=[0, 0, 1], number_of_elements=params.number_floors, spacing=3) return vkt.GeometryResult(building) ``` ## Want to learn how VIKTOR works?[​](/docs/tutorials/basic-3d-model/.md#want-to-learn-how-viktor-works "Direct link to Want to learn how VIKTOR works?") If you are interested in how VIKTOR works behind the scenes, for example how it processes your input, expand the tabs below! #### How does it work?[​](/docs/tutorials/basic-3d-model/.md#how-does-it-work "Direct link to How does it work?") How does the Parametrization work? In the **Parameterization** class you can add input fields that allow the user to provide input to your app, and there are more than 20 [different input fields](/docs/create-apps/user-input/.md) you can use, including numbers, text, colors, images and files. Inside the Parametrization class, you can also format the [layout of your app](/docs/create-apps/layout-and-styling/.md) by adding sections, tabs, steps and pages. To show your Parametrization in the app, we need to add the line `parametrization = Parametrization` inside the `Controller` class, because it is the controller that determines what is shown and not. How does the Parametrization get saved? So you may be wondering, how do you get the information from the parametrization to my controller? Well, we do this automatically for you. The values of all parameters are stored in a single variable called `params` , which is accessible inside the Controller class. These variables are stored in a `Munch`; this is similar to a dictionary, but works with point denotation. Example: * Let's say we have a variable called `height` as a NumberField in our `Parameterization`. * To use it in a method in the `Controller`, define it as: `def my_method(self, params, **kwargs)` * You can now make calculations inside that method using our height parameter as `params.height`! How does the Controller work? The **Controller** class is the place where you add everything you want to calculate and show. As explained in this tutorial, we show results in a `View` and we always add views in our controller. You can even add several views in a single app by adding them to the controller class... and yes, we have [many Views](/docs/create-apps/results-and-visualizations/.md),for showing graphs, maps, 3D models, reports, images and more. In the Controller, you also do or call your calculation. Remember that the user input given in the parametrization, is accessible inside the Controller class in the variable The `params`. ## What's next[​](/docs/tutorials/basic-3d-model/.md#whats-next "Direct link to What's next") Very impressive! You have now learned the basics of the VIKTOR `GeometryView`. In this tutorial, we have only scratched the surface of what you can do using geometries in VIKTOR. So don’t stop your journey there! If you like an extra challenge, here are some ideas: * Can you make the windows opaque? * Can you make the height of the windows/floors parametric as well? Maybe a client is looking for fancy floor-to-ceiling windows with minimal overhang? Or just follow some of our other [tutorials](/docs/tutorials/.md) More about geometries You can find more information about how to use the `GeometryView` in the [Geometry guide](/docs/create-apps/results-and-visualizations/threed-model/.md). It also includes some of the geometry elements that VIKTOR offers out of the box. --- # Your first ETABS app After you have downloaded the 'ETABS getting started' template, this step-by-step guide will explain you how to complete it. We will explain how you can process and visualize outputs from ETABS. You'll see how to export these outputs from ETABS into a file, upload them into VIKTOR and post-process reaction loads for various load combinations. Along the way, you will work with Plotly and Pandas, using the flexible tools and building blocks that VIKTOR offers. Here is what we'll cover: 1. [Add the required input fields](/docs/tutorials/etabs-getting-started/.md#1-add-input-fields) 2. [Processing the uploaded `.xlsx` file exported from ETABS](/docs/tutorials/etabs-getting-started/.md#2-process-the-xlsx-file) 3. [Adding processed data into a field so that the user can select from the results](/docs/tutorials/etabs-getting-started/.md#3-allow-user-selection-of-load-combinations) 4. [Visualizing results based on those selections](/docs/tutorials/etabs-getting-started/.md#4-visualize-reaction-loads-with-plotly) By the end of this tutorial, you will be able to generate a heatmap of the reaction loads for your structure by selecting specific load cases. This will allow you to gain valuable insights from your results and easily share them with your clients and team. Additionally, you will learn how to automate this process using VIKTOR. The final result will look like the figure below: ![](/assets/images/tutorial_post_processing_etabs_app_complete-8865fcdf600b903fee9186bf9b9728f7.png) ## 1. Add input fields[​](/docs/tutorials/etabs-getting-started/.md#1-add-input-fields "Direct link to 1. Add input fields") Let's add some text and input fields for the user to upload their file into. We will include a `FileField` to upload our `.xlsx` file and an `OptionField` to select a load combination from our Excel file. Replace the placeholder `Text` that explained you where to find these instructions with the **highlighted** lines of code in `app.py`, save the file and refresh the app in the browser. You should now see the input fields you just added to the code. ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=[]) class Controller(vkt.Controller): parametrization = Parametrization ``` The result should look like the image below. Now that the inputs are sorted, we will continue with processing the ETABS data. ![app](/assets/images/tutorial_post_processing_etabs_app_components-25b066b5d91373002aa25c6aab1b5a45.png) ## 2. Process the XLSX file[​](/docs/tutorials/etabs-getting-started/.md#2-process-the-xlsx-file "Direct link to 2. Process the XLSX file") ### Sample ETABS exported `.xlsx` file[​](/docs/tutorials/etabs-getting-started/.md#sample-etabs-exported-xlsx-file "Direct link to sample-etabs-exported-xlsx-file") For this tutorial, you can use this sample data from `etabs_tutorial.xlsx` located in your app folder, but don't worry; at the end of this tutorial, we will guide you on how to export this data from ETABS and create your own file. ### Processing the uploaded xlsx file[​](/docs/tutorials/etabs-getting-started/.md#processing-the-uploaded-xlsx-file "Direct link to Processing the uploaded xlsx file") The next step is to process the data from the uploaded Excel file. It's a good idea to do this processing in a separate function, that we'll name `process_etabs_file`. This function will extract the unique load combinations (which will be used later in our `OptionField`) and the joint reactions. The goal is to combine this data with the joint coordinates to create a DataFrame that can be used to plot the heatmap in the Plotly view. Below is the logic in the code, along with a breakdown. Add the highlighted lines of code to `app.py` and save the file.   ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=[]) class Controller(vkt.Controller): parametrization = Parametrization ``` ### How this works[​](/docs/tutorials/etabs-getting-started/.md#how-this-works "Direct link to How this works") 1. In the top of the file we import Pandas, which we'll use to load the file content into dataframes 2. The function reads the excel file and extract the necessary sheets: **Joint Reactions** and **Objects and Elements - Joints**. 3. Then we filter for and remove the rows that we want based on the required data, keeping columns `Global X`, `Global Y`, and `Global Z`. 4. Finally, merge the processed **Joint Reactions** data with the joint coordinates using the `Unique Name` column as the key. This merged DataFrame includes all the necessary information to plot a heatmap. 5. This functions returns two things at once, the unique load combinations and the merged dataframe. ## 3. Allow user selection of load combinations[​](/docs/tutorials/etabs-getting-started/.md#3-allow-user-selection-of-load-combinations "Direct link to 3. Allow user selection of load combinations") With the function to process the uploaded file done, we can now use that processed data in the `Parametrization`. We will allow users to select a load combination from the unique load combinations. To get the unique load combinations into the `OptionField`, we can use a callback function. Let's call it `get_load_combos`. It will get the unique load combinations from `read_file` and update our `OptionField` to display a dropdown with the correct options. Add the highlighted lines of code to `app.py` and don't forget to reference the `get_load_combos` in the `selected_load_combo` field. ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) # Only use the first returned item, the load_combos return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization ``` By replacing the `options=[]` with a reference to the callback function (`options=get_load_combos`) we fill the field with the processed load combos from the file (if there is a file uploaded). ## 4. Visualize reaction loads with Plotly[​](/docs/tutorials/etabs-getting-started/.md#4-visualize-reaction-loads-with-plotly "Direct link to 4. Visualize reaction loads with Plotly") Once the user selected a load combination, we filter the data to focus on the selected load combination. Then we use Plotly to generate an interactive heat map. To visualize a Plotly figure in a VIKTOR app we can add a `PloltyView` method to the `Controller`. We will add a scatter plot to represent each joint from the ETABS data, with its color indicating the magnitude of the reaction load (FZ) in kN. This visualization allows you to clearly observe how loads are distributed across the base floor, making it easier to analyze and interpret the results. Copy the **highlighted** piece of code and add it to `app.py`. ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) # Only use the first returned item, the load_combos return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyView("Heatmap") def plot_heat_map(params,**kwargs): if params.selected_load_combo: _, merged_df = process_etabs_file(params.xlsx_file) # Filter the dataframe based on the selected load combination filtered_df = merged_df[merged_df["Output Case"] == params.selected_load_combo] FZ_min, FZ_max = filtered_df["FZ"].min(), filtered_df["FZ"].max() # Create plotly scatter plot fig = go.Figure( data=go.Scatter( x=filtered_df["Global X"], y=filtered_df["Global Y"], mode='markers+text', marker=dict( size=16, color=filtered_df["FZ"], colorscale=[ [0, "green"], [0.5, "yellow"], [1, "red"] ], colorbar=dict(title="FZ (kN)"), cmin=FZ_min, cmax=FZ_max ), text=[f"{fz:.1f}" for fz in filtered_df["FZ"]], textposition="top right" ) ) # Style the plot fig.update_layout( title=f"Heatmap for Output Case: {params.selected_load_combo}", xaxis_title="X (m)", yaxis_title="Y (m)", plot_bgcolor='rgba(0,0,0,0)', ) fig.update_xaxes( linecolor='LightGrey', tickvals=filtered_df["Global X"], ticktext=[f"{x / 1000:.3f}" for x in filtered_df["Global X"]], ) fig.update_yaxes( linecolor='LightGrey', tickvals=filtered_df["Global Y"], ticktext=[f"{y / 1000:.3f}" for y in filtered_df["Global Y"]], ) return vkt.PlotlyResult(fig) else: return vkt.PlotlyResult({}) ``` ### This code explained[​](/docs/tutorials/etabs-getting-started/.md#this-code-explained "Direct link to This code explained") 1. At the top of the file, we import Plotly, which we'll use to create the plot 2. At the top of the function, we use `process_etabs_file` again, but this time we only use the second returned item, the merged dataframe. 3. The dataframe is filtered, based on the selected option in `params.selected_load_combo`. We also find the lowest and highest values for FZ. 4. Using Plotly, we create a scatter plot based on the filtered dataframe. Using the lowest and highest values for FZ the colors are determined for each point. 5. Finally, we apply some styling to the figure, like adding a title, setting linecolors and text for the tickmarks ### The resulting app[​](/docs/tutorials/etabs-getting-started/.md#the-resulting-app "Direct link to The resulting app") Refresh your app in the browser. You will now see the empty graph appear on the right side of the screen. You can now upload the Excel sheet with ETABS loads in the upload field. After that select one of the load combinations, and a heatmap will display the magnitudes, color-coded, along with the joint locations. You can try any combination and test it with any ETABS model. Our final app will look like this: ![app](/assets/images/tutorial_post_processing_etabs_app_complete-8865fcdf600b903fee9186bf9b9728f7.png) ## Complete code[​](/docs/tutorials/etabs-getting-started/.md#complete-code "Direct link to Complete code") Were you able to do everything in this tutorial without error? If not, you can always look at the full code: ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyView("Heatmap") def plot_heat_map(params,**kwargs): if params.selected_load_combo: _, merged_df = process_etabs_file(params.xlsx_file) # Filter the dataframe based on the selected load combination filtered_df = merged_df[merged_df["Output Case"] == params.selected_load_combo] FZ_min, FZ_max = filtered_df["FZ"].min(), filtered_df["FZ"].max() # Create plotly scatter plot fig = go.Figure( data=go.Scatter( x=filtered_df["Global X"], y=filtered_df["Global Y"], mode='markers+text', marker=dict( size=16, color=filtered_df["FZ"], colorscale=[ [0, "green"], [0.5, "yellow"], [1, "red"] ], colorbar=dict(title="FZ (kN)"), cmin=FZ_min, cmax=FZ_max ), text=[f"{fz:.1f}" for fz in filtered_df["FZ"]], textposition="top right" ) ) # Style the plot fig.update_layout( title=f"Heatmap for Output Case: {params.selected_load_combo}", xaxis_title="X (m)", yaxis_title="Y (m)", plot_bgcolor='rgba(0,0,0,0)', ) fig.update_xaxes( linecolor='LightGrey', tickvals=filtered_df["Global X"], ticktext=[f"{x / 1000:.3f}" for x in filtered_df["Global X"]], ) fig.update_yaxes( linecolor='LightGrey', tickvals=filtered_df["Global Y"], ticktext=[f"{y / 1000:.3f}" for y in filtered_df["Global Y"]], ) return vkt.PlotlyResult(fig) else: return vkt.PlotlyResult({}) ``` ## Export your own results from ETABS[​](/docs/tutorials/etabs-getting-started/.md#export-your-own-results-from-etabs "Direct link to Export your own results from ETABS") If you want to try this app with your own data, first run your analysis and then export the reaction loads from your ETABS model. Navigate to `File menu > Export > ETABS Tables to Excel` within ETABS, and select the **Joint Reactions** and **Objects and Elements - Joints** tables, as shown in the figure below: ![app](/assets/images/tutorial_post_processing_etabs_app_etabs_export_tables-3b6491b6ff487ff248154828d98bb520.png) warning Ensure that your exported Excel file contains these specific sheets. Without them, the app won’t be able to read and process the data correctly. Set the model units to international system units. The model expects the loads in kN and in millimeters (mm). ## What's next?[​](/docs/tutorials/etabs-getting-started/.md#whats-next "Direct link to What's next?") In this tutorial, you learned how to post-process results exported from ETABS. Your next goal could be to implement automation using the CSI API from your VIKTOR app. To achieve this, the best place to start is the following [tutorial](/docs/tutorials/integrate-etabs-sap2000/.md). If you want to explore more use cases where VIKTOR shines, feel free to check out our other [tutorials](/docs/tutorials/.md)! --- # Tutorial - Integrate Dynamo note Estimated time: 45 minutes
Difficulty level: Intermediate * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/integrate-dynamo/.md#introduction "Direct link to Introduction") Welcome to this tutorial on creating an app that integrates with Dynamo! In this tutorial, we will explore how to render a basic house with Dynamo and visualize it in your app. As a starting point, the user will provide parameters such as the number of houses, width, depth, number of floors, and heights for floors and roofs. These parameters are sent to Dynamo Sandbox using a worker, the program that establishes the connection between VIKTOR and the third-party software, and are used to generate the geometry of the house. The geometry is then converted to a mesh, which is rendered and visualized in VIKTOR. In this tutorial, we will cover the step-by-step process of setting up a VIKTOR app with a Dynamo integration: * [Setup VIKTOR app](/docs/tutorials/integrate-dynamo/.md#1-setup-a-viktor-app) * [Create a method to update Dynamo file](/docs/tutorials/integrate-dynamo/.md#2-create-a-method-to-update-dynamo-file) * [Create a mocked GeometryView](/docs/tutorials/integrate-dynamo/.md#3-create-a-geometryview-with-mocked-ouput-files) * [Create a data processing method](/docs/tutorials/integrate-dynamo/.md#4-create-a-data-processing-method) * [Create a Data View with the mocked output files](/docs/tutorials/integrate-dynamo/.md#5-create-a-dataview-with-mocked-ouput-files) * [Create a geometry processing method](/docs/tutorials/integrate-dynamo/.md#6-create-a-geometryanddataview-with-the-mocked-output-files) * [Add the logic to execute the Dynamo script with a worker](/docs/tutorials/integrate-dynamo/.md#7-integrate-dynamo) * [Setting up worker](/docs/tutorials/integrate-dynamo/.md#8-setting-up-worker) By the end of this tutorial, you will have created a simple VIKTOR application that generates the geometry of a house and calculates some basic properties. For the final result see the GIF below: ![](/assets/images/tutorial_dynamo_animation-aa15e4df6c7c7b04ae2303f71dda41a7.gif) tip You can find the complete code [below](/docs/tutorials/integrate-dynamo/.md#all-code-together) ## Pre-requisites[​](/docs/tutorials/integrate-dynamo/.md#pre-requisites "Direct link to Pre-requisites") Prerequisites * You have some experience with reading Python code In the tutorial, we added some links to additional information; but don't let them distract you too much. Stay focused on completing the tutorial. After this, you will know everything you need to create an app which includes an integration with Dynamo (Sandbox). ## 1. Setup a VIKTOR app[​](/docs/tutorials/integrate-dynamo/.md#1-setup-a-viktor-app "Direct link to 1. Setup a VIKTOR app") ### Create an empty app[​](/docs/tutorials/integrate-dynamo/.md#create-an-empty-app "Direct link to Create an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Add input fields[​](/docs/tutorials/integrate-dynamo/.md#add-input-fields "Direct link to Add input fields") We will add 6 numeric input fields to our app: `number_of_houses`, `number_of_floors`, `depth`, `width`, `height_floor` and `height_roof`. For these inputs a [`NumberField`](/sdk/api/parametrization/.md#_NumberField) will be used. Open `app.py`, and add the relevant fields to the `Parametrization` class. If you like you can accompany the fields with a descriptive text. After adding the fields your `app.py` file should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization ``` Refresh the development workspace in your browser and you should the input fields appear. ## 2. Create a method to update Dynamo file[​](/docs/tutorials/integrate-dynamo/.md#2-create-a-method-to-update-dynamo-file "Direct link to 2. Create a method to update Dynamo file") In this section, we will define a function that updates the Dynamo file with the parameters provided by the user. This will be done by defining a `staticmethod` on the `Controller` class, similar to what is described in the [Dynamo](/docs/create-apps/software-integrations/dynamo/.md) section of the VIKTOR documentation. Before you continue, download the sample [dynamo file](/files/docs/dynamo-tutorial/dynamo_model_sample_app.dyn) and save it the app folder next to `app.py`. The following code will update the nodes of the Dynamo file and generate an input file with the parameters defined in your app: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file ``` Let us go through the above mentioned logic: 1. Retrieve the input files for the analysis, in this case the `dynamo_model_sample_app.dyn` file, and create a `DynamoFile` object instantiated from the `dynamo_model_sample_app.dyn` file. You can download the sample dynamo model [here](/files/docs/dynamo-tutorial/dynamo_model_sample_app.dyn). 2. With the `update` method, the value of input nodes can be updated. 3. When all inputs have been updated as desired, the `generate` method can be used to generate an updated [`File`](/sdk/api/core/.md#_File) object. note Don't forget to import `Path` from the `pathlib` module ## 3. Create a GeometryView with mocked output files[​](/docs/tutorials/integrate-dynamo/.md#3-create-a-geometryview-with-mocked-output-files "Direct link to 3. Create a GeometryView with mocked output files") In this section we will add a [`GeometryView`](/sdk/api/views/.md#_GeometryView) to display the house's geometry. However, for now, we will use a mocked output file. In [section 7](/docs/tutorials/integrate-dynamo/.md#7-add-the-worker-logic-to-supply-the-real-output-files) we will create the json file using the Dynamo script. Before you continue, download the mocked output file [here](/files/docs/dynamo-tutorial/Mocked_3d_model.json) and save it in your app folder next to `app.py`. To visualize the mocked output add a `GeometryView` method to your `Controller` class, see code below: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @vkt.GeometryView("Mocked 3d model", x_axis_to_right=True) def mocked_geometry_view(self, params, **kwargs): # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis file_path = Path(__file__).parent / "Mocked_3d_model.json" threed_file = vkt.File.from_path(file_path) # Step 3: Processing geometry glb_file = vkt.dynamo.convert_geometry_to_glb(threed_file) return vkt.GeometryResult(geometry=glb_file) ``` Let us go through the above mentioned logic: 1. Update the Dynamo file with the `update_model` method(see section 2) 2. For now we are using a mocked file, instead of running the analysis in Dynamo. The mocked file can be downloaded [here](/files/docs/dynamo-tutorial/Mocked_3d_model.json). In [section 7](/docs/tutorials/integrate-dynamo/.md#7-add-the-worker-logic-to-supply-the-real-output-files) it is explained how to create the json file using the Dynamo script. 3. With the helper function [`convert_geometry_to_glb`](/sdk/api/external/dynamo/.md#_convert_geometry_to_glb), you can convert the json file to a GLB file, which can directly be visualized in a `GeometryView`. 4. Refresh your app in the browser, and you should see a 3D model of a house. ## 4. Create a data processing method[​](/docs/tutorials/integrate-dynamo/.md#4-create-a-data-processing-method "Direct link to 4. Create a data processing method") In this section, we will define code to extract data from the dynamo files. The dynamo file is used to get the node ID, and the `output.xml` file is used to get the result values. To do this we will add another `staticmethod` on the `Controller` class. See code below: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @vkt.GeometryView("Mocked 3d model", x_axis_to_right=True) def mocked_geometry_view(self, params, **kwargs): # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis file_path = Path(__file__).parent / "Mocked_3d_model.json" threed_file = vkt.File.from_path(file_path) # Step 3: Processing geometry glb_file = vkt.dynamo.convert_geometry_to_glb(threed_file) return vkt.GeometryResult(geometry=glb_file) @staticmethod def convert_dynamo_file_to_data_items(input_file: vkt.dynamo.DynamoFile, output_file: vkt.File) -> vkt.DataGroup: """Extracts the output of the Dynamo results by using the input and output files.""" # Collect ids for the computational output from the Dynamo file output_id_floor_area = input_file.get_node_id("(OUTPUT) Floor area per house") output_id_total_cost = input_file.get_node_id("(OUTPUT) Total cost") output_id_mki = input_file.get_node_id("(OUTPUT) MKI") output_id_co2 = input_file.get_node_id("(OUTPUT) CO2") # Collect the numerical results from the output file using the collected ids with output_file.open_binary() as f: floor_area = vkt.dynamo.get_dynamo_result(f, id_=output_id_floor_area) total_cost = vkt.dynamo.get_dynamo_result(f, id_=output_id_total_cost) mki = vkt.dynamo.get_dynamo_result(f, id_=output_id_mki) co2 = vkt.dynamo.get_dynamo_result(f, id_=output_id_co2) # Add values to a DataGroup to visualize them in the app data_group = vkt.DataGroup( vkt.DataItem(label="Floor area", value=round(float(floor_area), 2), suffix="m²"), vkt.DataItem(label="Total cost", value=round(float(total_cost), 2), suffix="€"), vkt.DataItem(label="MKI", value=round(float(mki), 2)), vkt.DataItem(label="CO₂ emission", value=round(float(co2), 2), suffix="ton CO₂"), ) return data_group ``` Let us go through the above mentioned logic: 1. Get the `node_id`, which corresponds to the same node id as the input file. 2. Collect the numerical results. 3. Create a `DataGroup` from the collected numerical results using the [`DataGroup`](/sdk/api/views/.md#_DataGroup) and [`DataItem`](/sdk/api/views/.md#_DataItem) classes. ## 5. Create a DataView with mocked output files[​](/docs/tutorials/integrate-dynamo/.md#5-create-a-dataview-with-mocked-output-files "Direct link to 5. Create a DataView with mocked output files") In this section we will create a [`DataView`](/sdk/api/views/.md#_DataView) to display the data. However, for now, we will use a mocked output file. In [section 7](/docs/tutorials/integrate-dynamo/.md#7-add-the-worker-logic-to-supply-the-real-output-files) we will generate the xml file using the Dynamo script. Before you continue, download the result file [here](/files/docs/dynamo-tutorial/Mocked_data_results.xml) and save it in your app folder next to `app.py`. To visualize the mocked output add a `DataView` method to your `Controller` class, see code below: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @vkt.GeometryView("Mocked 3d model", x_axis_to_right=True) def mocked_geometry_view(self, params, **kwargs): # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis file_path = Path(__file__).parent / "Mocked_3d_model.json" threed_file = vkt.File.from_path(file_path) # Step 3: Processing geometry glb_file = vkt.dynamo.convert_geometry_to_glb(threed_file) return vkt.GeometryResult(geometry=glb_file) @staticmethod def convert_dynamo_file_to_data_items(input_file: vkt.dynamo.DynamoFile, output_file: vkt.File) -> vkt.DataGroup: """Extracts the output of the Dynamo results by using the input and output files.""" # Collect ids for the computational output from the Dynamo file output_id_floor_area = input_file.get_node_id("(OUTPUT) Floor area per house") output_id_total_cost = input_file.get_node_id("(OUTPUT) Total cost") output_id_mki = input_file.get_node_id("(OUTPUT) MKI") output_id_co2 = input_file.get_node_id("(OUTPUT) CO2") # Collect the numerical results from the output file using the collected ids with output_file.open_binary() as f: floor_area = vkt.dynamo.get_dynamo_result(f, id_=output_id_floor_area) total_cost = vkt.dynamo.get_dynamo_result(f, id_=output_id_total_cost) mki = vkt.dynamo.get_dynamo_result(f, id_=output_id_mki) co2 = vkt.dynamo.get_dynamo_result(f, id_=output_id_co2) # Add values to a DataGroup to visualize them in the app data_group = vkt.DataGroup( vkt.DataItem(label="Floor area", value=round(float(floor_area), 2), suffix="m²"), vkt.DataItem(label="Total cost", value=round(float(total_cost), 2), suffix="€"), vkt.DataItem(label="MKI", value=round(float(mki), 2)), vkt.DataItem(label="CO₂ emission", value=round(float(co2), 2), suffix="ton CO₂"), ) return data_group @vkt.DataView("Mocked data results") def mocked_data_view(self, params, **kwargs): # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis file_path = Path(__file__).parent / "Mocked_data_results.xml" data_file = vkt.File.from_path(file_path) # Step 3: Process numerical output data_group = self.convert_dynamo_file_to_data_items(dynamo_file, data_file) return vkt.DataResult(data=data_group) ``` Let us go through the above mentioned logic: 1. Update the Dynamo file with the `update_model` method (see [section 1](/docs/tutorials/integrate-dynamo/.md#1-setup-a-viktor-app)) 2. For now we are using a mocked file, instead of running the analysis in Dynamo. The mocked file can be downloaded [here](/files/docs/dynamo-tutorial/Mocked_data_results.xml). 3. With the static method `convert_dynamo_file_to_data_items`, you can convert the .xml file to a `DataGroup`, which can be directly visualized in a `DataView`. 4. Refresh your app, and you should see a data view with the data. ## 6. Create a GeometryAndDataView with the mocked output files[​](/docs/tutorials/integrate-dynamo/.md#6-create-a-geometryanddataview-with-the-mocked-output-files "Direct link to 6. Create a GeometryAndDataView with the mocked output files") In this section we will combine the geometry view and data view in one view using the [`GeometryAndDataView`](/sdk/api/views/.md#_GeometryAndDataView) class. We will use the mocked files. To this end, replace the `mocked_data_view` and the `mocked_geometry_view` methods with a single `geometry_and_data_view` method: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @staticmethod def convert_dynamo_file_to_data_items(input_file: vkt.dynamo.DynamoFile, output_file: vkt.File) -> vkt.DataGroup: """Extracts the output of the Dynamo results by using the input and output files.""" # Collect ids for the computational output from the Dynamo file output_id_floor_area = input_file.get_node_id("(OUTPUT) Floor area per house") output_id_total_cost = input_file.get_node_id("(OUTPUT) Total cost") output_id_mki = input_file.get_node_id("(OUTPUT) MKI") output_id_co2 = input_file.get_node_id("(OUTPUT) CO2") # Collect the numerical results from the output file using the collected ids with output_file.open_binary() as f: floor_area = vkt.dynamo.get_dynamo_result(f, id_=output_id_floor_area) total_cost = vkt.dynamo.get_dynamo_result(f, id_=output_id_total_cost) mki = vkt.dynamo.get_dynamo_result(f, id_=output_id_mki) co2 = vkt.dynamo.get_dynamo_result(f, id_=output_id_co2) # Add values to a DataGroup to visualize them in the app data_group = vkt.DataGroup( vkt.DataItem(label="Floor area", value=round(float(floor_area), 2), suffix="m²"), vkt.DataItem(label="Total cost", value=round(float(total_cost), 2), suffix="€"), vkt.DataItem(label="MKI", value=round(float(mki), 2)), vkt.DataItem(label="CO₂ emission", value=round(float(co2), 2), suffix="ton CO₂"), ) return data_group @vkt.GeometryAndDataView("Mocked 3d/data", x_axis_to_right=True) def geometry_and_data_view(self, params, **kwargs): """The endpoint that initiates the logic to visualize the geometry and data executed and retrieved from a Dynamo script.""" # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis file_path = Path(__file__).parent / "Mocked_3d_model.json" threed_file = vkt.File.from_path(file_path) file_path = Path(__file__).parent / "Mocked_data_results.xml" data_file = vkt.File.from_path(file_path) # Step 3: Processing geometry glb_file = vkt.dynamo.convert_geometry_to_glb(threed_file) # Step 4: Process numerical output data_group = self.convert_dynamo_file_to_data_items(dynamo_file, data_file) return vkt.GeometryAndDataResult(geometry=glb_file, data=data_group) ``` ## 7. Integrate Dynamo[​](/docs/tutorials/integrate-dynamo/.md#7-integrate-dynamo "Direct link to 7. Integrate Dynamo") In this section, we will implement the logic to trigger the Dynamo calculation from your app. We will update step 2 of the `geometry_and_data_view` to run the Dynamo calculation. Please refer to the code snippet below: ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @staticmethod def convert_dynamo_file_to_data_items(input_file: vkt.dynamo.DynamoFile, output_file: vkt.File) -> vkt.DataGroup: """Extracts the output of the Dynamo results by using the input and output files.""" # Collect ids for the computational output from the Dynamo file output_id_floor_area = input_file.get_node_id("(OUTPUT) Floor area per house") output_id_total_cost = input_file.get_node_id("(OUTPUT) Total cost") output_id_mki = input_file.get_node_id("(OUTPUT) MKI") output_id_co2 = input_file.get_node_id("(OUTPUT) CO2") # Collect the numerical results from the output file using the collected ids with output_file.open_binary() as f: floor_area = vkt.dynamo.get_dynamo_result(f, id_=output_id_floor_area) total_cost = vkt.dynamo.get_dynamo_result(f, id_=output_id_total_cost) mki = vkt.dynamo.get_dynamo_result(f, id_=output_id_mki) co2 = vkt.dynamo.get_dynamo_result(f, id_=output_id_co2) # Add values to a DataGroup to visualize them in the app data_group = vkt.DataGroup( vkt.DataItem(label="Floor area", value=round(float(floor_area), 2), suffix="m²"), vkt.DataItem(label="Total cost", value=round(float(total_cost), 2), suffix="€"), vkt.DataItem(label="MKI", value=round(float(mki), 2)), vkt.DataItem(label="CO₂ emission", value=round(float(co2), 2), suffix="ton CO₂"), ) return data_group @vkt.GeometryAndDataView("Building 3D", duration_guess=5, x_axis_to_right=True) def geometry_and_data_view(self, params, **kwargs): """Run an analysis using Dynamo and visualize the geometry and data""" # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis files = [ ('input.dyn', input_file), ] analysis = vkt.dynamo.DynamoAnalysis(files=files, output_filenames=["output.xml", "geometry.json"]) analysis.execute(timeout=60) # Step 3: Processing geometry geometry_file = analysis.get_output_file('geometry.json', as_file=True) glb_file = vkt.dynamo.convert_geometry_to_glb(geometry_file) # Step 4: Process numerical output output_file = analysis.get_output_file('output.xml', as_file=True) data_group = self.convert_dynamo_file_to_data_items(dynamo_file, output_file) return vkt.GeometryAndDataResult(geometry=glb_file, data=data_group) ``` The steps in `geometry_and_data_view` explained: 1. Update the Dynamo file with the `update_model` method (see section 2) 2. We use the [`DynamoAnalysis`](/sdk/api/external/dynamo/.md#_DynamoAnalysis) to run the Dynamo script. The `executable_key` in the example above refers to the "dynamo" command in the configuration file of the worker. For more information on how to configure the worker, refer to next section. 3. Processing the geometry, the .json file can be obtained with the `get_ouput_file` method. With the helper function `convert_geometry_to_glb`, you can convert it to a GLB type file, which can directly be visualized in a `GeometryAndDataView`. 4. Processing geometry, the .xml file can be obtained with the `get_ouput_file`. method. With the static method `convert_dynamo_file_to_data_items`, you can convert the .xml file to a `Datagroup`, which can be directly visualized in `GeometryAndDataView`. ## 8. Setting up a worker[​](/docs/tutorials/integrate-dynamo/.md#8-setting-up-a-worker "Direct link to 8. Setting up a worker") A worker is a program that connects your app with third-party software to execute tasks and send results. The worker communicates with the VIKTOR cloud via an encrypted connection. For the Dynamo integration, the Dynamo worker must be installed. ### Installation[​](/docs/tutorials/integrate-dynamo/.md#installation "Direct link to Installation") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Dynamo** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it. In the browser, you can now click Finish. Continue the installation in the installer wizard. Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the DynamoWPFCLI executable 5. Make sure to launch the worker once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Dynamo** 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 Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. 4. In the installer wizard, select the DynamoWPFCLI executable 5. Make sure to launch the integration once the installation is finished. If you closed the integration, you can restart it through the desktop shortcut. ### Configuration[​](/docs/tutorials/integrate-dynamo/.md#configuration "Direct link to Configuration") To configure the worker, you first need to install FormIt, which can be downloaded from [here](https://formit.autodesk.com/). After it is installed, you can set up the worker to execute the logic when the input files have been sent by the VIKTOR app. The configuration of the worker is defined in the config.yaml file, which can be found in the same folder where the worker is installed (`C:\Users\{username}\AppData\Local\Viktor\` for development workers and `C:\Program Files\Viktor\` for production workers). Edit the `config.yaml` file as follows: ``` executables: dynamo: path: 'C:\Program Files\Autodesk\FormIt\DynamoSandbox\DynamoWPFCLI.exe' arguments: - '-o' - 'input.dyn' - '-v' - 'output.xml' - '-gp' - 'C:\Program Files\Autodesk\FormIt' - '-g' - 'geometry.json' maxParallelProcesses: 1 ``` * `path`: Here we define the path of the program to be executed. * `arguments`: Under this key we can list all arguments that can be added to the executable. This works similar to command-line arguments. * `-o` Open the dynamo script(input.dyn) * `-v` Ouput geometry file (name = output.xml) * `-gp` Path to local installation of Autodesk FormIt or Revit * `-g` Ouptut geometry file (name = geometry.json) For more information about the Dynamo CLI see the [Dynamo CLI documentation](https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Command-Line-Interface) ### Connection[​](/docs/tutorials/integrate-dynamo/.md#connection "Direct link to Connection") Once you have saved your `config.yaml` file, you can start the worker by double-clicking the shortcut on the desktop. If all went well, you will be presented with windon in which the message: "Successfully connected to the server" is displayed. Also in the top right corner in your VIKTOR environment you should see a green indicator in your worker overview, see the figure below. ![](/assets/images/tutorial_dynamo_connection-66da2008601364197682b134e73f0ad2.png) ## All code together[​](/docs/tutorials/integrate-dynamo/.md#all-code-together "Direct link to All code together") Now that the worker is successfully connected you can open your development workspace and generate new housing configurations based on the supplied input parameters! ``` from pathlib import Path import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D Dynamo app \n This app parametrically generates and visualises a 3D model of a house using a Dynamo script. \n\n Please fill in the following parameters:") number_of_houses = vkt.NumberField("Number of houses", max=8.0, min=1.0, variant='slider', step=1.0, default=3.0) number_of_floors = vkt.NumberField("Number of floors", max=5.0, min=1.0, variant='slider', step=1.0, default=2.0) depth = vkt.NumberField("Depth", max=10.0, min=5.0, variant='slider', step=1.0, default=8.0, suffix="m") width = vkt.NumberField("Width", max=6.0, min=4.0, variant='slider', step=1.0, default=5.0, suffix="m") height_floor = vkt.NumberField("Height floor", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') height_roof = vkt.NumberField("Height roof", max=3.0, min=2.0, variant='slider', step=0.1, default=2.5, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @staticmethod def update_model(params) -> tuple[vkt.File, vkt.dynamo.DynamoFile]: """This method updates the nodes of the Dynamo file with the parameters from the parametrization class.""" # Create a DynamoFile object using the sample file file_path = Path(__file__).parent / "dynamo_model_sample_app.dyn" dyn_file = vkt.dynamo.DynamoFile(vkt.File.from_path(file_path)) # Update the Dynamo file with parameters from user input dyn_file.update("Number of houses", params.number_of_houses) dyn_file.update("Number of floors", params.number_of_floors) dyn_file.update("Depth", params.depth) dyn_file.update("Width", params.width) dyn_file.update("Height floor", params.height_floor) dyn_file.update("Height roof", params.height_roof) # Generate updated file input_file = dyn_file.generate() return input_file, dyn_file @staticmethod def convert_dynamo_file_to_data_items(input_file: vkt.dynamo.DynamoFile, output_file: vkt.File) -> vkt.DataGroup: """Extracts the output of the Dynamo results by using the input and output files.""" # Collect ids for the computational output from the Dynamo file output_id_floor_area = input_file.get_node_id("(OUTPUT) Floor area per house") output_id_total_cost = input_file.get_node_id("(OUTPUT) Total cost") output_id_mki = input_file.get_node_id("(OUTPUT) MKI") output_id_co2 = input_file.get_node_id("(OUTPUT) CO2") # Collect the numerical results from the output file using the collected ids with output_file.open_binary() as f: floor_area = vkt.dynamo.get_dynamo_result(f, id_=output_id_floor_area) total_cost = vkt.dynamo.get_dynamo_result(f, id_=output_id_total_cost) mki = vkt.dynamo.get_dynamo_result(f, id_=output_id_mki) co2 = vkt.dynamo.get_dynamo_result(f, id_=output_id_co2) # Add values to a DataGroup to visualize them in the app data_group = vkt.DataGroup( vkt.DataItem(label="Floor area", value=round(float(floor_area), 2), suffix="m²"), vkt.DataItem(label="Total cost", value=round(float(total_cost), 2), suffix="€"), vkt.DataItem(label="MKI", value=round(float(mki), 2)), vkt.DataItem(label="CO₂ emission", value=round(float(co2), 2), suffix="ton CO₂"), ) return data_group @vkt.GeometryAndDataView("Building 3D", duration_guess=5, x_axis_to_right=True) def geometry_and_data_view(self, params, **kwargs): """Run an analysis using Dynamo and visualize the geometry and data""" # Step 1: Update model input_file, dynamo_file = self.update_model(params) # Step 2: Running analysis files = [('input.dyn', input_file)] analysis = vkt.dynamo.DynamoAnalysis(files=files, output_filenames=["output.xml", "geometry.json"]) analysis.execute(timeout=60) # Step 3: Processing geometry geometry_file = analysis.get_output_file('geometry.json', as_file=True) glb_file = vkt.dynamo.convert_geometry_to_glb(geometry_file) # Step 4: Process numerical output output_file = analysis.get_output_file('output.xml', as_file=True) data_group = self.convert_dynamo_file_to_data_items(dynamo_file, output_file) return vkt.GeometryAndDataResult(geometry=glb_file, data=data_group) ``` ## To infinity and beyond[​](/docs/tutorials/integrate-dynamo/.md#to-infinity-and-beyond "Direct link to To infinity and beyond") Nice! You are now able to create an app that can integrate with Dynamo (Sandbox) using a Dynamo Worker! Of course, the journey doesn't end here. Check out some of our other [tutorials](/docs/tutorials/.md) or try to replace Dynamo script from this tutorial with one of your own! --- # Tutorial - Integrate ETABS and SAP2000 note Estimated time: 55 minutes
Difficulty level: Intermediate * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/integrate-etabs-sap2000/.md#introduction "Direct link to Introduction") ETABS and SAP2000 are two of the most commonly used software tools for structural engineering. They offer a range of features for modeling and design, along with a robust API that automates various workflows. In this tutorial, you will learn how to create a VIKTOR web app that integrates these tools behind the scenes. Although this tutorial is written specifically for ETABS, it can easily be modified to use [SAP2000](/docs/tutorials/integrate-etabs-sap2000/.md#what-about-sap2000). Here are the main sections we will cover: 1. [Create a new VIKTOR app.](/docs/tutorials/integrate-etabs-sap2000/.md#create-a-new-viktor-app) 2. [Create a simple parametric model.](/docs/tutorials/integrate-etabs-sap2000/.md#lets-create-the-3d-model) 3. [Calculate the reaction loads of your model.](/docs/tutorials/integrate-etabs-sap2000/.md#hands-on-the-etabs-api) 4. [Display the reaction loads in your VIKTOR app.](/docs/tutorials/integrate-etabs-sap2000/.md#lets-integrate-the-worker-in-our-viktor-app) Here is a sneak peek at how the app will look: ![model](/assets/images/tutorial_etabs_sap_webapp-68ba25a66b118e6c43e67f53242b615b.png) ## Prerequisites and downloads[​](/docs/tutorials/integrate-etabs-sap2000/.md#prerequisites-and-downloads "Direct link to Prerequisites and downloads") Prerequisites * You have [installed VIKTOR](https://docs.viktor.ai/docs/getting-started/installation/) * You have some experience with reading Python code * You have some experience with ETABS/SAP2000 Before using the ETABS API in Python, ensure you have `pywin32` and `comtypes` installed in your *Python environment*. If they are not installed, you can add them using pip. Open Windows Powershell and run the following command: ``` pip install pywin32 comtypes ``` ## Create a new VIKTOR app[​](/docs/tutorials/integrate-etabs-sap2000/.md#create-a-new-viktor-app "Direct link to Create a new VIKTOR app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ## Let's define a simple structure[​](/docs/tutorials/integrate-etabs-sap2000/.md#lets-define-a-simple-structure "Direct link to Let's define a simple structure") To generate a simple moment frame, we use a parametric approach by defining the frame's `length` and `height` as variables. The function **create\_frame\_data** creates the frame’s topology using **nodes** and **lines** to represent its geometry. This approach allows us to generate different configurations by adjusting the `length` and `height` values. Additionally, the geometry is saved to a `json` file each time the function is executed. In the next sections, we will show how this function is used within the `Controller` class, triggered when new inputs are defined in the `Parametrization` class. Take a moment to review the following code snippet before continuing with the tutorial. ``` import viktor as vkt import json def create_frame_data(length, height): nodes = { 1:{"node_id": 1, "x": 0, "y": 0, "z": 0}, 2:{"node_id": 2, "x": 0, "y": length, "z": 0}, 3:{"node_id": 3, "x": 0, "y": 0, "z": height}, 4:{"node_id": 4, "x": 0, "y": length, "z": height}, 5:{"node_id": 5, "x": length, "y": 0, "z": 0}, 6:{"node_id": 6, "x": length, "y": length, "z": 0}, 7:{"node_id": 7, "x": length, "y": 0, "z": height}, 8:{"node_id": 8, "x": length, "y": length, "z": height}, } lines = { 1:{"line_id": 1, "node_i": 1, "node_j": 3}, 2:{"line_id": 2, "node_i": 2, "node_j": 4}, 3:{"line_id": 3, "node_i": 3, "node_j": 4}, 4:{"line_id": 4, "node_i": 6, "node_j": 8}, 5:{"line_id": 5, "node_i": 5, "node_j": 7}, 6:{"line_id": 6, "node_i": 3, "node_j": 7}, 7:{"line_id": 7, "node_i": 4, "node_j": 8}, 8:{"line_id": 8, "node_i": 7, "node_j": 8}, } return nodes, lines class Parametrization(vkt.Parametrization): pass class Controller(vkt.Controller): parametrization = Parametrization ``` ## Let's create the 3D model[​](/docs/tutorials/integrate-etabs-sap2000/.md#lets-create-the-3d-model "Direct link to Let's create the 3D model") Now that we have a function to generate the topology of our structure, it's time to define the inputs in our `Parametrization` class and implement the logic to create a 3D model of the frame in a `GeometryView`. You can refer to the [documentation](https://docs.viktor.ai/sdk/api/geometry/) for more details on how to work with 3D geometry in VIKTOR. The resulting code of your app is shown below: ``` import json import viktor as vkt def create_frame_data(length, height): nodes = { 1:{"node_id": 1, "x": 0, "y": 0, "z": 0}, 2:{"node_id": 2, "x": 0, "y": length, "z": 0}, 3:{"node_id": 3, "x": 0, "y": 0, "z": height}, 4:{"node_id": 4, "x": 0, "y": length, "z": height}, 5:{"node_id": 5, "x": length, "y": 0, "z": 0}, 6:{"node_id": 6, "x": length, "y": length, "z": 0}, 7:{"node_id": 7, "x": length, "y": 0, "z": height}, 8:{"node_id": 8, "x": length, "y": length, "z": height}, } lines = { 1:{"line_id": 1, "node_i": 1, "node_j": 3}, 2:{"line_id": 2, "node_i": 2, "node_j": 4}, 3:{"line_id": 3, "node_i": 3, "node_j": 4}, 4:{"line_id": 4, "node_i": 6, "node_j": 8}, 5:{"line_id": 5, "node_i": 5, "node_j": 7}, 6:{"line_id": 6, "node_i": 3, "node_j": 7}, 7:{"line_id": 7, "node_i": 4, "node_j": 8}, 8:{"line_id": 8, "node_i": 7, "node_j": 8}, } return nodes, lines class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS Base Reaction App Please fill in the following parameters: """ ) frame_length = vkt.NumberField("Frame Length", min=100, default=4000, suffix="mm") frame_height = vkt.NumberField("Frame Height", min=100, default=4000, suffix="mm") class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D Model", duration_guess=1, x_axis_to_right=True) def create_render(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height=params.frame_height) sections_group = [] for line_id, dict_vals in lines.items(): node_id_i = dict_vals["node_i"] node_id_j = dict_vals["node_j"] node_i = nodes[node_id_i] node_j = nodes[node_id_j] point_i = vkt.Point(node_i["x"], node_i["y"], node_i["z"]) point_j = vkt.Point(node_j["x"], node_j["y"], node_j["z"]) line_k = vkt.Line(point_i, point_j) section_k = vkt.RectangularExtrusion(300, 300, line_k, identifier=str(line_id)) sections_group.append(section_k) return vkt.GeometryResult(geometry=sections_group) ``` Great! Now, you can change the dimensions of your frame, and the model will render with the updated geometry. You should see an app like this in your browser: ![model](/assets/images/tutorial_etabs_sap_geo_view-4950796446a8136418a0ad3b6e298f49.png) However, since you're here to learn how to integrate ETABS or SAP2000, let's move on and start using the CSI API! ## Hands on the ETABS API[​](/docs/tutorials/integrate-etabs-sap2000/.md#hands-on-the-etabs-api "Direct link to Hands on the ETABS API") Let's create a new Python file called `run_etabs_model.py` in the same directory and add a `create_etabs_model` function. This function contains the logic to create our ETABS model using Python. The first step is to initialize the program with `comtypes`. Copy the snippet below, and make sure to update the `program_path` to match your ETABS version. You can run this code in **your Python environment**, and it will open a blank ETABS model. note If ETABS is running on a remote server, the `program_path` needs to match the ETABS location on the server where the worker is running. ``` import comtypes.client import pythoncom import json from pathlib import Path def create_etabs_model(): # Initialize ETABS model program_path=r"C:\Program Files\Computers and Structures\ETABS 22\ETABS.exe" pythoncom.CoInitialize() try: helper = comtypes.client.CreateObject("ETABSv1.Helper") helper = helper.QueryInterface(comtypes.gen.ETABSv1.cHelper) EtabsEngine = helper.CreateObject(program_path) EtabsEngine.ApplicationStart() EtabsObject = EtabsEngine.SapModel EtabsObject.InitializeNewModel(9) # Set units to mm EtabsObject.File.NewBlank() finally: pythoncom.CoUninitialize() if __name__ == "__main__": create_etabs_model() ``` ## Create the structure in ETABS[​](/docs/tutorials/integrate-etabs-sap2000/.md#create-the-structure-in-etabs "Direct link to Create the structure in ETABS") Next, let's extend the `create_etabs_model` function to add joints, members, and rigid supports. We'll load the nodes and lines geometry from the `inputs.json` file, then create the nodes and members in ETABS, followed by defining the material properties for the frame. Here's how all this looks in code: ``` def create_etabs_model(): # Initialize ETABS model program_path=r"C:\Program Files\Computers and Structures\ETABS 22\ETABS.exe" pythoncom.CoInitialize() try: helper = comtypes.client.CreateObject("ETABSv1.Helper") helper = helper.QueryInterface(comtypes.gen.ETABSv1.cHelper) EtabsEngine = helper.CreateObject(program_path) EtabsEngine.ApplicationStart() EtabsObject = EtabsEngine.SapModel EtabsObject.InitializeNewModel(9) # Set units to mm EtabsObject.File.NewBlank() finally: pythoncom.CoUninitialize() # Create joints input_json = Path.cwd() / "inputs.json" #only works when running python from the working directory! with open(input_json) as jsonfile: data = json.load(jsonfile) nodes, lines = data[:] # Create nodes for node_id, node in nodes.items(): ret, _ = EtabsObject.PointObj.AddCartesian( node["x"], node["y"], node["z"], " ", str(node_id)) ) # Create members MATERIAL_CONCRETE = 2 ret = EtabsObject.PropMaterial.SetMaterial("CONC", MATERIAL_CONCRETE) ret = EtabsObject.PropMaterial.SetMPIsotropic("CONC", 30000, 0.2, 0.0000055) section_name = "300x300 RC" ret = EtabsObject.PropFrame.SetRectangle(section_name, "CONC", 300, 300) for line_id, line in lines.items(): point_i = line["node_i"] point_j = line["node_j"] ret, _ = EtabsObject.FrameObj.AddByPoint( str(point_i), str(point_j), str(line_id), section_name, "Global" ) # Add rigid supports list_nodes = [1, 2, 5, 6] for node_id in list_nodes: ret = EtabsObject.PointObj.SetRestraint(str(node_id), [1, 1, 1, 1, 1, 1]) EtabsObject.View.RefreshView(0, False) if __name__ == "__main__": create_etabs_model() ``` ## Run the model[​](/docs/tutorials/integrate-etabs-sap2000/.md#run-the-model "Direct link to Run the model") Now you can save the model and run the analysis. By default, ETABS creates a load case called `Dead`, which includes only the self-weight of the structure. After the analysis, we can extract the reaction loads and save the results in a `.json` file to be used later in our VIKTOR app. ``` def create_etabs_model(): # Initialize ETABS model program_path=r"C:\Program Files\Computers and Structures\ETABS 22\ETABS.exe" pythoncom.CoInitialize() try: helper = comtypes.client.CreateObject("ETABSv1.Helper") helper = helper.QueryInterface(comtypes.gen.ETABSv1.cHelper) EtabsEngine = helper.CreateObject(program_path) EtabsEngine.ApplicationStart() EtabsObject = EtabsEngine.SapModel EtabsObject.InitializeNewModel(9) # Set units to mm EtabsObject.File.NewBlank() finally: pythoncom.CoUninitialize() # Create joints input_json = Path.cwd() / "inputs.json" #only works when running python from the working directory! with open(input_json) as jsonfile: data = json.load(jsonfile) nodes, lines = data[:] # Create nodes for node_id, node in nodes.items(): ret, _ = EtabsObject.PointObj.AddCartesian( node["x"], node["y"], node["z"], " ", str(node_id)) ) # Create members MATERIAL_CONCRETE = 2 ret = EtabsObject.PropMaterial.SetMaterial("CONC", MATERIAL_CONCRETE) ret = EtabsObject.PropMaterial.SetMPIsotropic("CONC", 30000, 0.2, 0.0000055) section_name = "300x300 RC" ret = EtabsObject.PropFrame.SetRectangle(section_name, "CONC", 300, 300) for line_id, line in lines.items(): point_i = line["node_i"] point_j = line["node_j"] ret, _ = EtabsObject.FrameObj.AddByPoint( str(point_i), str(point_j), str(line_id), section_name, "Global" ) # Add rigid supports list_nodes = [1, 2, 5, 6] for node_id in list_nodes: ret = EtabsObject.PointObj.SetRestraint(str(node_id), [1, 1, 1, 1, 1, 1]) EtabsObject.View.RefreshView(0, False) # Create the model and run the analysis file_path = Path.cwd() / "etabsmodel.edb" EtabsObject.File.Save(str(file_path)) EtabsObject.Analyze.RunAnalysis() # Get the reaction loads load_case = "Dead" ret = EtabsObject.Results.Setup.DeselectAllCasesAndCombosForOutput() reactions_list = list() ret = EtabsObject.Results.Setup.SetCaseSelectedForOutput(load_case) for node in list_nodes: *_, U1, U2, U3, R1, R2, R3, ret = EtabsObject.Results.JointReact( str(node), 0, 0 ) reaction = { "Node": str(node), "LoadCase": load_case, "U1": U1[0], "U2": U2[0], "U3": U3[0], "R1": R1[0], "R2": R2[0], "R3": R3[0], } reactions_list.append(reaction) # Save the output in a JSON output = Path.cwd() / "output.json" with open(output, "w") as jsonfile: json.dump(reactions_list, jsonfile) ret = EtabsEngine.ApplicationExit(False) return ret if __name__ == "__main__": create_etabs_model() ``` After running your `run_etabs_model.py` in your Python environment, you should end up with a model like the following: ![model](/assets/images/tutorial_etabs_model-b155492f041afdb2f65244333898ec2c.png) ## How to connect your VIKTOR app with the CSI API?[​](/docs/tutorials/integrate-etabs-sap2000/.md#how-to-connect-your-viktor-app-with-the-csi-api "Direct link to How to connect your VIKTOR app with the CSI API?") The connection between VIKTOR and SAP2000 or ETABS is managed by a “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 to test the integration by following this [tutorial](/docs/create-apps/software-integrations/etabs-and-sap2000/.md). ## Let's integrate the worker in our VIKTOR app[​](/docs/tutorials/integrate-etabs-sap2000/.md#lets-integrate-the-worker-in-our-viktor-app "Direct link to Let's integrate the worker in our VIKTOR app") In the `Controller` of our VIKTOR app, we need to set up the communication with the worker. To call the worker, we use the `ETABSAnalysis` class, which allows us to send inputs (files and objects) to the worker. In this example, we will send the `inputs.json` and `run_etabs_model.py` to be executed in the environment set up for the worker. This environment can be on your own computer or a remote server. When `run_etabs_model.py` is executed, it will generate the `output.json` file, and the worker will handle transferring this file from the server environment to our VIKTOR app. Here's how it looks in the code: ``` import json from io import BytesIO from pathlib import Path import viktor as vkt def create_frame_data(length, height): nodes = { 1:{"node_id": 1, "x": 0, "y": 0, "z": 0}, 2:{"node_id": 2, "x": 0, "y": length, "z": 0}, 3:{"node_id": 3, "x": 0, "y": 0, "z": height}, 4:{"node_id": 4, "x": 0, "y": length, "z": height}, 5:{"node_id": 5, "x": length, "y": 0, "z": 0}, 6:{"node_id": 6, "x": length, "y": length, "z": 0}, 7:{"node_id": 7, "x": length, "y": 0, "z": height}, 8:{"node_id": 8, "x": length, "y": length, "z": height}, } lines = { 1:{"line_id": 1, "node_i": 1, "node_j": 3}, 2:{"line_id": 2, "node_i": 2, "node_j": 4}, 3:{"line_id": 3, "node_i": 3, "node_j": 4}, 4:{"line_id": 4, "node_i": 6, "node_j": 8}, 5:{"line_id": 5, "node_i": 5, "node_j": 7}, 6:{"line_id": 6, "node_i": 3, "node_j": 7}, 7:{"line_id": 7, "node_i": 4, "node_j": 8}, 8:{"line_id": 8, "node_i": 7, "node_j": 8}, } return nodes, lines class Parametrization(vkt.Parametrization): intro = vkt.Text( "# ETABS Base Reaction App" "\n\n Please fill in the following parameters:" ) frame_length = vkt.NumberField("Frame Length", min=100, default=4000, suffix="mm") frame_height = vkt.NumberField("Frame Height", min=100, default=4000, suffix="mm") class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D Model", duration_guess=1, x_axis_to_right=True) def create_render(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height=params.frame_height) sections_group = [] for line_id, dict_vals in lines.items(): node_id_i = dict_vals["node_i"] node_id_j = dict_vals["node_j"] node_i = nodes[node_id_i] node_j = nodes[node_id_j] point_i = vkt.Point(node_i["x"], node_i["y"], node_i["z"]) point_j = vkt.Point(node_j["x"], node_j["y"], node_j["z"]) line_k = vkt.Line(point_i, point_j) section_k = vkt.RectangularExtrusion(300, 300, line_k, identifier=str(line_id)) sections_group.append(section_k) return vkt.GeometryResult(geometry=sections_group) def run_etabs(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height= params.frame_height) input_json = json.dumps([nodes, lines]) script_path = Path(__file__).parent / "run_etabs_model.py" files = [("inputs.json", BytesIO(bytes(input_json, 'utf8')))] etabs_analysis = vkt.etabs.ETABSAnalysis( script=vkt.File.from_path(script_path), files=files, output_filenames=["output.json"] ) etabs_analysis.execute(timeout=300) output_file = etabs_analysis.get_output_file("output.json", as_file=True) ``` And of course, we would like to see the results in a nice table, so we will decorate the previous function with a `TableView` and post-process the results from the `output.json` file, as shown below: ``` import json from io import BytesIO from pathlib import Path import viktor as vkt def create_frame_data(length, height): nodes = { 1:{"node_id": 1, "x": 0, "y": 0, "z": 0}, 2:{"node_id": 2, "x": 0, "y": length, "z": 0}, 3:{"node_id": 3, "x": 0, "y": 0, "z": height}, 4:{"node_id": 4, "x": 0, "y": length, "z": height}, 5:{"node_id": 5, "x": length, "y": 0, "z": 0}, 6:{"node_id": 6, "x": length, "y": length, "z": 0}, 7:{"node_id": 7, "x": length, "y": 0, "z": height}, 8:{"node_id": 8, "x": length, "y": length, "z": height}, } lines = { 1:{"line_id": 1, "node_i": 1, "node_j": 3}, 2:{"line_id": 2, "node_i": 2, "node_j": 4}, 3:{"line_id": 3, "node_i": 3, "node_j": 4}, 4:{"line_id": 4, "node_i": 6, "node_j": 8}, 5:{"line_id": 5, "node_i": 5, "node_j": 7}, 6:{"line_id": 6, "node_i": 3, "node_j": 7}, 7:{"line_id": 7, "node_i": 4, "node_j": 8}, 8:{"line_id": 8, "node_i": 7, "node_j": 8}, } return nodes, lines class Parametrization(vkt.Parametrization): intro = vkt.Text( "# ETABS Base Reaction App" "\n\n Please fill in the following parameters:" ) frame_length = vkt.NumberField("Frame Length", min=100, default=4000, suffix="mm") frame_height = vkt.NumberField("Frame Height", min=100, default=4000, suffix="mm") class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D Model", duration_guess=1, x_axis_to_right=True) def create_render(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height=params.frame_height) sections_group = [] for line_id, dict_vals in lines.items(): node_id_i = dict_vals["node_i"] node_id_j = dict_vals["node_j"] node_i = nodes[node_id_i] node_j = nodes[node_id_j] point_i = vkt.Point(node_i["x"], node_i["y"], node_i["z"]) point_j = vkt.Point(node_j["x"], node_j["y"], node_j["z"]) line_k = vkt.Line(point_i, point_j) section_k = vkt.RectangularExtrusion(300, 300, line_k, identifier=str(line_id)) sections_group.append(section_k) return vkt.GeometryResult(geometry=sections_group) @vkt.TableView("Base Reactions",duration_guess=10, update_label="Run ETABS analysis") def run_etabs(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height= params.frame_height) input_json = json.dumps([nodes, lines]) script_path = Path(__file__).parent / "run_etabs_model.py" files = [("inputs.json", BytesIO(bytes(input_json, 'utf8')))] etabs_analysis = vkt.etabs.ETABSAnalysis( script=vkt.File.from_path(script_path), files=files, output_filenames=["output.json"] ) etabs_analysis.execute(timeout=300) output_file = etabs_analysis.get_output_file("output.json", as_file=True) reactions = json.loads(output_file.getvalue()) data = [] for reaction in reactions: data.append([ reaction.get("Node", 0), reaction.get("LoadCase", "Dead"), round(reaction.get("U1", 0), 0), round(reaction.get("U2", 0), 0), round(reaction.get("U3", 0), 0) ]) return vkt.TableResult( data, row_headers=["Sup 1","Sup 2","Sup 3","Sup 4"], column_headers=["Node", "Load Case","U1[N]", "U2[N]", "U3[N]"], ) ``` Now you're ready to test your app. Make sure your worker is running and connected to your VIKTOR workspace, then try generating the model. After the analysis, your app should look like this: ![model](/assets/images/tutorial_etabs_sap_table_view-5c40ce41eb266cceb24ec740412e544a.JPG) ## What about SAP2000?[​](/docs/tutorials/integrate-etabs-sap2000/.md#what-about-sap2000 "Direct link to What about SAP2000?") You can integrate SAP2000 in the same way we did for ETABS. All you need to do is change the program path and the helper, as shown below. ``` import pythoncom import comtypes.client def initialize_sap2000( program_path=r"C:\Program Files\Computers and Structures\SAP2000 25\SAP2000.exe", ): pythoncom.CoInitialize() try: helper = comtypes.client.CreateObject("SAP2000v1.Helper") helper = helper.QueryInterface(comtypes.gen.SAP2000v1.cHelper) SapEngine = helper.CreateObject(program_path) SapEngine.ApplicationStart() SapObject = SapEngine.SapModel SapObject.InitializeNewModel() SapObject.File.NewBlank() return SapObject, SapEngine finally: pythoncom.CoUninitialize() ``` ## Your turn to build[​](/docs/tutorials/integrate-etabs-sap2000/.md#your-turn-to-build "Direct link to Your turn to build") You now have everything you need to start building powerful applications that integrate ETABS and SAP2000 into your VIKTOR apps. But the journey doesn’t end here, you can explore our other [tutorials](/docs/tutorials/.md) or try integrating your own ETABS or SAP2000 model. --- # Tutorial - Integrate Rhino/Grasshopper note Estimated time: 45 minutes
Difficulty level: Intermediate * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps)
***Not a reader?** feel free to follow this tutorial as a video*
## Introduction[​](/docs/tutorials/integrate-grasshopper/.md#introduction "Direct link to Introduction") Welcome to this tutorial on integrating Grasshopper with VIKTOR! In this tutorial, you will learn how to create a VIKTOR web app with a Grasshopper model running behind it by the following steps: 1. [Setup integration with Grasshopper](/docs/tutorials/integrate-grasshopper/.md#1-setup-integration-with-grasshopper) 2. [Build the VIKTOR app](/docs/tutorials/integrate-grasshopper/.md#2-build-the-viktor-app) 3. [Use your own Grasshopper model](/docs/tutorials/integrate-grasshopper/.md#3-use-your-own-grasshopper-model) By the end of this tutorial, you will have created a simple VIKTOR application that creates a geometry and data view of a simple box, see the image below: ![](/assets/images/tutorial_grasshopper_results-f939ef1c75b54353570a700e93960869.png) So, let's get started and learn how to create a VIKTOR app based on a Grasshopper model! ## Pre-requisites and downloads[​](/docs/tutorials/integrate-grasshopper/.md#pre-requisites-and-downloads "Direct link to Pre-requisites and downloads") Prerequisites * You have [installed VIKTOR](/docs/getting-started/installation/.md) on your computer * You have some experience with reading Python code * You have some experience with Rhino/Grasshopper Required Downloads * [sample\_box\_grasshopper.gh](/files/docs/grasshopper-tutorial/sample_box_grasshopper.gh) SDK version This code requires support for the GrasshopperAnalysis, which is available since SDK **v14.8.0**. Make sure use this SDK version or higher in your `requirements.txt` file. ## Explanation of setup[​](/docs/tutorials/integrate-grasshopper/.md#explanation-of-setup "Direct link to Explanation of setup") Before diving into the steps, let's explain how the integration will work. See the following diagram: ![](/assets/images/tutorial-grasshopper-integration-8c1af77e8d8dc7ea248d5be4162a43d4.png) The following will happen: 1. The user fills in input parameters in the **VIKTOR UI** 2. In **VIKTOR app.py** these input parameters will be sent together with a Grasshopper script (*sample\_box\_grasshopper.gh*) to the [worker](/docs/manage-apps/software-integrations/.md). 3. The **Grasshopper worker** will run **Rhino/Grasshopper** (on your local machine), based on the Grasshopper script (*sample\_box\_grasshopper.gh*) and the input parameters. 4. The Grasshopper model generates output data, which is sent back by the **worker**. 5. In **VIKTOR app.py**, the output data is converted into a 3dm geometry file, which will be visualized in the **VIKTOR UI**. Now let's setup everything to get this running! We will go through the diagram from right to left. Rhino 8 - plug-ins & .NET In order to install some older plug-ins, you may have had to set your .NET such that it is running in .NET Framework. If you did, please change it back to the default setting (.NET Core) for the integration to work using the `SetDotNetRuntime` in the Rhino command line. ## 1. Setup integration with Grasshopper[​](/docs/tutorials/integrate-grasshopper/.md#1-setup-integration-with-grasshopper "Direct link to 1. Setup integration with Grasshopper") A worker (integration) is a program that connects a VIKTOR app with third-party software to execute tasks and send back results. In this case, the worker will start Rhino/Grasshopper with the input data and send the resulting output data back. Before we setup the worker, we must first install the Hops plugin for Grasshopper. ### Install Hops plugin[​](/docs/tutorials/integrate-grasshopper/.md#install-hops-plugin "Direct link to Install Hops plugin") Hops is a plugin for Grasshopper, which will be used to make it possible to call the Grasshopper script externally, using a local Rhino Compute server. Follow these steps to install Hops: 1. Install Hops via the Package Manager in Rhino (type `PackageManager` on the Rhino command line and search for "Hops") ![](/assets/images/tutorial_grasshopper_packagemanager-2761170ce4873aef374134a6b32e1cee.png) 2. Make sure Rhino Compute will be launched at start up. In Grasshopper, go to `File -> Preferences` and check the following settings: ![](/assets/images/tutorial_grasshopper_settings-385bbda5010d974c567821d2016996c2.png) We recommend to uncheck *Hide Rhino.Compute Console Window*, because you can then easily see if Rhino Compute is running and debug when necessary. The full documentation of Hops can be found in the [Rhino documentation](https://developer.rhino3d.com/guides/compute/hops-component/). ### Install Grasshopper worker[​](/docs/tutorials/integrate-grasshopper/.md#install-grasshopper-worker "Direct link to Install Grasshopper worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **Grasshopper** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **Grasshopper** 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 Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. localhost port By default, the local RhinoCompute server runs on `http://localhost:6500/`, so this has been preselected in the installation wizard. If you have configured RhinoCompute to a different port, please update this accordingly during the installation. Once the installation has completed, the worker should start up automatically. If all went well, you will be presented with the worker terminal in which the message: **"Successfully connected to the server"** is displayed. In the top right corner in your viktor environment you should see a green indicator in your integrations overview, see the figure below. ![](/assets/images/tutorial_dynamo_connection-66da2008601364197682b134e73f0ad2.png) Nice work! The integration is ready to use, let's test the VIKTOR app. ### (optional) Check out Grasshopper model[​](/docs/tutorials/integrate-grasshopper/.md#optional-check-out-grasshopper-model "Direct link to (optional) Check out Grasshopper model") Before we start building the app, you might be curious to know what kind of Grasshopper model we will be integrating. If you want to check out the Grasshopper model, open the Grasshopper file (`sample_box_grasshopper.gh`) with the Grasshopper plugin and this should lead to the following view: ![](/assets/images/tutorial_grasshopper_open_models-f6514c40bb49e4a054b85193ccc58281.png) Let's take some time to check out what is happening in the Grasshopper script: ![](/assets/images/tutorial_grasshopper_script-4ccb11f965a8f7f97e55b0026c389671.png) 1. Three Hops input parameters (`width`, `length` and `height`) are defined based on the `Get Number` component of [Hops](https://developer.rhino3d.com/guides/compute/hops-component/#create-a-hops-function). 2. A simple box is created based on the width, length and height, which is subsequently meshed. 3. The mesh is baked into Rhino using the `Context Bake` component of Hops. If you change the input parameters, you will see that a box is drawn in Rhino. With this setup, we are ready to run this Grasshopper file from a Python script. ## 2. Build the VIKTOR app[​](/docs/tutorials/integrate-grasshopper/.md#2-build-the-viktor-app "Direct link to 2. Build the VIKTOR app") ### Create an empty app[​](/docs/tutorials/integrate-grasshopper/.md#create-an-empty-app "Direct link to Create an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Add input fields[​](/docs/tutorials/integrate-grasshopper/.md#add-input-fields "Direct link to Add input fields") We will add 3 input fields to our app: `width`, `length` and `height` using the `NumberField`. 1. Open `app.py`, import viktor and add the relevant fields to your parametrization. In the end your `app.py` file should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("## Grasshopper app \n This app parametrically generates and visualises a 3D model of a box using a Grasshopper script. \n\n Please fill in the following parameters:") # Input fields width = vkt.NumberField('Width', default=5) length = vkt.NumberField('Length', default=6) height = vkt.NumberField('Height', default=7) class Controller(vkt.Controller): parametrization = Parametrization ``` 2. Refresh your app in the browser, and you should see the input fields appear. ### Install additional dependencies[​](/docs/tutorials/integrate-grasshopper/.md#install-additional-dependencies "Direct link to Install additional dependencies") In the next step we will need the `rhino3dm` package. To be able to use this, we have to add it as dependency in the [requirements.txt](/docs/create-apps/development-tools-and-tips/use-python-packages/.md) file so that the contents look like this: ``` viktor==14.24.0 rhino3dm ``` If your terminal is still running, close the connection using Ctrl+C. Install the rhino3dm dependency: ``` viktor-cli install ``` And start your app: ``` viktor-cli start ``` ### Add the Python code to run Grasshopper[​](/docs/tutorials/integrate-grasshopper/.md#add-the-python-code-to-run-grasshopper "Direct link to Add the Python code to run Grasshopper") Now the app code can be extended to integrate the Grasshopper script. First, place the `sample_box_grasshopper.gh` file in the 'my-grasshopper-app' folder. Then change the code in `app.py` to the code below: ``` import viktor as vkt import json import rhino3dm from pathlib import Path class Parametrization(vkt.Parametrization): intro = vkt.Text("## Grasshopper app \n This app parametrically generates and visualizes a 3D model of a box using a Grasshopper script. \n\n Please fill in the following parameters:") # Input fields width = vkt.NumberField('Width', default=5) length = vkt.NumberField('Length', default=6) height = vkt.NumberField('Height', default=7) class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("Geometry", duration_guess=10, x_axis_to_right=True, update_label='Run Grasshopper') def run_grasshopper(self, params, **kwargs): grasshopper_script_path = Path(__file__).parent / "sample_box_grasshopper.gh" script = vkt.File.from_path(grasshopper_script_path) input_parameters = dict(params) # Run the Grasshopper analysis and obtain the output data analysis = vkt.grasshopper.GrasshopperAnalysis(script=script, input_parameters=input_parameters) analysis.execute(timeout=30) output = analysis.get_output() # Convert output data to mesh file3dm = rhino3dm.File3dm() obj = rhino3dm.CommonObject.Decode(json.loads(output["values"][0]["InnerTree"]['{0}'][0]["data"])) file3dm.Objects.Add(obj) # Write to geometry_file geometry_file = vkt.File() file3dm.Write(geometry_file.source, version=7) return vkt.GeometryResult(geometry=geometry_file, geometry_type="3dm") ``` If you now refresh your app, you should see the following: ![](/assets/images/tutorial_grasshopper_editor-20d58c5b3dbefe0586082dba915e7e26.png) Now press the **Run Grasshopper** button (be sure that the worker, Rhino and Grasshopper are running). You should see that Rhino Compute is run by the worker which will result in the following: ![](/assets/images/tutorial_grasshopper_results-f939ef1c75b54353570a700e93960869.png) Congratulations, you now have made a VIKTOR app with a Grasshopper model running behind it! ## 3. Use your own Grasshopper model[​](/docs/tutorials/integrate-grasshopper/.md#3-use-your-own-grasshopper-model "Direct link to 3. Use your own Grasshopper model") If you would like to integrate your own Grasshopper model in VIKTOR, you can adapt the app you just created. Take the following steps: ### Extend your Grasshopper model[​](/docs/tutorials/integrate-grasshopper/.md#extend-your-grasshopper-model "Direct link to Extend your Grasshopper model") As explained in [this section](/docs/tutorials/integrate-grasshopper/.md#optional-check-out-grasshopper-model), some specific things need to be defined in the Grasshopper model to make the integration work. 1. **Connect your specific input parameters by Hops components.** In order to update the parameters via Rhino Compute, create [Hops Get Components](https://developer.rhino3d.com/guides/compute/hops-component/#defining-inputs) for the parameters you want to update. As you can see highlighted in the image below, the names need to be *exactly* the same for the integration to work. ![](/assets/images/tutorial-grasshopper-use-your-own-779724c0ab9dd558dcdd80172bb4fb97.png) 2. **Mesh your final geometry.** In order for Rhino Compute to successfully export your geometry you need to mesh it because Rhino Compute can only export a mesh. If you don't, your geometry will not appear in the environment. 3. **Add the Context Bake component.** The Grasshopper node [Context Bake](https://developer.rhino3d.com/guides/compute/hops-component/#defining-outputs) is needed to bake the model. Flatten your inputs It is recommended to flatten the inputs in your grasshopper script, especially for simpler/smaller scripts. For larger grasshopper scripts, this may still be true, but it may be more efficient to use the Tree structure as input. Want to find out more? Check out the thread on the [community](https://community.viktor.ai/t/snippet-wednesday-grasshopper-tree-inputs/1572). ### Adjust the VIKTOR app code[​](/docs/tutorials/integrate-grasshopper/.md#adjust-the-viktor-app-code "Direct link to Adjust the VIKTOR app code") In the VIKTOR app code **adjust the parametrization** to match with your required input parameters. The rest of the code should not require any changes to work. ## To infinity and beyond[​](/docs/tutorials/integrate-grasshopper/.md#to-infinity-and-beyond "Direct link to To infinity and beyond") Great work! You are now able to create an app that can integrate with an external installation of Grasshopper through a Grasshopper Worker! Of course, the journey doesn't end here. Check out some of our other [tutorials](/docs/tutorials/.md) or go to the [next section](/docs/create-apps/.md) or try to connect your own Grasshopper script to your VIKTOR app! --- # Tutorial - Creating and analyzing a SCIA model note Estimated time: 60 minutes * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/integrate-scia/.md#introduction "Direct link to Introduction") This tutorial explains how a SCIA model can be created within VIKTOR, which can be used for analysis using an external coupling. The SCIA model that we will be constructing consists of a foundation slab with piles. * The starting app for this tutorial can be downloaded [here](/files/docs/scia-tutorial.zip). * The end result can be downloaded [here](/files/docs/scia-tutorial-complete.zip). Download the starting app to your hard disk. From within the app folder run the following command to install and start the app: ``` viktor-cli clean-start ``` In the browser, click the "Example" entity to open its editor and verify the app is installed and running as expected. ## Folder structure[​](/docs/tutorials/integrate-scia/.md#folder-structure "Direct link to Folder structure") The app has the following folder structure: ``` scia-tutorial ├── app.py ├── model.esa ├── requirements.txt └── viktor.config.toml ``` caution The example template SCIA file (model.esa) in this tutorial has been made in SCIA 19.0. The file cannot be opened nor run with versions < 19.0 (and is not guaranteed to work for > 19.0). If you are using a version of SCIA other than 19.0, a template file must be created for (and the worker must run) this specific version. This can be done with the following procedure: 1. Open a new project in your SCIA version of choice 2. Make sure that the material that will be used is present in the materials library 3. Setup the XML I/O document to export the desired results (see the [SCIA documentation](https://help.scia.net/19.0/en/pod/optimiser/xml_documents.htm)) 4. Save the empty file as *model.esa* 5. Replace the existing esa file with the just created one in the foundation folder Open `app.py` and have a look at the code that we have set up for you. Note that the code already creates an empty SCIA model and some basic class structure. We will extend the code and add specific SCIA objects, step-by-step, throughout this tutorial. ## Creating the corner nodes[​](/docs/tutorials/integrate-scia/.md#creating-the-corner-nodes "Direct link to Creating the corner nodes") If we assume that one of the corner points is located in the origin, the other three corner point locations can easily be calculated using `width_x` and `width_y`. Open `app.py` and add the following code `create_scia_model`: ``` def create_scia_model(self, params) -> vkt.scia.SciaModel: model = vkt.scia.SciaModel() ''' STRUCTURE ''' # create nodes at the slab corners width_x = params.geometry.slab.width_x * 1e-03 width_y = params.geometry.slab.width_y * 1e-03 n1 = model.create_node('n1', 0, 0, 0) # origin n2 = model.create_node('n2', 0, width_y, 0) n3 = model.create_node('n3', width_x, width_y, 0) n4 = model.create_node('n4', width_x, 0, 0) return model ``` note The corner nodes are defined in **clockwise direction**, since this order will be used later to create a 3D extrusion object. While setting up a SCIA model in VIKTOR, the 3D visualization is a very helpful feature to verify that the written logic does indeed create the model as desired. Therefore, we will extend `create_visualization_geometries` to get and show the just created nodes. This can easily be done by calling the `nodes` attribute of the `SciaModel`: ``` def create_visualization_geometries(self, params, scia_model): geometries = [] for node in scia_model.nodes: node_obj = vkt.Sphere(vkt.Point(node.x, node.y, node.z), params.geometry.slab.width_y * 1e-05) node_obj.material = vkt.Material('node', color=vkt.Color(0, 255, 0)) geometries.append(node_obj) return geometries ``` ![](/assets/images/tutorial-scia-corner-nodes-aa27cbc2e597e3ac841a98d22426bed7.png) *Corner nodes* ## Creating the piles[​](/docs/tutorials/integrate-scia/.md#creating-the-piles "Direct link to Creating the piles") For the purpose of this tutorial, some parameters like the number of piles and the distance between the piles and the edge are fixed. The locations of these piles however, depend on the dimensions of the slab: ``` ... import numpy as np import itertools def create_scia_model(self, params) -> vkt.scia.Model: ... # create the pile nodes number_of_piles_x = 4 number_of_piles_y = 3 pile_edge_distance = 0.3 pile_length = params.geometry.piles.length start_x = pile_edge_distance end_x = width_x - pile_edge_distance x = np.linspace(start_x, end_x, number_of_piles_x) start_y = pile_edge_distance end_y = width_y - pile_edge_distance y = np.linspace(start_y, end_y, number_of_piles_y) pile_positions = np.array(list(itertools.product(x, y))) pile_top_nodes = [] pile_bottom_nodes = [] for pile_id, (pile_x, pile_y) in enumerate(pile_positions, 1): n_top = model.create_node(f'K:p{pile_id}_t', pile_x, pile_y, 0) n_bottom = model.create_node(f'K:p{pile_id}_b', pile_x, pile_y, -pile_length) pile_top_nodes.append(n_top) pile_bottom_nodes.append(n_bottom) return model ``` Since we already loop through all the nodes in the `create_visualization_geometries` method (`for node in scia_model.nodes:`), the nodes located at the pile ends will automatically be visualized when the app is (automatically) restarted. ![](/assets/images/tutorial-scia-pile-nodes-8d45b27becf6ff6961f675c1caa507f1.png) *Pile nodes* The top and bottom nodes of the piles can now be used along with the pile diameter defined in the `Parametrization` to create a circular cross-section and beam elements. The cross-section in turn needs a `SciaMaterial` as input, which **needs to be defined in the .esa model** that is used. note The `Material` from the SCIA package is imported with a different name to prevent conflicts with the `Material` import from `viktor.geometry`. ``` def create_scia_model(self, params) -> vkt.scia.Model: ... # create pile beams pile_diameter = params.geometry.piles.diameter * 1e-03 material = vkt.scia.Material(0, 'C30/37') cross_section = model.create_circular_cross_section('concrete_pile', material, pile_diameter) pile_beams = [] for pile_id, (n_top, n_bottom) in enumerate(zip(pile_top_nodes, pile_bottom_nodes), 1): pile_beam = model.create_beam(n_top, n_bottom, cross_section) pile_beams.append(pile_beam) return model ``` For the visualization of the piles, a [`CircularExtrusion`](/sdk/api/geometry/.md#_CircularExtrusion) is used. This object needs a diameter and [`Line`](/sdk/api/geometry/.md#_Line) object which specifies the direction of the beam in terms of a start and end [`Point`](/sdk/api/geometry/.md#_Point). ``` def create_visualization_geometries(self, params, scia_model): ... # pile beams pile_diameter = params.geometry.piles.diameter * 1e-03 for beam in scia_model.beams: point_top = vkt.Point(beam.begin_node.x, beam.begin_node.y, beam.begin_node.z) point_bottom = vkt.Point(beam.end_node.x, beam.end_node.y, beam.end_node.z) beam_obj = vkt.CircularExtrusion(pile_diameter, vkt.Line(point_top, point_bottom)) beam_obj.material = vkt.Material('beam', roughness=1, opacity=0.3) geometries.append(beam_obj) ... ``` ![](/assets/images/tutorial-scia-pile-beams-163ef02495b591ed82aa6b1f7993fdf6.png) *Pile beams* ## Creating the slab[​](/docs/tutorials/integrate-scia/.md#creating-the-slab "Direct link to Creating the slab") The corner nodes that were created earlier can be used to create the concrete slab object. Extend the `create_scia_model` method with the following lines: ``` def create_scia_model(self, params) -> vkt.scia.Model: ... # create the concrete slab material = vkt.scia.Material(0, 'concrete_slab') thickness = params.geometry.slab.thickness * 1e-03 corner_nodes = [n1, n2, n3, n4] slab = model.create_plane(corner_nodes, thickness, name='foundation slab', material=material) return model ``` Again we can verify the position and dimensions of the created slab by means of visualization: ``` def create_visualization_geometries(self, params, scia_model): ... corner_points = [ vkt.Point(scia_model.nodes[0].x, scia_model.nodes[0].y, scia_model.nodes[0].z), vkt.Point(scia_model.nodes[1].x, scia_model.nodes[1].y, scia_model.nodes[1].z), vkt.Point(scia_model.nodes[2].x, scia_model.nodes[2].y, scia_model.nodes[2].z), vkt.Point(scia_model.nodes[3].x, scia_model.nodes[3].y, scia_model.nodes[3].z), vkt.Point(scia_model.nodes[0].x, scia_model.nodes[0].y, scia_model.nodes[0].z) ] thickness = params.geometry.slab.thickness * 1e-03 slab_obj = vkt.Extrusion(corner_points, vkt.Line(vkt.Point(0, 0, -thickness/2), vkt.Point(0, 0, thickness/2))) slab_obj.material = vkt.Material('slab', roughness=1, opacity=0.3) geometries.append(slab_obj) ... ``` ![](/assets/images/tutorial-scia-slab-7378714b202faede4692660c7b3a0bce.png) *Slab* ## Creating the supports[​](/docs/tutorials/integrate-scia/.md#creating-the-supports "Direct link to Creating the supports") Since the foundation will be completely underground, the following supports have to be attached: 1. Point supports ([`PointSupport`](/sdk/api/external/scia/.md#_PointSupport)) at the bottom of each pile: ``` def create_scia_model(self, params) -> vkt.scia.Model: ... ''' SUPPORTS ''' # create pile point supports freedom_v = ( vkt.scia.PointSupport.Freedom.FREE, vkt.scia.PointSupport.Freedom.FREE, vkt.scia.PointSupport.Freedom.FLEXIBLE, vkt.scia.PointSupport.Freedom.FREE, vkt.scia.PointSupport.Freedom.FREE, vkt.scia.PointSupport.Freedom.FREE ) kv = 400 * 1e06 stiffness_v = (0, 0, kv, 0, 0, 0) for pile_id, pile_beam in enumerate(pile_beams, 1): n_bottom = pile_beam.end_node model.create_point_support(f'Sn:p{pile_id}', n_bottom, vkt.scia.PointSupport.Type.STANDARD, freedom_v, stiffness_v, vkt.scia.PointSupport.CSys.GLOBAL) return model ``` 2. Line supports ([`LineSupport`](/sdk/api/external/scia/.md#_LineSupport)) on the piles: ``` def create_scia_model(self, params) -> vkt.scia.Model: ... # create pile line supports kh = 10 * 1e06 for pile_id, pile_beam in enumerate(pile_beams, 1): model.create_line_support_on_beam(pile_beam, x=vkt.scia.LineSupport.Freedom.FLEXIBLE, stiffness_x = kh, y=vkt.scia.LineSupport.Freedom.FLEXIBLE, stiffness_y = kh, z=vkt.scia.LineSupport.Freedom.FREE, rx=vkt.scia.LineSupport.Freedom.FREE, ry=vkt.scia.LineSupport.Freedom.FREE, rz=vkt.scia.LineSupport.Freedom.FREE, c_sys=vkt.scia.LineSupport.CSys.GLOBAL) return model ``` 3. Line supports ([`LineSupport`](/sdk/api/external/scia/.md#_LineSupport)) on the slab edges: ``` def create_scia_model(self, params) -> vkt.scia.Model: ... # create the slab supports stiffness_x = 50 * 1e06 stiffness_y = 50 * 1e06 for edge in (1, 3): model.create_line_support_on_plane((slab, edge), x=vkt.scia.LineSupport.Freedom.FLEXIBLE, stiffness_x=stiffness_x, y=vkt.scia.LineSupport.Freedom.FREE, z=vkt.scia.LineSupport.Freedom.FREE, rx=vkt.scia.LineSupport.Freedom.FREE, ry=vkt.scia.LineSupport.Freedom.FREE, rz=vkt.scia.LineSupport.Freedom.FREE) for edge in (2, 4): model.create_line_support_on_plane((slab, edge), x=vkt.scia.LineSupport.Freedom.FREE, y=vkt.scia.LineSupport.Freedom.FLEXIBLE, stiffness_y=stiffness_y, z=vkt.scia.LineSupport.Freedom.FREE, rx=vkt.scia.LineSupport.Freedom.FREE, ry=vkt.scia.LineSupport.Freedom.FREE, rz=vkt.scia.LineSupport.Freedom.FREE) return model ``` ## Creating the load combinations[​](/docs/tutorials/integrate-scia/.md#creating-the-load-combinations "Direct link to Creating the load combinations") Adding a load combination to the SCIA model is done in three steps, similarly as in the SCIA interface: 1. Create a load group ([`LoadGroup`](/sdk/api/external/scia/.md#_LoadGroup)) 2. Create a load case ([`LoadCase`](/sdk/api/external/scia/.md#_LoadCase)) 3. Create a load combination ([`LoadCombination`](/sdk/api/external/scia/.md#_LoadCombination)) ``` def create_scia_model(self, params) -> vkt.scia.Model: ... ''' SETS ''' # create the load group lg = model.create_load_group('LG1', vkt.scia.LoadGroup.LoadOption.VARIABLE, vkt.scia.LoadGroup.RelationOption.STANDARD, vkt.scia.LoadGroup.LoadTypeOption.CAT_G) # create the load case lc = model.create_variable_load_case('LC1', 'first load case', lg, vkt.scia.LoadCase.VariableLoadType.STATIC, vkt.scia.LoadCase.Specification.STANDARD, vkt.scia.LoadCase.Duration.SHORT) # create the load combination load_cases = { lc: 1 } model.create_load_combination('C1', vkt.scia.LoadCombination.Type.ENVELOPE_SERVICEABILITY, load_cases) return model ``` ## Creating the load(s)[​](/docs/tutorials/integrate-scia/.md#creating-the-loads "Direct link to Creating the load(s)") The last component of a complete SCIA model is the actual load that is applied on the structure. In this example, a simple uniform surface load is placed on the slab: ``` def create_scia_model(self, params) -> vkt.scia.Model: ... ''' LOADS ''' # create the load force = params.loads.input.uniform_load * 1e03 force *= -1 # in negative Z-direction model.create_surface_load('SF:1', lc, slab, vkt.scia.SurfaceLoad.Direction.Z, vkt.scia.SurfaceLoad.Type.FORCE, force, vkt.scia.SurfaceLoad.CSys.GLOBAL, vkt.scia.SurfaceLoad.Location.LENGTH) return model ``` ## Downloading the SCIA model[​](/docs/tutorials/integrate-scia/.md#downloading-the-scia-model "Direct link to Downloading the SCIA model") It is always helpful to generate the XML representation of the SCIA model and to manually load this input in the SCIA interface. This will help in verifying that, for example, all the loads are defined correctly in terms of placement and magnitude. In the app we will add a feature to download the necessary files. In order to be able to view the created model in the SCIA interface, the following three files are needed: 1. Empty SCIA model (`*.esa`) 2. Definition file (`*.def`) 3. Input file (`*.xml`) Now let's fill the download methods that we defined earlier in `Foundation`: ``` from pathlib import Path ... class Foundation(vkt.Controller): ... def download_scia_input_esa(self, params, **kwargs): scia_input_esa = self.get_scia_input_esa() return vkt.DownloadResult(scia_input_esa, 'model.esa') def download_scia_input_xml(self, params, **kwargs): scia_model = self.create_scia_model(params) input_xml, _ = scia_model.generate_xml_input() return vkt.DownloadResult(input_xml, 'test.xml') def download_scia_input_def(self, params, **kwargs): m = vkt.scia.Model() _, input_def = m.generate_xml_input() return vkt.DownloadResult(input_def, 'viktor.xml.def') def get_scia_input_esa(self) -> vkt.File: return vkt.File.from_path(Path(__file__).parent / 'model.esa') ``` note pathlib's `Path` object is VIKTOR's [recommended](/docs/create-apps/managing-files/.md) way of defining a path. You can now download the files from within VIKTOR. ## Viewing the model in SCIA[​](/docs/tutorials/integrate-scia/.md#viewing-the-model-in-scia "Direct link to Viewing the model in SCIA") caution SCIA 19.0 is required if using the example file. When the files are obtained, the empty .esa model can be opened in SCIA. This model will now be updated with the created input .xml file. In SCIA Engineer: 1. Click on `File` -> `Update` -> `XML file` 2. Select the `test.xml` file note It is important that the .xml and the .def files are located in the same directory, and the filename of the .def should not be changed. If this name is changed, make sure to also change the reference to this .def file in the input .xml file. The updated SCIA model should look like this: ![](/assets/images/tutorial-scia-model-scia-f6fcf3b5aa1afa7cb0f343a93097bb4f.png) *SCIA model generated by VIKTOR* ## Set up integration with SCIA[​](/docs/tutorials/integrate-scia/.md#set-up-integration-with-scia "Direct link to Set up integration with SCIA") ### Install SCIA worker[​](/docs/tutorials/integrate-scia/.md#install-scia-worker "Direct link to Install SCIA worker") Follow these steps to install the worker: * Development * Published App 1. Navigate to the "My Integrations" tab in your personal settings 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-dev-3e48cbb49064e926be6b80426e7fd165.png) 3.1. Select **SCIA** 3.2. Download the worker .msi (Microsoft Installer) and run it on the machine of choice 3.3. Copy the generated **connection key** and paste it when the installer asks for it caution You need to be an environment administrator in order to install a worker for a published app. 1. Navigate to the "Integrations" tab in the Administrator panel 2. Click "Add integration" 3. Follow the steps provided in the modal ![](/assets/images/create-integration-admin-598d0869714267fcb7a220c370dde5df.png) 3.1. Select **SCIA** 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 Connection Key The generated connection key **should be copied immediately** as VIKTOR will not preserve this data for security reasons. ### Add the Python code to run SCIA[​](/docs/tutorials/integrate-scia/.md#add-the-python-code-to-run-scia "Direct link to Add the Python code to run SCIA") The three files that are used for the verification above, can now be used as input for the external analysis. note An I/O document has to be defined in the `.esa` file, which has to be named "output". If not defined, the worker will not be able to write this expected document and fails to execute. In this example, the empty `model.esa` has the following structure of the I/O document: ![](data:image/png;base64,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) *I/O document of the esa model* Let's create a second view, which is a combination of geometry and data (results). Set the duration of this view to 60 seconds, which indicates that it concerns a long-running job with a manual update button. This button will be connected to the SCIA analysis: ``` class Foundation(vkt.Controller): ... @vkt.GeometryAndDataView("SCIA result", duration_guess=60, x_axis_to_right=True) def run_scia(self, params, **kwargs): scia_model = self.create_scia_model(params) # create input files input_xml, input_def = scia_model.generate_xml_input() input_esa = self.get_scia_input_esa() # analyze SCIA model scia_analysis = vkt.scia.SciaAnalysis(input_xml, input_def, input_esa) scia_analysis.execute(300) # timeout after 5 minutes data_result = vkt.DataGroup() geometries = self.create_visualization_geometries(params, scia_model) return vkt.GeometryAndDataResult(geometries, data_result) ``` After execution, the result can easily be called and parsed as desired. The "Reactions" results (defined in the I/O document) of the load combination C1 can be parsed from the analysis result using the provided output parser as is shown in the snippet below: ``` class Foundation(vkt.Controller): ... @vkt.GeometryAndDataView(...) def run_scia(self, params, **kwargs): scia_model = self.create_scia_model(params) # create input files input_xml, input_def = scia_model.generate_xml_input() input_esa = self.get_scia_input_esa() # analyze SCIA model scia_analysis = vkt.scia.SciaAnalysis(input_xml, input_def, input_esa) scia_analysis.execute(300) # timeout after 5 minutes scia_result = scia_analysis.get_xml_output_file() # parse analysis result result = vkt.scia.OutputFileParser.get_result(scia_result, "Reactions", parent='Combinations - C1') reactions = result['Nodal reactions'] max_rz = float(max(reactions['R_z'])) data_result = vkt.DataGroup( vkt.DataItem('SCIA results', ' ', subgroup=vkt.DataGroup( vkt.DataItem('Maximum pile reaction', max_rz, suffix='N', number_of_decimals=2) )) ) geometries = self.create_visualization_geometries(params, scia_model) return vkt.GeometryAndDataResult(geometries, data_result) ``` The pile reactions as seen from within the SCIA interface show a maximum of 3.3 kN (depending on your load input): ![](/assets/images/tutorial-scia-result-scia-7d2138b3714b62600ff4f2f835e94e55.png) *SCIA analysis result in SCIA* From the result obtained in VIKTOR we can validate that we indeed obtained the maximum reaction force of this load combination: ![](/assets/images/tutorial-scia-result-viktor-7af1b7a23a2bd6502dcd3a81985435bf.png) *SCIA analysis result obtained in VIKTOR* --- # Tutorial - Integrate STAAD.Pro note Estimated time: 55 minutes
Difficulty level: Intermediate * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/integrate-staadpro/.md#introduction "Direct link to Introduction") STAAD.Pro is one of the most widely used software tools for structural engineering. It offers a range of features for modeling and design, along with a robust API called OpenSTAAD that enables you to automate a workflow. In this tutorial, you will learn how to create a VIKTOR web app that integrates STAAD.Pro behind the scenes. Here are the main sections we will cover: 1. [Build a VIKTOR app.](/docs/tutorials/integrate-staadpro/.md#create-a-new-viktor-app) 2. [Create a simple parametric model.](/docs/tutorials/integrate-staadpro/.md#lets-create-our-3d-model) 3. [Calculate the member end forces of your model.](/docs/tutorials/integrate-staadpro/.md#working-with-openstaad-in-python) 4. [Display the member end forces in your VIKTOR app.](/docs/tutorials/integrate-staadpro/.md#lets-integrate-the-worker-in-our-viktor-app) Here is a sneak peek at how the app will look: ![model](/assets/images/tutorial_staadpro_webapp-fbf4f50595a69b7340f34e6f86c18ebf.png) ### Prerequisites and downloads[​](/docs/tutorials/integrate-staadpro/.md#prerequisites-and-downloads "Direct link to Prerequisites and downloads") PREREQUISITES You have [installed VIKTOR](/docs/getting-started/installation/.md) on your computer
You have some experience with reading Python code
You have some experience with STAAD.Pro Before using the OpenSTAAD API in Python, ensure you have `pywin32` and `comtypes` installed in your *main Python development environment*. If they are not installed, you can add them using pip: ``` pip install pywin32 comtypes openstaad ``` ## Create a new VIKTOR app[​](/docs/tutorials/integrate-staadpro/.md#create-a-new-viktor-app "Direct link to Create a new VIKTOR app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![Create app](/assets/images/tutorial_staadpro_create_new_app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the quickstart command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` RE-STARTING YOUR APP You only need to create an app template and install it once for each new app you want to make. as long as you don't close the terminal or your code editor, the app will update automatically once you save code in `app.py`. Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Let's define a simple frame[​](/docs/tutorials/integrate-staadpro/.md#lets-define-a-simple-frame "Direct link to Let's define a simple frame") To create a basic steel structure, we use a parametric method by setting the frame's `length` and `height` as adjustable variables. The `create_frame_data` function defines the frame's topology through **nodes** and **lines** to represent its geometry. By modifying the `length` and `height`, we can produce various configurations of the frame. Each execution of the function also saves the geometry in a `json` file. In the following sections, we will demonstrate how this function integrates with the `Controller` class, activated when new inputs are provided by the `Parametrization` class. You can extend your `app.py` to look something like this: ``` import viktor as vkt import json def create_frame_data(length, height, cross_section="IPE400"): nodes = { 1: {"node_id": 1, "x": 0, "z": 0, "y": 0}, 2: {"node_id": 2, "x": 0, "z": length, "y": 0}, 3: {"node_id": 3, "x": 0, "z": 0, "y": height}, 4: {"node_id": 4, "x": 0, "z": length, "y": height}, 5: {"node_id": 5, "x": length, "z": 0, "y": 0}, 6: {"node_id": 6, "x": length, "z": length, "y": 0}, 7: {"node_id": 7, "x": length, "z": 0, "y": height}, 8: {"node_id": 8, "x": length, "z": length, "y": height}, } lines = { 1: {"line_id": 1, "node_i": 1, "node_j": 3}, 2: {"line_id": 2, "node_i": 2, "node_j": 4}, 3: {"line_id": 3, "node_i": 3, "node_j": 4}, 4: {"line_id": 4, "node_i": 6, "node_j": 8}, 5: {"line_id": 5, "node_i": 5, "node_j": 7}, 6: {"line_id": 6, "node_i": 3, "node_j": 7}, 7: {"line_id": 7, "node_i": 4, "node_j": 8}, 8: {"line_id": 8, "node_i": 7, "node_j": 8}, 9: {"line_id": 9, "node_i": 1, "node_j": 4}, 10: {"line_id": 10, "node_i": 5, "node_j": 8}, } with open("inputs.json", "w") as jsonfile: json.dump([nodes, lines, cross_section], jsonfile) return nodes, lines class Parametrization(vkt.Parametrization): pass class Controller(vkt.Controller): parametrization = Parametrization ``` ## Let's create our 3D model[​](/docs/tutorials/integrate-staadpro/.md#lets-create-our-3d-model "Direct link to Let's create our 3D model") VIKTOR makes it easy to create various types of input fields for your application logic. You can use text fields, number fields, option fields, and many more to gather information from the user. You can find all available input components in the [VIKTOR documentation](/docs/create-apps/user-input/.md). This range of components lets you build clear and structured user interfaces without complex coding. The inputs defined in your `Parametrization` class are automatically available in the `params` object. You can retrieve a field's value, such as `frame_length`, by calling `params.frame_length`. This way, the parameter definitions stay decoupled from the rest of your logic, and you can easily access or modify the user input throughout your code. Now that we have our input fields, components, and our function to create the structure's topology, the next step is to build a 3D model of the frame, as shown in the code below. For this, we also use a convenient component called `GeometryView`. You can find more information about working with 3D geometry in VIKTOR in the [documentation](/docs/create-apps/results-and-visualizations/threed-model/.md). ``` import viktor as vkt import json from io import BytesIO from pathlib import Path from viktor.geometry import Point, Line, RectangularExtrusion def create_frame_data(length, height, cross_section="IPE400"): ... class Parametrization(vkt.Parametrization): intro = vkt.Text("# STAAD - Member End Forces App") inputs_title = vkt.Text('''## Frame Geometry Please fill in the following parameters to create the steel structure:''') frame_length = vkt.NumberField("Frame Length", min=0.3, default=8, suffix="m") frame_height = vkt.NumberField("Frame Height", min=1, default=6, suffix="m") line_break = vkt.LineBreak() section_title = vkt.Text('''## Frame Cross-Section Please select a cross section for the frame's elements:''') cross_sect = vkt.OptionField("Cross-Section", options=["IPE400", "IPE200"], default="IPE400") class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D Model", x_axis_to_right=True) def create_render(self, params, **kwargs): nodes, lines = create_frame_data(length=params.frame_length, height=params.frame_height) sections_group = [] for line_id, dict_vals in lines.items(): node_id_i = dict_vals["node_i"] node_id_j = dict_vals["node_j"] node_i = nodes[node_id_i] node_j = nodes[node_id_j] point_i = Point(node_i["x"], node_i["z"], node_i["y"]) point_j = Point(node_j["x"], node_j["z"], node_j["y"]) line_k = Line(point_i, point_j) cs_size = float(params.cross_sect[3:]) / 1000 # Convert from mm to meters section_k = RectangularExtrusion(cs_size, cs_size, line_k, identifier=str(line_id)) sections_group.append(section_k) return vkt.GeometryResult(geometry=sections_group) ``` Great! You can now modify the frame's dimensions and select a different cross-section, and the model will update to reflect the new geometry. Your browser should display an app that looks like this: ![model](/assets/images/tutorial_staadpro_geo_view-c64ec6e04cd7383c8437995f52db6202.png) Since you're here to learn how to integrate STAAD.Pro, let's move on and start using the OpenSTAAD API! ## Working with OpenSTAAD in Python[​](/docs/tutorials/integrate-staadpro/.md#working-with-openstaad-in-python "Direct link to Working with OpenSTAAD in Python") Let's create a new Python file called `run_staad_model.py` in the same directory and add the `run_staad` function. This function contains the logic to create our STAAD.Pro model using Python. The first step is to initialize the program with `subprocess`. Copy the snippet below, and make sure to update the `staad_path` to match your STAAD.Pro version. You can run this code in **your Python environment**, and it will launch STAAD.Pro and connect you to the OpenSTAAD API using `comtypes`. note If STAAD.Pro is running on a remote server, the `staad_path` needs to match the STAAD.Pro location on the server where the worker is running. ``` import subprocess import time import json import comtypes.client from pythoncom import CoInitialize, CoUninitialize from datetime import datetime from pathlib import Path from openstaad import Output def run_staad(): CoInitialize() # Replace with your version and file path. staad_path = r"C:\Program Files\Bentley\Engineering\STAAD.Pro 2024\STAAD\Bentley.Staad.exe" # Launch STAAD.Pro staad_process = subprocess.Popen([staad_path]) print("Launching STAAD.Pro...") time.sleep(15) # Connect to OpenSTAAD. openstaad = comtypes.client.GetActiveObject("StaadPro.OpenSTAAD") ``` ### Create the structure in STAAD.Pro[​](/docs/tutorials/integrate-staadpro/.md#create-the-structure-in-staadpro "Direct link to Create the structure in STAAD.Pro") Next, let's extend the `run_staad` function to add nodes, beams, and supports. We'll load the nodes and lines geometry from the `inputs.json` file, then create the nodes and beams in STAAD.Pro, followed by defining the material properties and the cross-section for the frame. Here's how all this looks in code: ``` def run_staad(): CoInitialize() # Launch STAAD.Pro and connect to OpenSTAAD as before... # Create a new STAAD file. now = datetime.now() timestamp = now.strftime("%Y-%m-%d_%H-%M") std_file_path = Path.cwd() / f"Structure_{timestamp}.std" length_unit = 4 # Meter force_unit = 5 # Kilo Newton openstaad.NewSTAADFile(str(std_file_path), length_unit, force_unit) # Load nodes and lines input_json = Path.cwd() / "inputs.json" with open(input_json) as jsonfile: data = json.load(jsonfile) nodes, lines, section_name = data[:] # Wait to load interface time.sleep(10) # Set Material and Beam Section staad_property = openstaad.Property staad_property._FlagAsMethod("SetMaterialName") staad_property._FlagAsMethod("CreateBeamPropertyFromTable") material_name = "STEEL" staad_property.SetMaterialName(material_name) country_code = 7 # European database # section_name is retrieved from inputs.json type_spec = 0 # ST (Single Section from Table) add_spec_1 = 0.0 # Not used for single sections add_spec_2 = 0.0 # Must be 0.0 # Create the beam property property_no = staad_property.CreateBeamPropertyFromTable( country_code, section_name, type_spec, add_spec_1, add_spec_2 ) # Create Members geometry = openstaad.Geometry geometry._FlagAsMethod("CreateNode") geometry._FlagAsMethod("CreateBeam") staad_property._FlagAsMethod("AssignBeamProperty") create_nodes = set() for line_id, vals in lines.items(): node_i_id = str(vals["node_i"]) node_i_coords = nodes[node_i_id] node_j_id = str(vals["node_j"]) node_j_coords = nodes[node_j_id] if node_i_id not in create_nodes: geometry.CreateNode( int(node_i_id), node_i_coords["x"], node_i_coords["y"], node_i_coords["z"] ) create_nodes.add(node_i_id) if node_j_id not in create_nodes: geometry.CreateNode( int(node_j_id), node_j_coords["x"], node_j_coords["y"], node_j_coords["z"] ) create_nodes.add(node_j_id) geometry.CreateBeam(int(line_id), node_i_id, node_j_id) # Assign beam property to beam ids staad_property.AssignBeamProperty(int(line_id), property_no) # Create supports support = openstaad.Support support._FlagAsMethod("CreateSupportFixed") support._FlagAsMethod("AssignSupportToNode") var_support_no = support.CreateSupportFixed() nodes_with_support = [1, 2, 5, 6] for node in nodes_with_support: support.AssignSupportToNode(node, var_support_no) ``` ### Run the analysis[​](/docs/tutorials/integrate-staadpro/.md#run-the-analysis "Direct link to Run the analysis") Now you can save the model and run the analysis. By default, we will create a load case that includes only the self-weight of the structure. After the analysis, we can extract the member end forces and save the results in a `.json` file to be used later in our VIKTOR app. ``` def run_staad(): # Previous code... # Create Load cases and add self-weight load = openstaad.Load load._FlagAsMethod("SetLoadActive") load._FlagAsMethod("CreateNewPrimaryLoad") load._FlagAsMethod("AddSelfWeightInXYZ") case_num = load.CreateNewPrimaryLoad("Self Weight") ret = load.SetLoadActive(case_num) # Load Case 1 ret = load.AddSelfWeightInXYZ(2, -1.0) # Load factor # Run analysis in silent mode command = openstaad.Command command._FlagAsMethod("PerformAnalysis") openstaad._FlagAsMethod("SetSilentMode") openstaad._FlagAsMethod("Analyze") openstaad._FlagAsMethod("isAnalyzing") command.PerformAnalysis(6) openstaad.SaveModel(1) time.sleep(3) openstaad.SetSilentMode(1) openstaad.Analyze() while openstaad.isAnalyzing(): print("...Analyzing") time.sleep(2) time.sleep(5) # Process Outputs output = Output() # GetMemberEndForces returns -> FX, FY, FZ, MX, MY and MZ (in order) end_forces = [list(output.GetMemberEndForces(beam=int(bid), start=False, lc=1)) for bid in lines] end_headers = [f"Beam:{lines[bid]['line_id']}/Node:{lines[bid]['node_j']}" for bid in lines] # Retrieve start forces and headers start_forces = [list(output.GetMemberEndForces(beam=int(bid), start=True, lc=1)) for bid in lines] start_headers = [f"Beam:{lines[bid]['line_id']}/Node:{lines[bid]['node_i']}" for bid in lines] # Combine forces and headers into lists of lists forces = end_forces + start_forces headers = end_headers + start_headers # Save to JSON file json_path = Path.cwd() / "output.json" with open(json_path, "w") as jsonfile: json.dump({"forces": forces, "headers": headers}, jsonfile) openstaad = None CoUninitialize() staad_process.terminate() return ret # Run the function if __name__ == "__main__":     openstaad = run_staad() ``` After running your `run_staad_model.py` in your Python environment, you should end up with a model like the following: ![model](/assets/images/tutorial_staadpro_model-9866e954f88e893e2024414c34e61ff8.png) ## Let's Integrate the worker in our VIKTOR app[​](/docs/tutorials/integrate-staadpro/.md#lets-integrate-the-worker-in-our-viktor-app "Direct link to Let's Integrate the worker in our VIKTOR app") A worker is simple program that lets you connect the app you have in the cloud to a server on which in this case STAAD.Pro and python can run to execute scripts and analyis' on models. Once we have a worker set up, we can connect our app! If you do not have access to a server with STAAD.Pro on it, do not worry, you can replicate this process on your local machine for the development of your applications. Don't have the worker installed yet? The connection between VIKTOR and STAAD.Pro is managed by the generic worker. You can install the worker on your local machine to test the integration by following this [guide](/docs/create-apps/software-integrations/staadpro/.md). n the `Controller` of our VIKTOR app, we need to set up the communication with the worker. To call the worker, we use the `PythonAnalysis` class, which allows us to send inputs (files and objects) to the worker. In this example, we will send the `inputs.json` and `run_staad_model.py` to be executed in the python environment set up for the worker. This environment can be on your own computer or a remote server. When `run_staad_model.py` is executed, it will generate the `output.json` file, and the worker will handle transferring this file from the server environment to our VIKTOR app. Here's how it looks in the code: ``` from viktor.external.python import PythonAnalysis from viktor.core import File from pathlib import Path from io import BytesIO class Controller(vkt.Controller): # Previous code... @vkt.TableView("Member End Forces", duration_guess=10, update_label="Run STAAD Analysis") def run_staad(self, params, **kwargs): nodes, lines = create_frame_data( length=params.frame_length, height=params.frame_height ) cross_section = params.cross_sect input_json = json.dumps([nodes, lines, cross_section]) script_path = Path(__file__).parent / "run_staad_model.py" script = File.from_path(script_path) files = [ ("inputs.json", BytesIO(bytes(input_json, "utf8"))), ] staad_analysis = PythonAnalysis( script=script, files=files, output_filenames=["output.json"] ) staad_analysis.execute(timeout=300) output_file = staad_analysis.get_output_file("output.json") output_file = json.loads(output_file.getvalue()) forces = [[round(force, 2) for force in row] for row in output_file["forces"]] return vkt.TableResult( forces, row_headers=output_file["headers"], column_headers=["FX [kN]", "FY [kN]", "FZ [kN] ", "MX [kN⋅m]", "MY [kN⋅m]", "MZ [kN⋅m]"], ) ``` Now you're ready to test your app. Make sure your worker is running and connected to your VIKTOR workspace, then try generating the model. After the analysis, your app should look like this: ![model](/assets/images/tutorial_staadpro_table_view-a621ff75c915f9658940322899e9dc12.jpg) ## Your turn to build[​](/docs/tutorials/integrate-staadpro/.md#your-turn-to-build "Direct link to Your turn to build") You now have everything you need to start building applications that integrate STAAD.Pro into your VIKTOR apps. You can also explore other [integration tutorials](/docs/tutorials/.md#intermediate-level) to learn how to connect more structural or geotechnical software to your apps! --- # Tutorial - Create an interactive map info Level: **Beginners**
Time: **20 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps)
***Not a reader?** feel free to follow this tutorial as a video* ## Introduction[​](/docs/tutorials/interactive-maps/.md#introduction "Direct link to Introduction") Welcome to this tutorial on how to create a web app that displays data on map, using VIKTOR and Python! As an engineer or data scientist, you may work with geo-located data. Visualizing this on a map is probably the best way to make this data insightful! In this tutorial, we will explore how to visualize points, lines, and polygons in a map with VIKTOR and python. We will also see how you can make this map interactive and ask users to provide a location. We will cover: 1. [Create an empty app template](/docs/tutorials/interactive-maps/.md#2-create-install-and-start-an-empty-app) 2. [Adding a map](/docs/tutorials/interactive-maps/.md#3-adding-a-map) 3. [Showing data on the map](/docs/tutorials/interactive-maps/.md#4-showing-data-on-the-map) 4. [Let's make it interactive!](/docs/tutorials/interactive-maps/.md#5-lets-make-it-interactive) 5. [Using custom markers and colors](/docs/tutorials/interactive-maps/.md#6-but-wait-there-is-more) By the end of this tutorial you will be able to place points, lines and polygons in a VIKTOR app and have a basic understanding of how you can use maps to enhance your visuals! It will look similar to the gif below: Need help? Are you encountering an error? Take a look at the [**complete app code**](/docs/tutorials/interactive-maps/.md#complete-app-code). Also know that you can always ask for help at our [**Community Forum**](https://community.viktor.ai/), where our developers are ready to help with any question related to the installation, coding and more. ## 1. Create, install and start an empty app[​](/docs/tutorials/interactive-maps/.md#1-create-install-and-start-an-empty-app "Direct link to 1. Create, install and start an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. Did you encounter any errors? * Always make sure to check the spelling of everything you placed in the command-line, a small mistake and the command you are trying to run may not be recognised! * If you are encountering: ``` ERROR: Exiting because of an error: no requirements.txt file PS C:\Users\\viktor-apps> ``` Then you are not in the correct folder! check the command-line and navigate to the map-tutorial folder. * If you are encountering: ``` Error: App definition is not compatible with the data currently stored in the database. Use the command 'viktor-cli clear' to clear the database. PS C:\Users\\viktor-apps\map-tutorial> ``` That means you have not cleared the database yet! Use the `viktor-cli clear` to clear and then you can use `viktor-cli start` to start the app. No need to install it again! Not seeing any of these errors? Head over to our community! There is a good chance another developer encountered it and solved it too! ## 2. Adding a map[​](/docs/tutorials/interactive-maps/.md#2-adding-a-map "Direct link to 2. Adding a map") The app we will be making during this tutorial will display flight paths for air traffic. It will also include functionality for visualizing a no-flight zone. To begin, we will add the map to our app using a [`MapView`](/sdk/api/views/.md#_MapView). Remember that we always add views in the `Controller` class. We will also create a list called `features`, containing everything we want to show on the map. The list is empty for now, but we will fill it in the following steps. 1. Open `app.py` and make sure your code looks like this. Notice that all the required import statements are already included. This will save us some back-and-forth along the way. If you like you can use the searchbar on the top-right of this page to get some more information on those features: ``` import viktor as vkt class Parametrization(vkt.Parametrization): pass class Controller(vkt.Controller): parametrization = Parametrization @vkt.MapView('Flight Analysis') def generate_map(self, params, **kwargs): features = [] return vkt.MapResult(features) ``` 2. Go to your cloud environment (e.g. [cloud.viktor.ai](https://cloud.viktor.ai/workspaces)) and open the development card. Great! You will be able to see the map. ![](/assets/images/tutorial-map-1-empty-map-c08e09fadb31c4549c2ec2bb1024676b.png) ## 3. Showing data on the map[​](/docs/tutorials/interactive-maps/.md#3-showing-data-on-the-map "Direct link to 3. Showing data on the map") We will draw a polygon on the map to mark the no-fly zone using [`MapPolygon`](/sdk/api/views/.md#_MapPolygon). To create this polygon, we must first define its corner using [`MapPoints`](/sdk/api/views/.md#_MapPoint). 1. Go to `app.py` and modify the code under the `MapView` so it looks like this: ``` @vkt.MapView('Flight Analysis') def generate_map(self, params, **kwargs): features = [] # Draw no-fly zone no_fly_zone = vkt.MapPolygon([ vkt.MapPoint(54.814614, -26.785331), vkt.MapPoint(54.610949, -15.190123), vkt.MapPoint(50.824269, -15.429211), vkt.MapPoint(50.864828, -26.741683)], ) features.append(no_fly_zone) return vkt.MapResult(features) ``` 2. Go to your app in the browser and refresh the page. Awesome! You should now be able to see the no-fly zone we just made ![](/assets/images/tutorial-map-2-polygon-39607e2fa3b1e1fce894f6b9fda03fff.png) ## 4. Let's make it interactive\![​](/docs/tutorials/interactive-maps/.md#4-lets-make-it-interactive "Direct link to 4. Let's make it interactive!") In this part of the tutorial, we will add some interactivity. We will define a flight path by letting the user choose the departing and arriving airport by clicking on the map! We will do this using [`GeoPointField`](/sdk/api/parametrization/.md#_GeoPointField). We just want to let you know that there is also [`GeoPolylineField`](/sdk/api/parametrization/.md#_GeoPolylineField) and [`GeoPolygonField`](/sdk/api/parametrization/.md#_GeoPolygonField) that you can use in your app. Also, we will add a [`Text`](/sdk/api/parametrization/.md#_Text) description that helps the users understand what they need to do. 1. Under your `Parametrization` class add these fields, and don’t forget to delete `pass`: ``` ... class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ✈️ Flight Analysis App! In this app, you can analyze a flight path and whether it passes through a no-fly zone. **Select two points** corresponding to the airports of departure and arrival. """) dep_airport = vkt.GeoPointField('Departing Airport') arr_airport = vkt.GeoPointField('Arriving Airport') ``` 2. Refresh the app and take a look. You will notice the new `GeoFields` and the description. Give them a try. 3. Maybe you already noticed this, but the markers disappear after clicking the map. To solve the problem, let’s add the points to our `features` list in the `MapView` list. Note that we will add an `if-statement` before adding them so the app does not give an error when the user hasn't clicked on the map yet (e.g. `params.dep_airport = None`) Under the line `features.append(no_fly_zone)` add: ``` ... features.append(no_fly_zone) # <--- this line is for your reference if params.dep_airport: dep_point = vkt.MapPoint.from_geo_point(params.dep_airport) features.append(dep_point) if params.arr_airport: arr_point = vkt.MapPoint.from_geo_point(params.arr_airport) features.append(arr_point) ``` 4. Since we are looking to analyze the flight, we also need to add a flight path. Let’s connect the dots 😉. Under the lines we just added, add: ``` if params.dep_airport and params.arr_airport: flight_path = vkt.MapLine(dep_point, arr_point) features.append(flight_path) ``` 5. Refresh your app and take a look. Fantastic, you have now made an app to add flight paths to a map and see whether they enter a no-fly zone. You have done a great job! 🥳 ![](/assets/images/tutorial-map-3-geofields-4c2cc29b28ba2a9202f676c7f757ea9a.png) ## 5. But wait... there is more\![​](/docs/tutorials/interactive-maps/.md#5-but-wait-there-is-more "Direct link to 5. But wait... there is more!") We made a beautiful app together, but let’s make it even better by adding some color, custom pins, and descriptive labels. Pins & Colors Here you can find a list of all [pins](/sdk/api/views/.md#_MapPoint) and [colors](/sdk/api/core/.md#_Color). 1. Let’s make it clear that it is a no-fly zone by making it red and adding a description that the user will see when clicking on the map. Do this by adding these lines of code where you define the `no_fly_zone`: ``` no_fly_zone = vkt.MapPolygon([ vkt.MapPoint(54.814614, -26.785331), vkt.MapPoint(54.610949, -15.190123), vkt.MapPoint(50.824269, -15.429211), vkt.MapPoint(50.864828, -26.741683)], color=vkt.Color.red(), # <--- add this line title="No-fly zone", # <--- add this line description="⛔ This is a no-fly zone. Stay out of this zone!" # <--- add this line ) ``` 2. We will make airport pins blue and change their icon. Find where we define `dep_point` and `arr_point` and modify the code like this: ``` dep_point = vkt.MapPoint.from_geo_point(params.dep_airport, icon='triangle', color=vkt.Color.blue()) ``` ``` arr_point = vkt.MapPoint.from_geo_point(params.arr_airport, icon='triangle-down', color=vkt.Color.blue()) ``` 3. Refresh your app and play with it. Congratulations! You made a wonderful interactive map and even personalized it by using custom icons and colors. You have done a great job and can be proud of yourself! 😎 By now, your app should look like this: ![](/assets/images/tutorial-map-4-custom-1e01e32c48c20adf950b9225f553d3e1.png) ## Complete app code[​](/docs/tutorials/interactive-maps/.md#complete-app-code "Direct link to Complete app code") Were you able to do everything in this tutorial without error? If not, you can always take a look at the full code: **Complete code** ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ✈️ Flight Analysis App! In this app, you can analyze a flight path and whether it passes through a no-fly zone. **Select two points** corresponding to the airports of departure and arrival. """) dep_airport = vkt.GeoPointField('Departing Airport') arr_airport = vkt.GeoPointField('Arriving Airport') class Controller(vkt.Controller): parametrization = Parametrization @vkt.MapView('Flight Analysis') def generate_map(self, params, **kwargs): features = [] # Draw no-fly zone no_fly_zone = vkt.MapPolygon([ vkt.MapPoint(54.814614, -26.785331), vkt.MapPoint(54.610949, -15.190123), vkt.MapPoint(50.824269, -15.429211), vkt.MapPoint(50.864828, -26.741683)], color=vkt.Color.red(), title="No-fly zone", description="⛔ This is a no-fly zone. Stay out of this zone!" ) features.append(no_fly_zone) # Draw airports if params.dep_airport: dep_point = vkt.MapPoint.from_geo_point(params.dep_airport, icon='triangle', color=vkt.Color.blue()) features.append(dep_point) if params.arr_airport: arr_point = vkt.MapPoint.from_geo_point(params.arr_airport, icon='triangle-down', color=vkt.Color.blue()) features.append(arr_point) # Draw flight path if params.dep_airport and params.arr_airport: flight_path = vkt.MapLine(dep_point, arr_point) features.append(flight_path) return vkt.MapResult(features) ``` ## Want to learn how VIKTOR works?[​](/docs/tutorials/interactive-maps/.md#want-to-learn-how-viktor-works "Direct link to Want to learn how VIKTOR works?") If you are interested in how VIKTOR works behind the scenes, for example how it processes your input, expand the tabs below! #### How does it work?[​](/docs/tutorials/interactive-maps/.md#how-does-it-work "Direct link to How does it work?") How does the Parametrization work? In the **Parameterization** class you can add input fields that allow the user to provide input to your app, and there are more than 20 [different input fields](/docs/create-apps/user-input/.md) you can use, including numbers, text, colors, images and files. Inside the Parametrization class, you can also format the [layout of your app](/docs/create-apps/layout-and-styling/.md) by adding sections, tabs, steps and pages. To show your Parametrization in the app, we need to add the line `parametrization = Parametrization` inside the `Controller` class, because it is the controller that determines what is shown and not. How does the Parametrization get saved? So you may be wondering, how do you get the information from the parametrization to my controller? Well, we do this automatically for you. The values of all parameters are stored in a single variable called `params` , which is accessible inside the Controller class. These variables are stored in a `Munch`; this is similar to a dictionary, but work with point denotation. Example: * Let's say we have a variable called `height` as a NumberField in our `Parameterization`. * To use it in a method in the `Controller`, define it as: `def my_method(self, params, **kwargs)` * You can now make calculations inside that method using our height parameter as `params.height`! How does the Controller work? The **Controller** class is the place where you add everything you want to calculate and show. As explained in this tutorial, we show results in a `View` and we always add views in our controller. You can even add several views in a single app by adding them to the controller class... and yes, we have [many Views](/docs/create-apps/results-and-visualizations/.md),for showing graphs, maps, 3D models, reports, images and more. In the Controller, you also do or call your calculation. Remember that the user input given in the parametrization, is accessible inside the Controller class in the variable The `params`. ## What's next[​](/docs/tutorials/interactive-maps/.md#whats-next "Direct link to What's next") Very impressive! You have now learned the basics of the VIKTOR `MapView`. In this tutorial, we have only scratched the surface of what you can do using maps. So don’t stop your journey there! If you like an extra challenge, here are some ideas: * Make the no-fly zone interactive using a `GeoPolygonField` * Make the flight path red when it crosses the no-fly zone and green when it doesn’t * Create a flight path that passes several points using a `GeoPolylineField` * Calculate the distance of the flight path and show it on the map Or just follow some of our other [tutorials](/docs/tutorials/.md) More about maps You can find more information about how to use maps in the [maps guide](/docs/create-apps/results-and-visualizations/map/.md). Also check more about [input fields for maps](/docs/create-apps/user-input/map-features/.md) --- # Tutorial - 3D models info Level: **Intermediate**
Time: **30 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) ## Introduction[​](/docs/tutorials/intermediate-3d-model/.md#introduction "Direct link to Introduction") As a designer or engineer, creating 3D models is an essential part of your work. 3D models can help you visualize and communicate complex concepts in a way that is easy to understand. In this tutorial, we will explore how to create 3D models in VIKTOR using Python. By the end of this tutorial, you will have the skills and knowledge needed to create your own 3D models in VIKTOR using Python. We will start with simple shapes and gradually work our way up to more complex models. Whether you are a beginner or an experienced designer, this tutorial will provide you with a solid foundation in 3D modeling with VIKTOR. This tutorial consists of six different sections: 1. [Create an empty app](/docs/tutorials/intermediate-3d-model/.md#1-create-install-and-start-an-empty-app) 2. [Set up the basis](/docs/tutorials/intermediate-3d-model/.md#2-set-up-the-basis) 3. [Drawing the bridge deck](/docs/tutorials/intermediate-3d-model/.md#3-drawing-the-bridge-deck) 4. [Adding supports](/docs/tutorials/intermediate-3d-model/.md#4-adding-supports) 5. [The finishing touches](/docs/tutorials/intermediate-3d-model/.md#5-the-finishing-touches) 6. [The complete app code](/docs/tutorials/intermediate-3d-model/.md#complete-app-code) To give you an idea of what you will be creating, here's a GIF of the application you will me making throughout this tutorial: ![](/assets/images/tutorial_three_d_animation-aa11aa168b90b5fb7ed3637b5f5b1cce.gif) *What the app looks like once you complete this tutorial* Need help? Are you encountering an error? Take a look at the [**complete app code**](/docs/tutorials/intermediate-3d-model/.md#complete-app-code). Also know that you can always ask for help at our [**Community Forum**](https://community.viktor.ai/), where our developers are ready to help with any question related to the installation, coding and more. ## 1. Create, install and start an empty app[​](/docs/tutorials/intermediate-3d-model/.md#1-create-install-and-start-an-empty-app "Direct link to 1. Create, install and start an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. Did you encounter any errors? * Always make sure to check the spelling of everything you placed in the command-line, a small mistake and the command you are trying to run may not be recognised! * If you are encountering: ``` ERROR: Exiting because of an error: no requirements.txt file PS C:\Users\\viktor-apps> ``` Then you are not in the correct folder! check the command-line and navigate to the 3D-model-tutorial folder. * If you are encountering: ``` Error: App definition is not compatible with the data currently stored in the database. Use the command 'viktor-cli clear' to clear the database. PS C:\Users\\viktor-apps\3D-model-tutorial> ``` That means you have not cleared the database yet! Use the `viktor-cli clear` to clear and then you can use `viktor-cli start` to start the app. No need to install it again! Not seeing any of these errors? Head over to our community! There is a good chance another developer encountered it and solved it too! ## 2. Set up the basis[​](/docs/tutorials/intermediate-3d-model/.md#2-set-up-the-basis "Direct link to 2. Set up the basis") In this tutorial we will make a 3D model. In this example case you will be modelling a bridge including a simplified version of the river running underneath it, the sloped embankment on the side of the river and the supports underneath the bridge. 🌉 Let's start easy and create a simple bridge deck and a river running underneath it, and some input fields to change the dimensions. ### Input fields[​](/docs/tutorials/intermediate-3d-model/.md#input-fields "Direct link to Input fields") We will add 4 inputfields to define the dimensions of our bridge, our app: `length`, `width`, `height` and `deck_thickness`. We will use a [`Numberfield`](/sdk/api/parametrization/.md#_NumberField), for each. 1. Open `app.py`, and add the relevant fields to your parametrization. It is always good to give people some context using [`Text`](/docs/create-apps/inform-end-user/text-blocks/.md) elements. Don't forget to import the necessary fields. In the end your `app.py` file should look like this: ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D model app 🌉\n This app parametrically generates and visualises a 3D model of a bridge") txt_deck = vkt.Text('### Deck layout ') # texts can be used for explanation in the user-interface length = vkt.NumberField("Deck length", min=6, default=100, suffix='m') width = vkt.NumberField("Deck width", min=2, default=20, suffix='m') deck_thickness = vkt.NumberField("Deck thickness", min=0.5, default=1, suffix='m') height = vkt.NumberField("Bridge height", min=2, default=10, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization ``` 2. Refresh your app, and you should see the input fields there. ### Basic set up & the river[​](/docs/tutorials/intermediate-3d-model/.md#basic-set-up--the-river "Direct link to Basic set up & the river") We don’t need a bridge if there is no river. So, let’s start with making the river step by step and set up the basis for the next parts, so we can explain some concepts. 1. We want to show a 3D model, so we will create a [`GeometryView`](/docs/create-apps/results-and-visualizations/threed-model/.md) inside your `controller` like this: ``` class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D", x_axis_to_right=True) def visualize_bridge(self, params, **kwargs): return vkt.GeometryResult(geometry_group) ``` 2. Inside `visualize_bridge`, we'll create a empty [`Group`](/sdk/api/geometry/.md#_Group) to store all elements we want to show: ``` # Create an empty group to hold all the geometry geometry_group = vkt.Group([]) ``` 3. Now we'll define the measurements of the river and bridge's surroundings. We don’t want to make new input field for that, so we will just use the bridge measurements for this. Inside `visualize_bridge`: ``` # Measurements environment env_width = params.length env_thick = params.deck_thickness # Thickness of water and embankment water_width = params.length - 2 * params.height # Assuming embankment at 45 deg ``` 4. Then, create a [`Material`](/sdk/api/geometry/.md#_Material) so we can make the water blue, and let's make it a bit transparent. Inside `visualize_bridge`: ``` # Create materials mat_water = vkt.Material('Water', color=vkt.Color.blue(), opacity=0.7) ``` 5. Next, create the water by drawing a box is using [`SquareBeam`](/sdk/api/geometry/.md#_SquareBeam) and add it to the `Group` we made before. Inside `visualize_bridge` add: ``` # Draw water water = vkt.SquareBeam(water_width, env_width, env_thick, material=mat_water) ``` 6. The last step is return the geometry, so it is visualized: ``` geometry_group.add([water]) ``` 7. Update your app, and you will see the river ### All code until now[​](/docs/tutorials/intermediate-3d-model/.md#all-code-until-now "Direct link to All code until now") Click here to see **all code until now** ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D model app 🌉\n This app parametrically generates and visualises a 3D model of a bridge") txt_deck = vkt.Text('### Deck layout ') # texts can be used for explanation in the user-interface length = vkt.NumberField("Deck length", min=6, default=100, suffix='m') width = vkt.NumberField("Deck width", min=2, default=20, suffix='m') deck_thickness = vkt.NumberField("Deck thickness", min=0.5, default=1, suffix='m') height = vkt.NumberField("Bridge height", min=2, default=10, suffix='m') class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D", x_axis_to_right=True) def visualize_bridge(self, params, **kwargs): # Create an empty group to hold all the geometry geometry_group = vkt.Group([]) # Measurements environment env_width = params.length env_thick = params.deck_thickness # Thickness of water and embankment water_width = params.length - 2 * params.height # Assuming embankment at 45 deg # Create materials mat_water = vkt.Material('Water', color=vkt.Color.blue(), opacity=0.7) # Draw water water = vkt.SquareBeam(water_width, env_width, env_thick, material=mat_water) geometry_group.add([water]) return vkt.GeometryResult(geometry_group) ``` ## 3. Drawing the bridge deck[​](/docs/tutorials/intermediate-3d-model/.md#3-drawing-the-bridge-deck "Direct link to 3. Drawing the bridge deck") Now that we have the basis for drawing our 3D models, and a beautiful river 😉, we can quickly create the bridge: ### Adding the deck[​](/docs/tutorials/intermediate-3d-model/.md#adding-the-deck "Direct link to Adding the deck") We'll create the bridge inside the `GeometryView`, like we did before. 1. Create the deck, using the `SquareBeam` function as well, and give the deck a width, length and thickness. ``` deck = vkt.SquareBeam(params.length, params.width, params.deck_thickness) ``` 2. `SquareBeam` creates a box with its centre at the origin (0, 0, 0). In order to move the deck to the correct position let's use [`translate`](/sdk/api/geometry/.md#_TransformableObject) ``` deck.translate((0, 0, params.height)) ``` 3. Now we will create the deck top, you can interpret this top as the asphalt layer of the bridge. But first, let's define a new material. This time we'll define the `Color` using RGB values: ``` mat_deck_top = vkt.Material('Deck top', color=vkt.Color(60, 60, 60)) ``` 4. Again, use `SquareBeam` and `translate` it in the z-direction: ``` deck_top = vkt.SquareBeam(params.length, params.width, params.deck_thickness / 4, material=mat_deck_top) deck_top.translate((0, 0, params.height + 5/8*params.deck_thickness)) ``` 5. Add the created elements to the geometry `Group` so they get visualized: ``` geometry_group.add([deck, deck_top]) ``` 6. Refresh your application, you should see the water and the bridge in 3D view. ## 5. Adding supports[​](/docs/tutorials/intermediate-3d-model/.md#5-adding-supports "Direct link to 5. Adding supports") That's a really beautiful bridge, but something feels wrong, it looks like the bridge is flying, so we are now going to generate some supports for it, parametrically of course. ### The plan[​](/docs/tutorials/intermediate-3d-model/.md#the-plan "Direct link to The plan") Before going into the code, let's discuss the plan. We will make a V-shaped support and place it on several locations according to a 'grid', as shown here: ![](/assets/images/tutorial-three-d-supports-aacfa2b654a79d0f9b75c1206ef8de34.png) ### Input fields[​](/docs/tutorials/intermediate-3d-model/.md#input-fields-1 "Direct link to Input fields") With that said, let's jump into the code. 1. We will add 2 input fields to our app: `support_amount`, `support_piles_amount`. These inputs will define how many supports we want. Inside the `parametrization` class add the following three lines of code: ``` txt_support = vkt.Text('### Support layout', flex=100) support_amount = vkt.NumberField("Number of supports", default=2, min=1) support_piles_amount = vkt.NumberField("Number of piles per support", min=2, default=3) ``` 2. Refresh your app and you should see the new input fields. ### Create one support[​](/docs/tutorials/intermediate-3d-model/.md#create-one-support "Direct link to Create one support") Next let's make the bridge supports. The supports each consist of two columns in a V-formation placed on a support box. As before, we will draw the different element inside the `GeometryView` 1. Inside your `GeometryView` before the `return`, we will define the pile diameter and the grid size. Note that we did not create an input field to define the diameter (but feel free), so we will make it equal to ½ of the deck thickness: ``` pile_diameter = params.deck_thickness / 2 grid_size_x = water_width / params.support_amount grid_size_y = (params.width - pile_diameter) / (params.support_piles_amount - 1) ``` 2. Draw one column and use [`mirror_object`](/sdk/api/geometry/.md#_mirror_object) to get the V-shape. We draw the column by extruding a circle along a line using [`CircularExtrusion`](/sdk/api/geometry/.md#_CircularExtrusion): ``` # Draw columns top_point = vkt.Point(-grid_size_x/2, 0, params.height) bottom_point = vkt.Point(0, 0, 0) column_line = vkt.Line(top_point, bottom_point) column_1 = vkt.CircularExtrusion(pile_diameter, column_line) column_2 = vkt.geometry.mirror_object(column_1, vkt.Point(0, 0, 0), (1, 0, 0)) ``` 3. Let's now add the box at the base to complete our support: ``` # Draw base column_base = vkt.SquareBeam(3 * pile_diameter, pile_diameter, 2*pile_diameter) ``` 4. For the next step, it is convenient to put the 3 elements we just made in a new `Group`: ``` support = vkt.Group([column_1, column_2, column_base]) ``` 5. Let's see our progress by temporarily adding the `support` to our `geometry_group` and updating your app: ``` geometry_group.add([support]) ``` 6. Before continuing, eliminate the line of code we added in the last step. ### Repeating the supports[​](/docs/tutorials/intermediate-3d-model/.md#repeating-the-supports "Direct link to Repeating the supports") We will now use the support we draw in the last section and repeat it according to our grid. As before, we will continue to work inside our `GeometryView`. Improve the speed of your app When we hear repeating, our Python minds immediately think in a for loop. But in VIKTOR, we do **not use a for loop** for making repetitive geometries. This will make you app unnecessary slow. For this `Pattern`, `LinearPattern`, and `BidirectionalPattern` are better suited. This can reduce the loading time from minutes to seconds in larger models. 1. First, place the `support` in the corner of the grid using `translate`: ``` support.translate((-water_width/2 + grid_size_x/2, -params.width/2 + pile_diameter/2, 0)) ``` 2. Now, we will copy the support using [`BidirectionalPattern`](/sdk/api/geometry/.md#_BidirectionalPattern). While this may seem like a difficult function at first, the implementation is surprisingly easy: ``` all_supports = vkt.BidirectionalPattern( base_object=support, direction_1=[1, 0, 0], direction_2=[0, 1, 0], number_of_elements_1=params.support_amount, number_of_elements_2=params.support_piles_amount, spacing_1=grid_size_x, spacing_2=grid_size_y ) ``` 3. Let's add `all_supports` to `geometry_group` so we visualize them ``` # Adding geometry group to geometry result geometry_group.add(all_supports) ``` 4. Refresh your app, and look how amazing your bridge is looking! ### All code until now[​](/docs/tutorials/intermediate-3d-model/.md#all-code-until-now-1 "Direct link to All code until now") Click here to see **all code until now** ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D model app 🌉\n This app parametrically generates and visualises a 3D model of a bridge") txt_deck = vkt.Text('### Deck layout ') # texts can be used for explanation in the user-interface length = vkt.NumberField("Deck length", min=6, default=100, suffix='m') width = vkt.NumberField("Deck width", min=2, default=20, suffix='m') deck_thickness = vkt.NumberField("Deck thickness", min=0.5, default=1, suffix='m') height = vkt.NumberField("Bridge height", min=2, default=10, suffix='m') txt_support = vkt.Text('### Support layout', flex=100) support_amount = vkt.NumberField("Number of supports", default=2, min=1) support_piles_amount = vkt.NumberField("Number of piles per support", min=2, default=3) class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D", x_axis_to_right=True) def visualize_bridge(self, params, **kwargs): # Create an empty group to hold all the geometry geometry_group = vkt.Group([]) # =============================== # Draw Environment # =============================== # Measurements environment env_width = params.length env_thick = params.deck_thickness # Thickness of water and embankment water_width = params.length - 2 * params.height # Assuming embankment at 45 deg # Create materials mat_water = vkt.Material('Water', color=vkt.Color.blue(), opacity=0.7) mat_deck_top = vkt.Material('Deck top', color=vkt.Color(60, 60, 60)) # Draw water water = vkt.SquareBeam(water_width, env_width, env_thick, material=mat_water) geometry_group.add([water]) # =============================== # Create Bridge # =============================== # Draw deck deck = vkt.SquareBeam(params.length, params.width, params.deck_thickness) deck.translate((0, 0, params.height)) deck_top = vkt.SquareBeam(params.length, params.width, params.deck_thickness / 4, material=mat_deck_top) deck_top.translate((0, 0, params.height + 5/8*params.deck_thickness)) geometry_group.add([deck, deck_top]) # Define grid pile_diameter = params.deck_thickness / 2 grid_size_x = water_width / params.support_amount grid_size_y = (params.width - pile_diameter) / (params.support_piles_amount - 1) # Draw columns top_point = vkt.Point(-grid_size_x/2, 0, params.height) bottom_point = vkt.Point(0, 0, 0) column_line = vkt.Line(top_point, bottom_point) column_1 = vkt.CircularExtrusion(pile_diameter, column_line) column_2 = vkt.geometry.mirror_object(column_1, vkt.Point(0, 0, 0), (1, 0, 0)) # Draw base column_base = vkt.SquareBeam(3 * pile_diameter, pile_diameter, 2*pile_diameter) # Pattern supports support = vkt.Group([column_1, column_2, column_base]) support.translate((-water_width/2 + grid_size_x/2, -params.width/2 + pile_diameter/2, 0)) all_supports = vkt.BidirectionalPattern( base_object=support, direction_1=[1, 0, 0], direction_2=[0, 1, 0], number_of_elements_1=params.support_amount, number_of_elements_2=params.support_piles_amount, spacing_1=grid_size_x, spacing_2=grid_size_y ) # Adding geometry group to geometry result geometry_group.add(all_supports) return vkt.GeometryResult(geometry_group) ``` ## 5. The finishing touches[​](/docs/tutorials/intermediate-3d-model/.md#5-the-finishing-touches "Direct link to 5. The finishing touches") You already made an amazing parametric bridge and learned the basics of creating 3D models in VIKTOR. In this chapter we just want to show you some little extras that can be useful during your app development journey. ### Drawing the embankment[​](/docs/tutorials/intermediate-3d-model/.md#drawing-the-embankment "Direct link to Drawing the embankment") We already learned that you can move things using `translate`. This is because everything you draw is a [`TransformableObject`](/sdk/api/geometry/.md#_TransformableObject). Besides `translate` you can also use other transformations, like [`rotate`](/sdk/api/geometry/.md#TransformableObject.rotate), [`mirror`](/sdk/api/geometry/.md#TransformableObject.mirror) and [`scale`](/sdk/api/geometry/.md#TransformableObject.scale). Let’s give this a try drawing the embankments. 1. In your `GeometryView`, let's add a new `Material`: ``` mat_grass = vkt.Material('Grass', color=vkt.Color.green()) ``` 2. Then, we will create, `rotate`, and `translate` the embankment, and make a copy of it : ``` # Draw embankment (assuming embankment at 45 deg) embankment_1 = vkt.SquareBeam(1.4 * params.height, env_width, env_thick, material=mat_grass) embankment_1.rotate(-math.pi / 4, direction=[0, 1, 0]) embankment_1.translate(((water_width+params.height)/2, 0, params.height/2)) embankment_2 = vkt.geometry.mirror_object(embankment_1, vkt.Point(0, 0, 0), (1, 0, 0)) ``` 3. As allways, add the objects to `geometry_group`: ``` geometry_group.add([embankment_1, embankment_2]) ``` 4. Don't forget to import: ``` import math ``` 5. Reload you app and see what happened ### A colorful bridge[​](/docs/tutorials/intermediate-3d-model/.md#a-colorful-bridge "Direct link to A colorful bridge") Until now, we did not give the bridge a color, which by is shown grey by default. We already learned that you can make a `Material` and give it a `Color`, but did you know that we can ask the user to give it a color too? To demonstrate this, let’s: 1. Create an ColorField: ``` bridge_color = vkt.ColorField('Bridge Color', default=vkt.Color(200, 200, 200)) ``` 2. Create a material ``` mat_bridge = vkt.Material('Bridge', color=params.bridge_color) ``` 3. Assign this material to any (or all) of `deck`, `column_1` and `column_base`. By adding `material=mat_bridge` to the `SquareBeam` and `CircularExtrusion` functions that generate these elements. 4. Reload and play with you app ## Complete app code[​](/docs/tutorials/intermediate-3d-model/.md#complete-app-code "Direct link to Complete app code") Were you able to do everything in this tutorial without error? If not, you can always look at the full code: **Complete code** ``` import viktor as vkt import math class Parametrization(vkt.Parametrization): intro = vkt.Text("# 3D model app 🌉\n This app parametrically generates and visualises a 3D model of a bridge") txt_deck = vkt.Text('### Deck layout ') # texts can be used for explanation in the user-interface length = vkt.NumberField("Deck length", min=6, default=100, suffix='m') width = vkt.NumberField("Deck width", min=2, default=20, suffix='m') deck_thickness = vkt.NumberField("Deck thickness", min=0.5, default=1, suffix='m') height = vkt.NumberField("Bridge height", min=2, default=10, suffix='m') txt_support = vkt.Text('### Support layout', flex=100) support_amount = vkt.NumberField("Number of supports", default=2, min=1) support_piles_amount = vkt.NumberField("Number of piles per support", min=2, default=3) bridge_color = vkt.ColorField('Bridge Color', default=vkt.Color(200, 200, 200)) class Controller(vkt.Controller): parametrization = Parametrization @vkt.GeometryView("3D", x_axis_to_right=True) def visualize_bridge(self, params, **kwargs): # Create an empty group to hold all the geometry geometry_group = vkt.Group([]) # Measurements environment env_width = params.length env_thick = params.deck_thickness # Thickness of water and embankment water_width = params.length - 2 * params.height # Assuming embankment at 45 deg # Create materials mat_water = vkt.Material('Water', color=vkt.Color.blue(), opacity=0.7) mat_deck_top = vkt.Material('Deck top', color=vkt.Color(60, 60, 60)) mat_grass = vkt.Material('Grass', color=vkt.Color.green()) mat_bridge = vkt.Material('Bridge', color=params.bridge_color) # =============================== # Draw environment # =============================== # Draw water water = vkt.SquareBeam(water_width, env_width, env_thick, material=mat_water) geometry_group.add([water]) # Draw embankment (at 45 deg) embankment_1 = vkt.SquareBeam(1.4 * params.height, env_width, env_thick, material=mat_grass) embankment_1.rotate(-math.pi / 4, direction=[0, 1, 0]) embankment_1.translate(((water_width+params.height)/2, 0, params.height/2)) embankment_2 = vkt.geometry.mirror_object(embankment_1, vkt.Point(0, 0, 0), (1, 0, 0)) # Add created geometries to geometry group geometry_group.add([embankment_1, embankment_2]) # =============================== # Create Bridge # =============================== # Draw deck deck = vkt.SquareBeam(params.length, params.width, params.deck_thickness, material=mat_bridge) deck.translate((0, 0, params.height)) deck_top = vkt.SquareBeam(params.length, params.width, params.deck_thickness / 4, material=mat_deck_top) deck_top.translate((0, 0, params.height + 5/8*params.deck_thickness)) geometry_group.add([deck, deck_top]) # Define grid pile_diameter = params.deck_thickness / 2 grid_size_x = water_width / params.support_amount grid_size_y = (params.width - pile_diameter) / (params.support_piles_amount - 1) # Draw columns top_point = vkt.Point(-grid_size_x/2, 0, params.height) bottom_point = vkt.Point(0, 0, 0) column_line = vkt.Line(top_point, bottom_point) column_1 = vkt.CircularExtrusion(pile_diameter, column_line, material=mat_bridge) column_2 = vkt.geometry.mirror_object(column_1, vkt.Point(0, 0, 0), (1, 0, 0)) # Draw base column_base = vkt.SquareBeam(3 * pile_diameter, pile_diameter, 2*pile_diameter, material=mat_bridge) support = vkt.Group([column_1, column_2, column_base]) support.translate((-water_width/2 + grid_size_x/2, -params.width/2 + pile_diameter/2, 0)) all_supports = vkt.BidirectionalPattern( base_object=support, direction_1=[1, 0, 0], direction_2=[0, 1, 0], number_of_elements_1=params.support_amount, number_of_elements_2=params.support_piles_amount, spacing_1=grid_size_x, spacing_2=grid_size_y ) # Adding geometry group to geometry result geometry_group.add(all_supports) return vkt.GeometryResult(geometry_group) ``` ## Want to learn how VIKTOR works?[​](/docs/tutorials/intermediate-3d-model/.md#want-to-learn-how-viktor-works "Direct link to Want to learn how VIKTOR works?") If you are interested in how VIKTOR works behind the scenes, for example how it processes your input, expand the tabs below! #### How does it work?[​](/docs/tutorials/intermediate-3d-model/.md#how-does-it-work "Direct link to How does it work?") How does the Parametrization work? In the **Parameterization** class you can add input fields that allow the user to provide input to your app, and there are more than 20 [different input fields](/docs/create-apps/user-input/.md) you can use, including numbers, text, colors, images and files. Inside the Parametrization class, you can also format the [layout of your app](/docs/create-apps/layout-and-styling/.md) by adding sections, tabs, steps and pages. To show your Parametrization in the app, we need to add the line `parametrization = Parametrization` inside the `Controller` class, because it is the controller that determines what is shown and not. How does the Parametrization get saved? So you may be wondering, how do you get the information from the parametrization to my controller? Well, we do this automatically for you. The values of all parameters are stored in a single variable called `params` , which is accessible inside the Controller class. These variables are stored in a `Munch`; this is similar to a dictionary, but work with point denotation. Example: * Let's say we have a variable called `height` as a NumberField in our `Parameterization`. * To use it in a method in the `Controller`, define it as: `def my_method(self, params, **kwargs)` * You can now make calculations inside that method using our height parameter as `params.height`! How does the Controller work? The **Controller** class is the place where you add everything you want to calculate and show. As explained in this tutorial, we show results in a `View` and we always add views in our controller. You can even add several views in a single app by adding them to the controller class... and yes, we have [many Views](/docs/create-apps/results-and-visualizations/.md),for showing graphs, maps, 3D models, reports, images and more. In the Controller, you also do or call your calculation. Remember that the user input given in the parametrization, is accessible inside the Controller class in the variable The `params`. ## To infinity and beyond\![​](/docs/tutorials/intermediate-3d-model/.md#to-infinity-and-beyond "Direct link to To infinity and beyond!") Well done! You are now able to create an app that can parametrically design a 3D model which includes rectangular as well as circular extrusions with mirror, rotate and pattern possibilities! Obviously there is way more to discover about VIKTOR and its 3D modelling capabilities. Check those out in [our documentation](/sdk/api/geometry/.md) Finally, the journey doesn't end here. Check out some of our other [tutorials](/docs/tutorials/.md) or go to the [next section](/docs/create-apps/.md) where you can see the different paths you can follow in your journey to learn more about VIKTOR. --- # Tutorial - Data Analysis with Plotly and Pandas info Level: **Beginners**
Time: **20 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps)
***Not a reader?** feel free to follow this tutorial as a video* ## Introduction[​](/docs/tutorials/plots-and-data/.md#introduction "Direct link to Introduction") In this tutorial we’ll make a VIKTOR app to process, visualize and summarize data from a `.csv`. We’ll do this by using two well-known Python libraries: Pandas and Plotly. Visualizing data is one of the best ways to find trends and patterns. By plotting or grouping the data, we can quickly find these trends and make better business decisions! It is also an excellent way to present results to stakeholders like your manager or another business unit. In this tutorial you will learn how to: 1. [Create an empty app template](/docs/tutorials/plots-and-data/.md#1-create-install-and-start-an-empty-app) 2. [Extract the data from a .csv](/docs/tutorials/plots-and-data/.md#2-extract-data-from-csv) 3. [Add input fields](/docs/tutorials/plots-and-data/.md#3-add-input-fields) 4. [Plot the data using Plotly](/docs/tutorials/plots-and-data/.md#4-plot-the-data) 5. [Add a data summary](/docs/tutorials/plots-and-data/.md#5-add-a-data-summary) By the end of this tutorial you will be able to create a colorful chart that can be used for analysis and saved for reports to help explain data. You will understand how to automate the process in VIKTOR and it will look similar to the gif below: Need help? Are you encountering an error? Take a look at the [**complete app code**](/docs/tutorials/plots-and-data/.md#complete-code). Also know that you can always ask for help at our [**Community Forum**](https://community.viktor.ai/), where our developers are ready to help with any question related to the installation, coding and more. ## 1. Create, install and start an empty app[​](/docs/tutorials/plots-and-data/.md#1-create-install-and-start-an-empty-app "Direct link to 1. Create, install and start an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` 4. We want to use Pandas and Plotly in this app. Open `requirements.txt` and add `plotly` and `pandas` under your `viktor` version (don't change that line): ``` viktor==X.X.X <-- Don't modify this line plotly pandas ``` Now disconnect your app by closing the connection using Ctrl+C to be able to install these new dependencies. You do this by entering the following command: ``` viktor-cli install ``` And reconnecting the app by entering the command: ``` viktor-cli start ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. Did you encounter any errors? * Always make sure to check the spelling of everything you placed in the command-line, a small mistake and the command you are trying to run may not be recognised! * If you are encountering: ``` ERROR: Exiting because of an error: no requirements.txt file PS C:\Users\\viktor-apps> ``` Then you are not in the correct folder! check the command-line and navigate to the data-analysis-tutorial folder. * If you are encountering: ``` Error: App definition is not compatible with the data currently stored in the database. Use the command 'viktor-cli clear' to clear the database. PS C:\Users\\viktor-apps\data-analysis-tutorial> ``` That means you have not cleared the database yet! Use the `viktor-cli clear` to clear and then you can use `viktor-cli start` to start the app. No need to install it again! Not seeing any of these errors? Head over to our community! There is a good chance another developer encountered it and solved it too! ## 2. Extract data from .csv[​](/docs/tutorials/plots-and-data/.md#2-extract-data-from-csv "Direct link to 2. Extract data from .csv") For this tutorial, we will dive into a dataset that contains the car sales data of a showroom. The CEO has asked you to create a tool so that they can compare which type of cars were sold. He did not specify what he wanted to compare so we will make this tool so that we compare any two properties of the sold cars as well as give some additional data/information that might be interesting. 1. Download the dataset [here](/files/docs/graph-tutorial/car-sales.csv). 2. Make sure the file name is `car-sales.csv` 3. Add the file to your app folder (`data-analysis-tutorial`) 4. We'll create the function `extract_data` to access the data using Pandas, and add all the necessary imports so that we don't need to do this later. Open `app.py` and make sure the first part of the code looks like this: ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go from pathlib import Path def extract_data(): parent_folder = Path(__file__).parent file_path = parent_folder/"car-sales.csv" data = pd.read_csv(file_path, sep=';') return data class Parametrization(vkt.Parametrization): # <--- this line is for your reference ``` ## 3. Add Input fields[​](/docs/tutorials/plots-and-data/.md#3-add-input-fields "Direct link to 3. Add Input fields") We want the CEO to interact with the app. For this, we will add two [`OptionFields`](/sdk/api/parametrization/.md#_OptionField). One to determine the variable on the X-axis and the other for the Y-axis. Also, we will make sure that the showed options correspond to the columns of the data set. Remember, we always add input fields in the `Parametrization` class. 1. In the `app.py` file make sure the code in the `Parametrization` class looks like this: ``` ... class Parametrization(vkt.Parametrization): introduction = vkt.Text( """ # 📊 Data Analysis App! In this app you can summarise data and visualise it in a PlotlyView. The app will summarise some data in the DataView and allow the user to choose a column to analyse to create the Plotly chart. """ ) # Add some input field for the user main_column = vkt.OptionField('Choose main property', options=extract_data().columns.values.tolist()) count_column = vkt.OptionField('Choose property to analyse', options=extract_data().columns.values.tolist()) class Controller(vkt.Controller): # <--- this line is for your reference ``` 2. Go to your cloud environment (e.g. [cloud.viktor.ai](https://cloud.viktor.ai/workspaces)) and open the development card. Great! You will be able to see your input fields. ![](/assets/images/tutorial-data-1-params-66c67690b9d95dba4562c3fe43c2aa71.png) *How the app should look after the parametrization* ## 4. Plot the data[​](/docs/tutorials/plots-and-data/.md#4-plot-the-data "Direct link to 4. Plot the data") Now, we'll make a bar chart to show the data. We will create the plot using Plotly, which is a well known plotting library. In VIKTOR, we show Plotly graphs in a [`PlotlyView`](/sdk/api/views/.md#_PlotlyView). We'll use the function `extract_data` to extract the data form the .csv, and Pandas to process it. Remember, we allways add views in our `Controller` class. 1. In `app.py`, find the `Controller` class and make it look like this: ``` class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyView('Bar chart') def generate_plotly_view(self, params, **kwargs): # Extract and edit data to make it easy to plot data = extract_data() edited_data = data.groupby(params.main_column)[params.count_column].value_counts().unstack().fillna(0) # Make the bar chart fig = go.Figure() for column in edited_data.columns: fig.add_trace(go.Bar(x=edited_data.index, y=edited_data[column], name=column)) # Edit the bar chart fig.update_layout(barmode='stack',xaxis_title=params.main_column,yaxis_title='Amount Sold') return vkt.PlotlyResult(fig) ``` 2. Refresh your app. Nice! You should now see a beautiful stacked bar chart of the data after you fill in the inputs. What you will also notice is that when you hover the mouse over one of the bars, Plotly will tell you the exact amount of cars with those two properties! ![](/assets/images/tutorial-data-2-plotly-51e607e01eb5d9fca8ce85b2419ea3d5.gif) *The app is almost finished! It should look similar to this* ## 5. Add a data summary[​](/docs/tutorials/plots-and-data/.md#5-add-a-data-summary "Direct link to 5. Add a data summary") Fantastic, we have a fully functioning app 🎉. But that doesn't mean we cannot make it better. Let's now add a summary with the most important data next to our graph. We'll show the total number of cars sold and the selected column's best-performing and least-performing property. Thanks to Pandas, we can easily compute the totals per column and find the highest and lowest value with just a single line per value. For this, we need to modify the `generate_plotly_view` method. Here are the required steps. The code is below. 1. Replace the `@PlotlyView` in your code for a [`@PlotlyAndDataView`](/sdk/api/views/.md#_PlotlyAndDataView), so we can also display data next to the plot. 2. Create a [`DataGroup`](/sdk/api/views/.md#_DataGroup) with the [`DataItems`](/sdk/api/views/.md#_DataItem) we want to display. 3. Make sure you return a [`PlotlyAndDataResult`](/sdk/api/views/.md#_PlotlyAndDataResult) with the plot and the `Datagroup` Here is the code for your reference: ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyAndDataView('Bar chart') # <--- Change the PlotlyView to PlotlyAndDataView def generate_plotly_view(self, params, **kwargs): # Extract and edit data to make it easy to plot data = extract_data() edited_data = data.groupby(params.main_column)[params.count_column].value_counts().unstack().fillna(0) # Make the bar chart fig = go.Figure() for column in edited_data.columns: fig.add_trace(go.Bar(x=edited_data.index, y=edited_data[column], name=column)) # Edit the bar chart fig.update_layout(barmode='stack', xaxis_title=params.main_column, yaxis_title='Amount Sold') # Create a summary with the data # <--- add this line summary = vkt.DataGroup( # <--- add this line vkt.DataItem("Total Sold" , len(data)), # <--- add this line vkt.DataItem("Most Occurring", edited_data.sum().idxmax()), # <--- add this line vkt.DataItem("Least Occurring", edited_data.sum().idxmin()), # <--- add this line ) return vkt.PlotlyAndDataResult(fig, summary) # <--- Modify this line (PlotlyResult to PlotlyAndDataResult) ``` Refresh your app. You can now see the data on the right of the chart, and you can hide it using the arrow so you can focus on the bar chart! Now select the 'Make' as main property and 'body-style' to analyse and try to find the best selling convertible and best selling car! You should find that the Alfa-Romero Convertible is the best selling Convertible and that the Toyota Hatchbacks are the overall best selling automobile! Can you also find the amount of cars with a diesel powered turbo engine? Which type of engine and fuel combination are your best seller? By now, your app should look like this: ![](/assets/images/tutorial-data-0-intro-b49325c20263b806588509bc4c56a14c.gif) *The app should now look like this* ## Complete code[​](/docs/tutorials/plots-and-data/.md#complete-code "Direct link to Complete code") Were you able to do everything in this tutorial without error? If not, you can always look at the full code: **Complete code** ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go from pathlib import Path def extract_data(): parent_folder = Path(__file__).parent file_path = parent_folder / "car-sales.csv" data = pd.read_csv(file_path, sep=';') return data class Parametrization(vkt.Parametrization): introduction = vkt.Text( """ # 📊 Data Analysis App! In this app you can summarise data and visualise it in a PlotlyView. The app will summarise some data in the DataView and allow the user to choose a column to analyse to create the Plotly chart. """ ) # Add some input field for the user main_column = vkt.OptionField('Choose main property', options=extract_data().columns.values.tolist()) count_column = vkt.OptionField('Choose property to analyse', options=extract_data().columns.values.tolist()) class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyAndDataView('Bar chart') def generate_plotly_view(self, params, **kwargs): # Extract and edit data to make it easy to plot data = extract_data() edited_data = data.groupby(params.main_column)[params.count_column].value_counts().unstack().fillna(0) # Make the bar chart fig = go.Figure() for column in edited_data.columns: fig.add_trace(go.Bar(x=edited_data.index, y=edited_data[column], name=column)) # Edit the bar chart fig.update_layout(barmode='stack', xaxis_title=params.main_column, yaxis_title='Amount Sold') # Create a summary with the data summary = vkt.DataGroup( vkt.DataItem("Total Sold" , len(data)), vkt.DataItem("Most Occurring", edited_data.sum().idxmax()), vkt.DataItem("Least Occurring", edited_data.sum().idxmin()), ) return vkt.PlotlyAndDataResult(fig, summary) ``` ## Want to learn how VIKTOR works?[​](/docs/tutorials/plots-and-data/.md#want-to-learn-how-viktor-works "Direct link to Want to learn how VIKTOR works?") If you are interested in how VIKTOR works behind the scenes, for example how it processes your input, expand the tabs below! #### How does it work?[​](/docs/tutorials/plots-and-data/.md#how-does-it-work "Direct link to How does it work?") How does the Parametrization work? In the **Parameterization** class you can add input fields that allow the user to provide input to your app, and there are more than 20 [different input fields](/docs/create-apps/user-input/.md) you can use, including numbers, text, colors, images and files. Inside the Parametrization class, you can also format the [layout of your app](/docs/create-apps/layout-and-styling/.md) by adding sections, tabs, steps and pages. To show your Parametrization in the app, we need to add the line `parametrization = Parametrization` inside the `Controller` class, because it is the controller that determines what is shown and not. How does the Parametrization get saved? So you may be wondering, how do you get the information from the parametrization to my controller? Well, we do this automatically for you. The values of all parameters are stored in a single variable called `params` , which is accessible inside the Controller class. These variables are stored in a `Munch`; this is similar to a dictionary, but work with point denotation. Example: * Let's say we have a variable called `height` as a NumberField in our `Parameterization`. * To use it in a method in the `Controller`, define it as: `def my_method(self, params, **kwargs)` * You can now make calculations inside that method using our height parameter as `params.height`! How does the Controller work? The **Controller** class is the place where you add everything you want to calculate and show. As explained in this tutorial, we show results in a `View` and we always add views in our controller. You can even add several views in a single app by adding them to the controller class... and yes, we have [many Views](/docs/create-apps/results-and-visualizations/.md),for showing graphs, maps, 3D models, reports, images and more. In the Controller, you also do or call your calculation. Remember that the user input given in the parametrization, is accessible inside the Controller class in the variable The `params`. ## What's next?[​](/docs/tutorials/plots-and-data/.md#whats-next "Direct link to What's next?") Very Impressive! you have mastered the basics on how you can use VIKTOR for data analysis. In this tutorial, we have only scratched the surface of what you can do with data so don't stop there! If you like an extra challenge, here are some ideas you can add: * Try analysing another dataset's columns, perhaps by uploading a set using the [`Filefield`](/sdk/api/parametrization/.md#_FileField) * extend the `DataGroup` to have an average and standard deviation of the property * Try to add another chart such as a hierarchy or pie chart suing a second `PlotlyView` * Display several charts on a single view using [subplots](https://plotly.com/python/subplots/) Or just follow some of our other [tutorials](/docs/tutorials/.md) More about plotting You can find more information about how to make plots in the [plotting guide](/docs/create-apps/results-and-visualizations/plots-charts-graphs/.md). Also check more about the possibilities of the [DataView](/docs/create-apps/results-and-visualizations/data-and-tables/.md) --- # Tutorial - Post-process ETABS data info Level: **Beginners**
Time: **20 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) In this tutorial, you will build a VIKTOR app to process and visualize outputs from ETABS. You'll see how to export these outputs from ETABS into a file, upload them into VIKTOR and post-process reaction loads for various load combinations. Along the way, you will work with Plotly and Pandas, using the flexible tools and building blocks that VIKTOR offers. Here is what we'll cover: 1. [Creating an app to take in a file](/docs/tutorials/process-etabs-data/.md#1-basic-setup) 2. [Processing the uploaded `.xlsx` file exported from ETABS](/docs/tutorials/process-etabs-data/.md#2-process-the-xlsx-file) 3. [Adding processed data into a field so that the user can select from the results](/docs/tutorials/process-etabs-data/.md#3-allow-user-selection-of-load-combinations) 4. [Visualizing results based on those selections](/docs/tutorials/process-etabs-data/.md#4-visualize-reaction-loads-with-plotly) By the end of this tutorial, you will be able to generate a heatmap of the reaction loads for your structure by selecting specific load cases. This will allow you to gain valuable insights from your results and easily share them with your clients and team. Additionally, you will learn how to automate this process using VIKTOR. The final result will look like the figure below: ![](/assets/images/tutorial_post_processing_etabs_app_complete-8865fcdf600b903fee9186bf9b9728f7.png) ## 1. Basic setup[​](/docs/tutorials/process-etabs-data/.md#1-basic-setup "Direct link to 1. Basic setup") ### Create an empty app[​](/docs/tutorials/process-etabs-data/.md#create-an-empty-app "Direct link to Create an empty app") Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name, 'spreadsheet-tutorial', and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Adding useful Python packages[​](/docs/tutorials/process-etabs-data/.md#adding-useful-python-packages "Direct link to Adding useful Python packages") We want to use the Python packages Pandas, Openpyxl, and Plotly in this app. Open `requirements.txt` and add `plotly`, `openpyxl` and `pandas` under your `viktor` version (don't change that line): ``` viktor==X.X.X <-- Don't modify this line plotly pandas openpyxl ``` Next, close the connection to your app in the terminal (if the app has been connected automatically). You can do this by using Ctrl+C. Open a new terminal and install the new dependencies (like `plotly` and `pandas`) in your Python environment by running this terminal: ``` viktor-cli install ``` And after that connect your app to the VIKTOR platform again: ``` viktor-cli start ``` **Keep the terminal open**, as closing it will disconnect your app. ### Adding input fields[​](/docs/tutorials/process-etabs-data/.md#adding-input-fields "Direct link to Adding input fields") Let's add some text and input fields for the user to upload their file into. We will include a `FileField` to upload our `.xlsx` file and an `OptionField` to select a load combination from our Excel file. Feel free to copy and paste the **highlighted** lines of code in `app.py`, save the file and refresh the app in the browser. You should now see the input fields you just added to the code. ``` import viktor as vkt class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=[]) class Controller(vkt.Controller): parametrization = Parametrization ``` The result should look like the image below. Now that the inputs are sorted, we will continue with processing the ETABS data. ![app](/assets/images/tutorial_post_processing_etabs_app_components-25b066b5d91373002aa25c6aab1b5a45.png) ## 2. Process the XLSX file[​](/docs/tutorials/process-etabs-data/.md#2-process-the-xlsx-file "Direct link to 2. Process the XLSX file") ### Sample ETABS exported `.xlsx` file[​](/docs/tutorials/process-etabs-data/.md#sample-etabs-exported-xlsx-file "Direct link to sample-etabs-exported-xlsx-file") For this tutorial, you can use this sample [Excel file](/files/docs/simple-etabs-data-tutorial/etabs_tutorial.xlsx) but don't worry; at the end of this tutorial, we will guide you on how to export this data from ETABS and create your own file. ### Processing the uploaded xlsx file[​](/docs/tutorials/process-etabs-data/.md#processing-the-uploaded-xlsx-file "Direct link to Processing the uploaded xlsx file") The next step is to process the data from the uploaded Excel file. It's a good idea to do this processing in a separate function, that we'll name `process_etabs_file`. This function will extract the unique load combinations (which will be used later in our `OptionField`) and the joint reactions. The goal is to combine this data with the joint coordinates to create a DataFrame that can be used to plot the heatmap in the Plotly view. Below is the logic in the code, along with a breakdown. Add the highlighted lines of code to `app.py` and save the file.   ``` import viktor as vkt import pandas as pd def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=[]) class Controller(vkt.Controller): parametrization = Parametrization ``` ### How this works[​](/docs/tutorials/process-etabs-data/.md#how-this-works "Direct link to How this works") 1. In the top of the file we import Pandas, which we'll use to load the file content into dataframes 2. The function reads the excel file and extract the necessary sheets: **Joint Reactions** and **Objects and Elements - Joints**. 3. Then we filter for and remove the rows that we want based on the required data, keeping columns `Global X`, `Global Y`, and `Global Z`. 4. Finally, merge the processed **Joint Reactions** data with the joint coordinates using the `Unique Name` column as the key. This merged DataFrame includes all the necessary information to plot a heatmap. 5. This functions returns two things at once, the unique load combinations and the merged dataframe. ## 3. Allow user selection of load combinations[​](/docs/tutorials/process-etabs-data/.md#3-allow-user-selection-of-load-combinations "Direct link to 3. Allow user selection of load combinations") With the function to process the uploaded file done, we can now use that processed data in the `Parametrization`. We will allow users to select a load combination from the unique load combinations. To get the unique load combinations into the `OptionField`, we can use a callback function. Let's call it `get_load_combos`. It will get the unique load combinations from `read_file` and update our `OptionField` to display a dropdown with the correct options. Add the highlighted lines of code to `app.py` and don't forget to reference the `get_load_combos` in the `selected_load_combo` field. ``` import viktor as vkt import pandas as pd def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) # Only use the first returned item, the load_combos return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization ``` By replacing the `options=[]` with a reference to the callback function (`options=get_load_combos`) we fill the field with the processed load combos from the file (if there is a file uploaded). ## 4. Visualize reaction loads with Plotly[​](/docs/tutorials/process-etabs-data/.md#4-visualize-reaction-loads-with-plotly "Direct link to 4. Visualize reaction loads with Plotly") Once the user selected a load combination, we filter the data to focus on the selected load combination. Then we use Plotly to generate an interactive heat map. To visualize a Plotly figure in a VIKTOR app we can add a `PloltyView` method to the `Controller`. We will add a scatter plot to represent each joint from the ETABS data, with its color indicating the magnitude of the reaction load (FZ) in kN. This visualization allows you to clearly observe how loads are distributed across the base floor, making it easier to analyze and interpret the results. Copy the **highlighted** piece of code and add it to `app.py`. Don't forget importing ploty on line 3! ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) # Only use the first returned item, the load_combos return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyView("Heatmap") def plot_heat_map(params,**kwargs): if params.selected_load_combo: _, merged_df = process_etabs_file(params.xlsx_file) # Filter the dataframe based on the selected load combination filtered_df = merged_df[merged_df["Output Case"] == params.selected_load_combo] FZ_min, FZ_max = filtered_df["FZ"].min(), filtered_df["FZ"].max() # Create plotly scatter plot fig = go.Figure( data=go.Scatter( x=filtered_df["Global X"], y=filtered_df["Global Y"], mode='markers+text', marker=dict( size=16, color=filtered_df["FZ"], colorscale=[ [0, "green"], [0.5, "yellow"], [1, "red"] ], colorbar=dict(title="FZ (kN)"), cmin=FZ_min, cmax=FZ_max ), text=[f"{fz:.1f}" for fz in filtered_df["FZ"]], textposition="top right" ) ) # Style the plot fig.update_layout( title=f"Heatmap for Output Case: {params.selected_load_combo}", xaxis_title="X (m)", yaxis_title="Y (m)", plot_bgcolor='rgba(0,0,0,0)', ) fig.update_xaxes( linecolor='LightGrey', tickvals=filtered_df["Global X"], ticktext=[f"{x / 1000:.3f}" for x in filtered_df["Global X"]], ) fig.update_yaxes( linecolor='LightGrey', tickvals=filtered_df["Global Y"], ticktext=[f"{y / 1000:.3f}" for y in filtered_df["Global Y"]], ) return vkt.PlotlyResult(fig) else: return vkt.PlotlyResult({}) ``` ### This code explained[​](/docs/tutorials/process-etabs-data/.md#this-code-explained "Direct link to This code explained") 1. At the top of the file, we import Plotly, which we'll use to create the plot 2. At the top of the function, we use `process_etabs_file` again, but this time we only use the second returned item, the merged dataframe. 3. The dataframe is filtered, based on the selected option in `params.selected_load_combo`. We also find the lowest and highest values for FZ. 4. Using Plotly, we create a scatter plot based on the filtered dataframe. Using the lowest and highest values for F the colors are determined for each point. 5. Finally, we apply some styling to the figure, like adding a title, setting linecolors and text for the tickmarks ### The resulting app[​](/docs/tutorials/process-etabs-data/.md#the-resulting-app "Direct link to The resulting app") Refresh your app in the browser. You will now see the empty graph appear on the right side of the screen. You can now upload the Excel sheet with ETABS loads in the upload field. After that select one of the load combinations, and a heatmap will display the magnitudes, color-coded, along with the joint locations. You can try any combination and test it with any ETABS model. Our final app will look like this: ![app](/assets/images/tutorial_post_processing_etabs_app_complete-8865fcdf600b903fee9186bf9b9728f7.png) ## Complete code[​](/docs/tutorials/process-etabs-data/.md#complete-code "Direct link to Complete code") Were you able to do everything in this tutorial without error? If not, you can always look at the full code: ``` import viktor as vkt import pandas as pd import plotly.graph_objects as go def process_etabs_file(uploaded_file): # Read the file into a dataframe sheet_names = ["Joint Reactions", "Objects and Elements - Joints"] with uploaded_file.file.open_binary() as fr: dataframes = pd.read_excel(fr, sheet_name=sheet_names, skiprows=1) # Process the 'Joint Reactions' dataframe loads_df = dataframes["Joint Reactions"].dropna(subset=["Unique Name", "Output Case"]).copy() # Process the 'Objects and Elements - Joints' dataframe cords = dataframes["Objects and Elements - Joints"].dropna( subset=["Element Name", "Object Name", "Global X", "Global Y", "Global Z"] ).copy() cords = cords.rename(columns={"Object Name": "Unique Name"}) # Get unique load case names as a list unique_output_cases = loads_df["Output Case"].unique().tolist() # Merge loads and cords dataframe merged_df = pd.merge(loads_df, cords, on="Unique Name", how="inner") return unique_output_cases, merged_df.reset_index(drop=True) def get_load_combos(params, **kwargs): if params.xlsx_file: load_combos, _ = process_etabs_file(params.xlsx_file) return load_combos return [] class Parametrization(vkt.Parametrization): intro = vkt.Text(""" # ETABS reaction heatmap This app allows you to inspect results from an uploaded ETABS output file. Export your ETABS model results to an .xlsx file and upload it below. After uploading your Excel file, select the load combination you want to visualize. Ensure the file includes the tables: - **Joint Reactions** - **Objects and Elements - Joints** """) xlsx_file = vkt.FileField("Upload ETABS exported .xlsx") lb = vkt.LineBreak() selected_load_combo = vkt.OptionField("Select available load combos", options=get_load_combos) class Controller(vkt.Controller): parametrization = Parametrization @vkt.PlotlyView("Heatmap") def plot_heat_map(params,**kwargs): if params.selected_load_combo: _, merged_df = process_etabs_file(params.xlsx_file) # Filter the dataframe based on the selected load combination filtered_df = merged_df[merged_df["Output Case"] == params.selected_load_combo] FZ_min, FZ_max = filtered_df["FZ"].min(), filtered_df["FZ"].max() # Create plotly scatter plot fig = go.Figure( data=go.Scatter( x=filtered_df["Global X"], y=filtered_df["Global Y"], mode='markers+text', marker=dict( size=16, color=filtered_df["FZ"], colorscale=[ [0, "green"], [0.5, "yellow"], [1, "red"] ], colorbar=dict(title="FZ (kN)"), cmin=FZ_min, cmax=FZ_max ), text=[f"{fz:.1f}" for fz in filtered_df["FZ"]], textposition="top right" ) ) # Style the plot fig.update_layout( title=f"Heatmap for Output Case: {params.selected_load_combo}", xaxis_title="X (m)", yaxis_title="Y (m)", plot_bgcolor='rgba(0,0,0,0)', ) fig.update_xaxes( linecolor='LightGrey', tickvals=filtered_df["Global X"], ticktext=[f"{x / 1000:.3f}" for x in filtered_df["Global X"]], ) fig.update_yaxes( linecolor='LightGrey', tickvals=filtered_df["Global Y"], ticktext=[f"{y / 1000:.3f}" for y in filtered_df["Global Y"]], ) return vkt.PlotlyResult(fig) else: return vkt.PlotlyResult({}) ``` ## Export your own results from ETABS[​](/docs/tutorials/process-etabs-data/.md#export-your-own-results-from-etabs "Direct link to Export your own results from ETABS") If you want to try this app with your own data, first run your analysis and then export the reaction loads from your ETABS model. Navigate to `File menu > Export > ETABS Tables to Excel` within ETABS, and select the **Joint Reactions** and **Objects and Elements - Joints** tables, as shown in the figure below: ![app](/assets/images/tutorial_post_processing_etabs_app_etabs_export_tables-3b6491b6ff487ff248154828d98bb520.png) warning Ensure that your exported Excel file contains these specific sheets. Without them, the app won’t be able to read and process the data correctly. Set the model units to international system units. The model expects the loads in kN and in millimeters (mm). ## What's next?[​](/docs/tutorials/process-etabs-data/.md#whats-next "Direct link to What's next?") In this tutorial, you learned how to post-process results exported from ETABS. Your next goal could be to implement automation using the CSI API from your VIKTOR app. To achieve this, the best place to start is the following [tutorial](/docs/tutorials/integrate-etabs-sap2000/.md). If you want to explore more use cases where VIKTOR shines, feel free to check out our other [tutorials](/docs/tutorials/.md)! --- # Tutorial - Post-process STAAD.Pro data note Level: **Beginners**
Time: **20 min** Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps) In this tutorial, you will build a VIKTOR app to process and visualize outputs from STAAD.PRO. You’ll learn how to export these outputs from STAAD.PRO into a VIKTOR web app and post-process design ratios for various cross-sections. Filtering, grouping, and visualizing these design ratio outputs is not possible directly in STAAD.PRO, and there is no native way to export these results directly to Excel. This tutorial will guide you through overcoming these limitations while exploring the powerful tools and building blocks that VIKTOR and Pandas provide. Here is what we'll cover: * [Create an app with an input block to receive STAAD.PRO data](/docs/tutorials/process-staad-data/.md#1-basic-setup) * [Create the structure of our app with steps](/docs/tutorials/process-staad-data/.md#2-creating-the-structure-of-our-app) * [Process the STAAD.PRO data](/docs/tutorials/process-staad-data/.md#3-process-the-staadpro-data) * [Allow user selection, grouping, and filtering of cross-sections](/docs/tutorials/process-staad-data/.md#4-allow-user-selection-of-cross-sections) * [Visualize results based on those selections](/docs/tutorials/process-staad-data/.md#5-visualize-design-ratios-with-viktor) By the end of this tutorial, you will be able to generate a table with a heatmap displaying design ratios for your structure by filtering or grouping specific cross-sections. You will also have the opportunity to test this using your own data by following the steps outlined in the final section of the tutorial. This will help you gain valuable insights from your results and effectively share them with your clients and team. ![final app](/assets/images/tutorial_staad_final_app-e10427c0885f46673be9d053028a774c.gif) ## 1. Basic setup[​](/docs/tutorials/process-staad-data/.md#1-basic-setup "Direct link to 1. Basic setup") Let’s create, install, and start a blank app template. We’ll use this blank template as the base for our design ratios app. Before we begin, ensure that any running app (like the demo app) is stopped. You can do this by closing the command-line shell (e.g., PowerShell) or by canceling the process with `Ctrl + C`. * **1.** Go to the App store in your VIKTOR environment to create a new app. After clicking **'Create app'**, choose the option **'Create blank app'** and enter a name and description of your choice. Submit the form by clicking **'Create and setup'**. ![Create app](/assets/images/tutorial_staad_create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) * **2.** Select **'Editor'** as app type and click **'Next'**. * **3.** Now follow the instructions to run the quickstart command to download the empty app template. After entering the command, click **'I have run the command'** to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established: INFO : INFO : https://cloud.viktor.ai/workspaces/XXX/app <--- navigate here to find your app INFO : INFO : The connection can be closed using Ctrl+C INFO : App is ready ``` RE-STARTING YOUR APP You only need to create an app template and install it once for each new app you want to make. The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. ### Adding useful Python packages[​](/docs/tutorials/process-staad-data/.md#adding-useful-python-packages "Direct link to Adding useful Python packages") We want to use Pandas and VIKTOR as our only dependencies in this app. Open `requirements.txt` and add `pandas` under your `viktor` version (do not change that line): ``` viktor==X.X.X # Don’t modify this line pandas ``` Next, close the connection to your app in the terminal (if the app has been connected automatically). You can do this by using `Ctrl+C`. Open a new terminal and install the new dependencies (like `pandas`) in your Python environment by running this command: ``` viktor-cli install ``` And after that, connect your app to the VIKTOR platform again: ``` viktor-cli start ``` **Keep the terminal open**, as closing it will disconnect your app. ## 2. Creating the structure of our app[​](/docs/tutorials/process-staad-data/.md#2-creating-the-structure-of-our-app "Direct link to 2. Creating the structure of our app") In this step, we will create the structure of our app by organizing it into steps using `vkt.Step`. This will help us separate the application into inputs and outputs. In the first step, we input the data coming from STAAD.PRO with the `vkt.Table`, and in the second step, we filter and group the results with a `TableView`. Later, we will add a `TableView` and the logic for the filtering and grouping components on step 2. Feel free to copy and paste the highlighted lines of code into `app.py`, save the file, and refresh the app in the browser. You should now see the input fields you just added to the code. ``` import viktor as vkt class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1 - Input Your Data!") step_1.intro = vkt.Text(""" # STAAD Design Ratio Analyzer This app allows you to visualize a heat map from your STAAD.PRO model results. You can filter and group them based on cross sections and visualize how they are distributed.""") step_1.table_input = vkt.Text(""" ## 1.0 Create the Input Table! Paste the design ratio data from your STAAD.PRO model!""") step_1.table = vkt.Table("### Beam Design Analysis") step_1.table.col_beam = vkt.TextField("Beam") step_1.table.col_analysis_property = vkt.TextField("Analysis Property") step_1.table.col_design_property = vkt.TextField("Design Property") step_1.table.col_actual_ratio = vkt.NumberField("Actual Ratio") step_1.table.col_allowable_ratio = vkt.NumberField("Allowable Ratio") step_1.table.col_normalized_ratio = vkt.NumberField("Normalized Ratio") step_1.table.col_clause = vkt.TextField("Clause") step_1.table.col_load_case = vkt.TextField("L/C") step_1.table.col_ax = vkt.TextField("Ax in²") step_1.table.col_iz = vkt.TextField("Iz in⁴") step_1.table.col_iy = vkt.TextField("Iy in⁴") step_1.table.col_ix = vkt.TextField("Ix in⁴") step_2 = vkt.Step("Step 2 - Post-Processing") step_2.process = vkt.Text(""" ## 2.0 Filter and Group Group or filter by a specific cross section. Use the options below to customize your view. If you want to list all cross-sections after selecting one, you can select the "All" option! """) step_2.group = vkt.BooleanField("### Group by Cross-Section") step_2.ln_break = vkt.LineBreak() step_2.cross_section = vkt.OptionField( "### Filter by Cross-Section", options=["Empty Options"] ) class Controller(vkt.Controller): parametrization = Parametrization() ``` ### How this works[​](/docs/tutorials/process-staad-data/.md#how-this-works "Direct link to How this works") * We organized our app into two steps using `vkt.Step`: * **Step 1** is for inputting data. We added introductory text using `vkt.Text` and created a table called `step_1.table` using `vkt.Table`. This table replicates the columns from the design ratio table in STAAD.PRO. * **Step 2** is for post-processing. This step includes the following features: * **Filtering**: * We use **`vkt.OptionField`** to show a list of cross-sections that the user can select. * Only design ratios of the selected cross-section will be displayed. * **Grouping**: * We use **`vkt.BooleanField`** to let the user group the design ratios by cross-section. * When grouping is enabled, the app displays only the **maximum design ratio** for each cross-section. * The `Controller` class sets `parametrization = Parametrization()` to link our parametrization to the controller. The result should look like the image below. Now that the inputs are ready, we will move on to process the STAAD.PRO data. ![Create app](/assets/images/tutorial_staad_inputs-2ec740c44624517352aaede9776dba57.JPG) ## 3. Process the STAAD.PRO data[​](/docs/tutorials/process-staad-data/.md#3-process-the-staadpro-data "Direct link to 3. Process the STAAD.PRO data") ### Sample STAAD.PRO design ratio data[​](/docs/tutorials/process-staad-data/.md#sample-staadpro-design-ratio-data "Direct link to Sample STAAD.PRO design ratio data") For this tutorial, you can use this in [TXT format](/files/docs/simple-staadpro-tutorial/sample_data.txt), which you can copy and paste into our `vkt.Table`. However, you can use your **own** design ratio data from STAAD.PRO. At the end of this tutorial, we will guide you on how to get this data from STAAD.PRO. info The last section of this tutorial shows how to get this data from STAAD.PRO. For now, you can use the sample `.TXT` file to complete and test the app! ### Processing the STAAD.PRO data[​](/docs/tutorials/process-staad-data/.md#processing-the-staadpro-data "Direct link to Processing the STAAD.PRO data") The next step is to process the data from the `vkt.Table`. It's a good idea to do this processing in a separate function, which we'll name `generate_dataframe`. This function will convert the table data into a **Pandas DataFrame** and rename the columns for easier access. Below is the logic in the code, along with a breakdown. Add the highlighted lines of code to `app.py` and save the file. ``` import viktor as vkt import pandas as pd def generate_dataframe(table_data): df = pd.DataFrame([dict(item) for item in table_data]) df.rename( columns={ "col_beam": "Beam", "col_analysis_property": "Analysis Property", "col_design_property": "Design Property", "col_actual_ratio": "Actual Ratio", "col_allowable_ratio": "Allowable Ratio", "col_normalized_ratio": "Normalized Ratio (Actual/Allowable)", "col_clause": "Clause", "col_load_case": "L/C", "col_ax": "Ax in²", "col_iz": "Iz in⁴", "col_iy": "Iy in⁴", "col_ix": "Ix in⁴", }, inplace=True, ) return df class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1 - Input Your Data!") step_1.intro = vkt.Text(""" # STAAD Design Ratio Analyzer This app allows you to visualize a heat map from your STAAD.PRO model results. You can filter and group them based on cross sections and visualize how they are distributed.""") step_1.table_input = vkt.Text(""" ## 1.0 Create the Input Table! Paste the design ratio data from your STAAD.PRO model!""") step_1.table = vkt.Table("### Beam Design Analysis") step_1.table.col_beam = vkt.TextField("Beam") step_1.table.col_analysis_property = vkt.TextField("Analysis Property") step_1.table.col_design_property = vkt.TextField("Design Property") step_1.table.col_actual_ratio = vkt.NumberField("Actual Ratio") step_1.table.col_allowable_ratio = vkt.NumberField("Allowable Ratio") step_1.table.col_normalized_ratio = vkt.NumberField("Normalized Ratio") step_1.table.col_clause = vkt.TextField("Clause") step_1.table.col_load_case = vkt.TextField("L/C") step_1.table.col_ax = vkt.TextField("Ax in²") step_1.table.col_iz = vkt.TextField("Iz in⁴") step_1.table.col_iy = vkt.TextField("Iy in⁴") step_1.table.col_ix = vkt.TextField("Ix in⁴") step_2 = vkt.Step("Step 2 - Post-Processing") step_2.process = vkt.Text(""" ## 2.0 Filter and Group Group or filter by a specific cross section. Use the options below to customize your view. If you want to list all cross-sections after selecting one, you can select the "All" option! """) step_2.group = vkt.BooleanField("### Group by Cross-Section") step_2.ln_break = vkt.LineBreak() step_2.cross_section = vkt.OptionField( "### Filter by Cross-Section", options=["Empty Options"] ) class Controller(vkt.Controller): parametrization = Parametrization() ``` ### How this works[​](/docs/tutorials/process-staad-data/.md#how-this-works-1 "Direct link to How this works") * At the top of the file, we import `pandas`, which we'll use to manipulate the data. * The function `generate_dataframe` converts the table data from the `Parametrization` into a `DataFrame` and renames the columns to more readable names. * This function returns the `DataFrame`, which will be used later to process and visualize the data. ## 4. Allow user selection of cross-sections[​](/docs/tutorials/process-staad-data/.md#4-allow-user-selection-of-cross-sections "Direct link to 4. Allow user selection of cross-sections") Now that we have implemented the `generate_dataframe` function, we can use the resulting DataFrame to create a list of cross sections. To do this, we can get the unique cross-section names from the "Design Property" column and convert them into a list. This list will be used in our `OptionField`. You can update the code as shown in the code snippet below! ``` import viktor as vkt import pandas as pd def generate_dataframe(table_data): df = pd.DataFrame([dict(item) for item in table_data]) df.rename( columns={ "col_beam": "Beam", "col_analysis_property": "Analysis Property", "col_design_property": "Design Property", "col_actual_ratio": "Actual Ratio", "col_allowable_ratio": "Allowable Ratio", "col_normalized_ratio": "Normalized Ratio (Actual/Allowable)", "col_clause": "Clause", "col_load_case": "L/C", "col_ax": "Ax in²", "col_iz": "Iz in⁴", "col_iy": "Iy in⁴", "col_ix": "Ix in⁴", }, inplace=True, ) return df def get_cross_sections(params, **kwargs): if params.step_1.table: df = generate_dataframe(params.step_1.table) secs = df["Design Property"].unique().tolist() secs.append("All") return secs return ["No data available! Please add table input."] class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1 - Input Your Data!") step_1.intro = vkt.Text(""" # STAAD Design Ratio Analyzer This app allows you to visualize a heat map from your STAAD.PRO model results. You can filter and group them based on cross sections and visualize how they are distributed.""") step_1.table_input = vkt.Text(""" ## 1.0 Create the Input Table! Paste the design ratio data from your STAAD.PRO model!""") step_1.table = vkt.Table("### Beam Design Analysis") step_1.table.col_beam = vkt.TextField("Beam") step_1.table.col_analysis_property = vkt.TextField("Analysis Property") step_1.table.col_design_property = vkt.TextField("Design Property") step_1.table.col_actual_ratio = vkt.NumberField("Actual Ratio") step_1.table.col_allowable_ratio = vkt.NumberField("Allowable Ratio") step_1.table.col_normalized_ratio = vkt.NumberField("Normalized Ratio") step_1.table.col_clause = vkt.TextField("Clause") step_1.table.col_load_case = vkt.TextField("L/C") step_1.table.col_ax = vkt.TextField("Ax in²") step_1.table.col_iz = vkt.TextField("Iz in⁴") step_1.table.col_iy = vkt.TextField("Iy in⁴") step_1.table.col_ix = vkt.TextField("Ix in⁴") step_2 = vkt.Step("Step 2 - Post-Processing") step_2.process = vkt.Text(""" ## 2.0 Filter and Group Group or filter by a specific cross section. Use the options below to customize your view. If you want to list all cross-sections after selecting one, you can select the "All" option! """) step_2.group = vkt.BooleanField("### Group by Cross-Section") step_2.ln_break = vkt.LineBreak() step_2.cross_section = vkt.OptionField( "### Filter by Cross-Section", options=get_cross_sections ) class Controller(vkt.Controller): parametrization = Parametrization() ``` ### How this works[​](/docs/tutorials/process-staad-data/.md#how-this-works-2 "Direct link to How this works") * The `get_cross_sections` function reads the DataFrame and extracts the unique values from the 'Design Property' column. * These unique cross-sections are returned as a list to be used as options in the `cross_section` `OptionField`. We also append "All" to the list to allow viewing all cross sections. * By setting `options=get_cross_sections` in the `OptionField`, we fill the field with the cross sections from the data (if there is data input). ## 5. Visualize design ratios with VIKTOR[​](/docs/tutorials/process-staad-data/.md#5-visualize-design-ratios-with-viktor "Direct link to 5. Visualize design ratios with VIKTOR") After the user inputs data into the `vkt.Table`, we want to create clear visualizations and add functionality to the `vkt.BooleanField` and `vkt.OptionField` for grouping and filtering. To do this, we will add a `TableView` that shows the design ratios in a table, sorted and colored based on their values. The logic for this will be implemented in the `table_design_ratios` method inside the `Controller` class. In addition, we will use a complementary function called `get_cell_color` to assign a color based on the design ratio values. This will allow us to create a heatmap within the table. Copy the highlighted piece of code and add it to `app.py`. ``` import viktor as vkt import pandas as pd def generate_dataframe(table_data): df = pd.DataFrame([dict(item) for item in table_data]) df.rename( columns={ "col_beam": "Beam", "col_analysis_property": "Analysis Property", "col_design_property": "Design Property", "col_actual_ratio": "Actual Ratio", "col_allowable_ratio": "Allowable Ratio", "col_normalized_ratio": "Normalized Ratio (Actual/Allowable)", "col_clause": "Clause", "col_load_case": "L/C", "col_ax": "Ax in²", "col_iz": "Iz in⁴", "col_iy": "Iy in⁴", "col_ix": "Ix in⁴", }, inplace=True, ) return df def get_cross_sections(params, **kwargs): if params.step_1.table: df = generate_dataframe(params.step_1.table) secs = df["Design Property"].unique().tolist() secs.append("All") return secs return ["No data available! Please add table input."] class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1 - Input Your Data!") step_1.intro = vkt.Text(""" # STAAD Design Ratio Analyzer This app allows you to visualize a heat map from your STAAD.PRO model results. You can filter and group them based on cross sections and visualize how they are distributed.""") step_1.table_input = vkt.Text(""" ## 1.0 Create the Input Table! Paste the design ratio data from your STAAD.PRO model!""") step_1.table = vkt.Table("### Beam Design Analysis") step_1.table.col_beam = vkt.TextField("Beam") step_1.table.col_analysis_property = vkt.TextField("Analysis Property") step_1.table.col_design_property = vkt.TextField("Design Property") step_1.table.col_actual_ratio = vkt.NumberField("Actual Ratio") step_1.table.col_allowable_ratio = vkt.NumberField("Allowable Ratio") step_1.table.col_normalized_ratio = vkt.NumberField("Normalized Ratio") step_1.table.col_clause = vkt.TextField("Clause") step_1.table.col_load_case = vkt.TextField("L/C") step_1.table.col_ax = vkt.TextField("Ax in²") step_1.table.col_iz = vkt.TextField("Iz in⁴") step_1.table.col_iy = vkt.TextField("Iy in⁴") step_1.table.col_ix = vkt.TextField("Ix in⁴") step_2 = vkt.Step("Step 2 - Post-Processing", views=["table_design_ratios"]) step_2.process = vkt.Text(""" ## 2.0 Filter and Group Group or filter by a specific cross section. Use the options below to customize your view. If you want to list all cross-sections after selecting one, you can select the "All" option! """) step_2.group = vkt.BooleanField("### Group by Cross-Section") step_2.ln_break = vkt.LineBreak() step_2.cross_section = vkt.OptionField( "### Filter by Cross-Section", options=get_cross_sections ) class Controller(vkt.Controller): parametrization = Parametrization() @vkt.TableView(label="Design Ratios by Cross Section") def table_design_ratios(self, params, **kwargs): if not params.step_1.table or len(params.step_1.table) == 0: return vkt.TableResult([["No data available! Please add table input."]]) df = generate_dataframe(params.step_1.table) # Group or filter the data based on user selection if params.step_2.group: # For each cross section, get the row with the maximum normalized ratio df = df.loc[ df.groupby("Design Property")[ "Normalized Ratio (Actual/Allowable)" ].idxmax() ].reset_index(drop=True) if params.step_2.cross_section and params.step_2.cross_section != "All": df = df[df["Design Property"] == params.step_2.cross_section] # Drop unnecessary columns df.drop( ["Ax in²", "Iz in⁴", "Iy in⁴", "Ix in⁴", "Analysis Property", "Clause"], axis=1, inplace=True, ) # Sort the DataFrame by Normalized Ratio in descending order df.sort_values( by="Normalized Ratio (Actual/Allowable)", ascending=False, inplace=True ) # Create table data with color-coded cells data = [] for _, row in df.iterrows(): ratio = row["Normalized Ratio (Actual/Allowable)"] color = self.get_cell_color(ratio) row_data = row.tolist() row_data[4] = vkt.TableCell(ratio, background_color=color) data.append(row_data) return vkt.TableResult( data, column_headers=df.columns.tolist(), enable_sorting_and_filtering=True ) def get_cell_color(self, ratio): if ratio >= 1: return vkt.Color(210, 0, 0) # Red elif ratio >= 0.85: return vkt.Color(255, 165, 0) # Orange else: return vkt.Color(0, 210, 0) # Green ``` ### How this works[​](/docs/tutorials/process-staad-data/.md#how-this-works-3 "Direct link to How this works") * We added the `table_design_ratios` method decorated with `@vkt.TableView`, which returns a `TableResult` to be displayed in the app. * We specified `views=["table_design_ratios"]` in `step_2`, so the `TableView` will appear in Step 2. * We check if there's data available; if not, we return a message indicating that to the user. * Depending on the user's selection of `group` and `cross_section`, we group or filter the DataFrame. * If `group` is selected, we group the data by "Design Property" and keep the row with the maximum "Normalized Ratio (Actual/Allowable)" for each group. * If a `cross_section` is selected and it's not "All", we filter the DataFrame to only include that cross-section. * We drop unnecessary columns to keep the table clean. * We sort the DataFrame by "Normalized Ratio (Actual/Allowable)" in descending order. * For each row, we create a `TableCell` for the "Normalized Ratio" column, setting the background color based on the value using the `get_cell_color` function. * The `get_cell_color` function determines the color based on the ratio value: * Ratios >= 1 are colored red (overutilized) * Ratios >= 0.85 and < 1 are colored orange (approaching maximum capacity) * Ratios < 0.85 are colored green (underutilized) ## The resulting app[​](/docs/tutorials/process-staad-data/.md#the-resulting-app "Direct link to The resulting app") Refresh your app in the browser. You will now see the table view appear in Step 2 of your app. For testing, feel free to copy the rows of the TXT file from [section 3](/docs/tutorials/process-staad-data/.md#3-process-the-staadpro-data), then create a new row in the table. Click the top-left checkbox, press `Ctrl + V`, and you will see your rows being populated. After that, you can choose to group or filter the results by cross-section and analyze them. ![Create app](/assets/images/tutorial_staad_results-0f6e600ff88100222b0198da3c9ed8e7.gif) note Ensure that there are no empty rows in the `vkt.Table`; otherwise, the app will complain. You can right-click on an empty row and delete it. You can use the **"Group by Cross-Section"** toggle to view the maximum design ratios for each cross-section. Alternatively, you can use the **"Filter by Cross-Section"** dropdown to focus on a specific cross-section and see how its design ratios are distributed. This provides flexibility in analyzing the data based on your needs. ## Complete code[​](/docs/tutorials/process-staad-data/.md#complete-code "Direct link to Complete code") Were you able to do everything in this tutorial without error? If not, you can always look at the full code: ``` import viktor as vkt import pandas as pd def generate_dataframe(table_data): df = pd.DataFrame([dict(item) for item in table_data]) df.rename( columns={ "col_beam": "Beam", "col_analysis_property": "Analysis Property", "col_design_property": "Design Property", "col_actual_ratio": "Actual Ratio", "col_allowable_ratio": "Allowable Ratio", "col_normalized_ratio": "Normalized Ratio (Actual/Allowable)", "col_clause": "Clause", "col_load_case": "L/C", "col_ax": "Ax in²", "col_iz": "Iz in⁴", "col_iy": "Iy in⁴", "col_ix": "Ix in⁴", }, inplace=True, ) return df def get_cross_sections(params, **kwargs): if params.step_1.table: df = generate_dataframe(params.step_1.table) secs = df["Design Property"].unique().tolist() secs.append("All") return secs return ["No data available! Please add table input."] class Parametrization(vkt.Parametrization): step_1 = vkt.Step("Step 1 - Input Your Data!") step_1.intro = vkt.Text(""" # STAAD Design Ratio Analyzer This app allows you to visualize a heat map from your STAAD.PRO model results. You can filter and group them based on cross sections and visualize how they are distributed.""") step_1.table_input = vkt.Text(""" ## 1.0 Create the Input Table! Paste the design ratio data from your STAAD.PRO model!""") step_1.table = vkt.Table("### Beam Design Analysis") step_1.table.col_beam = vkt.TextField("Beam") step_1.table.col_analysis_property = vkt.TextField("Analysis Property") step_1.table.col_design_property = vkt.TextField("Design Property") step_1.table.col_actual_ratio = vkt.NumberField("Actual Ratio") step_1.table.col_allowable_ratio = vkt.NumberField("Allowable Ratio") step_1.table.col_normalized_ratio = vkt.NumberField("Normalized Ratio") step_1.table.col_clause = vkt.TextField("Clause") step_1.table.col_load_case = vkt.TextField("L/C") step_1.table.col_ax = vkt.TextField("Ax in²") step_1.table.col_iz = vkt.TextField("Iz in⁴") step_1.table.col_iy = vkt.TextField("Iy in⁴") step_1.table.col_ix = vkt.TextField("Ix in⁴") step_2 = vkt.Step("Step 2 - Post-Processing", views=["table_design_ratios"]) step_2.process = vkt.Text(""" ## 2.0 Filter and Group Group or filter by a specific cross section. Use the options below to customize your view. If you want to list all cross-sections after selecting one, you can select the "All" option! """) step_2.group = vkt.BooleanField("### Group by Cross-Section") step_2.ln_break = vkt.LineBreak() step_2.cross_section = vkt.OptionField( "### Filter by Cross-Section", options=get_cross_sections ) class Controller(vkt.Controller): parametrization = Parametrization() @vkt.TableView(label="Design Ratios by Cross Section") def table_design_ratios(self, params, **kwargs): if not params.step_1.table or len(params.step_1.table) == 0: return vkt.TableResult([["No data available! Please add table input."]]) df = generate_dataframe(params.step_1.table) # Group or filter the data based on user selection if params.step_2.group: # For each cross section, get the row with the maximum normalized ratio df = df.loc[ df.groupby("Design Property")[ "Normalized Ratio (Actual/Allowable)" ].idxmax() ].reset_index(drop=True) if params.step_2.cross_section and params.step_2.cross_section != "All": df = df[df["Design Property"] == params.step_2.cross_section] # Drop unnecessary columns df.drop( ["Ax in²", "Iz in⁴", "Iy in⁴", "Ix in⁴", "Analysis Property", "Clause"], axis=1, inplace=True, ) # Sort the DataFrame by Normalized Ratio in descending order df.sort_values( by="Normalized Ratio (Actual/Allowable)", ascending=False, inplace=True ) # Create table data with color-coded cells data = [] for _, row in df.iterrows(): ratio = row["Normalized Ratio (Actual/Allowable)"] color = self.get_cell_color(ratio) row_data = row.tolist() row_data[4] = vkt.TableCell(ratio, background_color=color) data.append(row_data) return vkt.TableResult( data, column_headers=df.columns.tolist(), enable_sorting_and_filtering=True ) def get_cell_color(self, ratio): if ratio >= 1: return vkt.Color(210, 0, 0) # Red elif ratio >= 0.85: return vkt.Color(255, 165, 0) # Orange else: return vkt.Color(0, 210, 0) # Green ``` ## Export your own results from STAAD.PRO[​](/docs/tutorials/process-staad-data/.md#export-your-own-results-from-staadpro "Direct link to Export your own results from STAAD.PRO") To export the design ratios from your STAAD.PRO app, first run your analysis and design check. Then, right-click > **Tables** > **Design Results**, and simply copy and paste the data into the `vkt.Table` component in the app. Make sure there are no empty rows, and you are all set! You can see how this process works in the animation below. ![Export data](/assets/images/tutorial_staad_export_data-8f9f32e80c1c5b5dc30824c460ca92c8.gif) ## What's next?[​](/docs/tutorials/process-staad-data/.md#whats-next "Direct link to What's next?") In this tutorial, you learned how to post-process results exported from STAAD.PRO. Your next goal could be to implement automation using the STAAD.PRO API from your VIKTOR app. To achieve this, the best place to start is the following [tutorial](/docs/tutorials/integrate-staadpro/.md). --- # How to convert a Python Project to a VIKTOR app info Level: **Beginners**
Time: **30 min**
Prerequisites: * You have some experience with reading Python code * You have completed the installation and onboarding process of the VIKTOR platform * You have a Python project or script that you would like to convert to a VIKTOR app ***Not a reader?** feel free to follow this tutorial as a video* ## Introduction[​](/docs/tutorials/python-script-to-app/.md#introduction "Direct link to Introduction") Most Python projects start off with a simple script to help with a task, whether it is for automating or calculation purposes. These scripts can evolve into valuable tools that can have value far beyond your own use. In general, what keeps these scripts from being utilized by others is that it often does not have a user-friendly way of being operated (for example an intuitive interface), it generally requires an extensive user manual, and that distribution is nearly impossible, as these scripts almost always require a set of dependencies that need to be installed, not mentioning the rights that need to be allocated to the user to be able to install these programs and packages. The VIKTOR platform allows one to overcome these challenges by providing a platform, SDK and integration possibilities. In this piece we will provide a guide to easily convert your script into a VIKTOR web application, which will allow others to also share the value that you created, without the bottlenecks usually encountered. In this guide, we will explore how to convert your Python project to a VIKTOR app. We will cover: 1. [Where to start](/docs/tutorials/python-script-to-app/.md#where-to-start) 2. [Let's convert your script!](/docs/tutorials/python-script-to-app/.md#lets-convert-your-script) 3. [What's next?](/docs/tutorials/python-script-to-app/.md#whats-next) By the end of this guide, you will have a clear understanding how to convert your Python project to a VIKTOR app. info If you do not have a suitable Python script, consider writing something that you are familiar with such as a basic plot. This will remove the chance of knowledge gaps that you would have if you are given a script and allows you to focus on the VIKTOR elements. Throughout the guide, we added some links with additional information; but don't let them distract you too much. Stay focused on understanding the content. After this, you will know everything you need to convert your Python project to an app. ## Where to start[​](/docs/tutorials/python-script-to-app/.md#where-to-start "Direct link to Where to start") For the sake of this guide it is important to understand the fundamentals and typical layout of a VIKTOR app. These fundamentals are, however, elaborated upon earlier during the VIKTOR onboarding. So, if you want to directly get started in the steps to convert your script to an app, skip to the [Let’s convert your script!](/docs/tutorials/python-script-to-app/.md#lets-convert-your-script)! ### VIKTOR framework fundamentals[​](/docs/tutorials/python-script-to-app/.md#viktor-framework-fundamentals "Direct link to VIKTOR framework fundamentals") As the goal with this guide is to help you convert your script to a VIKTOR app, it is helpful to understand the fundamentals that make up the VIKTOR framework. In an attempt to give the clearest overview of the fundamentals, without oversimplifying, let us start with what we believe a good starting point is in understanding the VIKTOR framework. There are three aspects that are important to keep in mind when converting your script to an app, which are: 1. **Input:** The variables that can be adjusted for a calculation 2. **Results:** Results can either be presented visually or downloaded in a given file format. 3. **Stateless and containerized calculation:** A stateless calculation’s outcomes are not influenced by previous events, except if part of the calculation’s outcome is to alter the input (which will then alter the outcome of the next calculation). A deployed app also runs in isolation, which is what is meant by being containerized. These three points are important to remember when considering converting a script to a VIKTOR application. ### VIKTOR code layout[​](/docs/tutorials/python-script-to-app/.md#viktor-code-layout "Direct link to VIKTOR code layout") Now that we know how VIKTOR’s framework fundamentally works, let us look at an example of a VIKTOR app to explain a typical VIKTOR app code layout: ![An example of a VIKTOR app\'s code and interface.](/assets/images/tutorial-script-to-app-example-app-code-34de9a527edf3d75068b220cde4b4262.png) Be aware that this is just an example to explain the fundamentals from a code’s perspective, and that the VIKTOR platform provides an endless number of possibilities. Noting above’s example, let us try to connect the fundamentals to this example. #### Input[​](/docs/tutorials/python-script-to-app/.md#input "Direct link to Input") As a fundamental, the VIKTOR platform forces the developer to determine what the input variables of the calculation should be. This is done by defining all input parameters in the `Parametrization` class. There is an extensive amount of input, so this should not limit the developer. Refer to the [User input, fields and buttons](/docs/create-apps/user-input/.md) section in the documentation for a clear overview of the possibilities. ![Example of VIKTOR input widgets](/assets/images/tutorial-script-to-app-inputs-b08d63bbacf8fbd44ac982f6d389f73b.gif) #### Results[​](/docs/tutorials/python-script-to-app/.md#results "Direct link to Results") Whether the result of the calculation is a visualization of sorts or a download, this is a result of a method that is defined in the `Controller` class. A download is simply a file of bytes or strings, so any format can be downloaded. For visualizations, the following is possible: * **Images** (PNG, JPEG, SVG, GIF): these formats need to be saved to memory by using `BytesIO`, `StringIO` or VIKTOR’s `File` * **Maps** * **3D geometries** (any object that can be converted to a glb/gltf format, or by using the primitive geometries available in the VIKTOR SDK) * **PDFs** * Any result in **HTML** * **Plotly** Refer to the [Results and visualizations](/docs/create-apps/results-and-visualizations/.md) section in the documentation to read up more on this. ![The range of output that can be generated with VIKTOR](/assets/images/tutorial-script-to-app-visualisation-fdf3ac772a336bb47f3c598f90d55fe8.gif) #### Stateless calculation[​](/docs/tutorials/python-script-to-app/.md#stateless-calculation "Direct link to Stateless calculation") Any method that produces a result, presents a visualization, or produces a download must contain some logic. This logic can be defined directly in the method, split up into different methods, or defined in functions or classes in other files or directories within the app project. The requirement is that the code is written in such a way that the input provided (which can be retrieved from the `params` argument of the `Controller` class) always produces the same result when the input remains unchanged. In the event where a stateful event is wanted, the VIKTOR platform provides a `Storage` capability that allows developers to write data to a storage database that can be retrieved for the next calculation. #### Containerized calculation[​](/docs/tutorials/python-script-to-app/.md#containerized-calculation "Direct link to Containerized calculation") As the intent of building a web app is to run it on a server rather than locally, the app with all its logic and files needs to be able to run in an isolated environment. Therefore, one needs to make sure that the entire development is done within the project folder, and that, when referring to files and folders, that these paths are referenced relatively. ![What is stateless, containerized code, and what alternatives does VIKTOR bring.](/assets/images/tutorial-script-to-app-stateless-4253f8181ef631aae75c31cfd7cde478.png) #### *Other things to consider…*[​](/docs/tutorials/python-script-to-app/.md#other-things-to-consider "Direct link to other-things-to-consider") * If your code is written such that files are written to your local drive, it is suggested to convert this to saving the file to memory, or to use the VIKTOR SDK `Storage` functionality to store the file to a database. * If the Python code uses system dependencies or software that cannot be installed using `pip install`, we suggest using the integrations we provide. Or rewrite your code to use code that does not require these dependencies. ## Let’s convert your script\![​](/docs/tutorials/python-script-to-app/.md#lets-convert-your-script "Direct link to Let’s convert your script!") Now that we know the VIKTOR platform from fundamentals, and we have an idea how the code structure works for a VIKTOR application, let’s take that knowledge to convert a script to a VIKTOR application. ![The steps to convert a simple script to an app.](/assets/images/tutorial-script-to-app-steps-9cba2580799a959a6cc35328a0de3847.png) Take the following steps: ### 1. Create a VIKTOR app project.[​](/docs/tutorials/python-script-to-app/.md#1-create-a-viktor-app-project "Direct link to 1. Create a VIKTOR app project.") To create a new VIKTOR application project, use the `viktor-cli` to generate a project file structure automatically. The command to use is: ``` viktor-cli create-app –-app-type editor ``` ### 2. Collect all requirements of the python script.[​](/docs/tutorials/python-script-to-app/.md#2-collect-all-requirements-of-the-python-script "Direct link to 2. Collect all requirements of the python script.") A good place to start would be to collect a list of all the python packages that are being used in the script. Some examples of frequently used Python packages are: * Numpy * Scipy * Matplotlib * Pandas * Etc. Add these packages to the `requirements.txt` file. info If the Python script only works for a given Python version, make sure to indicate this in the `viktor.config.toml` file. ### 3. Convert script to a function.[​](/docs/tutorials/python-script-to-app/.md#3-convert-script-to-a-function "Direct link to 3. Convert script to a function.") A script can be converted to a VIKTOR app in many ways. One of the simpler ways of converting a script would be to rewrite the code such that it can run by calling a single function. This would entail you only need to consider what should be the result of the calculation, and then make sure that the result that you want to produce is returned by the function. E.g. if the result of the code is to produce a matplotlib plot, return a matplotlib figure, or if the result is a pandas dataframe, return that. If your code writes a file to a local drive, rewrite the code such that it returns the file as an object saved to memory, e.g. `BytesIO`, `StringIO` or `File`. ### 4. Create a view/download in the VIKTOR Controller[​](/docs/tutorials/python-script-to-app/.md#4-create-a-viewdownload-in-the-viktor-controller "Direct link to 4. Create a view/download in the VIKTOR Controller") In this step we will create a view or download functionality that can be seen in the interface of the VIKTOR app. Here are the steps: To use the newly created function in your VIKTOR app, import the function into the `app.py` file where the bare-bones VIKTOR app code structure resides. Depending on whether you would like to create a download functionality or visualization, follow the steps described in the subsection: #### 4.1 Download[​](/docs/tutorials/python-script-to-app/.md#41-download "Direct link to 4.1 Download") Here are the steps for a download functionality: 1. Create a download button: In the `Parametrization`, create a field with a `DownloadButton`, similar to the code snippet presented below: ``` import viktor as vkt class Parametrization(vkt.Parametrization): download_btn = vkt.DownloadButton('Download file', method='download_file') ``` 2. In the `Controller`, create a method with the same name as defined in the `method` argument (in the given example, `download_file`). Here is an example how this would look like: ``` import viktor as vkt class Controller(vkt.Controller): parametrization = Parametrization def download_file(self, params, **kwargs): return vkt.DownloadResult(file_content='', file_name='my_file.txt') ``` 3. Add your function to the method. The `file_content` that the VIKTOR platform expects is either string, bytes, `File` or `BytesIO`. Therefore, make sure to convert the type produced by the function if it does not suit any of the given types. ``` import viktor as vkt from .my_project import my_function # assuming that your function is within another file # Assuming that your function is within this project def my_function(): ... return class Controller(vkt.Controller): parametrization = Parametrization def download_file(self, params, **kwargs): result = my_function() return vkt.DownloadResult(file_content=result, file_name='my_file.txt') ``` #### 4.2 Visualization[​](/docs/tutorials/python-script-to-app/.md#42-visualization "Direct link to 4.2 Visualization") Here are the steps for a visualization: 1. Determine what type of visualization you want to create from the result of your function. 2. In the `Controller`, create a method with your name of choice. The result to be returned by the method is dependent on the type of visualization. 3. Add a decorator to your method that suits your visualization. 4. Add your function to the method. Depending on the View, the result may differ. Therefore, make sure to check the documentation for that given view, and convert the type produced by the function to the format that is expected. Here is an example of the result of the four steps: ``` import viktor as vkt from .my_project import my_function # assuming that your function is within another file # Assuming that your function is within this project def my_function(): ... return class Controller(vkt.Controller): parametrization = Parametrization @vkt.WebView("My View") def create_plot(self, params, **kwargs): my_result = my_function() return vkt.WebResult(my_result) ``` Here is a table overview of the steps, with the possible options: | Steps | Image | Map | 3D Geometry | PDF | HTML | Plotly | | ----------------------------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | 1. Determine type of visualization | This could be static plots such as Matplotlib, Seaborn, etc. or other type of images. | GeoJSONs or locations that can be visualized on a map | Any type of geometry that can be converted to glb/gltf, or some simple parameters that can be converted to simple VIKTOR geometries. | Word and Excel files can be converted to PDFs within VIKTOR! | HTML or URLs can be imbedded. | Plotly is a Python package with which you can create dynamic plots. | | 2. Create method with correct return type | `ImageResult` | `MapResult` or `GeoJSONResult` | `GeometryResult` | `PDFResult` | `WebResult` | `PlotlyResult` | | 3. Add decorator to your method | `ImageView` | `MapView` or `GeoJSONView` | `GeometryView` | `PDFView` | `WebView` | `PlotlyView` | | 4. Add your function to the method. | `BytesIO` for PNG, JPG/JPEG and GIF, `StringIO` for SVG | `MapView`: a list of VIKTOR map objects
`GeoJSONView`: a GeoJSON dict | This could either be a VIKTOR `Group` object, consisting of VIKTOR primitive Geometry objects, or...
a glTF/GLB or 3DM file as a VIKTOR `File` ojbect | You could reference a PDF from a URL, a path, or, probably the most common one, as a VIKTOR `File` | The HTML could be retrieved from a URL, static file as a path, or as an HTML string | A Plotly `Figure` object | If all went well, you will now have an application that displays the result of your function. ### 5. Create fields as input for calculation.[​](/docs/tutorials/python-script-to-app/.md#5-create-fields-as-input-for-calculation "Direct link to 5. Create fields as input for calculation.") We’ve created a visualization, but ideally, we would like to make the app dynamic based on input. To do this, the following steps can be followed: 1. Start by determining which variables you would like the user of the app to change. Add these variables as input to the function you’ve created from your script. 2. Add fields to the parametrization that correspond with these variables. For example, if there are three variables named `a`, `b` and `c` that can be adjusted, we can add these fields to the `Parametrization` as well: | Variable | Type | Field | | -------- | ------------------ | ----------- | | a | Float | NumberField | | b | Options of strings | OptionField | | c | File | FileField | | Etc. | | | ``` class Parametrization(vkt.Parametrization): a = vkt.NumberField('a') b = vkt.OptionField('b', options=['apple', 'pear', 'lemon']) c = vkt.FileField('Upload file') ``` 3. Add the parameters to the function. You may have noticed that the methods defined in the `Controller` have a `params` argument. You can access the parameters from that variable. Here is an example: ``` import viktor as vkt from .my_project import my_function # assuming that your function is within another file # Assuming that your function is within this project def my_function(a, b, c): ... return class Controller(vkt.Controller): parametrization = Parametrization @vkt.WebView("My View") def create_plot(self, params, **kwargs): result = my_function( a=params.a, b=params.b, c=params.c ) return vkt.WebResult(result) ``` ## What's next?[​](/docs/tutorials/python-script-to-app/.md#whats-next "Direct link to What's next?") And that's it! By following these steps, one should be able to convert a Python script to a VIKTOR app in no time. The VIKTOR platform provides much, much more in terms of functionalities and features. Therefore, if you want to explore the possibilities to improve your app, consider consulting the documentation. Topics that are of great interest to developers are: * [Layout and styling](/docs/create-apps/layout-and-styling/.md) * [Informing the end-user](/docs/create-apps/inform-end-user/text-blocks/.md) * [Managing files](/docs/create-apps/managing-files/downloading-files/.md) * [Software integrations](/docs/create-apps/software-integrations/.md) * and so much [more...](/docs/welcome/.md) There are also resources other than the documentation available that could help in the app development journey, such as: * [Blog posts](https://www.viktor.ai/blog/category/all/1) * [Other examples of apps](https://www.viktor.ai/apps-gallery/category/all/tag/all/1) * [White-papers (especially the one on "Building successful applications")](https://www.viktor.ai/white-papers) * [The community, for interactive discussions](https://community.viktor.ai/) --- # Tutorial - Spreadsheet Calculator info Level: **Beginners**
Time: **20 min**
Prerequisites: * You have an account and completed the installation process. No account? Get one [here](https://www.viktor.ai/start-building-apps) * You have some experience with reading Python code * [![](/img/illustrations/free-version-banner.svg)](https://www.viktor.ai/start-building-apps)
***Not a reader?** feel free to follow this tutorial as a video* ## Introduction[​](/docs/tutorials/spreadsheet-calculator/.md#introduction "Direct link to Introduction") Welcome to the spreadsheet calculations tutorial! In most branches of engineering, spreadsheets are the golden standard for sharing results and knowledge in a clear, well organised way. In this tutorial you will learn how to implement an existing calculation from an excel sheet into a VIKTOR web application. For this, the example we will use is a simply supported beam under load and all the calculations will be performed in the spreadsheet. In this tutorial we will cover: 1. [Create, install and start an empty app](/docs/tutorials/spreadsheet-calculator/.md#1-create-install-and-start-an-empty-app) 2. [The Excel spreadsheet](/docs/tutorials/spreadsheet-calculator/.md#2-the-excel-spreadsheet) 3. [Adding inputs and views](/docs/tutorials/spreadsheet-calculator/.md#3-adding-inputs-and-views) 4. [Downloading the spreadsheet](/docs/tutorials/spreadsheet-calculator/.md#4-download-the-spreadsheet) By the end of this tutorial, you will have created a VIKTOR application that generates calculations from a spreadsheet and that will allow the user to download the results to share with colleagues. You can test the final result below: info You can now also use the **'Create new app - Upload an Excel sheet'** option in the **App Store** to instantly generate the boilerplate code for your particular excel spreadsheet. However, we recommend that you follow this tutorial to get an understanding of the fundamentals of developing a VIKTOR app. ## 1. Create, install and start an empty app[​](/docs/tutorials/spreadsheet-calculator/.md#1-create-install-and-start-an-empty-app "Direct link to 1. Create, install and start an empty app") Need help? Are you encountering an error? Take a look at the [**complete app code**](/docs/tutorials/spreadsheet-calculator/.md#5-all-code-together). Also know that you can always ask for help at our [**Community Forum**](https://community.viktor.ai/), where our developers are ready to help with any question related to the installation, coding and more. Let's create, install and start an empty app. This will be the starting point for the rest of the tutorial. But before we start, make sure to shut down any app that is running (like the demo app) by closing the command-line shell (for example Powershell) or end the process using `Ctrl + C`. Follow these steps to create, install and start an empty app: 1. Go to the App store in your VIKTOR environment to create a new app. After clicking 'Create app' choose the option 'Create blank app' and enter a name, 'spreadsheet-tutorial', and description of your choice. Submit the form by clicking 'Create and setup'. ![](/assets/images/create-new-app-13be373b0c30ac3adf3f831c245506a2.gif) 2. Select 'Editor' as app type and click 'Next'. 3. Now follow the instructions to run the `quickstart` command to download the empty app template. After entering the command click 'I have run the command' to continue. The CLI will ask you to select your code editor of choice. Use the arrows and press enter to select a code editor. The app will now open in your code editor of choice. If all went well, your empty app is installed and connected to your development workspace. **Do not close the terminal** as this will break the connection with your app. The terminal in your code editor should show something like this: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` Re-starting your app * You only need create an app template and install it once for each new app you want to make. * The app will update automatically once you start adding code in `app.py`, as long as you don't close the terminal or your code editor. * Did you close your code editor? Use `viktor-cli start` to start the app again. No need to install, clear, etc. **Did you encounter any errors?** * Always make sure to check the spelling of everything you placed in the command-line, a small mistake and the command you are trying to run may not be recognised! * If you are encountering: ``` ERROR: Exiting because of an error: no requirements.txt file PS C:\Users\\viktor-apps> ``` Then you are not in the correct folder! check the command-line and navigate to the spreadsheet-tutorial folder. * If you are encountering: ``` Error: App definition is not compatible with the data currently stored in the database. Use the command 'viktor-cli clear' to clear the database. PS C:\Users\\viktor-apps\spreadsheet-tutorial> ``` That means you have not cleared the database yet! Use the `viktor-cli clear` to clear and then you can use `viktor-cli start` to start the app. No need to install it again! Not seeing any of these errors? Head over to our community! There is a good chance another developer encountered it and solved it too! ## 2. The Excel spreadsheet[​](/docs/tutorials/spreadsheet-calculator/.md#2-the-excel-spreadsheet "Direct link to 2. The Excel spreadsheet") As mentioned previously, this example will be of a simply supported beam under load. If you would like to use or modify the example spreadsheet used for this tutorial, you can download it [here](/files/docs/spreadsheet-calculator-tutorial/beam_calculation.xls) \[1]. You will need to add your spreadsheet to the root directory/folder, in this case the one we made when we made the empty app named 'spreadsheet-tutorial'. \[1] source: [https://stuff.mit.edu](https://stuff.mit.edu/afs/athena/course/2/2.75/fundamentals/FUNdaMENTALs%20Book%20pdf/FUNdaMENTALS%20Design%20Spreadsheets/Topic%208%20Structures%20Design%20Spreadsheets/Beam_simply_supported.xls) (04-05-2020) The app should now have the following folder structure: ``` spreadsheet-tutorial ├── tests ├── app.py ├── beam_calculation.xls ├── CHANGELOG.md ├── README.md ├── requirements.txt └── viktor.config.toml ``` To be able to use a spreadsheet as a calculation tool within a VIKTOR app, a few modifications must be performed to the spreadsheet file (more elaboration on this can be found [here](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md#calculation-sheet-set-up)). Open `beam_calculation.xls` and add two sheets: `viktor-input-sheet` and `viktor-output-sheet`. These sheets contain the input and output values respectively. In the `viktor-input-sheet`, add the following data: ![](/assets/images/spreadsheet-app-input-sheet-0660e7d09b6c3f614dd2d3136a0a0d3c.png) The values from `viktor-input-sheet` should now be used in the `Analysis` sheet. For example, cell C22 below refers to the "L" parameter defined in the `viktor-input-sheet` sheet: ![](/assets/images/spreadsheet-app-analysis-sheet-6d7b7c68f57038ec34004ccc2229ffc1.png) In the `viktor-output-sheet` the desired output parameters are defined, with their values taken from the `Analysis` sheet: ![](/assets/images/spreadsheet-app-output-sheet-d0eda0bd843b9c884176afb6d0af0cc1.png) You should now be able to change the values on the `viktor-input-sheet`, resulting in changed values in the `viktor-output-sheet`. If you got lost along the way, or want to take the easy route, download the fully adjusted spreadsheet [here](/files/docs/spreadsheet-calculator-tutorial-complete/beam_calculation.xls). ### Coupling the spreadsheet[​](/docs/tutorials/spreadsheet-calculator/.md#coupling-the-spreadsheet "Direct link to Coupling the spreadsheet") The spreadsheet is now ready to be used within the app. VIKTOR provides a helper class specifically for this task: [`SpreadsheetCalculation`](/sdk/api/external/spreadsheet/.md#_SpreadsheetCalculation). The first thing that needs to be done is to make sure that we can get to the spreadsheet. For this you may add the function `fill_spreadsheet` as described below. The `app.py` file should now look like this: ``` import viktor as vkt from pathlib import Path SPREADSHEET_PATH = Path(__file__).parent / "beam_calculation.xls" def fill_spreadsheet(params) -> vkt.spreadsheet.SpreadsheetCalculation: inputs = [ vkt.spreadsheet.SpreadsheetCalculationInput('L', params.beam.length), vkt.spreadsheet.SpreadsheetCalculationInput('W', params.beam.width), vkt.spreadsheet.SpreadsheetCalculationInput('H', params.beam.height), vkt.spreadsheet.SpreadsheetCalculationInput('E', params.beam.E), vkt.spreadsheet.SpreadsheetCalculationInput('aw', params.loads.aw), vkt.spreadsheet.SpreadsheetCalculationInput('wa', params.loads.wa), vkt.spreadsheet.SpreadsheetCalculationInput('wL', params.loads.wL) ] return vkt.spreadsheet.SpreadsheetCalculation.from_path(SPREADSHEET_PATH, inputs=inputs) class Parametrization(vkt.Parametrization): pass class Controller(vkt.Controller): parametrization = Parametrization ``` Great! Now that we are ready to process the excel sheet, let's start with providing the user with the possibility to enter inputs for that sheet. ## 3. Adding inputs and views[​](/docs/tutorials/spreadsheet-calculator/.md#3-adding-inputs-and-views "Direct link to 3. Adding inputs and views") Our workspace is still a bit empty, lets change that! First, lets add some inputs to our parametrization so that our user can make changes to the calculations. To reduce the clutter in our app, lets make a [`Section`](/sdk/api/parametrization/.md#_Section) for this and fill it with the parameters of the beam. The end result can be downloaded [here](/files/docs/spreadsheet-calculator-tutorial-complete.zip). Additionally, we will also add an [`Image`](/sdk/api/parametrization/.md#_Image) to our parametrization that will allow the user to check the locations and orientations of the parameters. For this we need to make two more modifications to our app. First, add a new folder called 'assets' to our 'spreadsheet-tutorial' app folder. You need to add the beam schematic from the top of the Analysis sheet to this folder (can also be downloaded here: [beam\_schematic.png](/files/docs/spreadsheet-calculator-tutorial/beam_schematic.png). The resulting folder structure would look like this: ``` spreadsheet-tutorial ├── tests ├── assets │ └── beam_schematic.png ├── app.py ├── beam_calculation.xls ├── CHANGELOG.md ├── README.md ├── requirements.txt └── viktor.config.toml ``` In the `viktor.config.toml` file remove the hashtag in order to add: `assets_path = "assets"` to the config. The full config file should now look like this: ``` # For all available configuration settings, please go to: # https://docs.viktor.ai/docs/create-apps/references/viktor-config-toml app_type = 'editor' assets_path = 'assets' # packages = [] python_version = '3.13' # welcome_text = 'welcome.md' registered_name = 'spreadsheet-tutorial' ``` Update the `Parametrization` to show the required input fields: ``` ... class Parametrization(vkt.Parametrization): beam = vkt.Section('Beam') beam.schematic = vkt.Image(path="beam_schematic.png") beam.length = vkt.NumberField('Length (L)', suffix='mm', default=80, max=100) beam.width = vkt.NumberField('Width (W)', suffix='mm', default=10) beam.height = vkt.NumberField('Height (H)', suffix='mm', default=10) beam.E = vkt.NumberField('Modulus of Elasticity (E)', default=200000, suffix='N/mm2') ``` This will allow you to change the parameters of the beam which are used in our spreadsheet calculations. But you may also want to change the way we load the beam. Lets also add some input fields for that in a new `Section`. ``` ... class Parametrization(vkt.Parametrization): beam = vkt.Section('Beam') beam.schematic = vkt.Image(path="beam_schematic.png") beam.length = vkt.NumberField('Length (L)', suffix='mm', default=80, max=100) beam.width = vkt.NumberField('Width (W)', suffix='mm', default=10) beam.height = vkt.NumberField('Height (H)', suffix='mm', default=10) beam.E = vkt.NumberField('Modulus of Elasticity (E)', default=200000, suffix='N/mm2') loads = vkt.Section('Loads') loads.aw = vkt.NumberField('Starting point of load (aw)', suffix='mm', default=9) loads.lb = vkt.LineBreak() loads.wa = vkt.NumberField('Distributed load amplitude (wa)', suffix='N/mm', flex=40, default=5) loads.wL = vkt.NumberField('Distributed load amplitude (wL)', suffix='N/mm', flex=40, default=5) ``` ### Showing results and a schematic[​](/docs/tutorials/spreadsheet-calculator/.md#showing-results-and-a-schematic "Direct link to Showing results and a schematic") If all went well, you should now be able to see all the inputs for the beam and loads in your workspace. Now let's display some results and a handy schematic so that the user knows what all the inputs mean and which way we have defined as positive and negative (coordinate system). For the results, let's add a [`TableView`](/sdk/api/views/.md#_TableView) to our controller. You will need to use the method we made earlier to grab the results from the spreadsheet. ``` ... class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Outputs") def spreadsheet_calculation(self, params, **kwargs) -> vkt.TableResult: sheet = fill_spreadsheet(params) result = sheet.evaluate() column_headers = [vkt.TableHeader("Value", num_decimals=2), "Unit", "Description"] row_headers = [ "maximum_deflection", "maximum_bending_stress", ] data = [ [result.values["maximum_deflection"], "microns", ""], [result.values["maximum_bending_stress"], "N/mm2", "Maximum bending stress along the beam"], ] return vkt.TableResult(data, row_headers=row_headers, column_headers=column_headers) ``` After reloading the app, you should now be able to see the maximum deflection and maximum bending stress in the workspace. tip If you get stuck, you can always try to have a quick peek at the [complete code](/docs/tutorials/spreadsheet-calculator/.md#6-all-code-together) at the end of this tutorial Beautiful! If all went well you should now be able to use the schematic as a reference to define your loads and dimensions of the beam and see the maximum stress and deflection in the `DataView`. ### Adding plots for analysis[​](/docs/tutorials/spreadsheet-calculator/.md#adding-plots-for-analysis "Direct link to Adding plots for analysis") To perform some analysis, lets add a plot to show the curvature along the beam. All the data points for this are already in the excel file so you will only need to extract and plot this data. The data we are using for this example is the deflection data but you can use any other data that the sheet provides as the `pandas` dataframe will have all the data. We can then make a figure using the `plotly.express` package and display this figure in our application. First, let's add the `plotly`, `pandas` and `openpyxl` packages to our app by updating the `requirements.txt` to: ``` viktor==... plotly pandas openpyxl ``` Second, let's add the imports and the `PlotlyView` to the controller: ``` import viktor as vkt import pandas as pd import plotly.express as px from pathlib import Path ... class Controller(vkt.Controller): ... @vkt.PlotlyView('Beam Curvature') def beam_curvature(self, params, **kwargs): sheet = fill_spreadsheet(params) result = sheet.evaluate(include_filled_file=True) evaluated_file = vkt.File.from_data(result.file_content) with evaluated_file.open_binary() as fp: data_df = pd.read_excel(fp, sheet_name='Data') deflection_data = data_df['Deflection (microns)'].head(params.beam.length+1) fig = px.line(deflection_data, title='Beam deflection', labels={'value': 'Deflection (microns)', 'index': 'Length (mm)'}) return vkt.PlotlyResult(fig) ``` ## 4. Download the spreadsheet[​](/docs/tutorials/spreadsheet-calculator/.md#4-download-the-spreadsheet "Direct link to 4. Download the spreadsheet") Now that we have all the functionality for our spreadsheet calculations, we can download the result as a spreadsheet to share with our colleagues in our next meeting. ``` ... class Parametrization(vkt.Parametrization): ... calculation_sheet = vkt.Section('Download') calculation_sheet.button = vkt.DownloadButton('Download', 'download_spreadsheet') ``` Then, to our controller class we need to add the method `download_spreadsheet` to download the spreadsheet. ``` ... class Controller(vkt.Controller): ... def download_spreadsheet(self, params, **kwargs): sheet = fill_spreadsheet(params) result = sheet.evaluate(include_filled_file=True) return vkt.DownloadResult(result.file_content, 'evaluated_beam.xlsx') ``` Give it a quick test to make sure you made no mistakes and everything works. Now admire the beautiful app you have made! ## 5. All code together[​](/docs/tutorials/spreadsheet-calculator/.md#5-all-code-together "Direct link to 5. All code together") Congratulations!!! This is concludes the tutorial, you have now built a fully functional app to perform spreadsheet calculations. Enjoy!!! **Complete app.py code** ``` import viktor as vkt import pandas as pd import plotly.express as px from pathlib import Path SPREADSHEET_PATH = Path(__file__).parent / "beam_calculation.xls" def fill_spreadsheet(params) -> vkt.spreadsheet.SpreadsheetCalculation: inputs = [ vkt.spreadsheet.SpreadsheetCalculationInput('L', params.beam.length), vkt.spreadsheet.SpreadsheetCalculationInput('W', params.beam.width), vkt.spreadsheet.SpreadsheetCalculationInput('H', params.beam.height), vkt.spreadsheet.SpreadsheetCalculationInput('E', params.beam.E), vkt.spreadsheet.SpreadsheetCalculationInput('aw', params.loads.aw), vkt.spreadsheet.SpreadsheetCalculationInput('wa', params.loads.wa), vkt.spreadsheet.SpreadsheetCalculationInput('wL', params.loads.wL) ] return vkt.spreadsheet.SpreadsheetCalculation.from_path(SPREADSHEET_PATH, inputs=inputs) class Parametrization(vkt.Parametrization): beam = vkt.Section('Beam') beam.schematic = vkt.Image(path="beam_schematic.png") beam.length = vkt.NumberField('Length (L)', suffix='mm', default=80, max=100) beam.width = vkt.NumberField('Width (W)', suffix='mm', default=10) beam.height = vkt.NumberField('Height (H)', suffix='mm', default=10) beam.E = vkt.NumberField('Modulus of Elasticity (E)', default=200000, suffix='N/mm2') loads = vkt.Section('Loads') loads.aw = vkt.NumberField('Starting point of load (aw)', suffix='mm', default=9) loads.lb = vkt.LineBreak() loads.wa = vkt.NumberField('Distributed load amplitude (wa)', suffix='N/mm', flex=40, default=5) loads.wL = vkt.NumberField('Distributed load amplitude (wL)', suffix='N/mm', flex=40, default=5) calculation_sheet = vkt.Section('Download') calculation_sheet.button = vkt.DownloadButton('Download', 'download_spreadsheet') class Controller(vkt.Controller): parametrization = Parametrization @vkt.TableView("Outputs") def spreadsheet_calculation(self, params, **kwargs) -> vkt.TableResult: sheet = fill_spreadsheet(params) result = sheet.evaluate() column_headers = [vkt.TableHeader("Value", num_decimals=2), "Unit", "Description"] row_headers = [ "maximum_deflection", "maximum_bending_stress", ] data = [ [result.values["maximum_deflection"], "microns", ""], [result.values["maximum_bending_stress"], "", "Maximum bending stress along the beam"], ] return vkt.TableResult(data, row_headers=row_headers, column_headers=column_headers) @vkt.PlotlyView('Beam Curvature') def beam_curvature(self, params, **kwargs): sheet = fill_spreadsheet(params) result = sheet.evaluate(include_filled_file=True) evaluated_file = vkt.File.from_data(result.file_content) with evaluated_file.open_binary() as fp: data_df = pd.read_excel(fp, sheet_name='Data') deflection_data = data_df['Deflection (microns)'].head(params.beam.length+1) fig = px.line(deflection_data, title='Beam deflection', labels={'value': 'Deflection (microns)', 'index':'Length (mm)'}) return vkt.PlotlyResult(fig) def download_spreadsheet(self, params, **kwargs): sheet = fill_spreadsheet(params) result = sheet.evaluate(include_filled_file=True) return vkt.DownloadResult(result.file_content, 'evaluated_beam.xlsx') ``` The full app-repository can be downloaded [here](/files/docs/spreadsheet-calculator-tutorial-complete.zip). ## Want to learn how VIKTOR works?[​](/docs/tutorials/spreadsheet-calculator/.md#want-to-learn-how-viktor-works "Direct link to Want to learn how VIKTOR works?") If you are interested in how VIKTOR works behind the scenes, for example how it processes your input, expand the tabs below! #### How does it work?[​](/docs/tutorials/spreadsheet-calculator/.md#how-does-it-work "Direct link to How does it work?") How does the Parametrization work? In the **Parameterization** class you can add input fields that allow the user to provide input to your app, and there are more than 20 [different input fields](/docs/create-apps/user-input/.md) you can use, including numbers, text, colors, images and files. Inside the Parametrization class, you can also format the [layout of your app](/docs/create-apps/layout-and-styling/.md) by adding sections, tabs, steps and pages. To show your Parametrization in the app, we need to add the line `parametrization = Parametrization` inside the `Controller` class, because it is the controller that determines what is shown and not. How does the Parametrization get saved? So you may be wondering, how do you get the information from the parametrization to my controller? Well, we do this automatically for you. The values of all parameters are stored in a single variable called `params` , which is accessible inside the Controller class. These variables are stored in a `Munch`; this is similar to a dictionary, but work with point denotation. Example: * Let's say we have a variable called `height` as a NumberField in our `Parameterization`. * To use it in a method in the `Controller`, define it as: `def my_method(self, params, **kwargs)` * You can now make calculations inside that method using our height parameter as `params.height`! How does the Controller work? The **Controller** class is the place where you add everything you want to calculate and show. As explained in this tutorial, we show results in a `View` and we always add views in our controller. You can even add several views in a single app by adding them to the controller class... and yes, we have [many Views](/docs/create-apps/results-and-visualizations/.md), for showing graphs, maps, 3D models, reports, images and more. In the Controller, you also do or call your calculation. Remember that the user input given in the parametrization, is accessible inside the Controller class in the variable The `params`. ## What's next[​](/docs/tutorials/spreadsheet-calculator/.md#whats-next "Direct link to What's next") Very impressive! You have now learned the basics of working with external files and programs. In this tutorial, we have only scratched the surface of what you can do these integrations. So don’t stop your journey there! If you like an extra challenge, here are some ideas: * Convert your excel sheet to a pdf and show it in a `PDFView` * Try to adjust the geometry to show the deformation of the beam * Or even try to re-write the logic of your Excel file to a python script to use directly in the app code! If you enjoyed this spreadsheet tutorial and want to explore some of the possibilities with Excel and VIKTOR, check out some of our other [tutorials](/docs/tutorials/.md) More about excel sheets You can find more information about how to use excel sheets in the [documents and spreadsheets guide](/docs/create-apps/documents-and-spreadsheets/spreadsheet-calculator/.md). Also check more about [documents and spreadsheets in general](/docs/create-apps/documents-and-spreadsheets/.md) --- # Tutorial - Using the Visual Builder What is the Visual Builder? The Visual Builder is a feature that can be used to create a user interface directly from your VIKTOR environment. It allows you to quickly put together your desired UI without writing a single line of code. You can find the Visual Builder under VIKTOR Labs in the main menu of your VIKTOR environment. In this short guide you will learn how to transfer a blueprint created with the Visual Builder to your Development Workspace. By doing so you will be able to develop your app further. Please make sure that you have [activated your account](/docs/getting-started/starter-guide/.md#activate-your-account) before starting this guide. * Local development * GitHub Codespaces 1. Create a new folder for your app Add a new folder in your filesystem (e.g. `C:\Users\\viktor-apps\my-app`) and open it in your code editor * VS Code * PyCharm ![](/assets/images/open-project-vscode-6d34038ba4376f298440093c970b9cbc.png) ![](/assets/images/open-project-pycharm-b906850784c94dccc84529214a3d8d83.png) 1) Open your codespace (see [setup instructions](/docs/getting-started/installation/cloud-based-development/.md#setup-instructions)) 2. Create app template files In the terminal, type the command shown below and hit enter ``` viktor-cli create-app --app-type editor ``` 3. Install and start the app We'll do a clean installation of the app's dependencies by running the following command in the terminal. Just be patient, this could take a few minutes. ``` viktor-cli clean-start ``` If all went well, your app is installed and running in your development workspace: ``` INFO : Connecting to cloud.viktor.ai... INFO : Connection is established (use Ctrl+C to close) INFO : INFO : Navigate to the link below to see your app in the browser INFO : https://cloud.viktor.ai/workspaces/XXX/app INFO : INFO : App code loaded, waiting for jobs... ``` **Do not close the terminal** as this will break the connection with your app. 4. Click 'Copy Blueprint' in the Visual Builder, replace the content of the `app.py` file with the generated Blueprint and save your file. 5. Go to your your development workspace to inspect the app you just created with the Visual Builder! Go to the the main menu, select 'Workspaces' and open your **Development** workspace by clicking the button. ![](/assets/images/development-workspace-card-de7a8ae2c5dc37567177db0708179443.png) --- # Use apps VIKTOR web applications are easy to distribute and use by others. There are, however, some restrictions in place in terms of supported platforms and software. ## Supported browsers[​](/docs/use-apps/.md#supported-browsers "Direct link to Supported browsers") VIKTOR app use is supported (and regularly tested) on the following browsers: * Chrome (Windows, Mac, Linux) * Firefox (Windows, Mac, Linux) We support the latest versions of these browsers. If you encounter problems running our web application, check that your browser version is not outdated or that the browser you are using is not discontinued. ## Supported screen sizes[​](/docs/use-apps/.md#supported-screen-sizes "Direct link to Supported screen sizes") The VIKTOR platform is built with desktop users in mind. While larger tablets might be able to display VIKTOR effectively in landscape mode, some features might not work as expected. ## Using VIKTOR apps on tablets[​](/docs/use-apps/.md#using-viktor-apps-on-tablets "Direct link to Using VIKTOR apps on tablets") Using a VIKTOR app on a tablet is not officially supported, but might work depending on your usecase. We advice to test your specific usecase when you are considering use on a tablet. Some considerations: * screen size: if the tablet has a sufficiently large screen, the viktor interface probably scales well enough to work in landscape mode. * browser: chrome on android probably works, but is not actively tested. * input device: on a tablet, a touch screen is used instead of a mouse. This difference is not actively tested, but it seems that most functionality correctly works. Some things you can do to make the most of the limited screen size: * choose a flat app structure (`simple` or `editor`). This eliminates the entity tree and simplifies navigation. * separate your input on pages with only input or only output. Again, this makes the interface simpler. ## Using VIKTOR on mobile phones[​](/docs/use-apps/.md#using-viktor-on-mobile-phones "Direct link to Using VIKTOR on mobile phones") Using VIKTOR apps from a mobile phone is not supported. Although it is technically possible to access the application from the web, the small screen makes the interface practically unusable. --- # Integrate your app in other software Sometimes it can be useful to integrate your VIKTOR app with other software, for example to: * Obtain data from an entity in your VIKTOR app, to be used in your calculation software * Push data from your BIM software (plugin) to one of your VIKTOR apps * Collect environment activity, to be shown in your own custom dashboard * Perform some calculation on the VIKTOR app to be further processed in your dedicated software There are 2 ways to do this: * Using the [SDK API](/docs/api/sdk/.md) * Using the [REST API](/docs/api/rest/.md) For more information on the different APIs and when to use what, please refer to the [API documentation](/docs/api/.md) --- # VIKTOR documentation VIKTOR is a platform for creating powerful and user-friendly web apps, all with pure Python! Create apps to automate your workflow, integrate with different software packages, and get better insights into your project through interactive visualizations. > "Automate the boring, engineer the awesome!" - VIKTOR ## [Get Started](/docs/getting-started/.md) Are you new to VIKTOR? Then this is a good place to start. ## [Create Apps](/docs/create-apps/.md) Learn how to create apps and get an overview of all available features. ## [Apps Gallery](https://www.viktor.ai/apps-gallery) Explore the app gallery, download the code, and use it to create your apps. ### Explore the docs\![​](/docs/welcome/.md#explore-the-docs "Direct link to Explore the docs!") * Get started with VIKTOR by activating your account and creating your first app. [Learn more](/docs/getting-started/.md) * Create apps is your go-to place when you are developing. It includes how-to guides, tutorials and examples, and it gives you an overview of all available features. [Learn more](/docs/create-apps/.md) * Publish apps explains how you can share your developed applications with your colleagues. [Learn more](/docs/publish-apps/.md) * Manage apps is for admins and covers how to publish and manage apps, permissions, user-management, SSO, security, activity dashboard and others platform capabilities. [Learn more](/docs/manage-apps/.md) ### API references[​](/docs/welcome/.md#api-references "Direct link to API references") * SDK reference gives you detailed information of all classes and functions that can be used to build your app. [Learn more](/sdk/api/.md) * CLI reference provides an explanation of all available command-line interface (CLI) commands. [Learn more](/docs/create-apps/references/cli/.md) * Backend API can be used to extract or modify data from your environment, integrate apps into your own software and workflows or automate tasks. [Learn more](/docs/api/.md) ## Community VIKTOR is not only a platform for quickly creating apps; we are also a community of enthusiastic and ambitious developers searching for new ways to engineer the awesome. Join our community and ask for support, share ideas and learn about the latest features. [Community Page](https://community.viktor.ai/) ![](/img/illustrations/illustration-community.svg) --- # What's new - July Welcome to the What's new page, here you will find all the latest updates. Stay tuned for more updates every month! Share your ideas! Got ideas for enhancing VIKTOR? Share on our [Community page](https://community.viktor.ai/c/feature-requests/7?utm_source=docs). Your input drives our feature development, so don't hesitate to contribute! ### App Builder Updates \[BETA][​](/docs/whats-new/.md#app-builder-updates-beta "Direct link to App Builder Updates \[BETA]") * The App Builder supports revision history!
When using the App Builder to make your own tools, prompting an addition or feature does not guarantee a perfect result. That's why we added the option to preview and restore previous results! [Learn more](https://docs.viktor.ai/docs/app-builder?utm_source=docs) * File as context for the App Builder!
Being able to upload a file is much more efficient than having to describe its contents to the App Builder. Want a calculation instead of a document? Just upload it and let the App Builder write the logic! [Learn more](https://docs.viktor.ai/docs/app-builder?utm_source=docs) ### Create Apps[​](/docs/whats-new/.md#create-apps "Direct link to Create Apps") * More control over Sections!
Sections in the editor are a great way to organize your app’s interface. And now, you have even more control over how they appear! [Learn more](https://docs.viktor.ai/docs/create-apps/layout-and-styling/tabs-and-sections/) * Integrate with a Personal Worker!
Setting up integrations just got a whole lot easier! You no longer need an admin to set up a worker on a server. Any user can now install a personal worker to connect with software. Let us know if you have any feedback on this feature through the Community! ### Missed something?[​](/docs/whats-new/.md#missed-something "Direct link to Missed something?") If you missed an update you can check out the blog posts of previous months or the changelogs to try and find it. ![](/img/docs/cards/previous-updates-icon.png) ## [All updates](/docs/whats-new/all-updates/.md) Catch up on all the updates on the VIKTOR platform ![](/img/docs/cards/changelog-sdk-icon.png) ## [Changelog SDK](/docs/whats-new/changelog-sdk/.md) Are you a developer? Checkout the latest and greatest features that have been added to the SDK. ![](/img/docs/cards/changelog-cli-icon.png) ## [Changelog CLI](/docs/whats-new/changelog-cli/.md) Are you a developer or admin? Checkout the latest additions to the CLI --- # All updates Latest features Looking for the latest updates? Click [here](/docs/whats-new/.md) Welcome to the page where you will find all the previous updates about the VIKTOR platform. If you missed an update you can check out the blog posts of previous months to try and find it. ## Updates from 2025[​](/docs/whats-new/all-updates/.md#updates-from-2025 "Direct link to Updates from 2025") * What's New in July 2025
Discover the latest and greatest of July in this blog post! [Learn more](https://www.viktor.ai/blog/203/what-s-new-in-viktor-july-2025) * What's New in June 2025
Discover the latest and greatest of June in this blog post! [Learn more](https://www.viktor.ai/blog/201/whats-new-in-viktor-june-2025) * What's New in May 2025
Discover the latest and greatest of May in this blog post! [Learn more](https://www.viktor.ai/blog/198/whats-new-in-viktor-may-2025) * What's New in April 2025
Discover the latest and greatest of April in this blog post! [Learn more](https://www.viktor.ai/blog/193/whats-new-in-viktor-april-2025) * What's New in March 2025
Discover the latest and greatest of March in this blog post! [Learn more](https://www.viktor.ai/blog/190/what-s-new-in-viktor-march-2025) * What's New in February 2025
Discover the latest and greatest of February in this blog post! [Learn more](https://www.viktor.ai/blog/187/what-s-new-in-viktor-february-2025) * What's New in January 2025
Discover the latest and greatest of January in this blog post! [Learn more](https://www.viktor.ai/blog/184/whats-new-in-viktor-january-2025) ## Updates from 2024[​](/docs/whats-new/all-updates/.md#updates-from-2024 "Direct link to Updates from 2024") * What's New in December 2024
Discover the latest and greatest of December in this blog post! [Learn more](https://www.viktor.ai/blog/181/what-s-new-in-viktor-december-2024) * What's New in November 2024
Discover the latest and greatest of November in this blog post! [Learn more](https://www.viktor.ai/blog/176/whats-new-in-viktor-november-2024?utm_source=docs) * What's New in October 2024
Discover the latest and greatest of October in this blog post! [Learn more](https://www.viktor.ai/blog/173/what-s-new-in-viktor-october-2024?utm_source=docs) * What's New in September 2024
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/169/whats-new-in-viktor-september-2024?utm_source=docs) * What's New in August 2024
Discover the latest and greatest of August in this blog post! [Learn more](https://www.viktor.ai/blog/167/what-s-new-in-viktor-august-2024?utm_source=docs) * What's New in July 2024
Discover the latest and greatest of June in this blog post! [Learn more](https://www.viktor.ai/blog/163/whats-new-in-viktor-july-2024?utm_source=docs) * What's New in June 2024
Discover the latest and greatest of June in this blog post! [Learn more](https://www.viktor.ai/blog/159/whats-new-in-viktor-june-2024?utm_source=docs) * What's New in May 2024
Discover the latest and greatest of May in this blog post! [Learn more](https://www.viktor.ai/blog/158/what-s-new-in-viktor-may-2024?utm_source=docs) * What's New in April 2024
Discover the latest and greatest of April in this blog post! [Learn more](https://www.viktor.ai/blog/156/what-s-new-in-viktor-april-2024?utm_source=docs) * What's New in March 2024
Discover the latest and greatest of March in this blog post! [Learn more](https://www.viktor.ai/blog/147/whats-new-in-viktor-march-2024?utm_source=docs) * What's New in February 2024
Discover the latest and greatest of February in this blog post! [Learn more](https://www.viktor.ai/blog/145/whats-new-in-viktor-february-2024?utm_source=docs) * What's New in January 2024
Discover the latest and greatest of January in this blog post! [Learn more](https://www.viktor.ai/blog/141/what-s-new-in-viktor-january-2024?utm_source=docs) ## Updates from 2023[​](/docs/whats-new/all-updates/.md#updates-from-2023 "Direct link to Updates from 2023") * What's New in December 2023
Discover the latest and greatest of December in this blog post! [Learn more](https://www.viktor.ai/blog/138/whats-new-in-viktor-december-2023?utm_source=docs) * What's New in November 2023
Discover the latest and greatest of November in this blog post! [Learn more](https://www.viktor.ai/blog/135/whats-new-in-viktor-november-2023?utm_source=docs) * What's New in October 2023
Discover the latest and greatest of October in this blog post! [Learn more](https://www.viktor.ai/blog/131/whats-new-in-viktor-october-2023?utm_source=docs) * What's New in September 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/128/whats-new-in-viktor-september-2023?utm_source=docs) * What's New in August 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/123/whats-new-in-viktor-august-2023?utm_source=docs) * What's New in July 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/118/whats-new-in-viktor-july-2023?utm_source=docs) * What's New in June 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/117/whats-new-in-viktor-june-2023?utm_source=docs) * What's New in May 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/111/whats-new-in-viktor-may-2023?utm_source=docs) * What's New in April 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/104/whats-new-in-viktor-april-2023?utm_source=docs) * What's New in March 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/101/whats-new-in-viktor-march-2023?utm_source=docs) * What's New in February 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/99/whats-new-in-viktor-february-2023?utm_source=docs) * What's New in January 2023
Discover the latest and greatest of September in this blog post! [Learn more](https://www.viktor.ai/blog/93/whats-new-in-viktor-january-2023?utm_source=docs) --- # Changelog All notable changes to the VIKTOR CLI will be documented in this file. *** ## v0.44.3 - 20/03/2025[​](/docs/whats-new/changelog-cli/.md#v0443---20032025 "Direct link to v0.44.3 - 20/03/2025") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed "Direct link to Fixed") * Prevent double reload on Windows by discarding file watch events for `__pycache__` directories *** ## v0.44.2 - 19/02/2025[​](/docs/whats-new/changelog-cli/.md#v0442---19022025 "Direct link to v0.44.2 - 19/02/2025") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed "Direct link to Changed") * Exit with proper code when error occurs during `ci-publish` *** ## v0.44.1 - 09/01/2025[​](/docs/whats-new/changelog-cli/.md#v0441---09012025 "Direct link to v0.44.1 - 09/01/2025") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-1 "Direct link to Changed") * Repeat tag and registered name before confirming publish ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-1 "Direct link to Fixed") * Do not trigger immediate reload when starting an app *** ## v0.44.0 - 19/12/2024[​](/docs/whats-new/changelog-cli/.md#v0440---19122024 "Direct link to v0.44.0 - 19/12/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added "Direct link to Added") * Attach digital signature to executable and installer *** ## v0.43.4 - 13/12/2024[​](/docs/whats-new/changelog-cli/.md#v0434---13122024 "Direct link to v0.43.4 - 13/12/2024") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-2 "Direct link to Fixed") * Set `UV_LINK_MODE=copy` to prevent installation errors when copying files inside virtual environment *** ## v0.43.3 - 10/12/2024[​](/docs/whats-new/changelog-cli/.md#v0433---10122024 "Direct link to v0.43.3 - 10/12/2024") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-3 "Direct link to Fixed") * Empty suggested app name when validation of registered name fails *** ## v0.43.2 - 09/12/2024[​](/docs/whats-new/changelog-cli/.md#v0432---09122024 "Direct link to v0.43.2 - 09/12/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-1 "Direct link to Added") * Add more information and options to 'invalid registered-name' prompt ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-4 "Direct link to Fixed") * Fix bug where registered-name would sometimes be treated as case-sensitive *** ## v0.43.1 - 02/12/2024[​](/docs/whats-new/changelog-cli/.md#v0431---02122024 "Direct link to v0.43.1 - 02/12/2024") *** ## v0.43.0 - 02/12/2024[​](/docs/whats-new/changelog-cli/.md#v0430---02122024 "Direct link to v0.43.0 - 02/12/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-2 "Direct link to Added") * Prompt to migrate development workspace when user maintains multiple apps * Add validation on provided registered-name, prompt to select if invalid ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-5 "Direct link to Fixed") * Fix error during publish when `assets_path` points to an empty directory *** ## v0.42.0 - 18/11/2024[​](/docs/whats-new/changelog-cli/.md#v0420---18112024 "Direct link to v0.42.0 - 18/11/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-3 "Direct link to Added") * Added `--use-pip` flag on the `install` command to switch to 'pip' as package manager (default is 'uv') ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-2 "Direct link to Changed") * The `install` command now uses 'uv' as package manager by default to improve performance ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-6 "Direct link to Fixed") * Fix setting incorrect UID / GID when running docker isolation on Windows *** ## v0.41.5 - 11/11/2024[​](/docs/whats-new/changelog-cli/.md#v0415---11112024 "Direct link to v0.41.5 - 11/11/2024") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-7 "Direct link to Fixed") * Fix quickstart command from unnecessarily prompting for `registered-name` *** ## v0.41.4 - 06/11/2024[​](/docs/whats-new/changelog-cli/.md#v0414---06112024 "Direct link to v0.41.4 - 06/11/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-4 "Direct link to Added") * Added `--registered-name` flag on the `clear` command ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-3 "Direct link to Changed") * Don't Prompt IDE when no IDEs are found on the machine of the user *** ## v0.41.3 - 04/11/2024[​](/docs/whats-new/changelog-cli/.md#v0413---04112024 "Direct link to v0.41.3 - 04/11/2024") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-8 "Direct link to Fixed") * Update false positive in `check-system` to properly handle new error format ## v0.41.2 - 29/10/2024[​](/docs/whats-new/changelog-cli/.md#v0412---29102024 "Direct link to v0.41.2 - 29/10/2024") *** ## v0.41.1 - 24/10/2024[​](/docs/whats-new/changelog-cli/.md#v0411---24102024 "Direct link to v0.41.1 - 24/10/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-4 "Direct link to Changed") * When running the `start`, `quickstart`, or `clean-start` commands the cli automatically updates to the latest version *** ## v0.41.0 - 24/10/2024[​](/docs/whats-new/changelog-cli/.md#v0410---24102024 "Direct link to v0.41.0 - 24/10/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-5 "Direct link to Added") * Support environment variable `VIKTOR_JS_SDK_PATH` used for WebView interaction * When running the `start` command the user is prompted to upgrade if a new cli version is available * Warn when starting an app that has no `registered_name` defined * Added `--registered-name` flag on the `start` command ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-5 "Direct link to Changed") * Removed environment variable `VIKTOR_SUBDOMAIN` which was incorrect and therefore has no use ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-9 "Direct link to Fixed") * Set ownership to HOME directory (docker isolation mode) to fix warnings regarding writing to cache (e.g. matplotlib, fontconfig etc.) *** ## v0.40.0 - 09/10/2024[​](/docs/whats-new/changelog-cli/.md#v0400---09102024 "Direct link to v0.40.0 - 09/10/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-6 "Direct link to Added") * Added marker for active account for account selection prompt * Support for Python 3.13 ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-6 "Direct link to Changed") * Automatically detect changes to `assets_path` when developing *** ## v0.39.0 - 05/09/2024[​](/docs/whats-new/changelog-cli/.md#v0390---05092024 "Direct link to v0.39.0 - 05/09/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-7 "Direct link to Added") * Added `hello-viktor` app to `quickstart` command * Added `activate` command * Added resources to the output table of the `apps` command ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-7 "Direct link to Changed") * Updated the embedded app templates to use a single viktor import * Updated style of the output table of the `apps` command *** ## v0.38.0 - 12/08/2024[​](/docs/whats-new/changelog-cli/.md#v0380---12082024 "Direct link to v0.38.0 - 12/08/2024") * Support blank apps in `quickstart` command *** ## v0.37.0 - 29/07/2024[​](/docs/whats-new/changelog-cli/.md#v0370---29072024 "Direct link to v0.37.0 - 29/07/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-8 "Direct link to Added") * Support Excel converter in `quickstart` command *** ## v0.36.2 - 24/07/2024[​](/docs/whats-new/changelog-cli/.md#v0362---24072024 "Direct link to v0.36.2 - 24/07/2024") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-10 "Direct link to Fixed") * Disable CGO *** ## v0.36.1 - 24/07/2024[​](/docs/whats-new/changelog-cli/.md#v0361---24072024 "Direct link to v0.36.1 - 24/07/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-8 "Direct link to Changed") * Updated golang to v1.22 and the dependencies to the latest versions ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-11 "Direct link to Fixed") * Remove venv when Python version check cannot be completed *** ## v0.36.0 - 25/06/2024[​](/docs/whats-new/changelog-cli/.md#v0360---25062024 "Direct link to v0.36.0 - 25/06/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-9 "Direct link to Added") * Added `quickstart` command to start developing from a sample app ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-12 "Direct link to Fixed") * Ignore nested `__pycache__` directories when gathering app files for publishing *** ## v0.35.0 - 29/04/2024[​](/docs/whats-new/changelog-cli/.md#v0350---29042024 "Direct link to v0.35.0 - 29/04/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-9 "Direct link to Changed") * Make `--tag` flag optional in `publish` command * Read `registered_name` from viktor.config.toml and make `--registered-name` flag optional in `publish` command ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-13 "Direct link to Fixed") * Fix URL to documentation in demo app *** ## v0.34.1 - 09/04/2024[​](/docs/whats-new/changelog-cli/.md#v0341---09042024 "Direct link to v0.34.1 - 09/04/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-10 "Direct link to Changed") * Removed installation of demo app from `get-started` command * When using `create-app` in GitHub Codespaces, the codespace Python version is set in viktor.config.toml * When using `publish` in GitHub Codespaces, the `--use-filesystem` flag will always be true * Ignore `__pycache__` directories when gathering app files for publishing *** ## v0.34.0 - 03/04/2024[​](/docs/whats-new/changelog-cli/.md#v0340---03042024 "Direct link to v0.34.0 - 03/04/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-10 "Direct link to Added") * Added `clean-start` command which combines `clear` + `install` + `start` * Support tag on `ci-publish` command ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-11 "Direct link to Changed") * Maximum length of publish tag increased from 20 to 128 characters *** ## v0.33.5 - 11/03/2024[​](/docs/whats-new/changelog-cli/.md#v0335---11032024 "Direct link to v0.33.5 - 11/03/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-11 "Direct link to Added") * Support environment variable `VIKTOR_CREDENTIALS` used for cloud-based development (e.g. GitHub Codespaces) ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-12 "Direct link to Changed") * Command `upgrade` logs new version when successfully upgraded * Set `x_axis_to_right=True` on `GeometryView` in demo * Command `check-system` now also verifies credentials * Removed neverssl check in `check-system` command *** ## v0.33.4 - 16/02/2024[​](/docs/whats-new/changelog-cli/.md#v0334---16022024 "Direct link to v0.33.4 - 16/02/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-13 "Direct link to Changed") * Improved internal error logging when freezing of virtual environment fails *** ## v0.33.3 - 12/02/2024[​](/docs/whats-new/changelog-cli/.md#v0333---12022024 "Direct link to v0.33.3 - 12/02/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-14 "Direct link to Changed") * Command `install` now uninstalls previous installation instead of removing the entire venv directory to resolve vscode intellisense (Pylance) issues * Omit the `` argument in the `create-app` command to create a new app in the current directory *** ## v0.33.2 - 02/02/2024[​](/docs/whats-new/changelog-cli/.md#v0332---02022024 "Direct link to v0.33.2 - 02/02/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-15 "Direct link to Changed") * Per user installation of CLI to no longer require administrator privileges *** ## v0.33.1 - 11/01/2024[​](/docs/whats-new/changelog-cli/.md#v0331---11012024 "Direct link to v0.33.1 - 11/01/2024") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-16 "Direct link to Changed") * Set default Python version of demo app to 3.12 ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-14 "Direct link to Fixed") * Unpin numpy in demo app to fix compatibility with Python 3.12 *** ## v0.33.0 - 08/01/2024[​](/docs/whats-new/changelog-cli/.md#v0330---08012024 "Direct link to v0.33.0 - 08/01/2024") ### Added[​](/docs/whats-new/changelog-cli/.md#added-12 "Direct link to Added") * Support for Python 3.12 * Show message to user if token has been deactivated ### Deprecated[​](/docs/whats-new/changelog-cli/.md#deprecated "Direct link to Deprecated") * Deprecated Python 3.8 *** ## v0.32.0 - 24/11/2023[​](/docs/whats-new/changelog-cli/.md#v0320---24112023 "Direct link to v0.32.0 - 24/11/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-13 "Direct link to Added") * Support 'packages' in viktor.config.toml *** ## v0.31.2 - 01/11/2023[​](/docs/whats-new/changelog-cli/.md#v0312---01112023 "Direct link to v0.31.2 - 01/11/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-17 "Direct link to Changed") * Add a flag to use pip truststore, this allows users to disable installation with truststore *** ## v0.31.1 - 31/10/2023[​](/docs/whats-new/changelog-cli/.md#v0311---31102023 "Direct link to v0.31.1 - 31/10/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-18 "Direct link to Changed") * Removed neverssl check from newAPI function *** ## v0.31.0 - 24/10/2023[​](/docs/whats-new/changelog-cli/.md#v0310---24102023 "Direct link to v0.31.0 - 24/10/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-19 "Direct link to Changed") * When available use `truststore` feature of pip to prevent SSL installation errors *** ## v0.30.7 - 23/10/2023[​](/docs/whats-new/changelog-cli/.md#v0307---23102023 "Direct link to v0.30.7 - 23/10/2023") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-15 "Direct link to Fixed") * Warning for Python version was always triggered instead of only for invalid Python versions *** ## v0.30.6 - 17/10/2023[​](/docs/whats-new/changelog-cli/.md#v0306---17102023 "Direct link to v0.30.6 - 17/10/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-20 "Direct link to Changed") * Log warning when found Python version with Python Launcher is not supported for use with VIKTOR *** ## v0.30.5 - 11/10/2023[​](/docs/whats-new/changelog-cli/.md#v0305---11102023 "Direct link to v0.30.5 - 11/10/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-21 "Direct link to Changed") * Added 'command' sentry tag on all commands * Print files to be uploaded during publish and prompt user to continue *** ## v0.30.4 - 19/09/2023[​](/docs/whats-new/changelog-cli/.md#v0304---19092023 "Direct link to v0.30.4 - 19/09/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-22 "Direct link to Changed") * Updated golang to v1.21 and the dependencies to the latest versions *** ## v0.30.3 - 28/08/2023[​](/docs/whats-new/changelog-cli/.md#v0303---28082023 "Direct link to v0.30.3 - 28/08/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-23 "Direct link to Changed") * Capture actual error message when activation code cannot be obtained *** ## v0.30.2 - 07/08/2023[​](/docs/whats-new/changelog-cli/.md#v0302---07082023 "Direct link to v0.30.2 - 07/08/2023") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-16 "Direct link to Fixed") * get-started now installs demo app in temporary dir to fix potential permission errors * `check-system` removed fall-back on ping command when curl is not available since it is unable to receive *** ## v0.30.1 - 18/07/2023[​](/docs/whats-new/changelog-cli/.md#v0301---18072023 "Direct link to v0.30.1 - 18/07/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-14 "Direct link to Added") * Added a prompt to overwrite configuration file entry if it is already present while rerunning the `get-started` command *** ## v0.30.0 - 11/07/2023[​](/docs/whats-new/changelog-cli/.md#v0300---11072023 "Direct link to v0.30.0 - 11/07/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-15 "Direct link to Added") * Read 'assets\_path' from viktor.config.toml and upload assets to S3 ### Removed[​](/docs/whats-new/changelog-cli/.md#removed "Direct link to Removed") * Removed `--region` flag from `publish`, `ci-publish`, `apps`, `describe` commands since apps are now automatically synced *** ## v0.29.11 - 16/06/2023[​](/docs/whats-new/changelog-cli/.md#v02911---16062023 "Direct link to v0.29.11 - 16/06/2023") * Only autoselect Python installation when running get-started, print the selected path and give hint how to change *** ## v0.29.10 - 09/06/2023[​](/docs/whats-new/changelog-cli/.md#v02910---09062023 "Direct link to v0.29.10 - 09/06/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-16 "Direct link to Added") * Add max-memory flag to install and test command to prevent container crashing on large packages ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-24 "Direct link to Changed") * `check-system` command shouldn't fail because curl or ping is not installed, instead a nil error is returned and message is logged in Sentry *** ## v0.29.9 - 24/05/2023[​](/docs/whats-new/changelog-cli/.md#v0299---24052023 "Direct link to v0.29.9 - 24/05/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-25 "Direct link to Changed") * Updated the text of the last step in demo app including utm source tag for tracking the clickthrough rate into the tutorial *** ## v0.29.8 - 16/05/2023[​](/docs/whats-new/changelog-cli/.md#v0298---16052023 "Direct link to v0.29.8 - 16/05/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-17 "Direct link to Added") * Added Stdout output to error tracking in Sentry when installation of the demo app fails ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-17 "Direct link to Fixed") * Properly skip virtual environment and .git directories during publish *** ## v0.29.7 - 26/04/2023[​](/docs/whats-new/changelog-cli/.md#v0297---26042023 "Direct link to v0.29.7 - 26/04/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-26 "Direct link to Changed") * Removed sentry error tracking when directory cannot be created or app files cannot be copied in `create-app` command *** ## v0.29.6 - 13/04/2023[​](/docs/whats-new/changelog-cli/.md#v0296---13042023 "Direct link to v0.29.6 - 13/04/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-27 "Direct link to Changed") * Select the currently active account by default instead of the default account when running configure without --name flag ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-18 "Direct link to Fixed") * Exclude false positive curl error from system check *** ## v0.29.5 - 12/04/2023[​](/docs/whats-new/changelog-cli/.md#v0295---12042023 "Direct link to v0.29.5 - 12/04/2023") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-19 "Direct link to Fixed") * Demo app crashes due to removed UserException in SDK v14 *** ## v0.29.4 - 12/04/2023[​](/docs/whats-new/changelog-cli/.md#v0294---12042023 "Direct link to v0.29.4 - 12/04/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-28 "Direct link to Changed") * Get latest SDK from PyPI instead of system ### Removed[​](/docs/whats-new/changelog-cli/.md#removed-1 "Direct link to Removed") * Removed U83 flag from app templates *** ## v0.29.3 - 17/03/2023[​](/docs/whats-new/changelog-cli/.md#v0293---17032023 "Direct link to v0.29.3 - 17/03/2023") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-20 "Direct link to Fixed") * Fixed numpy in demo app not compatible with Python 3.7 *** ## v0.29.2 - 17/03/2023[​](/docs/whats-new/changelog-cli/.md#v0292---17032023 "Direct link to v0.29.2 - 17/03/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-29 "Direct link to Changed") * Raise error when defining viktor in requirements.txt with a leading hashtag in combination with SDK > v13 ### Deprecated[​](/docs/whats-new/changelog-cli/.md#deprecated-1 "Direct link to Deprecated") * Python 3.7 *** ## v0.29.1 - 02/03/2023[​](/docs/whats-new/changelog-cli/.md#v0291---02032023 "Direct link to v0.29.1 - 02/03/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-30 "Direct link to Changed") * Cleaned up sentry error tracking and included curl exit status in sentry error tracking *** ## v0.29.0 - 24/02/2023[​](/docs/whats-new/changelog-cli/.md#v0290---24022023 "Direct link to v0.29.0 - 24/02/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-18 "Direct link to Added") * Added support for viktor in requirements.txt without a leading hashtag * Support Python 3.11 in viktor.config.toml ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-31 "Direct link to Changed") * Upgrade to go 1.20 * Added available options for app-type in `create-app` command help ### Deprecated[​](/docs/whats-new/changelog-cli/.md#deprecated-2 "Direct link to Deprecated") * Defining viktor in requirements.txt with a leading hashtag ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-21 "Direct link to Fixed") * Fix bug that autoreload didn't work if app folder name starts with "test" * Reverted pip install arguments back to a slice of strings as a single string doesn't work on Windows *** ## v0.28.0 - 08/02/2023[​](/docs/whats-new/changelog-cli/.md#v0280---08022023 "Direct link to v0.28.0 - 08/02/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-32 "Direct link to Changed") * Updated install command to be able to insert additional environment variables * Added "SDK version" to output of `apps` command * Added "App type", "SDK version", and "Python version" to output of `describe` command *** ## v0.27.6 - 03/02/2023[​](/docs/whats-new/changelog-cli/.md#v0276---03022023 "Direct link to v0.27.6 - 03/02/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-33 "Direct link to Changed") * Added provided path to error message when python installation is not valid * Added `--region` flag for multi-region architecture *** ## v0.27.5 - 02/02/2023[​](/docs/whats-new/changelog-cli/.md#v0275---02022023 "Direct link to v0.27.5 - 02/02/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-34 "Direct link to Changed") * Added clearer error messages why a Python version is not valid and when the activation code is expired *** ## v0.27.4 - 27/01/2023[​](/docs/whats-new/changelog-cli/.md#v0274---27012023 "Direct link to v0.27.4 - 27/01/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-35 "Direct link to Changed") * Track exact error that python path prompt returns, added cli version to sentry message *** ## v0.27.3 - 25/01/2023[​](/docs/whats-new/changelog-cli/.md#v0273---25012023 "Direct link to v0.27.3 - 25/01/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-36 "Direct link to Changed") * Add message to get-started command that window shouldn't be closed *** ## v0.27.2 - 23/01/2023[​](/docs/whats-new/changelog-cli/.md#v0272---23012023 "Direct link to v0.27.2 - 23/01/2023") ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-22 "Direct link to Fixed") * Fixed bug in regex that didn't handle spaces in Python paths correctly *** ## v0.27.1 - 20/01/2023[​](/docs/whats-new/changelog-cli/.md#v0271---20012023 "Direct link to v0.27.1 - 20/01/2023") ### Added[​](/docs/whats-new/changelog-cli/.md#added-19 "Direct link to Added") * Implemented Sentry to track errors in the get-started flow *** ## v0.27.0 - 17/01/2023[​](/docs/whats-new/changelog-cli/.md#v0270---17012023 "Direct link to v0.27.0 - 17/01/2023") ### Changed[​](/docs/whats-new/changelog-cli/.md#changed-37 "Direct link to Changed") * change configuration name generation to support multiregion * Place activation code for get-started on newline * Update warning for python version on how development version can be changed * Watch entire project folder, instead of just app.py or /app/ folder ### Fixed[​](/docs/whats-new/changelog-cli/.md#fixed-23 "Direct link to Fixed") * Support Python launcher 3.11 regex format when gathering available python installations *** --- # Changelog All notable changes to the viktor SDK will be documented in this file, categorized by version number. The changes can be categorized further in the following headers: * **Action Required**: when a backwards incompatible change is made, which requires actions in the application code. This header will only be present in major releases, on Beta features, or when a Python version is dropped. * **Added**: when a functionality is added, without breaking compatibility with older versions. * **Deprecated**: when an existing functionality will be removed in upcoming releases. You will find a reference to the upgrade instructions in this change. * **Docs**: when the change involves SDK documentation, docstring, and/or type hinting. * **Fixed**: when the change fixes a bug/error. * **Security**: when a vulnerability is fixed. Each change consists of a tag to annotate which VIKTOR module is involved. If the change encompasses multiple modules, the `viktor` tag is used. ## v14[​](/docs/whats-new/changelog-sdk/.md#v14 "Direct link to v14") *** ### v14.24.0 - 29/07/2025[​](/docs/whats-new/changelog-sdk/.md#v14240---29072025 "Direct link to v14.24.0 - 29/07/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added "Direct link to Added") * `core` Added allow\_saving to Controller. *** ### v14.23.0 - 22/07/2025[​](/docs/whats-new/changelog-sdk/.md#v14230---22072025 "Direct link to v14.23.0 - 22/07/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-1 "Direct link to Added") * `external` `OAuth2Integration` to support third-party OAuth 2.0 integrations *** ### v14.22.0 - 22/05/2025[​](/docs/whats-new/changelog-sdk/.md#v14220---22052025 "Direct link to v14.22.0 - 22/05/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-2 "Direct link to Added") * `geometry` Support counter-clockwise profile for `Polygon` extrusion * `views` Added `MapCircle` object * `views` Make private properties of `DataItem` public and make 'value' argument optional * `views` Directly use a plotly Figure object in `PlotlyResult` / `PlotlyAndDataResult` * `views` Append items to an existing data group using `DataGroup.add()` * `views` Added properties `GeoPoint.latitude` and `GeoPoint.longitude` * `geometry` Support hex value and RGB tuple as 'color' input on a `Material` * `views` `visible` argument on views to enable view visibility based on params *** ### v14.21.0 - 29/04/2025[​](/docs/whats-new/changelog-sdk/.md#v14210---29042025 "Direct link to v14.21.0 - 29/04/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-3 "Direct link to Added") * `parametrization` `initially_expanded` argument on `Section` to expand or collapse individual sections on editor entry * `parametrization` **\[BETA]** `Chat` field *** ### v14.20.1 - 24/03/2025[​](/docs/whats-new/changelog-sdk/.md#v14201---24032025 "Direct link to v14.20.1 - 24/03/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-4 "Direct link to Added") * `viktor` Support numpy v2 *** ### v14.20.0 - 05/03/2025[​](/docs/whats-new/changelog-sdk/.md#v14200---05032025 "Direct link to v14.20.0 - 05/03/2025") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-5 "Direct link to Added") * `result` DownloadResult allows file names consisting of non-ASCII characters and whitespaces * `parametrization` Support OutputField in DynamicArray #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs "Direct link to Docs") * `api_v1` Updated docstring reference `uses_privileged_api` to `enable_privileged_api` #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed "Direct link to Fixed") * `external` RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements * `parametrization` Error in FunctionLookup during generation of OutputField causes broken editor *** ### v14.19.0 - 08/01/2025[​](/docs/whats-new/changelog-sdk/.md#v14190---08012025 "Direct link to v14.19.0 - 08/01/2025") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/docs/whats-new/changelog-sdk/.md#added-6 "Direct link to Added") * `core` Appoint top-level entity as starting page with `InitialEntity` `use_as_start_page` argument *** ### v14.18.0 - 03/01/2025[​](/docs/whats-new/changelog-sdk/.md#v14180---03012025 "Direct link to v14.18.0 - 03/01/2025") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues-1 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/docs/whats-new/changelog-sdk/.md#added-7 "Direct link to Added") * `parametrization` Support 'name' on DynamicArray * `parametrization` Removed **\[BETA]** status from GeometrySelectField and GeometryMultiSelectField * `utils` Increased expiration of memoization results from 1 hour to 24 hours * `utils` Increased amount of locally stored memoization results from 10 to 50 items #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-1 "Direct link to Fixed") * `core` Remove newly created file key from storage in case subsequent Storage.set fails * `parametrization` Warning regarding numeric option value within a table is not triggered for AutocompleteField and MultiSelectField * `parametrization` Fixed typehint of default argument in GeometryMultiSelectField *** ### v14.17.0 - 03/12/2024[​](/docs/whats-new/changelog-sdk/.md#v14170---03122024 "Direct link to v14.17.0 - 03/12/2024") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues-2 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/docs/whats-new/changelog-sdk/.md#added-8 "Direct link to Added") * `external` DynamoAnalysis * `external` ETABSAnalysis * `external` MatlabAnalysis * `external` PlaxisAnalysis * `external` PythonAnalysis * `external` RevitAnalysis * `external` SAP2000Analysis * `external` TeklaAnalysis *** ### v14.16.2 - 30/10/2024[​](/docs/whats-new/changelog-sdk/.md#v14162---30102024 "Direct link to v14.16.2 - 30/10/2024") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues-3 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/docs/whats-new/changelog-sdk/.md#added-9 "Direct link to Added") * `external` Serialized SCIA model is compressed to allow for large input models *** ### v14.16.1 - 15/10/2024[​](/docs/whats-new/changelog-sdk/.md#v14161---15102024 "Direct link to v14.16.1 - 15/10/2024") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues-4 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-2 "Direct link to Fixed") * `api_v1` Fixed several Entity methods that did not work when using a Personal Access Token *** ### v14.16.0 - 08/10/2024[​](/docs/whats-new/changelog-sdk/.md#v14160---08102024 "Direct link to v14.16.0 - 08/10/2024") #### Known Issues[​](/docs/whats-new/changelog-sdk/.md#known-issues-5 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Action Required[​](/docs/whats-new/changelog-sdk/.md#action-required "Direct link to Action Required") * `viktor` Removed support for Python 3.8 #### Added[​](/docs/whats-new/changelog-sdk/.md#added-10 "Direct link to Added") * `viktor` Support for Python 3.13 #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated "Direct link to Deprecated") * `viktor` Support for Python 3.9 will be removed (#U91) #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-1 "Direct link to Docs") * `viktor` Fixed that public classes/functions not in **all** were excluded from the docs *** ### v14.15.2 - 04/09/2024[​](/docs/whats-new/changelog-sdk/.md#v14152---04092024 "Direct link to v14.15.2 - 04/09/2024") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-3 "Direct link to Fixed") * `views` Fixed TableView from pandas Styler object crashing on unsupported format * `viktor` Requests now use the user's system certificates to solve SSL cert verification errors *** ### v14.15.1 - 26/08/2024[​](/docs/whats-new/changelog-sdk/.md#v14151---26082024 "Direct link to v14.15.1 - 26/08/2024") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-4 "Direct link to Fixed") * `viktor` Lazy import of the `external` modules which fixes a potential ImportError and improves import speed * `views` Lazy import of pandas to improve import speed of the `views` module *** ### v14.15.0 - 22/08/2024[​](/docs/whats-new/changelog-sdk/.md#v14150---22082024 "Direct link to v14.15.0 - 22/08/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-11 "Direct link to Added") * `viktor` Support for single import (e.g. `import viktor as vkt; vkt.NumberField(...)`) * `core` Make 'label' on ViktorController optional * `views` Make 'duration\_guess' on all Views optional #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-5 "Direct link to Fixed") * `views` Fix bug with using `TableView` with `pandas` showing data incorrectly in certain cases * `views` Fix small typo in `SummaryItem` suffix docstring * `external` Fix error mapping for spreadsheet calculation (SpreadsheetCalculation) so more error information is shown * `external` Fix error mapping for spreadsheet renderer (SpreadsheetTemplate / render\_spreadsheet) so more error information is shown * `core` External services (e.g. `convert_word_to_pdf`, `render_jinja_template`, etc.) now show more error information *** ### v14.14.0 - 07/08/2024[​](/docs/whats-new/changelog-sdk/.md#v14140---07082024 "Direct link to v14.14.0 - 07/08/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-12 "Direct link to Added") * `utils` `render_jinja_template` now validates identifiers before filling template * `external` `render_word_file` and `WordFileTemplate.render()` now validate identifiers before filling template * `external` Added `file` property to `SpreadsheetCalculation` and `SpreadsheetResult` #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-6 "Direct link to Fixed") * `parametrization` Removed distracting warning when Controller contains an empty parametrization * `core` Delete temp file from disk after closing a `File.from_url` *** ### v14.13.0 - 10/07/2024[​](/docs/whats-new/changelog-sdk/.md#v14130---10072024 "Direct link to v14.13.0 - 10/07/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-13 "Direct link to Added") * `views` Added `TableView` for easy creation of output tables *** ### v14.12.0 - 01/07/2024[​](/docs/whats-new/changelog-sdk/.md#v14120---01072024 "Direct link to v14.12.0 - 01/07/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-14 "Direct link to Added") * `api_v1` Added `entity_compute` method for doing computations via the API #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-7 "Direct link to Fixed") * `external` Updated polling interval of external integrations to make short duration external computations more responsive *** ### v14.11.0 - 18/06/2024[​](/docs/whats-new/changelog-sdk/.md#v14110---18062024 "Direct link to v14.11.0 - 18/06/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-15 "Direct link to Added") * `api_v1` Added retries in relevant API calls * `parametrization` Added support for disabling a `Step` *** ### v14.10.1 - 17/06/2024[​](/docs/whats-new/changelog-sdk/.md#v14101---17062024 "Direct link to v14.10.1 - 17/06/2024") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-8 "Direct link to Fixed") * `viktor` Mark numpy v2 as incompatible with viktor *** ### v14.10.0 - 15/05/2024[​](/docs/whats-new/changelog-sdk/.md#v14100---15052024 "Direct link to v14.10.0 - 15/05/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-16 "Direct link to Added") * `parametrization` Added GeometrySelectField and GeometryMultiSelectField * `geometry` Added `identifier` to geometrical objects #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-9 "Direct link to Fixed") * `viktor` Fix command to also function for `app.py` *** ### v14.9.0 - 04/04/2024[​](/docs/whats-new/changelog-sdk/.md#v1490---04042024 "Direct link to v14.9.0 - 04/04/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-17 "Direct link to Added") * `api_v1` Added `API().get_workspace` and `API().get_workspaces` * `api_v1` Support to use the API module from outside of a VIKTOR app *** ### v14.8.0 - 28/02/2024[​](/docs/whats-new/changelog-sdk/.md#v1480---28022024 "Direct link to v14.8.0 - 28/02/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-18 "Direct link to Added") * `parametrization` Define dynamic option lists per dynamic array row * `views` `GeometryView` `x_axis_to_right` setting to set the initial x-axis orientation * `external` GrasshopperAnalysis #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-1 "Direct link to Deprecated") * `views` `GeometryView` initial x-axis orientation will be to the right by default (#U90) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-10 "Direct link to Fixed") * `parametrization` Fix incorrect or failing serialization when using non-native objects (e.g. Color, GeoPoint, etc.) in DynamicArray default *** ### v14.7.1 - 06/02/2024[​](/docs/whats-new/changelog-sdk/.md#v1471---06022024 "Direct link to v14.7.1 - 06/02/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-19 "Direct link to Added") * `parametrization` Added `workspace_id` in signature of controller methods and callback functions *** ### v14.7.0 - 10/01/2024[​](/docs/whats-new/changelog-sdk/.md#v1470---10012024 "Direct link to v14.7.0 - 10/01/2024") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-20 "Direct link to Added") * `viktor` Support for Python 3.12 * `parametrization` Support for (dynamic) visibility on `Page`, `Tab`, and `Section` * `parametrization` Support to specify `width` on a Page and Step to adjust the width-ratio between input and output of an editor * `external` SCIA binding: general cross-sections (polygon + openings only) #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-2 "Direct link to Deprecated") * `parametrization` Removed `always_available` from buttons (#U88) * `viktor` Support for Python 3.8 will be removed (#U89) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-11 "Direct link to Fixed") * `viktor` Upgrade vendored trimesh to resolve numpy deprecation *** ### v14.6.1 - 16/10/2023[​](/docs/whats-new/changelog-sdk/.md#v1461---16102023 "Direct link to v14.6.1 - 16/10/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-21 "Direct link to Added") * `views` Added the possibility to use a FileResource as input for the IFCResult and IFCAndDAtaResult #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-12 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` crashes due to incorrect parsing of line strips *** ### v14.6.0 - 03/10/2023[​](/docs/whats-new/changelog-sdk/.md#v1460---03102023 "Direct link to v14.6.0 - 03/10/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-22 "Direct link to Added") * `external` IDEA binding: added support to set name of design member * `external` IDEA binding: added support to set description of extreme * `external` IDEA binding: added support to set project data properties * `views` IFCView and IFCAndDataView #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-13 "Direct link to Fixed") * `geo` Fixed error caused by deprecated matplotlib style 'seaborn-whitegrid' * `viktor` Removed upper bounds of VIKTOR dependencies ('pandas' and 'munch') *** ### v14.5.0 - 05/09/2023[​](/docs/whats-new/changelog-sdk/.md#v1450---05092023 "Direct link to v14.5.0 - 05/09/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-23 "Direct link to Added") * `geometry` Metalness and roughness of default `Material` updated to 0.5 and 1.0 respectively * `geometry` `Material` properties can now be set on the instance (e.g. `mat.opacity = 0.3`) * `views` Support marker size of a `MapPoint` by specifying the `size` argument #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-3 "Direct link to Deprecated") * `geometry` Threejs properties renamed / removed from `Material` (#U87) *** ### v14.4.0 - 25/07/2023[​](/docs/whats-new/changelog-sdk/.md#v1440---25072023 "Direct link to v14.4.0 - 25/07/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-24 "Direct link to Added") * `views` Add `geometry_type` to `GeometryResult` and `GeometryAndDataResult` to support alternative geometry file formats (e.g. 3DM) *** ### v14.3.0 - 11/07/2023[​](/docs/whats-new/changelog-sdk/.md#v1430---11072023 "Direct link to v14.3.0 - 11/07/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-25 "Direct link to Added") * `external` SCIA binding: create averaging strips (POINT type only) * `parametrization` `Image` field that can be used to display a static image *** ### v14.2.1 - 15/06/2023[​](/docs/whats-new/changelog-sdk/.md#v1421---15062023 "Direct link to v14.2.1 - 15/06/2023") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-14 "Direct link to Fixed") * `api_v1` Regression in `len(entity.revisions())` causing an error *** ### v14.2.0 - 13/06/2023[​](/docs/whats-new/changelog-sdk/.md#v1420---13062023 "Direct link to v14.2.0 - 13/06/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-26 "Direct link to Added") * `parametrization` `ChildEntityManager` field that can be used to manage child entities *** ### v14.1.0 - 23/05/2023[​](/docs/whats-new/changelog-sdk/.md#v1410---23052023 "Direct link to v14.1.0 - 23/05/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-27 "Direct link to Added") * `external` SCIA binding: create selections *** ### v14.0.0 - 12/04/2023[​](/docs/whats-new/changelog-sdk/.md#v1400---12042023 "Direct link to v14.0.0 - 12/04/2023") #### Action Required[​](/docs/whats-new/changelog-sdk/.md#action-required-1 "Direct link to Action Required") * `viktor` Upgrade instructions U76 - U86 have been applied #### Added[​](/docs/whats-new/changelog-sdk/.md#added-28 "Direct link to Added") * `parametrization` `ColorField` which allow users to select from a color palette * `core` Non-breaking user messages using `UserMessage` * `testing` Allow for `Parametrization` class in `mock_params` #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-2 "Direct link to Docs") * `testing` Simplified `MockedEntity` example #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-15 "Direct link to Fixed") * `viktor` Fixed `matplotlib` dependency range set too strict *** ## v13[​](/docs/whats-new/changelog-sdk/.md#v13 "Direct link to v13") ### v13.8.0 - 16/02/2023[​](/docs/whats-new/changelog-sdk/.md#v1380---16022023 "Direct link to v13.8.0 - 16/02/2023") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-29 "Direct link to Added") * `viktor` Support for Python 3.11 *** ### v13.7.2 - 08/02/2023[​](/docs/whats-new/changelog-sdk/.md#v1372---08022023 "Direct link to v13.7.2 - 08/02/2023") #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-3 "Direct link to Docs") * `views` Added info about "id" attribute for interaction to docstring of GeoJSONResult * `result` Fixed example in `OptimizationResult` docstring #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-16 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` now correctly implements transparency * `geometry` Fixed rotation bug in Cone geometry when oriented in (0, -1, 0) direction *** ### v13.7.1 - 16/01/2023[​](/docs/whats-new/changelog-sdk/.md#v1371---16012023 "Direct link to v13.7.1 - 16/01/2023") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-17 "Direct link to Fixed") * `errors` Fixed `UserError` to accept multiple messages of any type, in line with `UserException` *** ### v13.7.0 - 16/12/2022[​](/docs/whats-new/changelog-sdk/.md#v1370---16122022 "Direct link to v13.7.0 - 16/12/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-30 "Direct link to Added") * `result` Support 'Munch' type in a `SetParamsResult` * `views` New `ImageView` and `ImageAndDataView` that accept 'svg', 'jpeg', 'png', 'gif' files * `parametrization` Validation of a `Step` using the `on_next` callback function * `errors` `UserError` to show an error to the user and mark fields invalid in the interface * `core` Show/hide top-level entities on the dashboard with `InitialEntity` `show_on_dashboard` argument #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-4 "Direct link to Deprecated") * `views` `SVGView`, `JPGView`, `PNGView` are replaced by `ImageView` (#U82) * `views` `SVGResult`, `JPGResult`, `PNGResult` are replaced by `ImageResult` (#U82) * `views` `SVGAndDataView`, `JPGAndDataView`, `PNGAndDataView` are replaced by `ImageAndDataView` (#U82) * `views` `SVGAndDataResult`, `JPGAndDataResult`, `PNGAndDataResult` are replaced by `ImageAndDataResult` (#U82) * `parametrization` Violated field constraints will block actions (#U83) * `viktor` `UserException` will be replaced by `UserError` (#U84) *** ### v13.6.2 - 05/12/2022[​](/docs/whats-new/changelog-sdk/.md#v1362---05122022 "Direct link to v13.6.2 - 05/12/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-18 "Direct link to Fixed") * `geometry` Regression in `CircularExtrusion` causing incorrect positioning *** ### v13.6.1 - 17/11/2022[​](/docs/whats-new/changelog-sdk/.md#v1361---17112022 "Direct link to v13.6.1 - 17/11/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-19 "Direct link to Fixed") * `views` Regression in SVGAndDataResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) *** ### v13.6.0 - 7/11/2022[​](/docs/whats-new/changelog-sdk/.md#v1360---7112022 "Direct link to v13.6.0 - 7/11/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-31 "Direct link to Added") * `viktor` Show progress messages in terminal * `geometry` Specify `shell_thickness` on a `CircularExtrusion` to create a hollow extrusion #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-5 "Direct link to Deprecated") * `geometry` Remove `open_ends` from `CircularExtrusion` (#U81) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-20 "Direct link to Fixed") * `codemod` Fixed codemods failing on f-string with unparenthesized tuples * `viktor` Ignore errors in sending progress messages * `views` Regression in SVGResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) *** ### v13.5.1 - 18/10/2022[​](/docs/whats-new/changelog-sdk/.md#v1351---18102022 "Direct link to v13.5.1 - 18/10/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-21 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` fix colors *** ### v13.5.0 - 11/10/2022[​](/docs/whats-new/changelog-sdk/.md#v1350---11102022 "Direct link to v13.5.0 - 11/10/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-32 "Direct link to Added") * `external` Added repr function to spreadsheet input classes * `external` Various analysis classes and functions now accept a `File` object, or return a `File` object if as\_file=True * `views` All image results (`PNGResult`, etc...) allow for image of type `File` * `geo` `gef_visualization` returns `File` object if as\_file=True * `views` `WebResult` allows for `html` of type `File` and `str` * `geometry` Support visualization of `Arc`, `Line`, and `Polyline` in a `GeometryView` * `testing` Various `mock_*Analysis` classes to facilitate easier testing of analysis classes #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-6 "Direct link to Deprecated") * `geometry` Remove `hex_to_rgb` and `rgb_to_hex` from geometry module (#U79) * `parametrization` Remove `min_message` and `max_message` from `NumberField`/`IntegerField` (#U80) *** ### v13.4.0 - 12/09/2022[​](/docs/whats-new/changelog-sdk/.md#v1340---12092022 "Direct link to v13.4.0 - 12/09/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-33 "Direct link to Added") * `external` Upload inputs of `render_word_file` and `WordFileTemplate.render` to s3 to prevent payload errors * `external` Added torsion and interaction results to `RcsOutputFileParser` #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-22 "Direct link to Fixed") * `codemod` U77 incorrectly includes yaml-comments in welcome\_text * `external` Dynamo `convert_geometry_to_glb` now generates double-sided faces * `codemod` U78 unintentionally removes comments from viktor.config.toml *** ### v13.3.1 - 24/08/2022[​](/docs/whats-new/changelog-sdk/.md#v1331---24082022 "Direct link to v13.3.1 - 24/08/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-23 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions * `external` Fix type-error in fill-spreadsheet helper * `geometry` `get_lowest_or_highest_profile_x` sometimes returns the incorrect profile * `parametrization` Raise a warning when using an `OptionField` with an `int` value in a `Table` *** ### v13.3.0 - 10/08/2022[​](/docs/whats-new/changelog-sdk/.md#v1330---10082022 "Direct link to v13.3.0 - 10/08/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-34 "Direct link to Added") * `parametrization` Increased character limit on `Text` element from 500 to 1800 * `testing` `mock_API` decorator to mock the `API` class in tests * `testing` `mock_params` function to convert a JSON/dict to the (deserialized) params * `testing` `mock_View` decorator to mock `View` decorators in tests * `testing` `mock_SciaAnalysis` to mock `SciaAnalysis.execute` and analysis returns in tests * `api_v1` Compare `EntityType`s or `User`s with "==" * `geometry` Compare `GeoPoint`s, `GeoPolyline`s, or `GeoPolygon`s with "==" #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-7 "Direct link to Deprecated") * `viktor` `app_type` entry should be defined in viktor.config.toml (#U78) *** ### v13.2.1 - 27/06/2022[​](/docs/whats-new/changelog-sdk/.md#v1321---27062022 "Direct link to v13.2.1 - 27/06/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-24 "Direct link to Fixed") * `codemod` U77 incorrectly fixing the `welcome_text` path *** ### v13.2.0 - 15/06/2022[​](/docs/whats-new/changelog-sdk/.md#v1320---15062022 "Direct link to v13.2.0 - 15/06/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-35 "Direct link to Added") * `geometry` Construct an extruded polygon using `Polygon.extrude()` * `geometry` Compare `Point`s and `Line`s with "==" (e.g. `Point(1, 1) == Point(1, 1)` -> True) * `geometry` Allow for indexing/iterating of `Vector`, `Point` and `Line` objects * `geometry` `Line` methods `project_point` and `distance_to_point` * `codemod` Apply all fixes of current major when using the `viktor-cli fix` command without --upgrade flag * `parametrization` Select interaction on Map/GeoJSONView #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-8 "Direct link to Deprecated") * `viktor` Removal of manifest (#U77) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-25 "Direct link to Fixed") * `geometry` bug in `points_are_coplanar` * `geometry` `point_is_on_bounded_line` now correctly calculates for 3D *** ### v13.1.0 - 06/05/2022[​](/docs/whats-new/changelog-sdk/.md#v1310---06052022 "Direct link to v13.1.0 - 06/05/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-36 "Direct link to Added") * `external` SCIA binding: `description` on (nonlinear) load combination * `external` SCIA binding: (general) solver settings * `external` SCIA binding: library cross-sections * `external` SCIA binding: basic project data * `external` SCIA binding: cross-links #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-26 "Direct link to Fixed") * `viktor` Set timeouts on addons requests to 60 seconds to prevent timeout errors * `external` SCIA binding: applying a line load on a circular plane edge no longer raises an error *** ### v13.0.0 - 13/04/2022[​](/docs/whats-new/changelog-sdk/.md#v1300---13042022 "Direct link to v13.0.0 - 13/04/2022") #### Action Required[​](/docs/whats-new/changelog-sdk/.md#action-required-2 "Direct link to Action Required") * `viktor` Upgrade instructions U61 - U75 have been applied #### Added[​](/docs/whats-new/changelog-sdk/.md#added-37 "Direct link to Added") * `core` `Storage` class to permanently store files which can be retrieved at any time * `parametrization` `FileField` and `MultiFileField` which allow users to upload one or multiple files * `parametrization` `EntityOptionField` and `EntityMultiSelectField` for generic selection of entities * `parametrization` `ViktorParametrization` as alias of `Parametrization` #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-9 "Direct link to Deprecated") * `codemod` Cleanup previously set flags which were necessary to migrate to v13 (#U76) *** ## v12[​](/docs/whats-new/changelog-sdk/.md#v12 "Direct link to v12") ### v12.12.2 - 23/08/2022[​](/docs/whats-new/changelog-sdk/.md#v12122---23082022 "Direct link to v12.12.2 - 23/08/2022") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-27 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions *** ### v12.12.1 - 11/04/2022[​](/docs/whats-new/changelog-sdk/.md#v12121---11042022 "Direct link to v12.12.1 - 11/04/2022") #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-4 "Direct link to Docs") * `external` Fixed example in Dynamo docstring #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-28 "Direct link to Fixed") * `parametrization` Fixed U74 warning not being logged in case of dynamic options *** ### v12.12.0 - 06/04/2022[​](/docs/whats-new/changelog-sdk/.md#v12120---06042022 "Direct link to v12.12.0 - 06/04/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-38 "Direct link to Added") * `views` `up_axis` setting to GeometryView and GeometryAndDataView * `views` `GeometryResult` accepts a GLB `File` * `views` Fix the font size of a `MapLabel` regardless of zoom level by setting the `fixed_size` flag * `external` Helper functions for updating Dynamo input files and processing output files (results + geometry) * `external` `GenericAnalysis.get_output_file` returns File object if as\_file=True * `parametrization` Support setting a `value` and a `label` of an `OptionField` option within a table * `parametrization` Added `entity_name` in signature of controller methods and callback functions #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-10 "Direct link to Deprecated") * `views` `GeometryResult` argument `visualization_group` renamed to `geometry` (#U73) * `parametrization` Setting both a `value` and a `label` of an `OptionField` option within a table will no longer be ignored (#U74) * `viktor` Removed `name` and `filename` from the params (#U75) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-29 "Direct link to Fixed") * `codemod` U68 fixed for the case of having multiple 'import as' aliases * `geometry` `Torus` and `ArcRevolve` showing wrong face normals and ignoring rotation angle *** ### v12.11.0 - 09/03/2022[​](/docs/whats-new/changelog-sdk/.md#v12110---09032022 "Direct link to v12.11.0 - 09/03/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-39 "Direct link to Added") * `viktor` Create a views-only entity type by omitting the `parametrization` attribute on the corresponding `Controller` class * `views` Select a custom map marker using the `icon` attribute on `MapPoint` #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-11 "Direct link to Deprecated") * `viktor` The `background_image` of a workspace is customizable through the admin panel instead of the manifest (#U71) * `api` The complete `viktor.api` module and all of its classes and functions (#U72) #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-5 "Direct link to Docs") * `views` Fixed example in PlotlyView docstring *** ### v12.10.0 - 08/02/2022[​](/docs/whats-new/changelog-sdk/.md#v12100---08022022 "Direct link to v12.10.0 - 08/02/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-40 "Direct link to Added") * `views` PlotlyView and PlotlyAndDataView * `api_v1` Various missing functionalities (e.g. to create, delete and modify entities) * `views` `GeometryResult` accepts a (sequence of) `TransformableObject`(s) * `testing` `mock_ParamsFromFile` to mock the `ParamsFromFile` class in tests #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-12 "Direct link to Deprecated") * `parametrization` Automatic selection of a single option in an `OptionField` will no longer be the standard behavior (#U69) * `geometry` Removed method `Polyline.from_dict` (#U70) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-30 "Direct link to Fixed") * `external` D-Foundations parser: `IsKsi3Used` incorrectly returns `True` *** ### v12.9.0 - 11/01/2022[​](/docs/whats-new/changelog-sdk/.md#v1290---11012022 "Direct link to v12.9.0 - 11/01/2022") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-41 "Direct link to Added") * `parametrization` `Step` which can be used to have pages within a predefined order, browsable through a previous and next button * `parametrization` `row_label` attribute on `DynamicArray` which can be used to prefix the row index #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-13 "Direct link to Deprecated") * `viktor` GEOLIB is now publicly available; hosting by VIKTOR will be terminated (#U67) * `parametrization` Input argument `require_all_fields` will be removed from buttons (#U68) *** ### v12.8.0 - 1/12/2021[​](/docs/whats-new/changelog-sdk/.md#v1280---1122021 "Direct link to v12.8.0 - 1/12/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-42 "Direct link to Added") * `external` Removed **\[BETA]** status from the Robot integration * `parametrization` Radio variant of `OptionField` (vertical + horizontal) #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-14 "Direct link to Deprecated") * `parametrization` Entity selection fields return an `Entity` object in the params instead of an integer (#U65) * `parametrization` NumberField variant attribute of type `str` ('slider') replaces type `Enum` (`NumberField.Variant.SLIDER`) (#U66) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-31 "Direct link to Fixed") * `external` D-Foundations and D-Settlement input file generation timeout increased to 30 seconds *** ### v12.7.0 - 3/11/2021[​](/docs/whats-new/changelog-sdk/.md#v1270---3112021 "Direct link to v12.7.0 - 3/11/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-43 "Direct link to Added") * `views` An `update_label` can be used to change the label of the update button of a View * `parametrization` A `description` can now be added on action buttons, to provide more information to the user through a tooltip * `external` IDEA-RCS RcsOutputFileParser: decision method added to fatigue results * `external` IDEA-RCS RcsOutputFileParser: obtain combined results per extreme using `section.extremes()` * `external` IDEA binding: `Member.create_bar_layer()` and `ReinforcedCrossSection.create_bar_layer()` to create multiple bars positioned on a line * `external` IDEA binding: `theta`, `theta_min`, `theta_max`, and `n_cycles_fatigue` can be set in the `CodeSettings` * `external` IDEA binding: `relative_humidity` can be set in the design member data * `external` IDEA binding: a general cross-section can be added to a model, defined by a set of coordinates * `parametrization` `Text` field that can be used to display a static text #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-6 "Direct link to Docs") * `parametrization` Parameter NumberField.step added to docstring * `parametrization` Fixed example in ParamsFromFile docstring #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-32 "Direct link to Fixed") * `external` Scia input file generation timeout increased to 30 seconds *** ### v12.6.0 - 29/09/2021[​](/docs/whats-new/changelog-sdk/.md#v1260---29092021 "Direct link to v12.6.0 - 29/09/2021") #### Action Required[​](/docs/whats-new/changelog-sdk/.md#action-required-3 "Direct link to Action Required") * `external` **\[BETA]** Robot binding: `requested_results` format has changed; specify per category which components are to be returned #### Added[​](/docs/whats-new/changelog-sdk/.md#added-44 "Direct link to Added") * `external` SCIA binding: Model.create\_numerical\_cross\_section * `external` SCIA binding: Model.create\_point\_load\_node * `external` SCIA binding: added `angle` argument to Model.create\_point\_load * `core` Controller attribute `summary` is no longer required to be defined * `core` Controller attributes (`label`, `summary`, `parametrization`, etc.) visible in stubs and docs #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-15 "Direct link to Deprecated") * `api_v1` `PrivilegedAPI` has been replaced by explicit `privileged` flag on the individual API calls (#U64) #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-7 "Direct link to Docs") * `geometry` Fixed code-block in `RDWGSConverter.from_wgs_to_rd()` * `viktor` Link to upgrade instruction webpage in deprecation warnings #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-33 "Direct link to Fixed") * `external` Word file rendering timeout increased to 60 seconds * `parametrization` Naming a table column 'name' does no longer cause a warning in the IDE about not being able to set the 'name' property *** ### v12.5.0 - 24/08/2021[​](/docs/whats-new/changelog-sdk/.md#v1250---24082021 "Direct link to v12.5.0 - 24/08/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-45 "Direct link to Added") * `parametrization` Page which can be used to construct a combination of inputs (e.g. tabs / sections) and outputs (views) * `core` Improved upload performance when no data is returned during post processing * `api_v1` Multiple API requests within the same job are now faster due to session sharing * `core` Improved error messages when a Summary is wrongly defined (e.g. non-existing SummaryItem 'source') * `geo` SoilLayout.filter\_layers\_on\_thickness merges adjacent layers with equal property values of type 'str', and raises a more explicit error otherwise * `external` IDEA-RCS `RcsOutputFileParser` which is an improved version of `OutputFileParser` (allowing large files) * `geometry` Improved performance of TriangleAssembly and Polygon visualization. Additionally a `skip_duplicate_vertices_check` flag can be set to boost performance further. * `parametrization` The width-ratio between input and output of an editor can be adjusted through a `width` argument on Parametrization * `parametrization` A `description` can now be added on a Field / Tab / Section / Page, to provide more information to the user through a tooltip * `views` A `description` can now be added on a View, to provide more information to the user through a tooltip #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-16 "Direct link to Deprecated") * `geo` Renamed `SoilLayout2D.threejs_visualisation()` to `SoilLayout2D.visualize_geometry()` and `SoilLayer2D.threejs_visualisation()` to `SoilLayer2D.visualize_geometry()` (#U62) * `parametrization` Input arguments `prefix` and `suffix` on a DateField will be removed (#U63) #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-8 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-34 "Direct link to Fixed") * `geometry` Small triangles return NaN when calling the area *** ### v12.4.0 - 14/07/2021[​](/docs/whats-new/changelog-sdk/.md#v1240---14072021 "Direct link to v12.4.0 - 14/07/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-46 "Direct link to Added") * `external` SCIA binding: NonLinearLoadCombination can be used in `Model.create_result_class()` #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-9 "Direct link to Docs") * `viktor` Added description of publish commands to cli guide #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-35 "Direct link to Fixed") * `external` Timeout issue when using large files in `render_spreadsheet()` and `SpreadsheetCalculation.evaluate()` *** ### v12.3.1 - 25/06/2021[​](/docs/whats-new/changelog-sdk/.md#v1231---25062021 "Direct link to v12.3.1 - 25/06/2021") #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-36 "Direct link to Fixed") * `parametrization` Issue where clicking "Add new row" on a Table does not work *** ### v12.3.0 - 25/06/2021[​](/docs/whats-new/changelog-sdk/.md#v1230---25062021 "Direct link to v12.3.0 - 25/06/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-47 "Direct link to Added") * `external` IDEA-RCS binding: fatigue loading can be applied on an extreme * `external` IDEA-RCS OutputFileParser: fatigue results can be parsed * `views` 'points' and 'holes' properties added on MapPolygon * `external` Log when external analysis job has been completed successfully * `parametrization` Simple options can be used in OptionField, AutocompleteField, MultiSelectField (e.g. `options=['A', 'B', 'C']`) #### Deprecated[​](/docs/whats-new/changelog-sdk/.md#deprecated-17 "Direct link to Deprecated") * `core` Entity-type information (`label`, `children`, and `show_children_as`) is moved from the manifest to the Controller (#U61) #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-37 "Direct link to Fixed") * `utils` Memoized functions called on app-load breaks in production *** ### v12.2.0 - 26/05/2021[​](/docs/whats-new/changelog-sdk/.md#v1220---26052021 "Direct link to v12.2.0 - 26/05/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-48 "Direct link to Added") * `parametrization` GeoPointField, GeoPolylineField, and GeoPolygonField can now be used in a DynamicArray * `external` **\[BETA]** RobotAnalysis #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-10 "Direct link to Docs") * `viktor` Regular docs maintenance *** ### v12.1.0 - 18/05/2021[​](/docs/whats-new/changelog-sdk/.md#v1210---18052021 "Direct link to v12.1.0 - 18/05/2021") #### Added[​](/docs/whats-new/changelog-sdk/.md#added-49 "Direct link to Added") * `parametrization` Parametrization can consist of 1 layer (Field) or 2 layers (Tab + Field, Section + Field) * `external` Improved error handling in execution of RFEMAnalysis * `geometry` Cone object * `api_v1` Allow negative indexing on EntityList * `parametrization` More consistent naming for many fields (old names will be deprecated in future) * `result` Allow for multiple files to be downloaded (as zip-file) in DownloadResult #### Docs[​](/docs/whats-new/changelog-sdk/.md#docs-11 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/docs/whats-new/changelog-sdk/.md#fixed-38 "Direct link to Fixed") * `parametrization` Setting field `name` argument using dot-notation within TableInput/DynamicArray was mistakenly allowed *** ### v12.0.0 - 20/04/2021[​](/docs/whats-new/changelog-sdk/.md#v1200---20042021 "Direct link to v12.0.0 - 20/04/2021") --- # SDK Reference Welcome to the SDK reference page. Here you will find the detailed API reference of the VIKTOR SDK which you can use to build your applications. * A list of all notable changes per SDK version can be found in the [Changelog](/sdk/13/changelog/.md). * All deprecations & upgrades can be found in [Upgrades](/sdk/13/upgrades/.md). To upgrade the version used in your app, please look at [this guide](/docs/publish-apps/upgrade-viktor-version/.md). --- # viktor.api\_v1 ## FileResource[​](/sdk/13/api/api-v1/.md#_FileResource "Direct link to FileResource") * *class *viktor.api\_v1.FileResource(*source\_id*, *api=None*)[¶](#FileResource "Permalink to this definition") File resource stored in the file manager. Warning Do not instantiate this class directly, it will be returned in the parameter set when using a [`FileField`](/sdk/13/api/parametrization/.md#FileField "viktor.parametrization.FileField") or [`MultiFileField`](/sdk/13/api/parametrization/.md#MultiFileField "viktor.parametrization.MultiFileField"). * *property *file*: [File](/sdk/13/api/core/.md#File "viktor.core.File")*[¶](#FileResource.file "Permalink to this definition") Returns the File object (URL-file) attached to the resource. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") - *property *filename*: str*[¶](#FileResource.filename "Permalink to this definition") Returns the filename of the resource (API call required!). * Return type `str` ## User[​](/sdk/13/api/api-v1/.md#_User "Direct link to User") * *class *viktor.api\_v1.User(*\**, *first\_name*, *last\_name*, *email*, *job\_title*)[¶](#User "Permalink to this definition") User information. * Parameters * **first\_name** (`str`) – user’s first name * **last\_name** (`str`) – user’s last name * **email** (`str`) – user’s email address * **job\_title** (`str`) – user’s job title - *property *full\_name*: str*[¶](#User.full_name "Permalink to this definition") User’s full name (first name + last name). * Return type `str` ## EntityType[​](/sdk/13/api/api-v1/.md#_EntityType "Direct link to EntityType") * *class *viktor.api\_v1.EntityType(*name*, *id\_*)[¶](#EntityType "Permalink to this definition") * Parameters * **name** (`str`) – Entity type name (not label). * **id** – Unique ID of the entity type. ## EntityRevision[​](/sdk/13/api/api-v1/.md#_EntityRevision "Direct link to EntityRevision") * *class *viktor.api\_v1.EntityRevision(*params*, *created\_date*)[¶](#EntityRevision "Permalink to this definition") * Parameters * **params** (`Munch`) – Stored params in the entity’s revision. * **created\_date** (`datetime`) – Date(time) of creation of the entity’s revision. ## Entity[​](/sdk/13/api/api-v1/.md#_Entity "Direct link to Entity") * *class *viktor.api\_v1.Entity(*api*, *origin\_id*, *operations*, *resolved=None*)[¶](#Entity "Permalink to this definition") Warning Do not instantiate this class directly, it is created by the API. * *property *name*: str*[¶](#Entity.name "Permalink to this definition") * Return type `str` - *property *entity\_type*: [EntityType](#EntityType "viktor.api_v1.EntityType")*[¶](#Entity.entity_type "Permalink to this definition") * Return type [`EntityType`](#EntityType "viktor.api_v1.EntityType") * *property *id*: int*[¶](#Entity.id "Permalink to this definition") * Return type `int` - *property *last\_saved\_params*: munch.Munch*[¶](#Entity.last_saved_params "Permalink to this definition") Get the params of the last saved entity revision. * Return type `Munch` * *property *last\_saved\_summary*: munch.Munch*[¶](#Entity.last_saved_summary "Permalink to this definition") Get the summary of the last saved entity revision. * Return type `Munch` - parent(*\**, *privileged=False*)[¶](#Entity.parent "Permalink to this definition") Get the parent of the entity. * Parameters **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") * children(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[¶](#Entity.children "Permalink to this definition") Get the child entities. * Parameters * **include\_params** (`bool`) – True to include the parameters of the child entities. * **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") - siblings(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[¶](#Entity.siblings "Permalink to this definition") Get the sibling entities. * Parameters * **include\_params** (`bool`) – True to include the parameters of the sibling entities. * **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") * get\_file()[¶](#Entity.get_file "Permalink to this definition") Get the file of the entity. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object (SourceType.URL) * Raises **ValueError** – if file does not have a file associated with it. - create\_child(*entity\_type\_name*, *name*, *\**, *params=None*, *privileged=False*, *\*\*kwargs*)[¶](#Entity.create_child "Permalink to this definition") Create a child entity with given name and type. Warning It is currently not possible to create a file-type entity Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. API.get\_entity\_children) within the same job because of internal caching. * Parameters * **entity\_type\_name** (`str`) – type of the entity to be created (type must be a child-type of the parent entity). * **name** (`str`) – name of the entity to be created. * **params** (`Union`\[`dict`, `Munch`, `None`]) – params to be stored on the newly created entity. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") * revisions()[¶](#Entity.revisions "Permalink to this definition") Get all revisions of the entity. * Return type `List`\[[`EntityRevision`](#EntityRevision "viktor.api_v1.EntityRevision")] - delete(*\**, *privileged=False*)[¶](#Entity.delete "Permalink to this definition") Delete the entity. * Parameters **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type `None` * set\_params(*params*, *\**, *privileged=False*)[¶](#Entity.set_params "Permalink to this definition") Create a new revision of the entity, storing given params. Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.last\_saved\_params) within the same job because of memoization. * Parameters * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") - rename(*name*, *\**, *privileged=False*)[¶](#Entity.rename "Permalink to this definition") Rename the entity (creates a revision). Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.name) within the same job because of memoization. * Parameters * **name** (`str`) – name of the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") ## EntityList[​](/sdk/13/api/api-v1/.md#_EntityList "Direct link to EntityList") * *class *viktor.api\_v1.EntityList(*api*, *relation*, *origin*, *entity\_type\_names*, *include\_params*, *\**, *privileged=False*)[¶](#EntityList "Permalink to this definition") Warning Do not instantiate this class directly, it is created by the API. Object which resembles a list of Entity’s. Most commonly used list operations are supported: ``` # indexing children = entity.children() children[0] # first child entity children[-1] # last child entity # length number_of_children = len(children) # for loop for child in children: # perform operation on child ``` ## API[​](/sdk/13/api/api-v1/.md#_API "Direct link to API") * *class *viktor.api\_v1.API[¶](#API "Permalink to this definition") Bases: `_API` Starting point of making an API call to, for example, retrieve properties of a parent or child entity. Note that the permissions of a user (group) are reflected on the permissions of this API call, e.g. if a user only has read-navigate or read-basic permission, calling the params (read-all) of the object using this API will NOT work for this specific user. Example: ``` current_entity = API().get_entity(entity_id) parent = current_entity.parent() parent_params = parent.last_saved_params ``` * get\_entity(*id\_*, *\**, *privileged=False*)[¶](#API.get_entity "Permalink to this definition") Get the entity with given id. * Parameters * **id** – entity\_id * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") - get\_entities\_by\_type(*entity\_type\_name*, *\**, *include\_params=True*, *privileged=False*)[¶](#API.get_entities_by_type "Permalink to this definition") Get all entities of the given type. * Parameters * **entity\_type\_name** (`str`) – entity type to get all entities for. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") * get\_root\_entities(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[¶](#API.get_root_entities "Permalink to this definition") Get the root entities. * Parameters * **include\_params** (`bool`) – True to include the parameters of the root entities. * **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") - get\_entity\_parent(*entity\_id*, *\**, *privileged=False*)[¶](#API.get_entity_parent "Permalink to this definition") Get the parent entity of the entity with given id. * Parameters **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") * get\_entity\_children(*entity\_id*, *\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[¶](#API.get_entity_children "Permalink to this definition") Get the child entities of the entity with given id. * Parameters * **include\_params** (`bool`) – True to include the parameters of the child entities. * **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") - get\_entity\_siblings(*entity\_id*, *\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[¶](#API.get_entity_siblings "Permalink to this definition") Get the sibling entities of the entity with given id. * Parameters * **include\_params** (`bool`) – True to include the parameters of the sibling entities. * **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`EntityList`](#EntityList "viktor.api_v1.EntityList") * get\_entity\_revisions(*entity\_id*, *\**, *privileged=False*)[¶](#API.get_entity_revisions "Permalink to this definition") Get all revisions of the entity with given id. * Parameters * **entity\_id** (`int`) – id of the entity to get the revisions from. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type `List`\[[`EntityRevision`](#EntityRevision "viktor.api_v1.EntityRevision")] - get\_entity\_file(*entity\_id*, *\**, *privileged=False*)[¶](#API.get_entity_file "Permalink to this definition") Get the file of the entity with given id. * Parameters * **entity\_id** (`int`) – id of the entity to get the file from. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object (SourceType.URL) * Raises **ValueError** – if file does not have a file associated with it. * get\_current\_user()[¶](#API.get_current_user "Permalink to this definition") * Return type [`User`](#User "viktor.api_v1.User") - create\_child\_entity(*parent\_entity\_id*, *entity\_type\_name*, *name*, *\**, *params=None*, *privileged=False*, *\*\*kwargs*)[¶](#API.create_child_entity "Permalink to this definition") Create a child entity with given name and type from parent entity with given id. Warning It is currently not possible to create a file-type entity Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. API.get\_entity\_children) within the same job because of memoization. * Parameters * **parent\_entity\_id** (`int`) – id of the parent entity to create the child from. * **entity\_type\_name** (`str`) – type of the entity to be created (type must be a child-type of the parent entity). * **name** (`str`) – name of the entity to be created. * **params** (`Union`\[`dict`, `Munch`, `None`]) – params to be stored on the newly created entity. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") * delete\_entity(*entity\_id*, *\**, *privileged=False*)[¶](#API.delete_entity "Permalink to this definition") Delete the entity with given id. * Parameters * **entity\_id** (`int`) – id of the entity to be deleted. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type `None` - rename\_entity(*entity\_id*, *name*, *\**, *privileged=False*)[¶](#API.rename_entity "Permalink to this definition") Rename the entity with given id (creates a revision). Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.name) within the same job because of memoization. * Parameters * **entity\_id** (`int`) – id of the entity to rename. * **name** (`str`) – name of the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") * set\_entity\_params(*entity\_id*, *params*, *\**, *privileged=False*)[¶](#API.set_entity_params "Permalink to this definition") Create a new revision of the entity with given id, storing given params. Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.last\_saved\_params) within the same job because of memoization. * Parameters * **entity\_id** (`int`) – id of the entity to create a revision for. * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key uses\_privileged\_api is set to true in the manifest. This is to provide an additional layer of security / awareness. * Return type [`Entity`](#Entity "viktor.api_v1.Entity") --- # viktor.core ## UserException[​](/sdk/13/api/core/.md#_UserException "Direct link to UserException") * *exception *viktor.core.UserException(*\*args*)[¶](#UserException "Permalink to this definition") Bases: `Exception` Deprecated, please use [`viktor.errors.UserError`](/sdk/13/api/errors/.md#UserError "viktor.errors.UserError") instead. ## InitialEntity[​](/sdk/13/api/core/.md#_InitialEntity "Direct link to InitialEntity") * *class *viktor.core.InitialEntity(*entity\_type\_name*, *name*, *\**, *params=None*, *children=None*, *show\_on\_dashboard=None*)[¶](#InitialEntity "Permalink to this definition") Construct an initial entity in the app.\_\_init\_\_py file. ``` from .settings_database.controller import Controller as SettingsDatabaseController from .project_folder.controller import Controller as ProjectFolderController from .project.controller import Controller as ProjectController from viktor import InitialEntity initial_entities = [ InitialEntity('SettingsDatabase', name='Settings', params=...), InitialEntity('ProjectFolder', name='Projects', children=[ InitialEntity('Project', 'Project X), InitialEntity('Project', 'Project Y), ]), ] ``` * Parameters * **entity\_type\_name** (`str`) – Type of the initial entity. * **name** (`str`) – Name of the initial entity. * **params** (`Union`\[`dict`, `str`, `None`]) – Optional params in dictionary format or path to a .json, relative to the app.\_\_init\_\_.py. Note that path traversal (beyond the root directory) is not permitted (e.g. “../../entity.json”). * **children** (`Optional`\[`List`\[[`InitialEntity`](#InitialEntity "viktor.core.InitialEntity")]]) – Optional child entities. * **show\_on\_dashboard** (`Optional`\[`bool`]) – Show/hide the entity on the dashboard. Only top-level entities can be shown (default: True) New in v13.7.0 ## ParamsFromFile[​](/sdk/13/api/core/.md#_ParamsFromFile "Direct link to ParamsFromFile") * *class *viktor.core.ParamsFromFile(*\**, *max\_size=None*, *file\_types=None*)[¶](#ParamsFromFile "Permalink to this definition") Decorator that can be used on a pre-process method during a file upload, to produce the parameter set that is stored in the database. Warning Prevent storing the complete file content on the properties if the file is large, as this may cause speed and/or stability issues. The file content can be retrieved at all times using the API whenever necessary. Example with nothing to store: ``` class Controller(ViktorController): ... @ParamsFromFile(...) def process_file(self, file: File, **kwargs): # viktor.core.File return {} ``` Example with parameters to store: ``` class Controller(ViktorController): ... @ParamsFromFile(...) def process_file(self, file: File, **kwargs): # viktor.core.File # app specific parsing logic file_content = file.getvalue() # or use reading in chunks, for large files number_of_entries = ... project_name = ... # linking the parsed output to the parametrization fields (names in database) return { 'tab': { 'section': { 'number_of_entries': number_of_entries, 'project_name': project_name } } } ``` Warning Loading the content of a large file in memory (file.getvalue()) may cause the app to crash (out-of-memory). Read the file content in chunks to avoid such memory issues (see [`File`](#File "viktor.core.File")). Note [`viktor.testing.mock_ParamsFromFile()`](/sdk/13/api/testing/.md#mock_ParamsFromFile "viktor.testing.mock_ParamsFromFile") can be used to test methods decorated with ParamsFromFile. * Parameters * **max\_size** (`Optional`\[`int`]) – optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). * **file\_types** (`Optional`\[`Sequence`\[`str`]]) – optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]). Note that the extensions are filtered regardless of capitalization. ## ViktorController[​](/sdk/13/api/core/.md#_ViktorController "Direct link to ViktorController") * *class *viktor.core.ViktorController(*\*\*kwargs*)[¶](#ViktorController "Permalink to this definition") The main function of the ViktorController is to “control” the information flow between the frontend (what is inputted by a user) and the application code (what is returned as a result of the user input). * label*: str*[¶](#ViktorController.label "Permalink to this definition") Entity-type label. - children*: Optional\[List\[str]]** = None*[¶](#ViktorController.children "Permalink to this definition") Optional list of child entity-types. * show\_children\_as*: Optional\[str]** = None*[¶](#ViktorController.show_children_as "Permalink to this definition") When children are defined, specify how they are shown in the interface (‘Table’ | ‘Cards’). - summary*: Optional\[[Summary](/sdk/13/api/views/.md#Summary "viktor.views.Summary")]** = None*[¶](#ViktorController.summary "Permalink to this definition") [`viktor.views.Summary`](/sdk/13/api/views/.md#Summary "viktor.views.Summary") of the entity-type. * parametrization*: Optional\[[Parametrization](/sdk/13/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization")]** = None*[¶](#ViktorController.parametrization "Permalink to this definition") [`viktor.parametrization.Parametrization`](/sdk/13/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization") that describes the entity-type. ## File[​](/sdk/13/api/core/.md#_File "Direct link to File") * *class *viktor.core.File(*\**, *data=None*, *path=None*, *url=None*, *\*\*kwargs*)[¶](#File "Permalink to this definition") Creates a File object. Only 1 of data, path or url should be set, or File() for writable file. Or use the corresponding class-methods. A File object can have one of the following 4 types: > * SourceType.DATA: File object with in-memory data as its source > > > * Created with File.from\_data(…) > > > > * writable: False > > * SourceType.PATH: File object with an existing file (path) as its source > > > * Created with File.from\_path(…) > > > > * writable: False > > * SourceType.URL: File object with a URL as its source > > > * Created with File.from\_url(…) > > > > * writable: False > > * SourceType.WRITABLE: File object with a (temporary) writable file on disk as its source > > > * Created with File() > > > > * writable: True (writing always takes place at end of file) Note: Reading from a File with SourceType.URL downloads (part of the) URL content to a (temporary) file on disk, so that re-reading (previously read) content within the same open-context does not require downloading twice. Opening the File object a second time DOES involve downloading the content anew. If such a File needs to be opened multiple times, consider copying the File locally ([`copy()`](#File.copy "viktor.core.File.copy")), so that downloading takes place only once. Example usage: > ``` > data_file = File.from_data("my content") > path_file = File.from_path(Path(__file__).parent / "my_file.txt") > url_file = File.from_url("https://...") > writable_file = File() > > data_content = data_file.getvalue_binary() # bytes (b"my content") > path_content = path_file.getvalue() # str > > with url_file.open() as r: # open in text-mode, so read -> str > first_character = r.read(1) # downloads only partially > all_other_characters = r.read() # downloads the rest > > with writable_file.open_binary() as w: # open as binary-mode, so read/write -> bytes > w.write(b"my content") > > writable_content = writable_file.getvalue() # "my content" > ``` * Parameters * **data** (`Union`\[`str`, `bytes`, `None`]) – in-memory data source (also [`from_data()`](#File.from_data "viktor.core.File.from_data")) * **path** (`Union`\[`str`, `bytes`, `PathLike`, `None`]) – existing file path source (also [`from_path()`](#File.from_path "viktor.core.File.from_path")) * **url** (`Optional`\[`str`]) – URL source (also [`from_url()`](#File.from_url "viktor.core.File.from_url")) - *class *SourceType(*value*)[¶](#File.SourceType "Permalink to this definition") Bases: `Enum` An enumeration. * DATA*: [SourceType](#File.SourceType "viktor.core.File.SourceType")** = 1*[¶](#File.SourceType.DATA "Permalink to this definition") - PATH*: [SourceType](#File.SourceType "viktor.core.File.SourceType")** = 2*[¶](#File.SourceType.PATH "Permalink to this definition") * URL*: [SourceType](#File.SourceType "viktor.core.File.SourceType")** = 3*[¶](#File.SourceType.URL "Permalink to this definition") - WRITABLE*: [SourceType](#File.SourceType "viktor.core.File.SourceType")** = 4*[¶](#File.SourceType.WRITABLE "Permalink to this definition") * *classmethod *from\_data(*data*)[¶](#File.from_data "Permalink to this definition") Create a File object with in-memory data as its source. * Return type [`File`](#File "viktor.core.File") - *classmethod *from\_path(*path*)[¶](#File.from_path "Permalink to this definition") Create a File object with an existing file (path) as its source. * Return type [`File`](#File "viktor.core.File") * *classmethod *from\_url(*url*, *\**, *headers=None*)[¶](#File.from_url "Permalink to this definition") Create a File object with a URL as its source. * Return type [`File`](#File "viktor.core.File") - *property *source*: Optional\[str]*[¶](#File.source "Permalink to this definition") Source of the File object: * SourceType.DATA -> None * SourceType.PATH -> path of (readable) file on disk * SourceType.URL -> url * SourceType.WRITABLE -> path of (writable) file on disk - Return type `Optional`\[`str`] * *property *source\_type*: [SourceType](#File.SourceType "viktor.core.File.SourceType")*[¶](#File.source_type "Permalink to this definition") Source type of the file. * Return type [`SourceType`](#File.SourceType "viktor.core.File.SourceType") - *property *writable*: bool*[¶](#File.writable "Permalink to this definition") Whether the File is writable or not (only True for SourceType.WRITABLE). * Return type `bool` * open(*encoding=None*)[¶](#File.open "Permalink to this definition") Open the file in text-mode. * Parameters **encoding** (`Optional`\[`str`]) – encoding used for reading the bytes -> str (default: default local encoding) * Return type `TextIO` * Returns opened text file - open\_binary()[¶](#File.open_binary "Permalink to this definition") Open the file in binary-mode. * Return type `BinaryIO` * Returns opened binary file * getvalue(*encoding=None*)[¶](#File.getvalue "Permalink to this definition") Read the content (text) of the file in memory. For large files, open the file and read in chunks, to prevent the app from running out of memory. * Return type `str` - getvalue\_binary()[¶](#File.getvalue_binary "Permalink to this definition") Read the content (binary) of the file in memory. For large files, open the file and read in chunks, to prevent the app from running out of memory. * Return type `bytes` * copy(*writable=False*)[¶](#File.copy "Permalink to this definition") Make a local copy of the file to disk. Example usages: URL-file that needs to be opened multiple times: ``` # copying to path-file prevents re-downloading if opening more than once. path_file = url_file.copy() # download the complete content locally with path_file.open() as r: # no downloading ... with path_file.open() as r: # no downloading ... ``` Make writable file from read-only file: ``` writable_file = read_only_file.copy(writable=True) with writable_file.open() as w: w.write("my content") ``` * Parameters **writable** (`bool`) – True to return writable file, False for read-only (default: False). * Return type [`File`](#File "viktor.core.File") * Returns File object (SourceType.WRITABLE if writable = True, else SourceType.PATH). ## Color[​](/sdk/13/api/core/.md#_Color "Direct link to Color") * *class *viktor.core.Color(*r: int*, *g: int*, *b: int*)[¶](#Color "Permalink to this definition") Bases: [`Color`](#Color "viktor.core.Color") Create an immutable instance of Color * Parameters * **r** – red-value (0-255) * **g** – green-value (0-255) * **b** – blue-value (0-255) - *static *black()[¶](#Color.black "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") * *static *white()[¶](#Color.white "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") - *static *red()[¶](#Color.red "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") * *static *lime()[¶](#Color.lime "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") - *static *green()[¶](#Color.green "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") * *static *blue()[¶](#Color.blue "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") - *static *viktor\_black()[¶](#Color.viktor_black "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") * *static *viktor\_blue()[¶](#Color.viktor_blue "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") - *static *viktor\_yellow()[¶](#Color.viktor_yellow "Permalink to this definition") * Return type [`Color`](#Color "viktor.core.Color") * *classmethod *from\_hex(*hex\_value*)[¶](#Color.from_hex "Permalink to this definition") Color defined by hexadecimal code. * Return type [`Color`](#Color "viktor.core.Color") - *classmethod *from\_deltares(*value*)[¶](#Color.from_deltares "Permalink to this definition") Color defined by Deltares-type integer. * Parameters **value** (`int`) – Integer representation of the color as used in the Deltares software series. * Return type [`Color`](#Color "viktor.core.Color") * *static *random()[¶](#Color.random "Permalink to this definition") Generate a random color. * Return type [`Color`](#Color "viktor.core.Color") - *property *rgb*: Tuple\[int, int, int]*[¶](#Color.rgb "Permalink to this definition") * Return type `Tuple`\[`int`, `int`, `int`] * *property *hex*: str*[¶](#Color.hex "Permalink to this definition") Hexadecimal representation of the color. * Return type `str` - *property *deltares*: int*[¶](#Color.deltares "Permalink to this definition") * Return type `int` * *static *rgb\_to\_hex(*r*, *g*, *b*, *include\_hashtag=True*)[¶](#Color.rgb_to_hex "Permalink to this definition") Conversion from red-green-blue to hexadecimal value * Return type `str` - *static *hex\_to\_rgb(*hex\_value*)[¶](#Color.hex_to_rgb "Permalink to this definition") Conversion from hexadecimal to red-green-blue value * Return type `Tuple`\[`int`, `int`, `int`] * *static *rgb\_to\_deltares(*r*, *g*, *b*)[¶](#Color.rgb_to_deltares "Permalink to this definition") Conversion from Deltares-type color value to red-green-blue value. :return Integer representation of the color as used in the Deltares software series. * Return type `int` - *static *deltares\_to\_rgb(*value*)[¶](#Color.deltares_to_rgb "Permalink to this definition") Conversion from red-green-blue to Deltares-type color value. * Parameters **value** (`int`) – Integer representation of the color as used in the Deltares software series. * Return type `Tuple`\[`int`, `int`, `int`] ## progress\_message[​](/sdk/13/api/core/.md#_progress_message "Direct link to progress_message") * viktor.core.progress\_message(*message*, *percentage=None*)[¶](#progress_message "Permalink to this definition") Send a user facing progress message informing the progress of an evaluation. Messages are truncated to 500 characters * Parameters * **message** (`str`) – Message shown to the user * **percentage** (`Optional`\[`float`]) – Value between 0 and 100 quantifying the progress * Return type `None` ## make\_data\_json\_serializable[​](/sdk/13/api/core/.md#_make_data_json_serializable "Direct link to make_data_json_serializable") * viktor.core.make\_data\_json\_serializable(*input\_data*)[¶](#make_data_json_serializable "Permalink to this definition") The python built-in json dump does not support all the desired types. This function converts those, thereby enabling broader json conversion. * numpy number types -> equivalent python builtin * datetime.datetime and datetime.date -> isoformat str * tuple -> list (otherwise sub elements cannot be converted due to tuple immutability) - Return type `Any` ## Storage[​](/sdk/13/api/core/.md#_Storage "Direct link to Storage") * *class *viktor.core.Storage[¶](#Storage "Permalink to this definition") Starting point to communicate with the storage to, for example, set or retrieve analysis results. The following actions are supported: ``` storage = Storage() # Setting data on a key storage.set('data_key_1', data=File.from_data('abc'), scope='entity') storage.set('data_key_2', data=File.from_data('def'), scope='entity') # Retrieve the data by key storage.get('data_key_1', scope='entity') # List available data keys (by prefix) storage.list(scope='entity') # lists all files in current entity scope storage.list(prefix='data_key_', scope='entity') # lists 'data_key_1', 'data_key_2', ... etc. # Delete data by key storage.delete('data_key_1', scope='entity') ``` For each of these methods, a scope can be defined to point to a specific section in the storage. These scopes ensure efficient arrangement and handling of data. The following scopes can be used: > * entity : when data needs to be accessed within a specific entity > > * workspace : when data needs to be accessed workspace-wide * set(*key*, *data*, *\**, *scope*, *entity=None*)[¶](#Storage.set "Permalink to this definition") Set data on a key for the specified scope. * Parameters * **key** (`str`) – Unique key on which the data is set (max. 64 characters). * **data** ([`File`](#File "viktor.core.File")) – Data to be stored. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** (`Optional`\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")]) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Return type `None` - get(*key*, *\**, *scope*, *entity=None*)[¶](#Storage.get "Permalink to this definition") Retrieve data from a key for the specified scope. * Parameters * **key** (`str`) – Unique key from which the data should be retrieved. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** (`Optional`\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")]) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Raises **FileNotFoundError** – When trying to retrieve a file that does not exist in the defined storage scope. * Return type [`File`](#File "viktor.core.File") * delete(*key*, *\**, *scope*, *entity=None*)[¶](#Storage.delete "Permalink to this definition") Delete a key-value pair for the specified scope. * Parameters * **key** (`str`) – Unique key from which the key-value pair should be deleted. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** (`Optional`\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")]) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Raises **FileNotFoundError** – When trying to delete a file that does not exist in the defined storage scope. * Return type `None` - list(*\**, *prefix=None*, *scope*, *entity=None*)[¶](#Storage.list "Permalink to this definition") List all available key-value pairs for the specified scope. * Parameters * **prefix** (`Optional`\[`str`]) – List all data of which the keys start with the provided prefix. Using a prefix potentially results in much higher performance due to a more efficient lookup in case of many stored files. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** (`Optional`\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")]) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Return type `Dict`\[`str`, [`File`](#File "viktor.core.File")] --- # viktor.errors ## Error[​](/sdk/13/api/errors/.md#_Error "Direct link to Error") * *exception *viktor.errors.Error[¶](#Error "Permalink to this definition") Bases: `Exception` ## EntityError[​](/sdk/13/api/errors/.md#_EntityError "Direct link to EntityError") * *exception *viktor.errors.EntityError[¶](#EntityError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Base class exception for all entity errors raised in the API. ## EntityCreateError[​](/sdk/13/api/errors/.md#_EntityCreateError "Direct link to EntityCreateError") * *exception *viktor.errors.EntityCreateError[¶](#EntityCreateError "Permalink to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if creation of an entity failed. ## EntityDeleteError[​](/sdk/13/api/errors/.md#_EntityDeleteError "Direct link to EntityDeleteError") * *exception *viktor.errors.EntityDeleteError[¶](#EntityDeleteError "Permalink to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if deletion of an entity failed. ## EntityNotFoundError[​](/sdk/13/api/errors/.md#_EntityNotFoundError "Direct link to EntityNotFoundError") * *exception *viktor.errors.EntityNotFoundError[¶](#EntityNotFoundError "Permalink to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if an entity is requested using the api module but does not exist. ## EntityReviseError[​](/sdk/13/api/errors/.md#_EntityReviseError "Direct link to EntityReviseError") * *exception *viktor.errors.EntityReviseError[¶](#EntityReviseError "Permalink to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if creating a revision (e.g. set params, rename) of an entity failed. ## ExecutionError[​](/sdk/13/api/errors/.md#_ExecutionError "Direct link to ExecutionError") * *exception *viktor.errors.ExecutionError[¶](#ExecutionError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs during the execution of an external analysis. ## GEFClassificationError[​](/sdk/13/api/errors/.md#_GEFClassificationError "Direct link to GEFClassificationError") * *exception *viktor.errors.GEFClassificationError[¶](#GEFClassificationError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during classification of [`viktor.geo.GEFData`](/sdk/13/api/geo/.md#GEFData "viktor.geo.GEFData"). ## GEFParsingError[​](/sdk/13/api/errors/.md#_GEFParsingError "Direct link to GEFParsingError") * *exception *viktor.errors.GEFParsingError[¶](#GEFParsingError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during parsing of a [`viktor.geo.GEFFile`](/sdk/13/api/geo/.md#GEFFile "viktor.geo.GEFFile"). ## InternalError[​](/sdk/13/api/errors/.md#_InternalError "Direct link to InternalError") * *exception *viktor.errors.InternalError[¶](#InternalError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception applicable for incorrect internal VIKTOR logic. Please contact VIKTOR. ## InputViolation[​](/sdk/13/api/errors/.md#_InputViolation "Direct link to InputViolation") * *class *viktor.errors.InputViolation(*message*, *fields*)[¶](#InputViolation "Permalink to this definition") New in v13.7.0 Annotate fields that should be marked as invalid in the interface, along with a message. Example: ``` InputViolation("Width cannot be larger than height", fields=['width', 'height']) ``` * Parameters * **message** (`str`) – Message that is shown to the user. * **fields** (`Sequence`\[`str`]) – Fields that are marked invalid in the interface. Note that these refer to the parametrization class attributes (e.g. ‘step\_1.field\_x’), and not the database location in case name is set. ## LicenseError[​](/sdk/13/api/errors/.md#_LicenseError "Direct link to LicenseError") * *exception *viktor.errors.LicenseError[¶](#LicenseError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an external analysis cannot be executed due to license issues. ## ModelError[​](/sdk/13/api/errors/.md#_ModelError "Direct link to ModelError") * *exception *viktor.errors.ModelError[¶](#ModelError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs within the model of one of the bindings (e.g. SCIA, D-Settlement, …). ## ParsingError[​](/sdk/13/api/errors/.md#_ParsingError "Direct link to ParsingError") * *exception *viktor.errors.ParsingError[¶](#ParsingError "Permalink to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs during parsing. ## SciaParsingError[​](/sdk/13/api/errors/.md#_SciaParsingError "Direct link to SciaParsingError") * *exception *viktor.errors.SciaParsingError[¶](#SciaParsingError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during parsing of SCIA output results. ## SpreadsheetError[​](/sdk/13/api/errors/.md#_SpreadsheetError "Direct link to SpreadsheetError") * *exception *viktor.errors.SpreadsheetError[¶](#SpreadsheetError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs in the Excel or Spreadsheet service. ## SummaryError[​](/sdk/13/api/errors/.md#_SummaryError "Direct link to SummaryError") * *exception *viktor.errors.SummaryError[¶](#SummaryError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during the generation of the summary. ## UserError[​](/sdk/13/api/errors/.md#_UserError "Direct link to UserError") * *exception *viktor.errors.UserError(*\*messages*, *input\_violations=None*)[¶](#UserError "Permalink to this definition") Bases: `Exception` New in v13.7.0 Exception that is shown to the user in the web-interface. Example: ``` raise UserError("The design is not feasible") ``` By providing input\_violations you can mark specific fields as invalid: ``` violations = [ InputViolation("Width cannot be larger than height", fields=['width', 'height']), InputViolation(...), ] raise UserError("The design is not feasible", input_violations=violations) ``` * Parameters * **messages** (`Any`) – Messages to be shown to the user. * **input\_violations** (`Optional`\[`Sequence`\[[`InputViolation`](#InputViolation "viktor.errors.InputViolation")]]) – Mark fields invalid in the interface, along with a message. ## ViewError[​](/sdk/13/api/errors/.md#_ViewError "Direct link to ViewError") * *exception *viktor.errors.ViewError[¶](#ViewError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during the generation of a view. ## WordFileError[​](/sdk/13/api/errors/.md#_WordFileError "Direct link to WordFileError") * *exception *viktor.errors.WordFileError[¶](#WordFileError "Permalink to this definition") Bases: `Exception` Exception raised if an error occurs during rendering of a Word file. --- # viktor.external.axisvm ## AxisVMAnalysis[​](/sdk/13/api/external/axisvm/.md#_AxisVMAnalysis "Direct link to AxisVMAnalysis") * *class *viktor.external.axisvm.AxisVMAnalysis(*model*, *\**, *return\_results=True*, *return\_model=False*, *report\_template=None*)[¶](#AxisVMAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Perform an analysis using AxisVM on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_results()`](#AxisVMAnalysis.get_results "viktor.external.axisvm.AxisVMAnalysis.get_results"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). The model file can be retrieved by calling [`get_model_file()`](#AxisVMAnalysis.get_model_file "viktor.external.axisvm.AxisVMAnalysis.get_model_file") and the result by calling [`get_result_file()`](#AxisVMAnalysis.get_result_file "viktor.external.axisvm.AxisVMAnalysis.get_result_file"). Usage: ``` axisvm_analysis = AxisVMAnalysis(model, return_results=True, return_model=True) axisvm_analysis.execute(timeout=10) results = axisvm_analysis.get_results() model_file = axisvm_analysis.get_model_file() result_file = axisvm_analysis.get_result_file() ``` Exceptions which can be raised during calculation: > * [`ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters * **model** ([`Model`](#Model "viktor.external.axisvm.Model")) – AxisVM model ([`Model`](#Model "viktor.external.axisvm.Model")) * **return\_results** (`bool`) – If True, an analysis will be run and the result file is returned. * **return\_model** (`bool`) – If True, the model file is returned. * **report\_template** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – (optional) report template that is added to AxisVM file - get\_results()[¶](#AxisVMAnalysis.get_results "Permalink to this definition") Retrieve the results (only if return\_results = True). `execute()` must be called first. The format of the returned dictionary is: ``` { 'Forces': , 'Displacements': , 'Sections': } ``` * Return type `dict` * get\_model\_file(*\**, *as\_file=False*)[¶](#AxisVMAnalysis.get_model_file "Permalink to this definition") Retrieve the model file (only if return\_model = True). [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Parameters **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] - get\_result\_file(*\**, *as\_file=False*)[¶](#AxisVMAnalysis.get_result_file "Permalink to this definition") Retrieve the result file (only if return\_results = True). [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Parameters **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] ## CircleArc[​](/sdk/13/api/external/axisvm/.md#_CircleArc "Direct link to CircleArc") * *class *viktor.external.axisvm.CircleArc(*center*, *normal\_vector*, *alpha*)[¶](#CircleArc "Permalink to this definition") Circular arc defined by its center, normal vector and angle. Used in various methods, in conjunction with a start and end point. * Parameters * **center** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the arc’s center point. * **normal\_vector** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) component \[m] of the arc plane’s normal vector. * **alpha** (`float`) – signed angle \[rad]. Positive angle is counterclockwise, from the start point. ## Object[​](/sdk/13/api/external/axisvm/.md#_Object "Direct link to Object") * *class *viktor.external.axisvm.Object(*id\_*)[¶](#Object "Permalink to this definition") Bases: `ABC` Abstract base class of all AxisVM objects. Do not use this \_\_init\_\_ directly. * *property *id*: int*[¶](#Object.id "Permalink to this definition") Object id. * Return type `int` ## Reference[​](/sdk/13/api/external/axisvm/.md#_Reference "Direct link to Reference") * *class *viktor.external.axisvm.Reference(*id\_*)[¶](#Reference "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object"), `ABC` Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## Material[​](/sdk/13/api/external/axisvm/.md#_Material "Direct link to Material") * *class *viktor.external.axisvm.Material(*id\_*, *name*)[¶](#Material "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *DesignCode(*value*)[¶](#Material.DesignCode "Permalink to this definition") Bases: `Enum` National design code. * OTHER*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 0*[¶](#Material.DesignCode.OTHER "Permalink to this definition") - HUNGARIAN\_MSZ*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 1*[¶](#Material.DesignCode.HUNGARIAN_MSZ "Permalink to this definition") * EURO\_CODE*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 2*[¶](#Material.DesignCode.EURO_CODE "Permalink to this definition") - ROMANIAN\_STAS*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 4*[¶](#Material.DesignCode.ROMANIAN_STAS "Permalink to this definition") * DUTCH\_NEN*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 5*[¶](#Material.DesignCode.DUTCH_NEN "Permalink to this definition") - GERMAN\_DIN1045\_1*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 6*[¶](#Material.DesignCode.GERMAN_DIN1045_1 "Permalink to this definition") * SWISS\_SIA26X*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 7*[¶](#Material.DesignCode.SWISS_SIA26X "Permalink to this definition") - EURO\_CODE\_GER*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 8*[¶](#Material.DesignCode.EURO_CODE_GER "Permalink to this definition") * ITALIAN*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 9*[¶](#Material.DesignCode.ITALIAN "Permalink to this definition") - EURO\_CODE\_AUSTRIAN*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 10*[¶](#Material.DesignCode.EURO_CODE_AUSTRIAN "Permalink to this definition") * EURO\_CODE\_UK*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 11*[¶](#Material.DesignCode.EURO_CODE_UK "Permalink to this definition") - EURO\_CODE\_NL*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 12*[¶](#Material.DesignCode.EURO_CODE_NL "Permalink to this definition") * EURO\_CODE\_FIN*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 13*[¶](#Material.DesignCode.EURO_CODE_FIN "Permalink to this definition") - EURO\_CODE\_RO*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 14*[¶](#Material.DesignCode.EURO_CODE_RO "Permalink to this definition") * EURO\_CODE\_HU*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 15*[¶](#Material.DesignCode.EURO_CODE_HU "Permalink to this definition") - EURO\_CODE\_CZ*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 16*[¶](#Material.DesignCode.EURO_CODE_CZ "Permalink to this definition") * EURO\_CODE\_B*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 17*[¶](#Material.DesignCode.EURO_CODE_B "Permalink to this definition") - EURO\_CODE\_PL*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 18*[¶](#Material.DesignCode.EURO_CODE_PL "Permalink to this definition") * EURO\_CODE\_DK*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 19*[¶](#Material.DesignCode.EURO_CODE_DK "Permalink to this definition") - EURO\_CODE\_S*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 20*[¶](#Material.DesignCode.EURO_CODE_S "Permalink to this definition") * US*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 21*[¶](#Material.DesignCode.US "Permalink to this definition") - CA\_NBCC*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 22*[¶](#Material.DesignCode.CA_NBCC "Permalink to this definition") * CA\_ONTARIO*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 23*[¶](#Material.DesignCode.CA_ONTARIO "Permalink to this definition") - CA\_BRIDGE*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 24*[¶](#Material.DesignCode.CA_BRIDGE "Permalink to this definition") * EURO\_CODE\_SK*: [DesignCode](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 25*[¶](#Material.DesignCode.EURO_CODE_SK "Permalink to this definition") - *property *name*: str*[¶](#Material.name "Permalink to this definition") Name of the material. * Return type `str` ## Node[​](/sdk/13/api/external/axisvm/.md#_Node "Direct link to Node") * *class *viktor.external.axisvm.Node(*id\_*, *x*, *y*, *z*)[¶](#Node "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *x*: float*[¶](#Node.x "Permalink to this definition") X-coordinate. * Return type `float` - *property *y*: float*[¶](#Node.y "Permalink to this definition") Y-coordinate. * Return type `float` * *property *z*: float*[¶](#Node.z "Permalink to this definition") Z-coordinate. * Return type `float` ## CrossSection[​](/sdk/13/api/external/axisvm/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.axisvm.CrossSection(*id\_*, *name*)[¶](#CrossSection "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *Process(*value*)[¶](#CrossSection.Process "Permalink to this definition") Bases: `Enum` Manufacturing process. * OTHER*: [Process](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 0*[¶](#CrossSection.Process.OTHER "Permalink to this definition") - ROLLED*: [Process](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 1*[¶](#CrossSection.Process.ROLLED "Permalink to this definition") * WELDED*: [Process](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 2*[¶](#CrossSection.Process.WELDED "Permalink to this definition") - COLD\_FORMED*: [Process](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 3*[¶](#CrossSection.Process.COLD_FORMED "Permalink to this definition") - *property *name*: str*[¶](#CrossSection.name "Permalink to this definition") Name of the cross-section. * Return type `str` ## Line[​](/sdk/13/api/external/axisvm/.md#_Line "Direct link to Line") * *class *viktor.external.axisvm.Line(*id\_*, *interface*, *node1*, *node2*)[¶](#Line "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *start\_node*: [Node](#Node "viktor.external.axisvm.Node")*[¶](#Line.start_node "Permalink to this definition") Start node of the line. * Return type [`Node`](#Node "viktor.external.axisvm.Node") - *property *end\_node*: [Node](#Node "viktor.external.axisvm.Node")*[¶](#Line.end_node "Permalink to this definition") End node of the line. * Return type [`Node`](#Node "viktor.external.axisvm.Node") * define\_as\_beam(*material*, *css\_start*, *css\_end=None*, *\**, *local\_z\_reference=None*)[¶](#Line.define_as_beam "Permalink to this definition") Define the line as beam with given material and cross-section. * Parameters * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the beam. * **css\_start** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam. * **css\_end** (`Optional`\[[`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")]) – cross-section at the start node of the beam (default: same as css\_start). * **local\_z\_reference** (`Optional`\[[`Reference`](#Reference "viktor.external.axisvm.Reference")]) – local z-reference (must be of type vector) (default: auto). * Return type [`Member`](#Member "viktor.external.axisvm.Member") - split\_by\_number(*n*)[¶](#Line.split_by_number "Permalink to this definition") Split the line in ‘n’ equal parts. * Parameters **n** (`int`) – number of parts after the split. * Return type `None` ## Member[​](/sdk/13/api/external/axisvm/.md#_Member "Direct link to Member") * *class *viktor.external.axisvm.Member(*line*, *type\_*)[¶](#Member "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## Domain[​](/sdk/13/api/external/axisvm/.md#_Domain "Direct link to Domain") * *class *viktor.external.axisvm.Domain(*id\_*, *interface*)[¶](#Domain "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *SurfaceType(*value*)[¶](#Domain.SurfaceType "Permalink to this definition") Bases: `Enum` Finite element type. * HOLE*: [SurfaceType](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 0*[¶](#Domain.SurfaceType.HOLE "Permalink to this definition") - MEMBRANE\_STRESS*: [SurfaceType](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 1*[¶](#Domain.SurfaceType.MEMBRANE_STRESS "Permalink to this definition") * MEMBRANE\_STRAIN*: [SurfaceType](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 2*[¶](#Domain.SurfaceType.MEMBRANE_STRAIN "Permalink to this definition") - PLATE*: [SurfaceType](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 3*[¶](#Domain.SurfaceType.PLATE "Permalink to this definition") * SHELL*: [SurfaceType](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 4*[¶](#Domain.SurfaceType.SHELL "Permalink to this definition") - *class *MeshType(*value*)[¶](#Domain.MeshType "Permalink to this definition") Bases: `Enum` Contour division method. * ADAPTIVE*: [MeshType](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")** = 0*[¶](#Domain.MeshType.ADAPTIVE "Permalink to this definition") - UNIFORM*: [MeshType](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")** = 1*[¶](#Domain.MeshType.UNIFORM "Permalink to this definition") * *class *MeshGeometry(*value*)[¶](#Domain.MeshGeometry "Permalink to this definition") Bases: `Enum` Mesh geometry type. * TRIANGLE*: [MeshGeometry](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 0*[¶](#Domain.MeshGeometry.TRIANGLE "Permalink to this definition") - QUAD*: [MeshGeometry](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 1*[¶](#Domain.MeshGeometry.QUAD "Permalink to this definition") * MIXED*: [MeshGeometry](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 2*[¶](#Domain.MeshGeometry.MIXED "Permalink to this definition") - *class *EccentricityType(*value*)[¶](#Domain.EccentricityType "Permalink to this definition") Bases: `Enum` Type of eccentricity. * CONSTANT*: [EccentricityType](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 1*[¶](#Domain.EccentricityType.CONSTANT "Permalink to this definition") - ONE\_WAY*: [EccentricityType](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 2*[¶](#Domain.EccentricityType.ONE_WAY "Permalink to this definition") * TWO\_WAY*: [EccentricityType](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 3*[¶](#Domain.EccentricityType.TWO_WAY "Permalink to this definition") - TOP\_ALIGNED*: [EccentricityType](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 4*[¶](#Domain.EccentricityType.TOP_ALIGNED "Permalink to this definition") * BOTTOM\_ALIGNED*: [EccentricityType](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 5*[¶](#Domain.EccentricityType.BOTTOM_ALIGNED "Permalink to this definition") * generate\_mesh(*mesh\_geometry*, *mesh\_size*, *\**, *mesh\_type=MeshType.UNIFORM*, *fit\_to\_point\_loads=None*, *fit\_to\_line\_loads=None*, *fit\_to\_surface\_loads=None*, *quad\_mesh\_quality=2*)[¶](#Domain.generate_mesh "Permalink to this definition") Generate a mesh on the domain. * Parameters * **mesh\_geometry** ([`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")) – mesh geometry type. * **mesh\_size** (`float`) – average mesh size \[m]. * **mesh\_type** ([`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")) – contour division method (default: uniform). * **fit\_to\_point\_loads** (`Optional`\[`float`]) – fit mesh to point loads (default: false). * **fit\_to\_line\_loads** (`Optional`\[`float`]) – fit mesh to line loads (default: false). * **fit\_to\_surface\_loads** (`Optional`\[`float`]) – fit mesh to surface loads (default: false) * **quad\_mesh\_quality** (`int`) – smoothing quality (1-6) (default: 2) * Return type `None` - set\_eccentricity(*eccentricity\_type*, *\**, *ecc\_1=None*, *p1=None*, *ecc\_2=None*, *p2=None*, *ecc\_3=None*, *p3=None*)[¶](#Domain.set_eccentricity "Permalink to this definition") Set eccentricity for the domain. * Parameters * **eccentricity\_type** ([`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")) – type of eccentricity. * **ecc\_1** (`Optional`\[`float`]) – eccentricity \[m] at reference point 1. * **p1** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 1. * **ecc\_2** (`Optional`\[`float`]) – eccentricity \[m] at reference point 2. * **p2** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 2. * **ecc\_3** (`Optional`\[`float`]) – eccentricity \[m] at reference point 3. * **p3** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 3. * Return type `None` ## NodeSupport[​](/sdk/13/api/external/axisvm/.md#_NodeSupport "Direct link to NodeSupport") * *class *viktor.external.axisvm.NodeSupport(*id\_*)[¶](#NodeSupport "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## LineSupport[​](/sdk/13/api/external/axisvm/.md#_LineSupport "Direct link to LineSupport") * *class *viktor.external.axisvm.LineSupport(*id\_*)[¶](#LineSupport "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *NonLinearity(*value*)[¶](#LineSupport.NonLinearity "Permalink to this definition") Bases: `Enum` Type of non-linear behavior. * LINEAR*: [NonLinearity](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 0*[¶](#LineSupport.NonLinearity.LINEAR "Permalink to this definition") - TENSION\_ONLY*: [NonLinearity](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 1*[¶](#LineSupport.NonLinearity.TENSION_ONLY "Permalink to this definition") * COMPRESSION\_ONLY*: [NonLinearity](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 2*[¶](#LineSupport.NonLinearity.COMPRESSION_ONLY "Permalink to this definition") ## LoadCase[​](/sdk/13/api/external/axisvm/.md#_LoadCase "Direct link to LoadCase") * *class *viktor.external.axisvm.LoadCase(*id\_*, *name*)[¶](#LoadCase "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *name*: str*[¶](#LoadCase.name "Permalink to this definition") Name of the load case. * Return type `str` ## Load[​](/sdk/13/api/external/axisvm/.md#_Load "Direct link to Load") * *class *viktor.external.axisvm.Load(*id\_*)[¶](#Load "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *DistributionType(*value*)[¶](#Load.DistributionType "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [DistributionType](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 0*[¶](#Load.DistributionType.GLOBAL "Permalink to this definition") - LOCAL*: [DistributionType](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 1*[¶](#Load.DistributionType.LOCAL "Permalink to this definition") * PROJECTED*: [DistributionType](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 2*[¶](#Load.DistributionType.PROJECTED "Permalink to this definition") - *class *SurfaceDistributionType(*value*)[¶](#Load.SurfaceDistributionType "Permalink to this definition") Bases: `Enum` An enumeration. * SURFACE*: [SurfaceDistributionType](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")** = 0*[¶](#Load.SurfaceDistributionType.SURFACE "Permalink to this definition") - PROJECTED*: [SurfaceDistributionType](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")** = 1*[¶](#Load.SurfaceDistributionType.PROJECTED "Permalink to this definition") * *class *System(*value*)[¶](#Load.System "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [System](#Load.System "viktor.external.axisvm.Load.System")** = 0*[¶](#Load.System.GLOBAL "Permalink to this definition") - LOCAL*: [System](#Load.System "viktor.external.axisvm.Load.System")** = 1*[¶](#Load.System.LOCAL "Permalink to this definition") * REFERENCE*: [System](#Load.System "viktor.external.axisvm.Load.System")** = 2*[¶](#Load.System.REFERENCE "Permalink to this definition") - *class *Axis(*value*)[¶](#Load.Axis "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 0*[¶](#Load.Axis.X "Permalink to this definition") - Y*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 1*[¶](#Load.Axis.Y "Permalink to this definition") * Z*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 2*[¶](#Load.Axis.Z "Permalink to this definition") - XX*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 3*[¶](#Load.Axis.XX "Permalink to this definition") * YY*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 4*[¶](#Load.Axis.YY "Permalink to this definition") - ZZ*: [Axis](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 5*[¶](#Load.Axis.ZZ "Permalink to this definition") ## LoadCombination[​](/sdk/13/api/external/axisvm/.md#_LoadCombination "Direct link to LoadCombination") * *class *viktor.external.axisvm.LoadCombination(*id\_*, *name*)[¶](#LoadCombination "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *Type(*value*)[¶](#LoadCombination.Type "Permalink to this definition") Bases: `Enum` An enumeration. * OTHER*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 0*[¶](#LoadCombination.Type.OTHER "Permalink to this definition") - SLS\_1*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 1*[¶](#LoadCombination.Type.SLS_1 "Permalink to this definition") * SLS\_CHAR*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 1*[¶](#LoadCombination.Type.SLS_CHAR "Permalink to this definition") - SLS\_2*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 2*[¶](#LoadCombination.Type.SLS_2 "Permalink to this definition") * SLS\_FREQ*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 2*[¶](#LoadCombination.Type.SLS_FREQ "Permalink to this definition") - SLS\_3*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 3*[¶](#LoadCombination.Type.SLS_3 "Permalink to this definition") * SLS\_QUASI*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 3*[¶](#LoadCombination.Type.SLS_QUASI "Permalink to this definition") - ULS\_1*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 4*[¶](#LoadCombination.Type.ULS_1 "Permalink to this definition") * ULS*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 4*[¶](#LoadCombination.Type.ULS "Permalink to this definition") - ULS\_2*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 5*[¶](#LoadCombination.Type.ULS_2 "Permalink to this definition") * ULS\_SEISMIC*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 5*[¶](#LoadCombination.Type.ULS_SEISMIC "Permalink to this definition") - ULS\_3*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 6*[¶](#LoadCombination.Type.ULS_3 "Permalink to this definition") * ULS\_EXCEPTIONAL*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 6*[¶](#LoadCombination.Type.ULS_EXCEPTIONAL "Permalink to this definition") - ULS\_ALL*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 7*[¶](#LoadCombination.Type.ULS_ALL "Permalink to this definition") * ULS\_AB*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 8*[¶](#LoadCombination.Type.ULS_AB "Permalink to this definition") - ULS\_A*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 9*[¶](#LoadCombination.Type.ULS_A "Permalink to this definition") * ULS\_B*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 10*[¶](#LoadCombination.Type.ULS_B "Permalink to this definition") - ULS\_ALL\_AB*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 11*[¶](#LoadCombination.Type.ULS_ALL_AB "Permalink to this definition") * ULS\_A1*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 12*[¶](#LoadCombination.Type.ULS_A1 "Permalink to this definition") - ULS\_A2*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 13*[¶](#LoadCombination.Type.ULS_A2 "Permalink to this definition") * ULS\_A3*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 14*[¶](#LoadCombination.Type.ULS_A3 "Permalink to this definition") - ULS\_A4*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 15*[¶](#LoadCombination.Type.ULS_A4 "Permalink to this definition") * ULS\_A5*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 16*[¶](#LoadCombination.Type.ULS_A5 "Permalink to this definition") - ULS\_A6*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 17*[¶](#LoadCombination.Type.ULS_A6 "Permalink to this definition") * ULS\_A7*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 18*[¶](#LoadCombination.Type.ULS_A7 "Permalink to this definition") - ULS\_A8*: [Type](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 19*[¶](#LoadCombination.Type.ULS_A8 "Permalink to this definition") - *property *name*: str*[¶](#LoadCombination.name "Permalink to this definition") Name of the load case. * Return type `str` ## Section[​](/sdk/13/api/external/axisvm/.md#_Section "Direct link to Section") * *class *viktor.external.axisvm.Section(*id\_*, *interface*, *name*)[¶](#Section "Permalink to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *name*: str*[¶](#Section.name "Permalink to this definition") Name of the section. * Return type `str` ## ReferenceInterface[​](/sdk/13/api/external/axisvm/.md#_ReferenceInterface "Direct link to ReferenceInterface") * *class *viktor.external.axisvm.ReferenceInterface[¶](#ReferenceInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.references`](#Model.references "viktor.external.axisvm.Model.references") * create\_point(*x*, *y*, *z*)[¶](#ReferenceInterface.create_point "Permalink to this definition") Create a reference point. * Parameters * **x** (`float`) – x-position \[m]. * **y** (`float`) – y-position \[m]. * **z** (`float`) – z-position \[m]. * Return type [`Reference`](#Reference "viktor.external.axisvm.Reference") - create\_vector(*point\_1*, *point\_2*)[¶](#ReferenceInterface.create_vector "Permalink to this definition") Create a reference vector. * Parameters * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the start point. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the end point. * Return type [`Reference`](#Reference "viktor.external.axisvm.Reference") * create\_axis(*point\_1*, *point\_2*)[¶](#ReferenceInterface.create_axis "Permalink to this definition") Create a reference axis. * Parameters * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the start point. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the end point. * Return type [`Reference`](#Reference "viktor.external.axisvm.Reference") - create\_plane(*point\_1*, *point\_2*, *point\_3*)[¶](#ReferenceInterface.create_plane "Permalink to this definition") Create a reference plane. * Parameters * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 1. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 2. * **point\_3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 3. * Return type [`Reference`](#Reference "viktor.external.axisvm.Reference") * create\_angle(*angle*)[¶](#ReferenceInterface.create_angle "Permalink to this definition") Create a reference angle. * Parameters **angle** (`float`) – angle \[rad]. * Return type [`Reference`](#Reference "viktor.external.axisvm.Reference") ## MaterialInterface[​](/sdk/13/api/external/axisvm/.md#_MaterialInterface "Direct link to MaterialInterface") * *class *viktor.external.axisvm.MaterialInterface[¶](#MaterialInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.materials`](#Model.materials "viktor.external.axisvm.Model.materials") * create\_concrete\_eurocode(*\**, *e\_x*, *e\_y=None*, *e\_z=None*, *nu\_x*, *nu\_y=None*, *nu\_z=None*, *alpha\_x=0.0*, *alpha\_y=None*, *alpha\_z=None*, *rho*, *f\_ck*, *gamma\_c*, *alpha\_cc*, *phi\_t=0.0*, *material\_code=None*, *name=None*)[¶](#MaterialInterface.create_concrete_eurocode "Permalink to this definition") Create a concrete material according to the Eurocode. * Parameters * **e\_x** (`float`) – Young’s modulus of elasticity \[kN/m2] in local x-direction. * **e\_y** (`Optional`\[`float`]) – Young’s modulus of elasticity \[kN/m2] in local y-direction (default = e\_x). * **e\_z** (`Optional`\[`float`]) – Young’s modulus of elasticity \[kN/m2] in local z-direction (default = e\_x). * **nu\_x** (`float`) – Poisson’s ratio \[-] in local x-direction (0 <= nu <= 0.5). * **nu\_y** (`Optional`\[`float`]) – Poisson’s ratio \[-] in local y-direction (0 <= nu <= 0.5) (default = nu\_x). * **nu\_z** (`Optional`\[`float`]) – Poisson’s ratio \[-] in local z-direction (0 <= nu <= 0.5) (default = nu\_x). * **alpha\_x** (`float`) – thermal expansion coefficient \[1/C] in local x-direction (default = 0.0). * **alpha\_y** (`Optional`\[`float`]) – thermal expansion coefficient \[1/C] in local y-direction (default = alpha\_x). * **alpha\_z** (`Optional`\[`float`]) – thermal expansion coefficient \[1/C] in local z-direction (default = alpha\_x). * **rho** (`float`) – density \[kg/m3]. * **f\_ck** (`float`) – characteristic compressive cylinder strength \[kN/m2] at 28 days. * **gamma\_c** (`float`) – safety factor \[-]. * **alpha\_cc** (`float`) – concrete strength-reduction factor for sustained loading \[-]. * **phi\_t** (`float`) – creeping factor \[-] (default = 0.0). * **material\_code** (`Optional`\[`str`]) – material code name, as shown in the interface (default: auto). * **name** (`Optional`\[`str`]) – material name, as shown in the interface (default: auto). * Return type [`Material`](#Material "viktor.external.axisvm.Material") - add\_from\_catalog(*name*, *national\_design\_code*)[¶](#MaterialInterface.add_from_catalog "Permalink to this definition") Adds a material from the catalog. * Parameters * **name** (`str`) – name of the material to be added (must exist in the corresponding national design code). * **national\_design\_code** ([`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")) – national design code in which the material with given name resides. * Return type [`Material`](#Material "viktor.external.axisvm.Material") ## NodeInterface[​](/sdk/13/api/external/axisvm/.md#_NodeInterface "Direct link to NodeInterface") * *class *viktor.external.axisvm.NodeInterface[¶](#NodeInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.nodes`](#Model.nodes "viktor.external.axisvm.Model.nodes") * create(*x*, *y*, *z*)[¶](#NodeInterface.create "Permalink to this definition") Create a node at the given position and with given degree-of-freedom. * Parameters * **x** (`float`) – x-position \[m]. * **y** (`float`) – y-position \[m]. * **z** (`float`) – z-position \[m]. * Return type [`Node`](#Node "viktor.external.axisvm.Node") ## CrossSectionInterface[​](/sdk/13/api/external/axisvm/.md#_CrossSectionInterface "Direct link to CrossSectionInterface") * *class *viktor.external.axisvm.CrossSectionInterface[¶](#CrossSectionInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.cross_sections`](#Model.cross_sections "viktor.external.axisvm.Model.cross_sections") * create\_circular(*diameter*, *\**, *name=None*)[¶](#CrossSectionInterface.create_circular "Permalink to this definition") Create a circular cross-section with given diameter. * Parameters * **diameter** (`float`) – diameter \[m] of the cross-section. * **name** (`Optional`\[`str`]) – name of the cross-section (must be unique) (default: auto). * Return type [`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection") - create\_rectangular(*width*, *height*, *\**, *process=Process.OTHER*, *name=None*)[¶](#CrossSectionInterface.create_rectangular "Permalink to this definition") Create a rectangular cross-section with given width and height. * Parameters * **width** (`float`) – width \[m] of the cross-section. * **height** (`float`) – height \[m] of the cross-section. * **process** ([`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")) – process (default: other). * **name** (`Optional`\[`str`]) – name of the cross-section (must be unique) (default: auto). * Return type [`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection") ## LineInterface[​](/sdk/13/api/external/axisvm/.md#_LineInterface "Direct link to LineInterface") * *class *viktor.external.axisvm.LineInterface[¶](#LineInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.lines`](#Model.lines "viktor.external.axisvm.Model.lines") * create(*start\_node*, *end\_node*, *circle\_arc=None*)[¶](#LineInterface.create "Permalink to this definition") Create a line between start and end node. * Parameters * **start\_node** ([`Node`](#Node "viktor.external.axisvm.Node")) – start node. * **end\_node** ([`Node`](#Node "viktor.external.axisvm.Node")) – end node. * **circle\_arc** (`Optional`\[[`CircleArc`](#CircleArc "viktor.external.axisvm.CircleArc")]) – circular arc between the nodes (default: straight line). * Return type [`Line`](#Line "viktor.external.axisvm.Line") - define\_as\_beam(*line*, *material*, *css\_start*, *css\_end=None*, *\**, *local\_z\_reference=None*)[¶](#LineInterface.define_as_beam "Permalink to this definition") Define a line as beam with given material and cross-section. * Parameters * **line** ([`Line`](#Line "viktor.external.axisvm.Line")) – line to define as beam. * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the beam. * **css\_start** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam. * **css\_end** (`Optional`\[[`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")]) – cross-section at the start node of the beam (default: same as css\_start). * **local\_z\_reference** (`Optional`\[[`Reference`](#Reference "viktor.external.axisvm.Reference")]) – local z-reference (must be of type vector) (default: auto). * Return type [`Member`](#Member "viktor.external.axisvm.Member") * split\_by\_number(*line*, *n*)[¶](#LineInterface.split_by_number "Permalink to this definition") Split a line in ‘n’ equal parts. * Parameters * **line** ([`Line`](#Line "viktor.external.axisvm.Line")) – line to split. * **n** (`int`) – number of parts after the split. * Return type `None` ## DomainInterface[​](/sdk/13/api/external/axisvm/.md#_DomainInterface "Direct link to DomainInterface") * *class *viktor.external.axisvm.DomainInterface[¶](#DomainInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.domains`](#Model.domains "viktor.external.axisvm.Model.domains") * create(*lines*, *\**, *surface\_type*, *thickness*, *material*)[¶](#DomainInterface.create "Permalink to this definition") Create a domain from given lines. * Parameters * **lines** (`List`\[[`Line`](#Line "viktor.external.axisvm.Line")]) – lines to create a domain from (lines must form a closed loop!). * **surface\_type** ([`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")) – finite element surface type. * **thickness** (`float`) – thickness \[m] of the surface. * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the surface. * Return type [`Domain`](#Domain "viktor.external.axisvm.Domain") - generate\_mesh\_on\_domains(*domains*, *mesh\_geometry*, *mesh\_size*, *\**, *mesh\_type=MeshType.UNIFORM*, *fit\_to\_point\_loads=None*, *fit\_to\_line\_loads=None*, *fit\_to\_surface\_loads=None*, *quad\_mesh\_quality=2*)[¶](#DomainInterface.generate_mesh_on_domains "Permalink to this definition") Generate a mesh on one or more domains. * Parameters * **domains** (`List`\[[`Domain`](#Domain "viktor.external.axisvm.Domain")]) – domain(s) to generate the mesh on. * **mesh\_geometry** ([`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")) – mesh geometry type. * **mesh\_size** (`float`) – average mesh size \[m]. * **mesh\_type** ([`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")) – contour division method (default: uniform). * **fit\_to\_point\_loads** (`Optional`\[`float`]) – fit mesh to point loads (default: false). * **fit\_to\_line\_loads** (`Optional`\[`float`]) – fit mesh to line loads (default: false). * **fit\_to\_surface\_loads** (`Optional`\[`float`]) – fit mesh to surface loads (default: false) * **quad\_mesh\_quality** (`int`) – smoothing quality (1-6) (default: 2) * Return type `None` * set\_eccentricity(*domain*, *eccentricity\_type*, *\**, *ecc\_1=None*, *p1=None*, *ecc\_2=None*, *p2=None*, *ecc\_3=None*, *p3=None*)[¶](#DomainInterface.set_eccentricity "Permalink to this definition") Set eccentricity for a domain. * Parameters * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to set eccentricity. * **eccentricity\_type** ([`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")) – type of eccentricity. * **ecc\_1** (`Optional`\[`float`]) – eccentricity \[m] at reference point 1. * **p1** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 1. * **ecc\_2** (`Optional`\[`float`]) – eccentricity \[m] at reference point 2. * **p2** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 2. * **ecc\_3** (`Optional`\[`float`]) – eccentricity \[m] at reference point 3. * **p3** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – (x, y, z) position \[m] of reference point 3. * Return type `None` ## NodeSupportInterface[​](/sdk/13/api/external/axisvm/.md#_NodeSupportInterface "Direct link to NodeSupportInterface") * *class *viktor.external.axisvm.NodeSupportInterface(*lines*)[¶](#NodeSupportInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.node_supports`](#Model.node_supports "viktor.external.axisvm.Model.node_supports") * create\_relative\_to\_member(*node*, *\**, *stiffness\_x=0.0*, *stiffness\_y=0.0*, *stiffness\_z=0.0*, *stiffness\_xx=0.0*, *stiffness\_yy=0.0*, *stiffness\_zz=0.0*, *resistance\_x=0.0*, *resistance\_y=0.0*, *resistance\_z=0.0*, *resistance\_xx=0.0*, *resistance\_yy=0.0*, *resistance\_zz=0.0*, *non\_linearity\_x=NonLinearity.LINEAR*, *non\_linearity\_y=NonLinearity.LINEAR*, *non\_linearity\_z=NonLinearity.LINEAR*, *non\_linearity\_xx=NonLinearity.LINEAR*, *non\_linearity\_yy=NonLinearity.LINEAR*, *non\_linearity\_zz=NonLinearity.LINEAR*)[¶](#NodeSupportInterface.create_relative_to_member "Permalink to this definition") Create a nodal support, relative to the member’s local coordinate system. * Parameters * **node** ([`Node`](#Node "viktor.external.axisvm.Node")) – node to create the support on. Must be an end-point of a member of type beam or rib. * **stiffness\_x** (`float`) – translational stiffness \[kN/m] in local x-direction (default = 0.0). * **stiffness\_y** (`float`) – translational stiffness \[kN/m] in local y-direction (default = 0.0). * **stiffness\_z** (`float`) – translational stiffness \[kN/m] in local z-direction (default = 0.0). * **stiffness\_xx** (`float`) – rotational stiffness \[kNm/rad] around the local x-axis (default = 0.0). * **stiffness\_yy** (`float`) – rotational stiffness \[kNm/rad] around the local y-axis (default = 0.0). * **stiffness\_zz** (`float`) – rotational stiffness \[kNm/rad] around the local z-axis (default = 0.0). * **resistance\_x** (`float`) – translational resistance \[kN/m] in local x-direction (default = 0.0). * **resistance\_y** (`float`) – translational resistance \[kN/m] in local y-direction (default = 0.0). * **resistance\_z** (`float`) – translational resistance \[kN/m] in local z-direction (default = 0.0). * **resistance\_xx** (`float`) – rotational resistance \[kNm/m] around the local x-axis (default = 0.0). * **resistance\_yy** (`float`) – rotational resistance \[kNm/m] around the local y-axis (default = 0.0). * **resistance\_zz** (`float`) – rotational resistance \[kNm/m] around the local z-axis (default = 0.0). * **non\_linearity\_x** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local x-direction (default: linear). * **non\_linearity\_y** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local y-direction (default: linear). * **non\_linearity\_z** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local z-direction (default: linear). * **non\_linearity\_xx** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local x-axis (default: linear). * **non\_linearity\_yy** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local y-axis (default: linear). * **non\_linearity\_zz** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local z-axis (default: linear). * Return type [`NodeSupport`](#NodeSupport "viktor.external.axisvm.NodeSupport") ## LineSupportInterface[​](/sdk/13/api/external/axisvm/.md#_LineSupportInterface "Direct link to LineSupportInterface") * *class *viktor.external.axisvm.LineSupportInterface[¶](#LineSupportInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.line_supports`](#Model.line_supports "viktor.external.axisvm.Model.line_supports") * create\_on\_member(*member*, *k\_x*, *k\_y*, *k\_z*, *\**, *non\_linearity\_x=NonLinearity.LINEAR*, *non\_linearity\_y=NonLinearity.LINEAR*, *non\_linearity\_z=NonLinearity.LINEAR*, *resistance\_fx=0.0*, *resistance\_fy=0.0*, *resistance\_fz=0.0*)[¶](#LineSupportInterface.create_on_member "Permalink to this definition") Create a line support on a member (beam), in the member’s coordinate system. * Parameters * **member** ([`Member`](#Member "viktor.external.axisvm.Member")) – member (beam) to create the line support on. * **k\_x** (`float`) – stiffness \[kN/m/m] in the local x-direction. * **k\_y** (`float`) – stiffness \[kN/m/m] in the local y-direction. * **k\_z** (`float`) – stiffness \[kN/m/m] in the local z-direction. * **non\_linearity\_x** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local x-direction (default: linear). * **non\_linearity\_y** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local y-direction (default: linear). * **non\_linearity\_z** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local z-direction (default: linear). * **resistance\_fx** (`float`) – resistance \[kN/m] in the local x-direction (default: 0.0). * **resistance\_fy** (`float`) – resistance \[kN/m] in the local y-direction (default: 0.0). * **resistance\_fz** (`float`) – resistance \[kN/m] in the local z-direction (default: 0.0). * Return type [`LineSupport`](#LineSupport "viktor.external.axisvm.LineSupport") ## LoadCaseInterface[​](/sdk/13/api/external/axisvm/.md#_LoadCaseInterface "Direct link to LoadCaseInterface") * *class *viktor.external.axisvm.LoadCaseInterface[¶](#LoadCaseInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.load_cases`](#Model.load_cases "viktor.external.axisvm.Model.load_cases") * create(*name=None*)[¶](#LoadCaseInterface.create "Permalink to this definition") Create a load case. * Parameters **name** (`Optional`\[`str`]) – name of the load case (default: auto). * Return type [`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase") ## LoadInterface[​](/sdk/13/api/external/axisvm/.md#_LoadInterface "Direct link to LoadInterface") * *class *viktor.external.axisvm.LoadInterface[¶](#LoadInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.loads`](#Model.loads "viktor.external.axisvm.Model.loads") * create\_domain\_linear(*load\_case*, *domain*, *load*, *\**, *component*, *point\_1*, *point\_2*, *point\_3*, *distribution\_type=DistributionType.GLOBAL*, *load\_on\_hole=False*)[¶](#LoadInterface.create_domain_linear "Permalink to this definition") Create a linear distributed load on a domain. * Parameters * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * **load** (`Tuple`\[`float`, `float`, `float`]) – magnitude of the load at (point\_1, point\_2, point\_3) \[kN]. * **component** ([`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")) – direction of the load (X, Y, Z only). * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 1. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 2. * **point\_3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 3. * **distribution\_type** ([`DistributionType`](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")) – distribution type (default: GLOBAL). * **load\_on\_hole** (`bool`) – apply load on hole (default: False -> loads disappear on holes). * Return type [`Load`](#Load "viktor.external.axisvm.Load") - create\_domain\_constant(*load\_case*, *domain*, *load*, *\**, *distribution\_type=SurfaceDistributionType.SURFACE*, *system=System.GLOBAL*)[¶](#LoadInterface.create_domain_constant "Permalink to this definition") Create a constant distributed load on a domain. * Parameters * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * **load** (`Tuple`\[`float`, `float`, `float`]) – magnitude of the load (x, y, z) \[kN]. * **distribution\_type** ([`SurfaceDistributionType`](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")) – distribution type (default: SURFACE). * **system** ([`System`](#Load.System "viktor.external.axisvm.Load.System")) – coordinate system (default: GLOBAL). * Return type [`Load`](#Load "viktor.external.axisvm.Load") * create\_domain\_self\_weight(*load\_case*, *domain*)[¶](#LoadInterface.create_domain_self_weight "Permalink to this definition") Create a self-weight load on a domain. * Parameters * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * Return type [`Load`](#Load "viktor.external.axisvm.Load") - create\_beam\_self\_weight(*load\_case*, *member*)[¶](#LoadInterface.create_beam_self_weight "Permalink to this definition") Create a self-weight load on a member (beam). * Parameters * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **member** ([`Member`](#Member "viktor.external.axisvm.Member")) – member to create the load on. * Return type [`Load`](#Load "viktor.external.axisvm.Load") ## LoadCombinationInterface[​](/sdk/13/api/external/axisvm/.md#_LoadCombinationInterface "Direct link to LoadCombinationInterface") * *class *viktor.external.axisvm.LoadCombinationInterface[¶](#LoadCombinationInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.load_combinations`](#Model.load_combinations "viktor.external.axisvm.Model.load_combinations") * create(*combination\_type*, *load\_case\_factors*, *\**, *name=None*)[¶](#LoadCombinationInterface.create "Permalink to this definition") Create a load combination from given load cases and factors. * Parameters * **combination\_type** ([`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")) – load combination type. * **load\_case\_factors** (`Dict`\[[`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase"), `float`]) – factorized load cases {load\_case: factor}. * **name** (`Optional`\[`str`]) – name of the load combination (default: auto). * Return type [`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination") ## SectionInterface[​](/sdk/13/api/external/axisvm/.md#_SectionInterface "Direct link to SectionInterface") * *class *viktor.external.axisvm.SectionInterface[¶](#SectionInterface "Permalink to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.sections`](#Model.sections "viktor.external.axisvm.Model.sections") * create(*start\_point*, *end\_point*, *normal\_vector*, *\**, *name=None*)[¶](#SectionInterface.create "Permalink to this definition") Create a section (segment) from coordinates, to obtain results from. * Parameters * **start\_point** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the section’s start point. * **end\_point** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the section’s end point. * **normal\_vector** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) components \[m] of the section plane’s normal vector. * **name** (`Optional`\[`str`]) – name of the section (default: auto). * Return type [`Section`](#Section "viktor.external.axisvm.Section") ## ResultInterface[​](/sdk/13/api/external/axisvm/.md#_ResultInterface "Direct link to ResultInterface") * *class *viktor.external.axisvm.ResultInterface(*nodes*, *node\_supports*, *lines*, *sections*)[¶](#ResultInterface "Permalink to this definition") * nodal\_displacements(*nodes=None*, *\**, *by\_load\_case=True*)[¶](#ResultInterface.nodal_displacements "Permalink to this definition") Request nodal displacements for all load cases or combinations. * Parameters * **nodes** (`Optional`\[`List`\[[`Node`](#Node "viktor.external.axisvm.Node")]]) – nodes to request the results for, or None for all nodes (default: all nodes). * **by\_load\_case** (`bool`) – True to get result on all load cases; False to get results on all load combinations. * Return type `None` - nodal\_support\_forces(*node\_supports=None*, *\**, *by\_load\_case=True*)[¶](#ResultInterface.nodal_support_forces "Permalink to this definition") Request nodal support forces for all load cases or combinations. * Parameters * **node\_supports** (`Optional`\[`List`\[[`NodeSupport`](#NodeSupport "viktor.external.axisvm.NodeSupport")]]) – node supports to request the results for, or None for all node supports (default: all node supports). * **by\_load\_case** (`bool`) – True to get result on all load cases; False to get results on all load combinations. * Return type `None` * line\_forces(*members=None*, *\**, *by\_load\_case=True*)[¶](#ResultInterface.line_forces "Permalink to this definition") Request line forces for all load cases or combinations. * Parameters * **members** (`Optional`\[`List`\[[`Member`](#Member "viktor.external.axisvm.Member")]]) – members to request the results for, or None for all members (default: all members). * **by\_load\_case** (`bool`) – True to get the result on all load cases; False to get results on all load combinations. * Return type `None` - section\_surface\_forces(*sections*, *cases*, *chain\_index=1*)[¶](#ResultInterface.section_surface_forces "Permalink to this definition") Request section chain’s surface forces for given load combinations. * Parameters * **sections** (`List`\[[`Section`](#Section "viktor.external.axisvm.Section")]) – sections to request the results for, or None for all sections (default: all sections). * **cases** (`List`\[[`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination")]) – list of load combinations to request the results for. * **chain\_index** (`int`) – index of the segment chain to request the results for (default: 1). * Return type `None` * section\_surface\_stresses(*sections*, *cases*, *chain\_index=1*)[¶](#ResultInterface.section_surface_stresses "Permalink to this definition") Request section chain’s surface stresses for given load combinations. * Parameters * **sections** (`List`\[[`Section`](#Section "viktor.external.axisvm.Section")]) – sections to request the results for, or None for all sections (default: all sections). * **cases** (`List`\[[`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination")]) – list of load combinations to request the results for. * **chain\_index** (`int`) – index of the segment chain to request the results for (default: 1). * Return type `None` ## Model[​](/sdk/13/api/external/axisvm/.md#_Model "Direct link to Model") * *class *viktor.external.axisvm.Model[¶](#Model "Permalink to this definition") Can be used to construct an AxisVM model, which can be used as input of [`AxisVMAnalysis`](#AxisVMAnalysis "viktor.external.axisvm.AxisVMAnalysis"). Objects are created/modified through the methods on their respective interface (see the properties below for all available interfaces). The following basic actions can be performed on all interfaces (example: node interface): * cast to list, indexing and slicing: > ``` > nodes = list(model.nodes) # List[Node] > node2 = model.nodes[1] # Node > nodes_2_3 = model.nodes[1:3] # List[Node] > ``` * iteration: > ``` > for node in model.nodes: > print(node.id) > ``` * length: > ``` > number_of_nodes = len(model.nodes) > ``` * containment check: > ``` > node_in_model = node in model.nodes # bool > ``` Example usage: ``` model = Model() material = model.materials.add_from_catalog('C12/15', AxisVMMaterial.DesignCode.EURO_CODE) cross_section = model.cross_sections.create_rectangular(0.01, 0.01) n1 = model.nodes.create(0, 0, 0) n2 = model.nodes.create(1, 0, 0) beam = model.lines.create(n1, n2).define_as_beam(material, cross_section) model.node_supports.create_relative_to_member(n1, stiffness_x=1e10, stiffness_y=1e10, stiffness_z=1e10, stiffness_xx=1e10, stiffness_yy=1e10, stiffness_zz=1e10) load_case = model.load_cases.create() model.loads.create_beam_self_weight(load_case, beam) model.results.nodal_displacements([n2]) ``` * *property *references*: [ReferenceInterface](#ReferenceInterface "viktor.external.axisvm.ReferenceInterface")*[¶](#Model.references "Permalink to this definition") Interface for creating reference points, vectors, axes, planes and angles. * Return type [`ReferenceInterface`](#ReferenceInterface "viktor.external.axisvm.ReferenceInterface") - *property *materials*: [MaterialInterface](#MaterialInterface "viktor.external.axisvm.MaterialInterface")*[¶](#Model.materials "Permalink to this definition") Interface for creating materials. * Return type [`MaterialInterface`](#MaterialInterface "viktor.external.axisvm.MaterialInterface") * *property *nodes*: [NodeInterface](#NodeInterface "viktor.external.axisvm.NodeInterface")*[¶](#Model.nodes "Permalink to this definition") Interface for creating nodes. * Return type [`NodeInterface`](#NodeInterface "viktor.external.axisvm.NodeInterface") - *property *cross\_sections*: [CrossSectionInterface](#CrossSectionInterface "viktor.external.axisvm.CrossSectionInterface")*[¶](#Model.cross_sections "Permalink to this definition") Interface for creating cross-sections. * Return type [`CrossSectionInterface`](#CrossSectionInterface "viktor.external.axisvm.CrossSectionInterface") * *property *lines*: [LineInterface](#LineInterface "viktor.external.axisvm.LineInterface")*[¶](#Model.lines "Permalink to this definition") Interface for creating lines, beams, etc. * Return type [`LineInterface`](#LineInterface "viktor.external.axisvm.LineInterface") - *property *domains*: [DomainInterface](#DomainInterface "viktor.external.axisvm.DomainInterface")*[¶](#Model.domains "Permalink to this definition") Interface for creating domains. * Return type [`DomainInterface`](#DomainInterface "viktor.external.axisvm.DomainInterface") * *property *node\_supports*: [NodeSupportInterface](#NodeSupportInterface "viktor.external.axisvm.NodeSupportInterface")*[¶](#Model.node_supports "Permalink to this definition") Interface for creating node supports. * Return type [`NodeSupportInterface`](#NodeSupportInterface "viktor.external.axisvm.NodeSupportInterface") - *property *line\_supports*: [LineSupportInterface](#LineSupportInterface "viktor.external.axisvm.LineSupportInterface")*[¶](#Model.line_supports "Permalink to this definition") Interface for creating line supports. * Return type [`LineSupportInterface`](#LineSupportInterface "viktor.external.axisvm.LineSupportInterface") * *property *load\_cases*: [LoadCaseInterface](#LoadCaseInterface "viktor.external.axisvm.LoadCaseInterface")*[¶](#Model.load_cases "Permalink to this definition") Interface for creating load cases. * Return type [`LoadCaseInterface`](#LoadCaseInterface "viktor.external.axisvm.LoadCaseInterface") - *property *loads*: [LoadInterface](#LoadInterface "viktor.external.axisvm.LoadInterface")*[¶](#Model.loads "Permalink to this definition") Interface for creating loads. * Return type [`LoadInterface`](#LoadInterface "viktor.external.axisvm.LoadInterface") * *property *load\_combinations*: [LoadCombinationInterface](#LoadCombinationInterface "viktor.external.axisvm.LoadCombinationInterface")*[¶](#Model.load_combinations "Permalink to this definition") Interface for creating load combinations. * Return type [`LoadCombinationInterface`](#LoadCombinationInterface "viktor.external.axisvm.LoadCombinationInterface") - *property *sections*: [SectionInterface](#SectionInterface "viktor.external.axisvm.SectionInterface")*[¶](#Model.sections "Permalink to this definition") Interface for creating sections, on which results can be obtained. * Return type [`SectionInterface`](#SectionInterface "viktor.external.axisvm.SectionInterface") * *property *results*: [ResultInterface](#ResultInterface "viktor.external.axisvm.ResultInterface")*[¶](#Model.results "Permalink to this definition") Interface for requesting results from the worker (only requested results will be returned). * Return type [`ResultInterface`](#ResultInterface "viktor.external.axisvm.ResultInterface") --- # viktor.external.dfoundations ## DFoundationsAnalysis[​](/sdk/13/api/external/dfoundations/.md#_DFoundationsAnalysis "Direct link to DFoundationsAnalysis") * *class *viktor.external.dfoundations.DFoundationsAnalysis(*input\_file*)[¶](#DFoundationsAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DFoundationsAnalysis can be used to perform an analysis using D-Foundations on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DFoundationsAnalysis.get_output_file "viktor.external.dfoundations.DFoundationsAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Note: the input for the BytesIO object should be of type bytes. You can convert a string to bytes by calling the method `encode()`. Default encoding is ‘utf-8’. Usage: ``` input_file = BytesIO("dfoundations input file body".encode('utf-8')) dfoundations_analysis = DFoundationsAnalysis(input_file=input_file) dfoundations_analysis.execute(timeout=10) output_file = dfoundations_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – .foi input file. - get\_output\_file(*extension='.fod'*, *\**, *as\_file=False*)[¶](#DFoundationsAnalysis.get_output_file "Permalink to this definition") * Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DFoundationsAnalysis.get_output_file "viktor.external.dfoundations.DFoundationsAnalysis.get_output_file") afterwards. - Parameters * **extension** (`str`) – extension of the file you want to return; one of: ‘.fos’, ‘.fod’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – return as BytesIO (default) or File - Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] - Returns * File, if as\_file = True * BytesIO, if as\_file = False (default) ## SoilType[​](/sdk/13/api/external/dfoundations/.md#_SoilType "Direct link to SoilType") * *class *viktor.external.dfoundations.SoilType(*value*)[¶](#SoilType "Permalink to this definition") Bases: `Enum` An enumeration. * GRAVEL*: [SoilType](#SoilType "viktor.external.dfoundations.SoilType")** = 0*[¶](#SoilType.GRAVEL "Permalink to this definition") - SAND*: [SoilType](#SoilType "viktor.external.dfoundations.SoilType")** = 1*[¶](#SoilType.SAND "Permalink to this definition") * LOAM*: [SoilType](#SoilType "viktor.external.dfoundations.SoilType")** = 2*[¶](#SoilType.LOAM "Permalink to this definition") - CLAY*: [SoilType](#SoilType "viktor.external.dfoundations.SoilType")** = 3*[¶](#SoilType.CLAY "Permalink to this definition") * PEAT*: [SoilType](#SoilType "viktor.external.dfoundations.SoilType")** = 4*[¶](#SoilType.PEAT "Permalink to this definition") ## MaxConeResistType[​](/sdk/13/api/external/dfoundations/.md#_MaxConeResistType "Direct link to MaxConeResistType") * *class *viktor.external.dfoundations.MaxConeResistType(*value*)[¶](#MaxConeResistType "Permalink to this definition") Bases: `Enum` An enumeration. * STANDARD*: [MaxConeResistType](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")** = 0*[¶](#MaxConeResistType.STANDARD "Permalink to this definition") - MANUAL*: [MaxConeResistType](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")** = 1*[¶](#MaxConeResistType.MANUAL "Permalink to this definition") ## CPTRule[​](/sdk/13/api/external/dfoundations/.md#_CPTRule "Direct link to CPTRule") * *class *viktor.external.dfoundations.CPTRule(*value*)[¶](#CPTRule "Permalink to this definition") Bases: `Enum` An enumeration. * NEN*: [CPTRule](#CPTRule "viktor.external.dfoundations.CPTRule")** = 0*[¶](#CPTRule.NEN "Permalink to this definition") - NEN\_STRESS*: [CPTRule](#CPTRule "viktor.external.dfoundations.CPTRule")** = 0*[¶](#CPTRule.NEN_STRESS "Permalink to this definition") * CUR*: [CPTRule](#CPTRule "viktor.external.dfoundations.CPTRule")** = 1*[¶](#CPTRule.CUR "Permalink to this definition") - TYPE\_3*: [CPTRule](#CPTRule "viktor.external.dfoundations.CPTRule")** = 2*[¶](#CPTRule.TYPE_3 "Permalink to this definition") * QC\_ONLY*: [CPTRule](#CPTRule "viktor.external.dfoundations.CPTRule")** = 3*[¶](#CPTRule.QC_ONLY "Permalink to this definition") ## ConstructionSequence[​](/sdk/13/api/external/dfoundations/.md#_ConstructionSequence "Direct link to ConstructionSequence") * *class *viktor.external.dfoundations.ConstructionSequence(*value*)[¶](#ConstructionSequence "Permalink to this definition") Bases: `Enum` An enumeration. * CPT\_EXCAVATION\_INSTALL*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 1*[¶](#ConstructionSequence.CPT_EXCAVATION_INSTALL "Permalink to this definition") - INSTALL\_CPT\_EXCAVATION*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 2*[¶](#ConstructionSequence.INSTALL_CPT_EXCAVATION "Permalink to this definition") * EXCAVATION\_CPT\_INSTALL*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 3*[¶](#ConstructionSequence.EXCAVATION_CPT_INSTALL "Permalink to this definition") - EXCAVATION\_INSTALL\_CPT*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 4*[¶](#ConstructionSequence.EXCAVATION_INSTALL_CPT "Permalink to this definition") * INSTALL\_EXCAVATION\_CPT*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 5*[¶](#ConstructionSequence.INSTALL_EXCAVATION_CPT "Permalink to this definition") - CPT\_INSTALL\_EXCAVATION*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 6*[¶](#ConstructionSequence.CPT_INSTALL_EXCAVATION "Permalink to this definition") * EXCAVATION\_CPT\_BOTH\_BEFORE\_AND\_AFTER\_INSTALL*: [ConstructionSequence](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 7*[¶](#ConstructionSequence.EXCAVATION_CPT_BOTH_BEFORE_AND_AFTER_INSTALL "Permalink to this definition") ## CalculationType[​](/sdk/13/api/external/dfoundations/.md#_CalculationType "Direct link to CalculationType") * *class *viktor.external.dfoundations.CalculationType(*value*)[¶](#CalculationType "Permalink to this definition") Bases: `Enum` An enumeration. * DESIGN\_CALCULATION*: [CalculationType](#CalculationType "viktor.external.dfoundations.CalculationType")** = 0*[¶](#CalculationType.DESIGN_CALCULATION "Permalink to this definition") - COMPLETE\_CALCULATION*: [CalculationType](#CalculationType "viktor.external.dfoundations.CalculationType")** = 1*[¶](#CalculationType.COMPLETE_CALCULATION "Permalink to this definition") * INDICATION\_BEARING\_CAPACITY*: [CalculationType](#CalculationType "viktor.external.dfoundations.CalculationType")** = 2*[¶](#CalculationType.INDICATION_BEARING_CAPACITY "Permalink to this definition") - BEARING\_CAPACITY\_AT\_FIXED\_PILE\_TIP\_LEVEL*: [CalculationType](#CalculationType "viktor.external.dfoundations.CalculationType")** = 3*[¶](#CalculationType.BEARING_CAPACITY_AT_FIXED_PILE_TIP_LEVEL "Permalink to this definition") * PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY*: [CalculationType](#CalculationType "viktor.external.dfoundations.CalculationType")** = 4*[¶](#CalculationType.PILE_TIP_LEVEL_AND_NET_BEARING_CAPACITY "Permalink to this definition") ## PileType[​](/sdk/13/api/external/dfoundations/.md#_PileType "Direct link to PileType") * *class *viktor.external.dfoundations.PileType(*value*)[¶](#PileType "Permalink to this definition") Bases: `Enum` An enumeration. * PREFAB\_CONCRETE*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 0*[¶](#PileType.PREFAB_CONCRETE "Permalink to this definition") - CLOSED\_STEEL*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 1*[¶](#PileType.CLOSED_STEEL "Permalink to this definition") * DRIVEN\_TUBE\_BACK\_DRIVING*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 2*[¶](#PileType.DRIVEN_TUBE_BACK_DRIVING "Permalink to this definition") - DRIVEN\_TUBE\_BACK\_VIBRATION*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 3*[¶](#PileType.DRIVEN_TUBE_BACK_VIBRATION "Permalink to this definition") * TAPERED\_TIMBER*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 4*[¶](#PileType.TAPERED_TIMBER "Permalink to this definition") - STRAIGHT\_TIMBER*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 5*[¶](#PileType.STRAIGHT_TIMBER "Permalink to this definition") * SCREW\_LOST\_TIP*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 6*[¶](#PileType.SCREW_LOST_TIP "Permalink to this definition") - SCREW\_WITH\_GROUT*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 7*[¶](#PileType.SCREW_WITH_GROUT "Permalink to this definition") * PREFAB\_WITH\_GROUT*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 8*[¶](#PileType.PREFAB_WITH_GROUT "Permalink to this definition") - PREFAB\_WITHOUT\_GROUT*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 9*[¶](#PileType.PREFAB_WITHOUT_GROUT "Permalink to this definition") * STEEL*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 10*[¶](#PileType.STEEL "Permalink to this definition") - CONTINUOUS\_FLIGHT\_AUGER*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 11*[¶](#PileType.CONTINUOUS_FLIGHT_AUGER "Permalink to this definition") * BORED\_DRILLING*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 12*[¶](#PileType.BORED_DRILLING "Permalink to this definition") - BORED\_SHELLING*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 13*[¶](#PileType.BORED_SHELLING "Permalink to this definition") * OPEN\_STEEL*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 14*[¶](#PileType.OPEN_STEEL "Permalink to this definition") - MV*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 15*[¶](#PileType.MV "Permalink to this definition") * MICRO\_DOUBLE\_EXTORTED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 16*[¶](#PileType.MICRO_DOUBLE_EXTORTED "Permalink to this definition") - MICRO\_DOUBLE\_NOT\_EXTORTED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 17*[¶](#PileType.MICRO_DOUBLE_NOT_EXTORTED "Permalink to this definition") * MICRO\_SINGLE\_EXTORTED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 18*[¶](#PileType.MICRO_SINGLE_EXTORTED "Permalink to this definition") - MICRO\_SINGLE\_NOT\_EXTORTED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 19*[¶](#PileType.MICRO_SINGLE_NOT_EXTORTED "Permalink to this definition") * MICRO\_ANCHOR\_BORED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 20*[¶](#PileType.MICRO_ANCHOR_BORED "Permalink to this definition") - MICRO\_ANCHOR\_SCREWED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 21*[¶](#PileType.MICRO_ANCHOR_SCREWED "Permalink to this definition") * MICRO\_VIBRATED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 22*[¶](#PileType.MICRO_VIBRATED "Permalink to this definition") - GROUTED\_STEEL\_PROFILE*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 23*[¶](#PileType.GROUTED_STEEL_PROFILE "Permalink to this definition") * GROUTED\_STEEL\_PIPE*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 24*[¶](#PileType.GROUTED_STEEL_PIPE "Permalink to this definition") - USER\_DEFINED\_VIBRATING*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 25*[¶](#PileType.USER_DEFINED_VIBRATING "Permalink to this definition") * USER\_DEFINED\_LOW\_VIBRATING*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 26*[¶](#PileType.USER_DEFINED_LOW_VIBRATING "Permalink to this definition") - USER\_DEFINED*: [PileType](#PileType "viktor.external.dfoundations.PileType")** = 27*[¶](#PileType.USER_DEFINED "Permalink to this definition") ## PileTypeClayLoamPeat[​](/sdk/13/api/external/dfoundations/.md#_PileTypeClayLoamPeat "Direct link to PileTypeClayLoamPeat") * *class *viktor.external.dfoundations.PileTypeClayLoamPeat(*value*)[¶](#PileTypeClayLoamPeat "Permalink to this definition") Bases: `Enum` An enumeration. * ACCORDING\_TO\_STANDARD*: [PileTypeClayLoamPeat](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")** = 0*[¶](#PileTypeClayLoamPeat.ACCORDING_TO_STANDARD "Permalink to this definition") - USER\_DEFINED*: [PileTypeClayLoamPeat](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")** = 1*[¶](#PileTypeClayLoamPeat.USER_DEFINED "Permalink to this definition") ## PileLoadSettlementCurve[​](/sdk/13/api/external/dfoundations/.md#_PileLoadSettlementCurve "Direct link to PileLoadSettlementCurve") * *class *viktor.external.dfoundations.PileLoadSettlementCurve(*value*)[¶](#PileLoadSettlementCurve "Permalink to this definition") Bases: `Enum` An enumeration. * ONE*: [PileLoadSettlementCurve](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 0*[¶](#PileLoadSettlementCurve.ONE "Permalink to this definition") - TWO*: [PileLoadSettlementCurve](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 1*[¶](#PileLoadSettlementCurve.TWO "Permalink to this definition") * THREE*: [PileLoadSettlementCurve](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 2*[¶](#PileLoadSettlementCurve.THREE "Permalink to this definition") ## PileMaterial[​](/sdk/13/api/external/dfoundations/.md#_PileMaterial "Direct link to PileMaterial") * *class *viktor.external.dfoundations.PileMaterial(*value*)[¶](#PileMaterial "Permalink to this definition") Bases: `Enum` An enumeration. * CONCRETE*: [PileMaterial](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 0*[¶](#PileMaterial.CONCRETE "Permalink to this definition") - STEEL*: [PileMaterial](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 1*[¶](#PileMaterial.STEEL "Permalink to this definition") * TIMBER*: [PileMaterial](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 2*[¶](#PileMaterial.TIMBER "Permalink to this definition") - WOOD*: [PileMaterial](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 2*[¶](#PileMaterial.WOOD "Permalink to this definition") * USER\_DEFINED*: [PileMaterial](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 3*[¶](#PileMaterial.USER_DEFINED "Permalink to this definition") ## PileSlipLayer[​](/sdk/13/api/external/dfoundations/.md#_PileSlipLayer "Direct link to PileSlipLayer") * *class *viktor.external.dfoundations.PileSlipLayer(*value*)[¶](#PileSlipLayer "Permalink to this definition") Bases: `Enum` An enumeration. * NONE*: [PileSlipLayer](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 0*[¶](#PileSlipLayer.NONE "Permalink to this definition") - SYNTHETIC*: [PileSlipLayer](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 1*[¶](#PileSlipLayer.SYNTHETIC "Permalink to this definition") * BENTONITE*: [PileSlipLayer](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 2*[¶](#PileSlipLayer.BENTONITE "Permalink to this definition") - BITUMEN*: [PileSlipLayer](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 3*[¶](#PileSlipLayer.BITUMEN "Permalink to this definition") * USER\_DEFINED*: [PileSlipLayer](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 4*[¶](#PileSlipLayer.USER_DEFINED "Permalink to this definition") ## Metadata[​](/sdk/13/api/external/dfoundations/.md#_Metadata "Direct link to Metadata") * *class *viktor.external.dfoundations.Metadata(*file\_name='-'*, *company='-'*, *title\_1='-'*, *title\_2='-'*, *geotechnical\_consultant=''*, *design\_engineer=''*, *principal=''*, *project\_id=''*, *location=''*, *current\_date=False*, *current\_time=False*)[¶](#Metadata "Permalink to this definition") Data container for metadata to be added to the D-Foundations input file. * Parameters * **file\_name** (`str`) – file name, as shown in the input file header * **company** (`str`) – company name, as shown in the input file header * **title\_1** (`str`) – * **title\_2** (`str`) – * **geotechnical\_consultant** (`str`) – * **design\_engineer** (`str`) – * **principal** (`str`) – * **project\_id** (`str`) – * **location** (`str`) – * **current\_date** (`bool`) – date, as shown in the input file header * **current\_time** (`bool`) – time, as shown in the input file header ## BearingPilesCalculationOptions[​](/sdk/13/api/external/dfoundations/.md#_BearingPilesCalculationOptions "Direct link to BearingPilesCalculationOptions") * *class *viktor.external.dfoundations.BearingPilesCalculationOptions(*calculation\_type*, *rigid*, *max\_allowed\_settlement\_str\_geo=150*, *max\_allowed\_settlement\_sls=150*, *max\_allowed\_relative\_rotation\_str\_geo=100*, *max\_allowed\_relative\_rotation\_sls=300*, *\**, *xi3=None*, *xi4=None*, *gamma\_b=None*, *gamma\_s=None*, *gamma\_fnk=None*, *area=None*, *e\_ea\_gem=None*, *write\_intermediate\_results=False*, *use\_pile\_group=True*, *overrule\_excavation=False*, *suppress\_qciii\_reduction=False*, *use\_almere\_rules=False*, *use\_extra\_almere\_rules=False*, *trajectory\_begin\_end\_interval=None*, *net\_bearing\_capacity=None*, *cpt\_test\_level=None*)[¶](#BearingPilesCalculationOptions "Permalink to this definition") Bases: `_CalculationOptions` * Parameters * **calculation\_type** ([`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")) – * **rigid** (`bool`) – True for rigid, False for non-rigid * **max\_allowed\_settlement\_str\_geo** (`int`) – \[mm] * **max\_allowed\_relative\_rotation\_str\_geo** (`int`) – 1 : \[-] * **max\_allowed\_settlement\_sls** (`int`) – \[mm] * **max\_allowed\_relative\_rotation\_sls** (`int`) – 1 : \[-] * **xi3** (`Optional`\[`float`]) – ξ\_3 \[-] * **xi4** (`Optional`\[`float`]) – ξ\_4 \[-] * **gamma\_b** (`Optional`\[`float`]) – γ\_b \[-] * **gamma\_s** (`Optional`\[`float`]) – γ\_s \[-] * **gamma\_fnk** (`Optional`\[`float`]) – γ\_f;nk \[-] * **area** (`Optional`\[`float`]) – \[m²] * **e\_ea\_gem** (`Optional`\[`float`]) – E\_ea;gem \[kN/m2] * **write\_intermediate\_results** (`bool`) – * **use\_pile\_group** (`bool`) – * **overrule\_excavation** (`bool`) – * **suppress\_qciii\_reduction** (`bool`) – * **use\_almere\_rules** (`bool`) – * **use\_extra\_almere\_rules** (`bool`) – * **trajectory\_begin\_end\_interval** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – tuple(\[m], \[m], \[m]) * **net\_bearing\_capacity** (`Optional`\[`int`]) – \[kN] * **cpt\_test\_level** (`Optional`\[`float`]) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘calculation\_type’ is DESIGN\_CALCULATION or INDICATION\_BEARING\_CAPACITY or PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and trajectory\_begin\_end\_interval’ is not set. * if the number of iterations > 151, based on the provided ‘trajectory\_begin\_end\_interval’. * if ‘calculation\_type’ is PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘net\_bearing\_capacity’ is not set. * if ‘calculation\_type’ is DESIGN\_CALCULATION or COMPLETE\_CALCULATION and ‘cpt\_test\_level’ is not set. ## TensionPilesCalculationOptions[​](/sdk/13/api/external/dfoundations/.md#_TensionPilesCalculationOptions "Direct link to TensionPilesCalculationOptions") * *class *viktor.external.dfoundations.TensionPilesCalculationOptions(*calculation\_type*, *rigid*, *unit\_weight\_water=9.81*, *surcharge=0.0*, *\**, *xi3=None*, *xi4=None*, *gamma\_m\_var\_qc=None*, *gamma\_st=None*, *gamma\_gamma=None*, *use\_compaction=False*, *overrule\_excavation=False*, *overrule\_excess\_pore\_pressure=True*, *trajectory\_begin\_end\_interval=None*, *net\_bearing\_capacity=None*)[¶](#TensionPilesCalculationOptions "Permalink to this definition") Bases: `_CalculationOptions` Data container for the calculation options for a Tension Piles (EC7-NL) model. * Parameters * **calculation\_type** ([`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")) – valid types: * CalculationType.INDICATION\_BEARING\_CAPACITY * CalculationType.BEARING\_CAPACITY\_AT\_FIXED\_PILE\_TIP\_LEVEL * CalculationType.PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY * **rigid** (`bool`) – True for rigid, False for non-rigid * **unit\_weight\_water** (`float`) – \[kN/m3] * **surcharge** (`float`) – \[kN/m2] * **xi3** (`Optional`\[`float`]) – ξ\_3 \[-] * **xi4** (`Optional`\[`float`]) – ξ\_4 \[-] * **gamma\_m\_var\_qc** (`Optional`\[`float`]) – γ\_m;var;qc \[-] * **gamma\_st** (`Optional`\[`float`]) – γ\_st \[-] * **gamma\_gamma** (`Optional`\[`float`]) – γ\_γ \[-] * **overrule\_excavation** (`bool`) – * **use\_compaction** (`bool`) – * **overrule\_excess\_pore\_pressure** (`bool`) – * **trajectory\_begin\_end\_interval** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – tuple(\[m], \[m], \[m]) * **net\_bearing\_capacity** (`Optional`\[`int`]) – \[kN] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘calculation\_type’ is not one of the valid types. * if ‘calculation\_type’ is INDICATION\_BEARING\_CAPACITY or PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘trajectory\_begin\_end\_interval’ is not set. * if the number of iterations > 151, based on the provided ‘trajectory\_begin\_end\_interval’. * if ‘calculation\_type’ is PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘net\_bearing\_capacity’ is not set. ## ProfileLayer[​](/sdk/13/api/external/dfoundations/.md#_ProfileLayer "Direct link to ProfileLayer") * *class *viktor.external.dfoundations.ProfileLayer(*top\_level*, *material*, *ad\_pore\_pressure\_at\_top=0.0*, *ad\_pore\_pressure\_at\_bottom=0.0*, *ocr=1.0*)[¶](#ProfileLayer "Permalink to this definition") Data container for a single layer within a profile. * Parameters * **top\_level** (`float`) – \[m] * **material** (`str`) – name of the material. * **ad\_pore\_pressure\_at\_top** (`float`) – \[kN/m2]. Tensions Piles (EC7-NL) model only. Ignored for other model types. * **ad\_pore\_pressure\_at\_bottom** (`float`) – \[kN/m2]. Tensions Piles (EC7-NL) model only. Ignored for other model types. * **ocr** (`float`) – \[-]. Tensions Piles (EC7-NL) model only. Ignored for other model types. - *property *material*: str*[¶](#ProfileLayer.material "Permalink to this definition") * Return type `str` ## RectPile[​](/sdk/13/api/external/dfoundations/.md#_RectPile "Direct link to RectPile") * *class *viktor.external.dfoundations.RectPile(*width*, *length*)[¶](#RectPile "Permalink to this definition") Bases: `_PileShape` Rectangular pile. * Parameters * **width** (`float`) – \[m] * **length** (`float`) – \[m] ## RectEnlPile[​](/sdk/13/api/external/dfoundations/.md#_RectEnlPile "Direct link to RectEnlPile") * *class *viktor.external.dfoundations.RectEnlPile(*base\_width*, *base\_length*, *base\_height*, *shaft\_width*, *shaft\_length*)[¶](#RectEnlPile "Permalink to this definition") Bases: `_PileShape` Round pile with enlarged base. * Parameters * **base\_width** (`float`) – \[m] * **base\_length** (`float`) – \[m] * **base\_height** (`float`) – \[m] * **shaft\_width** (`float`) – \[m]. Must be smaller than ‘base\_width’. * **shaft\_length** (`float`) – \[m]. Must be smaller than ‘base\_length’. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘shaft\_width’ is not smaller than ‘base\_width’. * if ‘shaft\_length’ is not smaller than ‘base\_length’. ## SectionPile[​](/sdk/13/api/external/dfoundations/.md#_SectionPile "Direct link to SectionPile") * *class *viktor.external.dfoundations.SectionPile(*width*, *length*)[¶](#SectionPile "Permalink to this definition") Bases: [`RectPile`](#RectPile "viktor.external.dfoundations.RectPile") Section pile. Rectangular pile. * Parameters * **width** (`float`) – \[m] * **length** (`float`) – \[m] ## UserPile[​](/sdk/13/api/external/dfoundations/.md#_UserPile "Direct link to UserPile") * *class *viktor.external.dfoundations.UserPile(*circumference*, *cross\_section*)[¶](#UserPile "Permalink to this definition") Bases: `_PileShape` User defined pile. * Parameters * **circumference** (`float`) – \[m] * **cross\_section** (`float`) – \[m2] ## RoundPile[​](/sdk/13/api/external/dfoundations/.md#_RoundPile "Direct link to RoundPile") * *class *viktor.external.dfoundations.RoundPile(*diameter*)[¶](#RoundPile "Permalink to this definition") Bases: `_PileShape` Round pile. * Parameters **diameter** (`float`) – \[m] ## TaperPile[​](/sdk/13/api/external/dfoundations/.md#_TaperPile "Direct link to TaperPile") * *class *viktor.external.dfoundations.TaperPile(*diameter\_tip*, *increase*)[¶](#TaperPile "Permalink to this definition") Bases: `_PileShape` Round tapered pile. * Parameters * **diameter\_tip** (`float`) – \[m] * **increase** (`float`) – \[m/m’] ## HollowPile[​](/sdk/13/api/external/dfoundations/.md#_HollowPile "Direct link to HollowPile") * *class *viktor.external.dfoundations.HollowPile(*external\_diameter*, *wall\_thickness*)[¶](#HollowPile "Permalink to this definition") Bases: `_PileShape` Round hollow pile with closed base. * Parameters * **external\_diameter** (`float`) – \[m] * **wall\_thickness** (`float`) – \[mm]. Must be smaller than half of ‘external\_diameter’. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘wall\_thickness’ is not smaller than half of ‘external\_diameter’. - *property *internal\_diameter*: float*[¶](#HollowPile.internal_diameter "Permalink to this definition") * Return type `float` ## HollowOpenPile[​](/sdk/13/api/external/dfoundations/.md#_HollowOpenPile "Direct link to HollowOpenPile") * *class *viktor.external.dfoundations.HollowOpenPile(*external\_diameter*, *wall\_thickness*)[¶](#HollowOpenPile "Permalink to this definition") Bases: `_PileShape` Round open-ended hollow pile. * Parameters * **external\_diameter** (`float`) – \[m] * **wall\_thickness** (`float`) – \[mm]. Must be smaller than half of ‘external\_diameter’. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘wall\_thickness’ is not smaller than half of ‘external\_diameter’. - *property *internal\_diameter*: float*[¶](#HollowOpenPile.internal_diameter "Permalink to this definition") * Return type `float` ## LostTipPile[​](/sdk/13/api/external/dfoundations/.md#_LostTipPile "Direct link to LostTipPile") * *class *viktor.external.dfoundations.LostTipPile(*base\_diameter*, *pile\_diameter*)[¶](#LostTipPile "Permalink to this definition") Bases: `_PileShape` Round pile with lost tip. * Parameters * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## RoundEnlPile[​](/sdk/13/api/external/dfoundations/.md#_RoundEnlPile "Direct link to RoundEnlPile") * *class *viktor.external.dfoundations.RoundEnlPile(*base\_diameter*, *pile\_diameter*, *base\_height*)[¶](#RoundEnlPile "Permalink to this definition") Bases: [`LostTipPile`](#LostTipPile "viktor.external.dfoundations.LostTipPile") Round pile with enlarged base. * Parameters * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * **base\_height** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## DrivenBasePile[​](/sdk/13/api/external/dfoundations/.md#_DrivenBasePile "Direct link to DrivenBasePile") * *class *viktor.external.dfoundations.DrivenBasePile(*base\_diameter*, *pile\_diameter*, *base\_height*)[¶](#DrivenBasePile "Permalink to this definition") Bases: [`RoundEnlPile`](#RoundEnlPile "viktor.external.dfoundations.RoundEnlPile") Round pile with in situ formed base. Round pile with enlarged base. * Parameters * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * **base\_height** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## HShapedPile[​](/sdk/13/api/external/dfoundations/.md#_HShapedPile "Direct link to HShapedPile") * *class *viktor.external.dfoundations.HShapedPile(*height*, *width*, *thickness\_web*, *thickness\_flange*)[¶](#HShapedPile "Permalink to this definition") Bases: `_PileShape` H-shaped profile. * Parameters * **height** (`float`) – \[m] * **width** (`float`) – \[m] * **thickness\_web** (`float`) – \[mm]. Must be smaller than ‘width’. * **thickness\_flange** (`float`) – \[mm]. Must be smaller than half of ‘height’. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘thickness\_web’ is not smaller than ‘width’. * if ‘thickness\_flange’ is not smaller than half of ‘height’. ## BearingPilesModel[​](/sdk/13/api/external/dfoundations/.md#_BearingPilesModel "Direct link to BearingPilesModel") * *class *viktor.external.dfoundations.BearingPilesModel(*construction\_sequence*, *calculation\_options*, *excavation\_level*, *reduction\_cone\_resistance=None*, *\**, *create\_default\_materials=True*)[¶](#BearingPilesModel "Permalink to this definition") Bases: `_Model` Create a Bearing Piles (EC7-NL) model. * Parameters * **construction\_sequence** ([`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")) – * **calculation\_options** ([`BearingPilesCalculationOptions`](#BearingPilesCalculationOptions "viktor.external.dfoundations.BearingPilesCalculationOptions")) – * **excavation\_level** (`float`) – \[m] * **reduction\_cone\_resistance** (`Optional`\[`float`]) – Distance edge pile to excavation boundary \[m] to implement ‘Begemann’. ‘None’ to implement ‘Safe (NEN)’. * **create\_default\_materials** (`bool`) – whether to start with the default D-Foundations materials. The default materials are: > * BClay, clean, moderate > > * BClay, clean, modstiff > > * BClay, clean, stiff > > * BClay, clean, weak > > * BClay, sl san, moderate > > * BClay, sl san, modstiff > > * BClay, sl san, stiff > > * BClay, sl san, weak > > * BGravel, clean, moderate > > * BGravel, clean, stiff > > * BGravel, ve sil, moderate > > * BGravel, ve sil, stiff > > * BLoam, clean, moderate > > * BLoam, clean, modstiff > > * BLoam, clean, stiff > > * BLoam, clean, weak > > * BLoam, sl san, moderate > > * BLoam, sl san, modstiff > > * BLoam, sl san, stiff > > * BLoam, sl san, weak > > * BPeat, sl san, moderate > > * BPeat, sl san, stiff > > * BPeat, sl san, weak > > * BSand, clean, loose > > * BSand, clean, moderate > > * BSand, clean, stiff > > * BSand, ve sil, loose > > * BSand, ve sil, moderate > > * BSand, ve sil, stiff > > * Clay, clean, moderate > > * Clay, clean, stiff > > * Clay, clean, weak > > * Clay, organ, moderate > > * Clay, organ, weak > > * Clay, sl san, moderate > > * Clay, sl san, stiff > > * Clay, sl san, weak > > * Clay, ve san, stiff > > * Gravel, sl sil, loose > > * Gravel, sl sil, moderate > > * Gravel, sl sil, stiff > > * Gravel, ve sil, loose > > * Gravel, ve sil, moderate > > * Gravel, ve sil, stiff > > * Loam, sl san, moderate > > * Loam, sl san, stiff > > * Loam, sl san, weak > > * Loam, ve san, stiff > > * Peat, mod pl, moderate > > * Peat, not pl, weak > > * Sand, clean, loose > > * Sand, clean, moderate > > * Sand, clean, stiff > > * Sand, sl sil, moderate > > * Sand, ve sil, loose * materials[¶](#BearingPilesModel.materials "Permalink to this definition") Lists all materials currently in de model. * Return type `Dict`\[`str`, `Dict`\[`str`, `Any`]] - profiles[¶](#BearingPilesModel.profiles "Permalink to this definition") Lists all profiles currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] * pile\_types[¶](#BearingPilesModel.pile_types "Permalink to this definition") Lists all pile types currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] - piles[¶](#BearingPilesModel.piles "Permalink to this definition") Lists all piles currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] * generate\_input\_file(*metadata=None*, *\**, *as\_file=False*)[¶](#BearingPilesModel.generate_input_file "Permalink to this definition") Generate a D-Foundations input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **metadata** (`Optional`\[[`Metadata`](#Metadata "viktor.external.dfoundations.Metadata")]) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **as\_file** (`bool`) – return as BytesIO (default) or File * Return type `Union`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `BytesIO`] - create\_material(*name*, *soil\_type*, *gamma\_unsat*, *gamma\_sat*, *friction\_angle*, *diameter\_d50=0.2*, *color=None*)[¶](#BearingPilesModel.create_material "Permalink to this definition") Create a material with the given name and properties. * Parameters * **name** (`str`) – name of the material to create (max. 25 characters) * **soil\_type** ([`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")) – \[-] * **gamma\_unsat** (`float`) – gamma-unsaturated, dry \[kN/m³] * **gamma\_sat** (`float`) – gamma-saturated, wet \[kN/m³] * **friction\_angle** (`float`) – phi \[degree] * **diameter\_d50** (`float`) – median \[mm] * **color** (`Optional`\[[`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")]) – color for visualization in deltares software (None for default color ‘white’) * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type `None` * create\_profile(*name*, *layers*, *x*, *y*, *measurements*, *phreatic\_level*, *pile\_tip\_level*, *overconsolidation\_ratio*, *top\_positive\_skin\_friction*, *bottom\_negative\_skin\_friction*, *expected\_ground\_level\_settlement*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[¶](#BearingPilesModel.create_profile "Permalink to this definition") Create a profile manually. * Parameters * **name** (`str`) – name of the profile (must be unique). * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **measurements** (`List`\[`Tuple`\[`float`, `float`]]) – list of measurement data (level \[m], qc-value \[MPa]). * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **overconsolidation\_ratio** (`float`) – overconsolidation ratio of bearing zone \[-] * **top\_positive\_skin\_friction** (`float`) – top of positive skin friction \[m] * **bottom\_negative\_skin\_friction** (`float`) – bottom of negative skin friction \[m] * **expected\_ground\_level\_settlement** (`float`) – \[m] * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) – * **min\_layer\_thickness** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * Return type `None` - import\_profile(*cpt*, *layers*, *x*, *y*, *phreatic\_level*, *pile\_tip\_level*, *overconsolidation\_ratio*, *top\_positive\_skin\_friction*, *bottom\_negative\_skin\_friction*, *expected\_ground\_level\_settlement*, *name=None*, *manual\_ground\_level=None*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[¶](#BearingPilesModel.import_profile "Permalink to this definition") Create a profile by importing a CPT-file. * Parameters * **cpt** ([`GEFData`](/sdk/13/api/geo/.md#GEFData "viktor.geo.GEFData")) – CPT file to import. * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **overconsolidation\_ratio** (`float`) – overconsolidation ratio of bearing zone \[-] * **top\_positive\_skin\_friction** (`float`) – top of positive skin friction \[m] * **bottom\_negative\_skin\_friction** (`float`) – bottom of negative skin friction \[m] * **expected\_ground\_level\_settlement** (`float`) – \[m] * **name** (`Optional`\[`str`]) – name of the profile (must be unique). None for default (name of the cpt). * **manual\_ground\_level** (`Optional`\[`float`]) – set to override the ground level \[m] from the cpt. * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) – * **min\_layer\_thickness** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * if ground level could not be read from cpt file. * Return type `None` * create\_pile\_type(*name*, *shape*, *pile\_type*, *slip\_layer*, *type\_sand\_gravel=None*, *type\_clay\_loam\_peat=None*, *type\_p=None*, *load\_settlement\_curve=None*, *material=None*, *factor\_sand\_gravel=None*, *factor\_clay\_loam\_peat=None*, *factor\_pile\_class=None*, *e\_modulus=None*, *slip\_layer\_adhesion=None*, *\**, *use\_pre\_2016=False*, *as\_prefab=False*, *qciii\_reduction=None*, *overrule\_tip\_section\_factor=None*, *overrule\_tip\_shape\_factor=None*)[¶](#BearingPilesModel.create_pile_type "Permalink to this definition") Create a pile type with the given properties. * Parameters * **name** (`str`) – name of the pile type. Must be unique. Max. 10 characters. * **shape** (`_PileShape`) – pile type shape class instance. See below for possible shapes. * **pile\_type** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – predefined/user-defined pile type. Only certain types are valid in combination with the provided ‘shape’. For more information on valid combinations, please refer to the D-Foundations software. * **slip\_layer** ([`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")) – * **type\_sand\_gravel** (`Optional`\[[`PileType`](#PileType "viktor.external.dfoundations.PileType")]) – pile type for α\_s sand/gravel * **type\_clay\_loam\_peat** (`Optional`\[[`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")]) – pile type for α\_s clay/loam/peat * **type\_p** (`Optional`\[[`PileType`](#PileType "viktor.external.dfoundations.PileType")]) – pile type for α\_p * **load\_settlement\_curve** (`Optional`\[[`PileLoadSettlementCurve`](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")]) – * **material** (`Optional`\[[`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")]) – * **factor\_sand\_gravel** (`Optional`\[`float`]) – α\_s \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **factor\_clay\_loam\_peat** (`Optional`\[`float`]) – α\_s \[-]. Only required if ‘type\_clay\_loam\_peat’ is of type user-defined. * **factor\_pile\_class** (`Optional`\[`float`]) – α\_p \[-]. Only required if ‘type\_p’ is of type user-defined. * **e\_modulus** (`Optional`\[`float`]) – Young’s modulus \[kN/m2]. Only required if ‘material’ is of type user-defined. * **slip\_layer\_adhesion** (`Optional`\[`float`]) – Representative cohesion \[kN/m2]. Only required if ‘slip\_layer’ is of type user-defined. * **use\_pre\_2016** (`bool`) – * **as\_prefab** (`bool`) – * **qciii\_reduction** (`Optional`\[`float`]) – \[%] * **overrule\_tip\_section\_factor** (`Optional`\[`float`]) – Pile top cross section factor (s) \[-] * **overrule\_tip\_shape\_factor** (`Optional`\[`float`]) – Pile tip shape factor (β) \[-] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘pile\_type’ is of type user-defined and ‘type\_sand\_gravel’ is not set. * if ‘pile\_type’ is of type user-defined and ‘type\_clay\_loam\_peat’ is not set. * if ‘pile\_type’ is of type user-defined and ‘material’ is not set. * if ‘pile\_type’ is of type user-defined and ‘type\_p’ is not set. * if ‘pile\_type’ is of type user-defined and ‘load\_settlement\_curve’ is not set. * if ‘type\_sand\_gravel’ is of type user-defined and ‘factor\_sand\_gravel’ is not set. * if ‘type\_clay\_loam\_peat’ is of type user-defined and ‘factor\_clay\_loam\_peat’ is not set. * if ‘material’ is of type user-defined and ‘e\_modulus’ is not set. * if ‘type\_p’ is of type user-defined and ‘factor\_pile\_class’ is not set. * if ‘slip\_layer’ is of type user-defined and ‘slip\_layer\_adhesion’ is not set. * if an invalid ‘shape’ is provided. * if a ‘pile\_type’ is provided that is invalid in combination with the given ‘shape’. * if one of the types PileType.USER\_DEFINED\_VIBRATING or PileType.USER\_DEFINED\_LOW\_VIBRATING is selected for ‘type\_sand\_gravel’ or ‘type\_p’ (no valid options). * if a pile type with the give name already exists. * if ‘factor\_sand\_gravel’, ‘factor\_clay\_loam\_peat’ or ‘factor\_pile\_class’ is outside valid range 0-9. * if ‘overrule\_tip\_section\_factor’ or ‘overrule\_tip\_shape\_factor’ is outside valid range 0-10. Possible shapes are: > * RectPile > > * RectEnlPile > > * SectionPile > > * RoundPile > > * TaperPile > > * HollowPile > > * HollowOpenPile > > * RoundEnlPile > > * LostTipPile > > * DrivenBasePile > > * HShapedPile * Return type `None` - create\_pile(*name*, *x*, *y*, *pile\_head\_level*, *surcharge*, *limit\_state\_str\_geo*, *serviceability\_limit\_state*)[¶](#BearingPilesModel.create_pile "Permalink to this definition") Create a pile with given properties. * Parameters * **name** (`str`) – name of the pile. Must be unique. Max. 10 characters. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **pile\_head\_level** (`float`) – \[m R.L.] * **surcharge** (`float`) – \[kN/m2] * **limit\_state\_str\_geo** (`float`) – Limit state STR/GEO \[kN] * **serviceability\_limit\_state** (`float`) – \[kN] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if pile with given name already exists. * if name exceeds the max. number of characters (10). * Return type `None` ## TensionPilesModel[​](/sdk/13/api/external/dfoundations/.md#_TensionPilesModel "Direct link to TensionPilesModel") * *class *viktor.external.dfoundations.TensionPilesModel(*construction\_sequence*, *calculation\_options*, *excavation\_level*, *reduction\_cone\_resistance=None*, *\**, *create\_default\_materials=True*)[¶](#TensionPilesModel "Permalink to this definition") Bases: `_Model` Create a Tension Piles (EC7-NL) model. * Parameters * **construction\_sequence** ([`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")) – * **calculation\_options** ([`TensionPilesCalculationOptions`](#TensionPilesCalculationOptions "viktor.external.dfoundations.TensionPilesCalculationOptions")) – * **excavation\_level** (`float`) – \[m] * **reduction\_cone\_resistance** (`Optional`\[`float`]) – Distance edge pile to excavation boundary \[m] to implement ‘Begemann’. ‘None’ to implement ‘Safe (NEN)’. * **create\_default\_materials** (`bool`) – whether to start with the default D-Foundations materials. The default materials are: > * BClay, clean, moderate > > * BClay, clean, modstiff > > * BClay, clean, stiff > > * BClay, clean, weak > > * BClay, sl san, moderate > > * BClay, sl san, modstiff > > * BClay, sl san, stiff > > * BClay, sl san, weak > > * BGravel, clean, moderate > > * BGravel, clean, stiff > > * BGravel, ve sil, moderate > > * BGravel, ve sil, stiff > > * BLoam, clean, moderate > > * BLoam, clean, modstiff > > * BLoam, clean, stiff > > * BLoam, clean, weak > > * BLoam, sl san, moderate > > * BLoam, sl san, modstiff > > * BLoam, sl san, stiff > > * BLoam, sl san, weak > > * BPeat, sl san, moderate > > * BPeat, sl san, stiff > > * BPeat, sl san, weak > > * BSand, clean, loose > > * BSand, clean, moderate > > * BSand, clean, stiff > > * BSand, ve sil, loose > > * BSand, ve sil, moderate > > * BSand, ve sil, stiff > > * Clay, clean, moderate > > * Clay, clean, stiff > > * Clay, clean, weak > > * Clay, organ, moderate > > * Clay, organ, weak > > * Clay, sl san, moderate > > * Clay, sl san, stiff > > * Clay, sl san, weak > > * Clay, ve san, stiff > > * Gravel, sl sil, loose > > * Gravel, sl sil, moderate > > * Gravel, sl sil, stiff > > * Gravel, ve sil, loose > > * Gravel, ve sil, moderate > > * Gravel, ve sil, stiff > > * Loam, sl san, moderate > > * Loam, sl san, stiff > > * Loam, sl san, weak > > * Loam, ve san, stiff > > * Peat, mod pl, moderate > > * Peat, not pl, weak > > * Sand, clean, loose > > * Sand, clean, moderate > > * Sand, clean, stiff > > * Sand, sl sil, moderate > > * Sand, ve sil, loose * materials[¶](#TensionPilesModel.materials "Permalink to this definition") Lists all materials currently in de model. * Return type `Dict`\[`str`, `Dict`\[`str`, `Any`]] - profiles[¶](#TensionPilesModel.profiles "Permalink to this definition") Lists all profiles currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] * pile\_types[¶](#TensionPilesModel.pile_types "Permalink to this definition") Lists all pile types currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] - piles[¶](#TensionPilesModel.piles "Permalink to this definition") Lists all piles currently in de model. * Return type `List`\[`Dict`\[`str`, `Any`]] * generate\_input\_file(*metadata=None*, *\**, *as\_file=False*)[¶](#TensionPilesModel.generate_input_file "Permalink to this definition") Generate a D-Foundations input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **metadata** (`Optional`\[[`Metadata`](#Metadata "viktor.external.dfoundations.Metadata")]) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **as\_file** (`bool`) – return as BytesIO (default) or File * Return type `Union`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `BytesIO`] - create\_material(*name*, *soil\_type*, *gamma\_unsat*, *gamma\_sat*, *friction\_angle*, *diameter\_d50=0.2*, *max\_cone\_resist\_type=MaxConeResistType.STANDARD*, *max\_cone\_resist=0.0*, *apply\_tension=True*, *min\_void\_ratio=0.4*, *max\_void\_ratio=0.8*, *color=None*)[¶](#TensionPilesModel.create_material "Permalink to this definition") Create a material with the given name and properties. * Parameters * **name** (`str`) – name of the material to create (max. 25 characters) * **color** (`Optional`\[[`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")]) – color for visualization in deltares software (None for default color ‘white’) * **soil\_type** ([`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")) – \[-] * **gamma\_unsat** (`float`) – gamma-unsaturated, dry \[kN/m³] * **gamma\_sat** (`float`) – gamma-saturated, wet \[kN/m³] * **friction\_angle** (`float`) – phi \[degree] * **diameter\_d50** (`float`) – median \[mm] * **max\_cone\_resist\_type** ([`MaxConeResistType`](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")) – \[-] * **max\_cone\_resist** (`float`) – \[MPa] * **apply\_tension** (`bool`) – True (default) / False * **min\_void\_ratio** (`float`) – \[-] * **max\_void\_ratio** (`float`) – \[-] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type `None` * create\_profile(*name*, *layers*, *x*, *y*, *measurements*, *phreatic\_level*, *pile\_tip\_level*, *top\_tension\_zone*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[¶](#TensionPilesModel.create_profile "Permalink to this definition") Create a profile manually. * Parameters * **name** (`str`) – name of the profile (must be unique). * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **measurements** (`List`\[`Tuple`\[`float`, `float`]]) – list of measurement data (level \[m], qc-value \[MPa]). * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **top\_tension\_zone** (`float`) – Top of tension zone \[m] * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) – * **min\_layer\_thickness** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * Return type `None` - import\_profile(*cpt*, *layers*, *x*, *y*, *phreatic\_level*, *pile\_tip\_level*, *top\_tension\_zone*, *name=None*, *manual\_ground\_level=None*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[¶](#TensionPilesModel.import_profile "Permalink to this definition") Create a profile by importing a CPT-file. * Parameters * **cpt** ([`GEFData`](/sdk/13/api/geo/.md#GEFData "viktor.geo.GEFData")) – CPT file to import. * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **top\_tension\_zone** (`float`) – Top of tension zone \[m] * **name** (`Optional`\[`str`]) – name of the profile (must be unique). None for default (name of the cpt). * **manual\_ground\_level** (`Optional`\[`float`]) – set to override the ground level \[m] from the cpt. * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) – * **min\_layer\_thickness** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * if ground level could not be read from cpt file. * Return type `None` * create\_pile\_type(*name*, *shape*, *type\_sand\_gravel*, *type\_clay\_loam\_peat*, *material*, *factor\_sand\_gravel=None*, *factor\_clay\_loam\_peat=None*, *unit\_weight\_material=None*)[¶](#TensionPilesModel.create_pile_type "Permalink to this definition") Create a pile type with the given properties. * Parameters * **name** (`str`) – name of the pile type. Must be unique. Max. 10 characters. * **shape** (`_PileShape`) – pile type shape class instance. See below for possible shapes. * **type\_sand\_gravel** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – pile type for α\_t sand/gravel. predefined/user-defined pile type. Only certain types are valid in combination with the provided ‘shape’. For more information on valid combinations, please refer to the D-Foundations software. * **type\_clay\_loam\_peat** ([`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")) – pile type for α\_t clay/loam/peat. * **material** ([`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")) – * **factor\_sand\_gravel** (`Optional`\[`float`]) – α\_t \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **factor\_clay\_loam\_peat** (`Optional`\[`float`]) – α\_t \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **unit\_weight\_material** (`Optional`\[`float`]) – unit weight pile material \[kN/m3]. Only required if ‘material’ is of type ser-defined. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘type\_sand\_gravel’ is of type user-defined and ‘factor\_sand\_gravel’ is not set. * if ‘type\_clay\_loam\_peat’ is of type user-defined and ‘factor\_clay\_loam\_peat’ is not set. * if ‘material’ is of type user-defined and ‘unit\_weight\_material’ is not set. * if an invalid ‘shape’ is provided. * if a ‘type\_sand\_gravel’ is provided that is invalid in combination with the given ‘shape’. * if a pile type with the give name already exists. * if ‘factor\_sand\_gravel’ or ‘factor\_clay\_loam\_peat’ is outside valid range 0-9. Possible shapes are: > * RectPile > > * RectEnlPile > > * UserPile > > * RoundPile > > * TaperPile > > * HollowPile > > * HollowOpenPile > > * RoundEnlPile > > * LostTipPile > > * DrivenBasePile > > * HShapedPile * Return type `None` - create\_pile(*name*, *x*, *y*, *pile\_head\_level*, *load\_max\_min=None*)[¶](#TensionPilesModel.create_pile "Permalink to this definition") Create a pile with given properties. * Parameters * **name** (`str`) – name of the pile. Must be unique. Max. 10 characters. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **pile\_head\_level** (`float`) – \[m R.L.] * **load\_max\_min** (`Optional`\[`Tuple`\[`float`, `float`]]) – (max. load \[kN], min. load \[kN]). None for ‘No’ use of alternating loads. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if pile with given name already exists. * if name exceeds the max. number of characters (10). * Return type `None` ## OutputFileParser[​](/sdk/13/api/external/dfoundations/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.dfoundations.OutputFileParser(*fod\_file*)[¶](#OutputFileParser "Permalink to this definition") Helper class to extract results from a D-Foundations output file (.fod). Currently the following versions are (partly) supported: * * v17: * Tension Piles model * Bearing Piles model - Preliminary Design (calculation options only) * * v19: * Tension Piles model * Bearing Piles model - Verification Example usage: ``` parser = OutputFileParser(fod_file) calculation_parameters = parser.calculation_parameters results = parser.results(False) ``` * Parameters **fod\_file** (`StringIO`) – D-Foundations output file (.fod) - *property *raw\_results*: str*[¶](#OutputFileParser.raw_results "Permalink to this definition") * Return type `str` * *abstract property *calculation\_parameters*: Dict\[str, Union\[float, bool]]*[¶](#OutputFileParser.calculation_parameters "Permalink to this definition") Calculation parameters. * Return type `Dict`\[`str`, `Union`\[`float`, `bool`]] - *abstract *results(*as\_pandas=True*)[¶](#OutputFileParser.results "Permalink to this definition") All result data. * Parameters **as\_pandas** (`bool`) – True to return the results as a dictionary of pandas DataFrame objects. False for dicts. * Return type `Dict`\[`str`, `Union`\[`DataFrame`, `Dict`\[`str`, `Any`]]] --- # viktor.external.dgeostability ## DGeoStabilityAnalysis[​](/sdk/13/api/external/dgeostability/.md#_DGeoStabilityAnalysis "Direct link to DGeoStabilityAnalysis") * *class *viktor.external.dgeostability.DGeoStabilityAnalysis(*input\_file*)[¶](#DGeoStabilityAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DGeoStabilityAnalysis can be used to perform an analysis using DGeoStability on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DGeoStabilityAnalysis.get_output_file "viktor.external.dgeostability.DGeoStabilityAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` dgeostability_analysis = DGeoStabilityAnalysis(input_file=input_file) dgeostability_analysis.execute(timeout=10) output_file = dgeostability_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – .sti input file. - get\_output\_file(*extension='.sto'*, *\**, *as\_file=False*)[¶](#DGeoStabilityAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DGeoStabilityAnalysis.get_output_file "viktor.external.dgeostability.DGeoStabilityAnalysis.get_output_file") afterwards. * Parameters * **extension** (`str`) – extension of the file you want to return; ‘.sto’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.dsettlement ## DSettlementAnalysis[​](/sdk/13/api/external/dsettlement/.md#_DSettlementAnalysis "Direct link to DSettlementAnalysis") * *class *viktor.external.dsettlement.DSettlementAnalysis(*input\_file*)[¶](#DSettlementAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DSettlementAnalysis can be used to perform an analysis using DSettlement on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DSettlementAnalysis.get_output_file "viktor.external.dsettlement.DSettlementAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` input_file = File.from_data("dsettlement input file body") dsettlement_analysis = DSettlementAnalysis(input_file=input_file) dsettlement_analysis.execute(timeout=10) output_file = dsettlement_analysis.get_output_file() # obtain output file in BytesIO sld_file = dsettlement_analysis.get_sld_file() # obtain sld file in StringIO (to post-process) ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – .sli input file. - get\_output\_file(*extension='.sld'*, *\**, *as\_file=False*)[¶](#DSettlementAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DSettlementAnalysis.get_output_file "viktor.external.dsettlement.DSettlementAnalysis.get_output_file") afterwards. * Parameters * **extension** (`str`) – extension of the file you want to return; one of: ‘.sld’, ‘.slo’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * get\_sld\_file(*\**, *as\_file=False*)[¶](#DSettlementAnalysis.get_sld_file "Permalink to this definition") Method to retrieve the sld (result) file. * Parameters **as\_file** (`bool`) – return as StringIO (default) or File New in v13.5.0 * Raises **ValueError** – if file can not be obtained. * Return type `Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## CalculationModel[​](/sdk/13/api/external/dsettlement/.md#_CalculationModel "Direct link to CalculationModel") * *class *viktor.external.dsettlement.CalculationModel(*value*)[¶](#CalculationModel "Permalink to this definition") Bases: `Enum` An enumeration. * NEN\_KOPPEJAN*: [CalculationModel](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 0*[¶](#CalculationModel.NEN_KOPPEJAN "Permalink to this definition") - NEN\_BJERRUM*: [CalculationModel](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 1*[¶](#CalculationModel.NEN_BJERRUM "Permalink to this definition") * ISOTACHE*: [CalculationModel](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 2*[¶](#CalculationModel.ISOTACHE "Permalink to this definition") ## ConsolidationModel[​](/sdk/13/api/external/dsettlement/.md#_ConsolidationModel "Direct link to ConsolidationModel") * *class *viktor.external.dsettlement.ConsolidationModel(*value*)[¶](#ConsolidationModel "Permalink to this definition") Bases: `Enum` An enumeration. * DARCY*: [ConsolidationModel](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")** = 0*[¶](#ConsolidationModel.DARCY "Permalink to this definition") - TERZAGHI*: [ConsolidationModel](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")** = 1*[¶](#ConsolidationModel.TERZAGHI "Permalink to this definition") ## DrainType[​](/sdk/13/api/external/dsettlement/.md#_DrainType "Direct link to DrainType") * *class *viktor.external.dsettlement.DrainType(*value*)[¶](#DrainType "Permalink to this definition") Bases: `Enum` An enumeration. * STRIP*: [DrainType](#DrainType "viktor.external.dsettlement.DrainType")** = 0*[¶](#DrainType.STRIP "Permalink to this definition") - COLUMN*: [DrainType](#DrainType "viktor.external.dsettlement.DrainType")** = 1*[¶](#DrainType.COLUMN "Permalink to this definition") * SAND\_WALL*: [DrainType](#DrainType "viktor.external.dsettlement.DrainType")** = 2*[¶](#DrainType.SAND_WALL "Permalink to this definition") ## DrainGrid[​](/sdk/13/api/external/dsettlement/.md#_DrainGrid "Direct link to DrainGrid") * *class *viktor.external.dsettlement.DrainGrid(*value*)[¶](#DrainGrid "Permalink to this definition") Bases: `Enum` An enumeration. * TRIANGULAR*: [DrainGrid](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 0*[¶](#DrainGrid.TRIANGULAR "Permalink to this definition") - RECTANGULAR*: [DrainGrid](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 1*[¶](#DrainGrid.RECTANGULAR "Permalink to this definition") * UNDETERMINED*: [DrainGrid](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 2*[¶](#DrainGrid.UNDETERMINED "Permalink to this definition") ## DrainageSimpleMode[​](/sdk/13/api/external/dsettlement/.md#_DrainageSimpleMode "Direct link to DrainageSimpleMode") * *class *viktor.external.dsettlement.DrainageSimpleMode(*begin\_time*, *end\_time*, *underpressure*, *dewatering\_head\_or\_pressure*)[¶](#DrainageSimpleMode "Permalink to this definition") Simple drainage schema; to be used in VerticalDrain. * Parameters * **begin\_time** (`float`) – \[days] * **end\_time** (`float`) – \[days] * **underpressure** (`float`) – \[kPa] * **dewatering\_head\_or\_pressure** (`float`) – water head \[m] or tube pressure (if VerticalDrain.drain\_type = SAND\_WALL) \[kPa] ## Metadata[​](/sdk/13/api/external/dsettlement/.md#_Metadata "Direct link to Metadata") * *class *viktor.external.dsettlement.Metadata(*file\_name='-'*, *company='-'*, *created\_by='-'*, *title\_1='-'*, *title\_2='-'*, *title\_3='-'*, *write\_date=False*, *write\_time=False*)[¶](#Metadata "Permalink to this definition") Data-class for defining metadata. * Parameters * **file\_name** (`str`) – * **company** (`str`) – * **created\_by** (`str`) – * **title\_1** (`str`) – max. 50 characters * **title\_2** (`str`) – max. 50 characters * **title\_3** (`str`) – max. 50 characters * **write\_date** (`bool`) – True to write the current date to the sli file; False for dummy (‘01/01/1900’) * **write\_time** (`bool`) – True to write the current date to the sli file; False for dummy (‘00:00:00’) * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if title\_1, title\_2 or title\_3 has more than 50 characters ## VerticalDrain[​](/sdk/13/api/external/dsettlement/.md#_VerticalDrain "Direct link to VerticalDrain") * *class *viktor.external.dsettlement.VerticalDrain(*drain\_type*, *range\_from*, *range\_to*, *bottom\_position*, *center\_to\_center*, *width\_diameter*, *thickness=None*, *position\_drain=None*, *grid=None*, *start\_of\_drainage=None*, *phreatic\_level\_in\_drain=None*, *schedule=None*)[¶](#VerticalDrain "Permalink to this definition") Data-class for setting vertical drain options. * Parameters * **drain\_type** ([`DrainType`](#DrainType "viktor.external.dsettlement.DrainType")) – drain type. * **range\_from** (`float`) – range \[m] from which drainage takes place. * **range\_to** (`float`) – range \[m] to which drainage takes place. * **bottom\_position** (`float`) – position of bottom (depth) of drains \[m]. * **center\_to\_center** (`float`) – center-to-center distance of drains \[m]. * **width\_diameter** (`float`) – width (or diameter for drain\_type = COLUMN) of drains \[m]. * **thickness** (`Optional`\[`float`]) – thickness of strip \[m]. Must be set for drain\_type = STRIP. * **position\_drain** (`Optional`\[`float`]) – drain position \[m]. Must be set for drain\_type = SAND\_WALL (only if schedule is defined). * **grid** (`Optional`\[[`DrainGrid`](#DrainGrid "viktor.external.dsettlement.DrainGrid")]) – drain grid type. Must be set for drain\_type = STRIP | COLUMN. * **start\_of\_drainage** (`Optional`\[`float`]) – start time of drainage \[days]. Must be set for simple and no schedule. * **phreatic\_level\_in\_drain** (`Optional`\[`float`]) – phreatic level in drain \[m]. Must be set for simple and no schedule. * **schedule** (`Union`\[[`DrainageSimpleMode`](#DrainageSimpleMode "viktor.external.dsettlement.DrainageSimpleMode"), `List`\[`Tuple`\[`float`, `float`, `float`]], `None`]) – DrainageSimpleMode for simple schedule; list of (time \[days], underpressure \[kPa], water head \[m] (if drain\_type = STRIP | COLUMN) / tube pressure \[kPa] (if drain\_type = SAND\_WALL)) for detailed schedule (default: no schedule). - *property *position\_drain*: Optional\[float]*[¶](#VerticalDrain.position_drain "Permalink to this definition") * Return type `Optional`\[`float`] ## Model1D[​](/sdk/13/api/external/dsettlement/.md#_Model1D "Direct link to Model1D") * *class *viktor.external.dsettlement.Model1D(*calculation\_model*, *consolidation\_model*, *create\_default\_materials=True*, *\**, *natural\_strain=False*, *water\_unit\_weight=9.81*, *verticals\_discretization=100*, *verticals\_z\_coordinate=0.0*, *maintain\_profile=False*, *profile\_unit\_weight\_above\_phreatic\_level=10.0*, *profile\_unit\_weight\_below\_phreatic\_level=10.0*, *end\_of\_settlement\_calculation=10000*, *vertical\_drain=None*)[¶](#Model1D "Permalink to this definition") Bases: `_Model` Model for a 1D D-Settlement analysis. Example usage: ``` # instantiate 1D model model = Model1D(CalculationModel.NEN_KOPPEJAN, ConsolidationModel.TERZAGHI) # update the geometry model.create_material("my_mat", 21.0, 19.0, color=Color(0, 0, 0)) model.update_geometry(-1.0, [(1.0, "Loam"), (0.0, "my_mat")], phreatic_level=-3.0) # add load(s) model.create_uniform_load("my_load", 0, 0.001, 0.0, 0.0) # generate the input file input_file = model.generate_input_file() ``` * Parameters * **calculation\_model** ([`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")) – * **consolidation\_model** ([`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")) – * **create\_default\_materials** (`bool`) – start with default materials or none * **natural\_strain** (`bool`) – if False -> linear strain * **water\_unit\_weight** (`float`) – in \[kN/m³] * **vertical\_drain** (`Optional`\[[`VerticalDrain`](#VerticalDrain "viktor.external.dsettlement.VerticalDrain")]) – parameters for vertical drains, or None (default) to disable option - materials[¶](#Model1D.materials "Permalink to this definition") * Return type `Dict`\[`str`, `_Material`] * create\_material(*name*, *gam\_dry*, *gam\_wet*, *color=None*, *\**, *initial\_void\_ratio=0.0*, *cohesion=0.0*, *phi=0.0*, *precon\_isotache\_type=0*, *precon\_koppejan\_type=0*, *use\_equivalent\_age=0*, *equivalent\_age=0.0*, *pc=0.0*, *ocr=1.0*, *pop=0.0*, *limit\_stress=1.0*, *drained=0*, *ap\_as\_approximation\_by\_cp\_cs=0*, *cv=10.0*, *permeability\_ver=0.05*, *permeability\_hor\_factor=1.0*, *storage\_type=0*, *permeability\_strain\_modulus=1000000000000000.0*, *use\_prob\_defaults=1*, *std\_gam\_dry=0.0*, *std\_gam\_wet=0.0*, *std\_cv=0.0*, *std\_pc=0.0*, *std\_pri\_comp\_index=0.0*, *std\_sec\_comp\_index=0.0*, *std\_sec\_comp\_rate=0.0*, *std\_ocr=0.0*, *std\_permeability\_ver=0.0*, *std\_pop=0.0*, *std\_permeability\_hor\_factor=0.0*, *std\_initial\_void\_ratio=0.0*, *std\_permeability\_strain\_modulus=0.0*, *std\_limit\_stress=0.0*, *std\_cp=0.0*, *std\_cp1=0.0*, *std\_cs=0.0*, *std\_cs1=0.0*, *std\_ap=0.0*, *std\_asec=0.0*, *std\_car=0.0*, *std\_ca=0.0*, *std\_r\_ratio=0.0*, *std\_c\_ratio=0.0*, *std\_s\_ratio=0.0*, *std\_cr\_index=0.0*, *std\_cc\_index=0.0*, *std\_csw\_index=0.0*, *dist\_gam\_dry=2*, *dist\_gam\_wet=2*, *dist\_cv=2*, *dist\_pc=2*, *dist\_pri\_comp\_index=2*, *dist\_sec\_comp\_index=2*, *dist\_sec\_comp\_rate=2*, *dist\_ocr=2*, *dist\_permeability\_ver=2*, *dist\_pop=2*, *dist\_permeability\_hor\_factor=2*, *dist\_initial\_void\_ratio=2*, *dist\_permeability\_strain\_modulus=2*, *dist\_limit\_stress=2*, *dist\_cp=2*, *dist\_cp1=2*, *dist\_cs=2*, *dist\_cs1=2*, *dist\_ap=2*, *dist\_asec=2*, *dist\_car=2*, *dist\_ca=2*, *dist\_r\_ratio=2*, *dist\_c\_ratio=2*, *dist\_s\_ratio=2*, *dist\_cr\_index=2*, *dist\_cc\_index=2*, *dist\_csw\_index=2*, *cor\_cp\_cp1=0.0*, *cor\_cs\_cp1=0.0*, *cor\_cs1\_cp1=0.0*, *cor\_ap\_cp1=0.0*, *cor\_asec\_cp1=0.0*, *cor\_cr\_index\_cc\_index=0.0*, *cor\_r\_ratio\_c\_ratio=0.0*, *cor\_ca\_cc\_index\_or\_c\_ratio=0.0*, *cor\_pri\_comp\_index\_sec\_comp\_index=0.0*, *cor\_sec\_comp\_rate\_sec\_comp\_index=0.0*, *cp=1.0*, *cp1=1.0*, *cs=1.0*, *cs1=1.0*, *ap=1.0*, *asec=1.0*, *car=0.0*, *ca=1.0*, *comp\_ratio=1*, *r\_ratio=1.0*, *c\_ratio=1.0*, *s\_ratio=0.0*, *cr\_index=1.0*, *cc\_index=1.0*, *csw\_index=0.0*, *pri\_comp\_index=0.01*, *sec\_comp\_index=0.1*, *sec\_comp\_rate=0.005*, *horizontal\_behaviour\_type=2*, *elasticity=1000.0*, *default\_elasticity=1*)[¶](#Model1D.create_material "Permalink to this definition") Create a material with the given name and properties. * Parameters * **name** (`str`) – name of the material to create (max. 25 characters) * **color** (`Optional`\[[`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")]) – color for visualization in deltares software (None for random color) * **gam\_dry** (`float`) – unit weight above phreatic level in \[kN/m³] * **gam\_wet** (`float`) – unit weight below phreatic level in \[kN/m³] * **...****.** – etc. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type `None` - create\_uniform\_load(*name*, *time*, *unit\_weight*, *height*, *y\_application*)[¶](#Model1D.create_uniform_load "Permalink to this definition") Create a uniform load with the given name and properties. * Parameters * **name** (`str`) – name of the uniform load to create * **time** (`int`) – in \[days], -1 for initial load * **unit\_weight** (`float`) – in \[kN/m³] * **height** (`float`) – in \[m] * **y\_application** (`float`) – in \[m] * Return type `None` * set\_calculation\_times(*\*time*)[¶](#Model1D.set_calculation_times "Permalink to this definition") (Re)set calculation time(s) * Parameters **time** (`int`) – one or more calculation times at which results will be obtained # todo: days * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if time < 0 or > end time * if duplicates exist * Return type `None` - generate\_input\_file(*metadata=None*, *\**, *dissipation\_calculation=None*, *as\_file=False*)[¶](#Model1D.generate_input_file "Permalink to this definition") Generate a D-Settlement input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **metadata** (`Optional`\[[`Metadata`](#Metadata "viktor.external.dsettlement.Metadata")]) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **dissipation\_calculation** (`Optional`\[`_Vertical`]) – select vertical to add dissipation calculation; ‘None’ to disable. * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * *property *bottom\_level*: float*[¶](#Model1D.bottom_level "Permalink to this definition") * Return type `float` - *property *top\_level*: float*[¶](#Model1D.top_level "Permalink to this definition") * Return type `float` * *property *layers*: List\[Tuple\[float, str]]*[¶](#Model1D.layers "Permalink to this definition") * Return type `List`\[`Tuple`\[`float`, `str`]] - *property *phreatic\_level*: Optional\[float]*[¶](#Model1D.phreatic_level "Permalink to this definition") * Return type `Optional`\[`float`] * update\_geometry(*bottom\_level*, *layers*, *phreatic\_level=None*)[¶](#Model1D.update_geometry "Permalink to this definition") Overwrite the current (default if not updated before) geometry with the given data. * Parameters * **bottom\_level** (`float`) – bottom level of the bottom-most layer \[m] * **layers** (`List`\[`Tuple`\[`float`, `str`]]) – list of layers defined by top level \[m] and material name (must be created beforehand with [`create_material()`](#Model1D.create_material "viktor.external.dsettlement.Model1D.create_material") or one of the default materials). Should be defined from top to bottom. * **phreatic\_level** (`Optional`\[`float`]) – in \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if layers are not defined from top to bottom * if lowest layer top level is below given bottom level * if material with given name does not exist Example usage: ``` model.update_geometry(-1, [(1.0, "Loam"), (0.0, "Sand")], phreatic_level=-3) ``` * Return type `None` ## Model2D[​](/sdk/13/api/external/dsettlement/.md#_Model2D "Direct link to Model2D") * *class *viktor.external.dsettlement.Model2D(*calculation\_model*, *consolidation\_model*, *boundary\_bottom*, *create\_default\_materials=True*, *\**, *natural\_strain=False*, *limits=(0.0, 100.0)*, *water\_unit\_weight=9.81*, *verticals\_discretization=100*, *verticals\_z\_coordinate=0.0*, *maintain\_profile=False*, *profile\_time=0*, *profile\_unit\_weight\_above\_phreatic\_level=10.0*, *profile\_unit\_weight\_below\_phreatic\_level=10.0*, *end\_of\_settlement\_calculation=10000*, *stress\_distribution\_loads=False*, *vertical\_drain=None*)[¶](#Model2D "Permalink to this definition") Bases: `_Model` Model for a 2D D-Settlement analysis. Example usage: ``` # Initialize parameters for vertical drainage, to be used in the init of Model2D. vertical_drain = VerticalDrain(DrainType.SAND_WALL, 5.0, 90.0, 0.0, 2.0, 4.0, start_of_drainage=2.0, phreatic_level_in_drain=4.0) # Create the model (NEN - Koppejan / Terzaghi) with a starting bottom boundary, vertical drainage and # miscellaneous default parameters. model = Model2D(CalculationModel.NEN_KOPPEJAN, ConsolidationModel.TERZAGHI, boundary_bottom=[(0.0, 0.0), (100.0, 0.0)], vertical_drain=vertical_drain) # Create points for defining boundaries and pl-lines. points_boundary1 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 2.5)]] points_boundary2 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 7.5)]] points_boundary3 = [model.create_point(x, y) for (x, y) in [(0.0, 10.0), (25, 10.0), (75, 10.0), (100.0, 10.0)]] points_plline1 = [model.create_point(x, y) for (x, y) in [(0.0, 4.0), (100.0, 4.0)]] points_plline2 = [model.create_point(x, y) for (x, y) in [(0.0, 6.0), (100.0, 6.0)]] # Create the pl-lines. plline1 = model.create_pl_line(points_plline1, is_phreatic=True) plline2 = model.create_pl_line(points_plline2) # Create the layers. model.create_layer(points_boundary1, 'Sand', pl_line_top=99, pl_line_bottom=plline2) model.create_layer(points_boundary2, 'Soft Clay', pl_line_top=99, pl_line_bottom=99) model.create_layer(points_boundary3, 'Loam', pl_line_top=plline1, pl_line_bottom=99) # Create verticals. model.create_vertical(45.0) model.create_vertical(50.0) model.create_vertical(55.0) # Create loads. model.create_non_uniform_load('load1', [(25, 10.0), (50.0, 12.0), (75, 10.0)]) # Create calculation/residual times. model.set_calculation_times(1, 4, 2, 5) # Generate the input file for the model as if it was generated by D-Settlement. input_file = model.generate_input_file() ``` * Parameters * **calculation\_model** ([`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")) – Specifies which calculation model is used. * **consolidation\_model** ([`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")) – Specifies which consolidation model is used. * **boundary\_bottom** (`List`\[`Tuple`\[`float`, `float`]]) – The bottom boundary of the geometry. * **create\_default\_materials** (`bool`) – start with default materials or none * **natural\_strain** (`bool`) – Indicates if natural strain is used. If False, linear strain is used. * **water\_unit\_weight** (`float`) – in \[kN/m³] * **stress\_distribution\_loads** (`bool`) – True for ‘Simulate’, False for ‘None’ (default). * **vertical\_drain** (`Optional`\[[`VerticalDrain`](#VerticalDrain "viktor.external.dsettlement.VerticalDrain")]) – parameters for vertical drains, or None (default) to disable option - materials[¶](#Model2D.materials "Permalink to this definition") * Return type `Dict`\[`str`, `_Material`] * create\_material(*name*, *gam\_dry*, *gam\_wet*, *color=None*, *\**, *initial\_void\_ratio=0.0*, *cohesion=0.0*, *phi=0.0*, *precon\_isotache\_type=0*, *precon\_koppejan\_type=0*, *use\_equivalent\_age=0*, *equivalent\_age=0.0*, *pc=0.0*, *ocr=1.0*, *pop=0.0*, *limit\_stress=1.0*, *drained=0*, *ap\_as\_approximation\_by\_cp\_cs=0*, *cv=10.0*, *permeability\_ver=0.05*, *permeability\_hor\_factor=1.0*, *storage\_type=0*, *permeability\_strain\_modulus=1000000000000000.0*, *use\_prob\_defaults=1*, *std\_gam\_dry=0.0*, *std\_gam\_wet=0.0*, *std\_cv=0.0*, *std\_pc=0.0*, *std\_pri\_comp\_index=0.0*, *std\_sec\_comp\_index=0.0*, *std\_sec\_comp\_rate=0.0*, *std\_ocr=0.0*, *std\_permeability\_ver=0.0*, *std\_pop=0.0*, *std\_permeability\_hor\_factor=0.0*, *std\_initial\_void\_ratio=0.0*, *std\_permeability\_strain\_modulus=0.0*, *std\_limit\_stress=0.0*, *std\_cp=0.0*, *std\_cp1=0.0*, *std\_cs=0.0*, *std\_cs1=0.0*, *std\_ap=0.0*, *std\_asec=0.0*, *std\_car=0.0*, *std\_ca=0.0*, *std\_r\_ratio=0.0*, *std\_c\_ratio=0.0*, *std\_s\_ratio=0.0*, *std\_cr\_index=0.0*, *std\_cc\_index=0.0*, *std\_csw\_index=0.0*, *dist\_gam\_dry=2*, *dist\_gam\_wet=2*, *dist\_cv=2*, *dist\_pc=2*, *dist\_pri\_comp\_index=2*, *dist\_sec\_comp\_index=2*, *dist\_sec\_comp\_rate=2*, *dist\_ocr=2*, *dist\_permeability\_ver=2*, *dist\_pop=2*, *dist\_permeability\_hor\_factor=2*, *dist\_initial\_void\_ratio=2*, *dist\_permeability\_strain\_modulus=2*, *dist\_limit\_stress=2*, *dist\_cp=2*, *dist\_cp1=2*, *dist\_cs=2*, *dist\_cs1=2*, *dist\_ap=2*, *dist\_asec=2*, *dist\_car=2*, *dist\_ca=2*, *dist\_r\_ratio=2*, *dist\_c\_ratio=2*, *dist\_s\_ratio=2*, *dist\_cr\_index=2*, *dist\_cc\_index=2*, *dist\_csw\_index=2*, *cor\_cp\_cp1=0.0*, *cor\_cs\_cp1=0.0*, *cor\_cs1\_cp1=0.0*, *cor\_ap\_cp1=0.0*, *cor\_asec\_cp1=0.0*, *cor\_cr\_index\_cc\_index=0.0*, *cor\_r\_ratio\_c\_ratio=0.0*, *cor\_ca\_cc\_index\_or\_c\_ratio=0.0*, *cor\_pri\_comp\_index\_sec\_comp\_index=0.0*, *cor\_sec\_comp\_rate\_sec\_comp\_index=0.0*, *cp=1.0*, *cp1=1.0*, *cs=1.0*, *cs1=1.0*, *ap=1.0*, *asec=1.0*, *car=0.0*, *ca=1.0*, *comp\_ratio=1*, *r\_ratio=1.0*, *c\_ratio=1.0*, *s\_ratio=0.0*, *cr\_index=1.0*, *cc\_index=1.0*, *csw\_index=0.0*, *pri\_comp\_index=0.01*, *sec\_comp\_index=0.1*, *sec\_comp\_rate=0.005*, *horizontal\_behaviour\_type=2*, *elasticity=1000.0*, *default\_elasticity=1*)[¶](#Model2D.create_material "Permalink to this definition") Create a material with the given name and properties. * Parameters * **name** (`str`) – name of the material to create (max. 25 characters) * **color** (`Optional`\[[`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")]) – color for visualization in deltares software (None for random color) * **gam\_dry** (`float`) – unit weight above phreatic level in \[kN/m³] * **gam\_wet** (`float`) – unit weight below phreatic level in \[kN/m³] * **...****.** – etc. * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type `None` - create\_uniform\_load(*name*, *time*, *unit\_weight*, *height*, *y\_application*)[¶](#Model2D.create_uniform_load "Permalink to this definition") Create a uniform load with the given name and properties. * Parameters * **name** (`str`) – name of the uniform load to create * **time** (`int`) – in \[days], -1 for initial load * **unit\_weight** (`float`) – in \[kN/m³] * **height** (`float`) – in \[m] * **y\_application** (`float`) – in \[m] * Return type `None` * set\_calculation\_times(*\*time*)[¶](#Model2D.set_calculation_times "Permalink to this definition") (Re)set calculation time(s) * Parameters **time** (`int`) – one or more calculation times at which results will be obtained # todo: days * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if time < 0 or > end time * if duplicates exist * Return type `None` - generate\_input\_file(*metadata=None*, *\**, *dissipation\_calculation=None*, *as\_file=False*)[¶](#Model2D.generate_input_file "Permalink to this definition") Generate a D-Settlement input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **metadata** (`Optional`\[[`Metadata`](#Metadata "viktor.external.dsettlement.Metadata")]) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **dissipation\_calculation** (`Optional`\[`_Vertical`]) – select vertical to add dissipation calculation; ‘None’ to disable. * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * create\_point(*x*, *y*)[¶](#Model2D.create_point "Permalink to this definition") Create a point with given x and y coordinates. * Parameters * **x** (`float`) – in \[m] * **y** (`float`) – in \[m] * Return type `_Point` * Returns \_Point which can be used to create boundaries for layers or pl-lines. - create\_pl\_line(*points*, *is\_phreatic=False*)[¶](#Model2D.create_pl_line "Permalink to this definition") Create a piezometric level line (pl-line) from the given points. * Parameters * **points** (`List`\[`_Point`]) – list of points that define the pl-line * **is\_phreatic** (`bool`) – whether to set the current pl-line as the phreatic line (overwrites previous!) * Return type `_PlLine` * Returns pl-line * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘points’ contains duplicates * if start and end ‘points’ are not on the left and right boundary limit respectively * if ‘points’ are not in ascending X-direction * if ‘is\_phreatic’ is True but was already set before * create\_layer(*boundary\_top*, *material*, *pl\_line\_top*, *pl\_line\_bottom*)[¶](#Model2D.create_layer "Permalink to this definition") Define layers from bottom to top. * Parameters * **boundary\_top** (`List`\[`_Point`]) – boundary at top of layer * **material** (`str`) – name of the material to be used (must be created beforehand) * **pl\_line\_top** (`Union`\[`_PlLine`, `int`]) – pl-line at top, or 0 for no pressure, or 99 for interpolation * **pl\_line\_bottom** (`Union`\[`_PlLine`, `int`]) – pl-line at bottom, or 0 for no pressure, or 99 for interpolation * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name does not exist * if boundary\_bottom is provided for layer other than first * if pl\_line\_top or pl\_line\_bottom are not valid * if ‘points’ contains duplicates * if start and end ‘points’ are not on the left and right boundary limit respectively * if ‘points’ are not in ascending X-direction * if ‘is\_phreatic’ is True but was already set before * Return type `_Layer` - create\_vertical(*x*)[¶](#Model2D.create_vertical "Permalink to this definition") Create vertical based on x-coordinate. * Parameters **x** (`float`) – \[m] * Raises [**ModelError**](/sdk/13/api/errors/.md#ModelError "viktor.errors.ModelError") – if x < left boundary limit or > right boundary limit * Return type `_Vertical` * create\_non\_uniform\_load(*name*, *points*, *time=0*, *end\_time=0*, *gamma\_dry=10.0*, *gamma\_wet=10.0*, *temporary=False*)[¶](#Model2D.create_non_uniform_load "Permalink to this definition") Create a non-uniform load. DSettlement assumes that a non-uniform load is caused by soil self weight. Initial loads only affects the initial stresses and do not cause creep or consolidation. * Parameters * **name** (`str`) – Name of the load. * **points** (`List`\[`Tuple`\[`float`, `float`]]) – Points, as x-y coordinates, of the load. The first and last points must be located on a layer or another non-uniform load. * **time** (`int`) – The moment the load is laid down \[days]. If time is set to -1 days, the load is considered an initial load. * **end\_time** (`int`) – The moment the load is removed (only in the case of temporary loads) \[days]. * **temporary** (`bool`) – Bool which indicates if the load is a temporary load. * **gamma\_dry** (`float`) – Total unit weight above phreatic level \[kN/m3]. * **gamma\_wet** (`float`) – Total unit weight below phreatic level \[kN/m3]. * Return type `_NonUniformLoad` ## OutputFileParser[​](/sdk/13/api/external/dsettlement/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.dsettlement.OutputFileParser(*sld\_file*)[¶](#OutputFileParser "Permalink to this definition") Helper class to extract results from a D-Settlement output file (.sld). Example usage: ``` parser = OutputFileParser(sld_file) vertical_results = parser.vertical_results residual_times = parser.residual_times ``` * *property *raw\_results*: str*[¶](#OutputFileParser.raw_results "Permalink to this definition") Raw result data. For convenience, specific data can also be extracted using available methods. * Return type `str` - *property *vertical\_results*: Dict\[int, Dict\[str, Any]]*[¶](#OutputFileParser.vertical_results "Permalink to this definition") Returns results for all verticals. Structure of dictionary: ``` { vertical number: int: { coordinates: { x: float z: float }, time_settlement_per_load: { time_step_count: int load_step_count: int time: List[float] [days] load_1: List[float] [kPa] load_2: List[float] [kPa] ... (depending on model) }, depths: List[float] leakages: List[float] -> empty for some models drained_layers: List[float] -> empty for some models stresses: { -> empty for some models initial_total_stress: List[float] ... (depending on model) }, vertical_data: { time: float: { settlement: List[float] ... (depending on model) } }, } } ``` * Return type `Dict`\[`int`, `Dict`\[`str`, `Any`]] * *property *residual\_times*: Dict\[int, Dict\[str, List\[float]]]*[¶](#OutputFileParser.residual_times "Permalink to this definition") Returns the residual times. Structure of dictionary: ``` { vertical number: int: { Time: List[float] Settlement: List[float] ... } } ``` * Return type `Dict`\[`int`, `Dict`\[`str`, `List`\[`float`]]] --- # viktor.external.dsheetpiling ## DSheetPilingAnalysis[​](/sdk/13/api/external/dsheetpiling/.md#_DSheetPilingAnalysis "Direct link to DSheetPilingAnalysis") * *class *viktor.external.dsheetpiling.DSheetPilingAnalysis(*input\_file*)[¶](#DSheetPilingAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DSheetPilingAnalysis can be used to perform an analysis using D-Sheet Piling on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DSheetPilingAnalysis.get_output_file "viktor.external.dsheetpiling.DSheetPilingAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` dsheetpiling_analysis = DSheetPilingAnalysis(input_file=input_file) dsheetpiling_analysis.execute(timeout=10) output_file = dsheetpiling_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – .shi input file. - get\_output\_file(*extension='.shd'*, *\**, *as\_file=False*)[¶](#DSheetPilingAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DSheetPilingAnalysis.get_output_file "viktor.external.dsheetpiling.DSheetPilingAnalysis.get_output_file") afterwards. * Parameters * **extension** (`str`) – extension of the file you want to return; one of: ‘.shd’, ‘.shs’, ‘.shl’, ‘.sho’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.dstability ## DStabilityAnalysis[​](/sdk/13/api/external/dstability/.md#_DStabilityAnalysis "Direct link to DStabilityAnalysis") * *class *viktor.external.dstability.DStabilityAnalysis(*input\_file*)[¶](#DStabilityAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DStabilityAnalysis can be used to perform an analysis using D-Stability on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DStabilityAnalysis.get_output_file "viktor.external.dstability.DStabilityAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Example usage: ``` file = File() # create a writable File object path = Path(file.source) # request its path dstability_model.serialize(path) # let GEOLIB write to the file analysis = DStabilityAnalysis(input_file=file) # pass the file with content to DStabilityAnalysis analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** ([`File`](/sdk/13/api/core/.md#File "viktor.core.File")) – File object with the body of the .stix input file. - get\_output\_file(*extension='.stix'*)[¶](#DStabilityAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DStabilityAnalysis.get_output_file "viktor.external.dstability.DStabilityAnalysis.get_output_file") afterwards. * Parameters **extension** (`str`) – extension of the file you want to return; ‘.stix’ * Return type `Optional`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")] --- # viktor.external.dynamo ## DynamoFile[​](/sdk/13/api/external/dynamo/.md#_DynamoFile "Direct link to DynamoFile") * *class *viktor.external.dynamo.DynamoFile(*file*)[¶](#DynamoFile "Permalink to this definition") Dynamo file instantiated from an existing input .dyn file. This class allows for easy transformation of input nodes by means of the [`update()`](#DynamoFile.update "viktor.external.dynamo.DynamoFile.update") method. * Parameters **file** ([`File`](/sdk/13/api/core/.md#File "viktor.core.File")) – Dynamo input file (.dyn). - generate()[¶](#DynamoFile.generate "Permalink to this definition") Generate the (updated) Dynamo input file. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * update(*name*, *value*)[¶](#DynamoFile.update "Permalink to this definition") Update the value of an input node with specified name. * Parameters * **name** (`str`) – Name of the input node. * **value** (`Any`) – New input value. * Return type `None` - get\_node\_id(*name*)[¶](#DynamoFile.get_node_id "Permalink to this definition") Retrieve the unique node id by name. * Parameters **name** (`str`) – Name of the node. * Return type `str` ## get\_dynamo\_result[​](/sdk/13/api/external/dynamo/.md#_get_dynamo_result "Direct link to get_dynamo_result") * viktor.external.dynamo.get\_dynamo\_result(*file*, *id\_*)[¶](#get_dynamo_result "Permalink to this definition") Extract results from a Dynamo output file (.xml) by means of a node ‘id’, which can be obtained by calling [`get_node_id()`](#DynamoFile.get_node_id "viktor.external.dynamo.DynamoFile.get_node_id"). Example using BytesIO: ``` input_file = DynamoFile(file) output_id = input_file.get_node_id("Area") # output node called "Area" ... output_file = dynamo_analysis.get_output_file(filename='output.xml') # viktor.external.generic.GenericAnalysis result = get_dynamo_result(output_file, id_=output_id) ``` Example using [`File`](/sdk/13/api/core/.md#File "viktor.core.File"): ``` input_file = DynamoFile(file) output_id = input_file.get_node_id("Area") # output node called "Area" ... output_file = dynamo_analysis.get_output_file(filename='output.xml', as_file=True) # viktor.external.generic.GenericAnalysis with output_file.open_binary() as f: result = get_dynamo_result(f, id_=output_id) ``` * Parameters * **file** (`BinaryIO`) – Dynamo output file (.xml). * **id** – Unique identifier of the output result node. * Return type `str` ## convert\_geometry\_to\_glb[​](/sdk/13/api/external/dynamo/.md#_convert_geometry_to_glb "Direct link to convert_geometry_to_glb") * viktor.external.dynamo.convert\_geometry\_to\_glb(*file*, *filter=None*)[¶](#convert_geometry_to_glb "Permalink to this definition") Convert a Dynamo geometry file (.json) to a GLB file, which can directly be used in a [`GeometryResult`](/sdk/13/api/views/.md#GeometryResult "viktor.views.GeometryResult"). Filter specific geometric objects by id, obtained by calling [`get_node_id()`](#DynamoFile.get_node_id "viktor.external.dynamo.DynamoFile.get_node_id"): ``` input_file = DynamoFile(file) sphere_id = input_file.get_node_id("Sphere") # geometry node called "Sphere" ... geometry_file = dynamo_analysis.get_output_file(filename='geometry.json', as_file=True) # viktor.external.generic.GenericAnalysis glb_file = convert_geometry_to_glb(geometry_file, filter=[sphere_id]) ``` * Parameters * **file** ([`File`](/sdk/13/api/core/.md#File "viktor.core.File")) – Dynamo geometry file (.json). * **filter** (`Optional`\[`List`\[`str`]]) – Filter geometric objects by id (default: include all). * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") --- # viktor.external.etabs Added in v14.17.0 --- # viktor.external.excel ## Macro[​](/sdk/13/api/external/excel/.md#_Macro "Direct link to Macro") * *class *viktor.external.excel.Macro(*command*)[¶](#Macro "Permalink to this definition") Class for defining an Excel macro. * Parameters **command** (`str`) – the name of the Excel Macro command. - serialize()[¶](#Macro.serialize "Permalink to this definition") * Return type `dict` ## Excel[​](/sdk/13/api/external/excel/.md#_Excel "Direct link to Excel") * *class *viktor.external.excel.Excel(*template*, *named\_input\_cells=None*, *direct\_input\_cells=None*, *macros=None*, *named\_output\_cells=None*, *direct\_output\_cells=None*, *extension='.xlsm'*, *typed\_results=False*)[¶](#Excel "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Excel can be used to perform an analysis of an Excel sheet using a third-party worker. This Excel sheet may contain macros (i.e. .xlsm extension). To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_named_cell_result()`](#Excel.get_named_cell_result "viktor.external.excel.Excel.get_named_cell_result") or [`get_direct_cell_result()`](#Excel.get_direct_cell_result "viktor.external.excel.Excel.get_direct_cell_result"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Example: ``` named_input_cells = [NamedInputCell('x', x)] direct_output_cells = [DirectOutputCell('Sheet1', 'B', 3)] excel_analysis = Excel(template, named_input_cells=named_input_cells, direct_output_cells=direct_output_cells, extension='.xlsx') excel_analysis.execute(timeout=10) result = excel.get_direct_cell_result('Sheet1', 'B', 3) ``` * Parameters * **template** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – Excel template to be filled, executed and returned. * **named\_input\_cells** (`Optional`\[`List`\[[`NamedInputCell`](/sdk/13/api/external/spreadsheet/.md#NamedInputCell "viktor.external.spreadsheet.NamedInputCell")]]) – A list of named cells containing input values. * **direct\_input\_cells** (`Optional`\[`List`\[[`DirectInputCell`](/sdk/13/api/external/spreadsheet/.md#DirectInputCell "viktor.external.spreadsheet.DirectInputCell")]]) – A list of direct cells containing input values. * **macros** (`Optional`\[`List`\[[`Macro`](#Macro "viktor.external.excel.Macro")]]) – A list of macros to be executed. The order of the list is preserved. This means the first macro in the list will be executed first, the second macro wil be executed second, etc. * **named\_output\_cells** (`Optional`\[`List`\[[`NamedOutputCell`](/sdk/13/api/external/spreadsheet/.md#NamedOutputCell "viktor.external.spreadsheet.NamedOutputCell")]]) – A list of named cells of which the result after evaluation is desired. * **direct\_output\_cells** (`Optional`\[`List`\[[`DirectOutputCell`](/sdk/13/api/external/spreadsheet/.md#DirectOutputCell "viktor.external.spreadsheet.DirectOutputCell")]]) – A list of direct cells of which the result after evaluation is desired. * **extension** (`str`) – Extension of the file you want to evaluate: ‘.xlsm’ | ‘.xlsx’. * **typed\_results** (`bool`) – Cell results are of the same type as spreadsheet, if False, all values are str Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * execute(*timeout=30*)[¶](#Excel.execute "Permalink to this definition") Run method to start an external Excel analysis using a VIKTOR worker. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **timeout** (`int`) – Timeout period in seconds. * Raises * TimeoutError when timeout has been exceeded * ConnectionError if no worker installed or connected * [`viktor.errors.LicenseError`](/sdk/13/api/errors/.md#LicenseError "viktor.errors.LicenseError") if no license is available * [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError") if the external program cannot execute with the provided inputs * Return type `None` - result\_available()[¶](#Excel.result_available "Permalink to this definition") * Return type `bool` * Returns True if excel has returned a result. Warning! This does not necessarily have to be a successful result. * get\_named\_cell\_result(*name*)[¶](#Excel.get_named_cell_result "Permalink to this definition") Function which may be called after excel.execute(). It can be used to fetch the result of a named cell. * Parameters **name** (`str`) – Name of the named cell of which the result is desired. * Returns The result contained in the named cell corresponding to name. * Return type Check `worker_version` to know which type of result is expected: * worker\_version < 1 returns the result with type str. * worker version >= 1 returns the result with type depending on cell type: > * cell type integer / long returns integer > > * cell type single / double / currency / decimal returns float > > * cell type string returns string > > * cell type boolean returns boolean > > * cell type date returns RFC 3339 format string (e.g. “1998-02-23T00:00:00Z”) - get\_direct\_cell\_result(*sheet\_name*, *column*, *row*)[¶](#Excel.get_direct_cell_result "Permalink to this definition") Function which may be called after excel.execute(). It can be used to fetch the result of a direct cell. * Parameters * **sheet\_name** (`str`) – Name of the worksheet of the desired cell. * **column** (`str`) – Name of the column of the desired cell. * **row** (`int`) – Name of the row of the desired cell. * Returns The result contained in the cell corresponding to (sheet\_name, column, row). * Return type Check `worker_version` to know which type of result is expected: * worker\_version < 1 returns the result with type str. * worker version >= 1 returns the result with type depending on cell type: > * cell type integer / long returns integer > > * cell type single / double / currency / decimal returns float > > * cell type string returns string > > * cell type boolean returns boolean > > * cell type date returns RFC 3339 format string (e.g. “1998-02-23T00:00:00Z”) * get\_filled\_template()[¶](#Excel.get_filled_template "Permalink to this definition") New in v13.5.0 Retrieve the filled-in template if available, otherwise raises a SpreadsheetError. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") - *property *filled\_template*: BytesIO*[¶](#Excel.filled_template "Permalink to this definition") A BytesIO object which contains the filled template if available, otherwise raises a SpreadsheetError. * Return type `BytesIO` * *property *success*: Optional\[bool]*[¶](#Excel.success "Permalink to this definition") True if excel has returned a successful result, False if excel has returned an unsuccessful result, None otherwise. * Return type `Optional`\[`bool`] - *property *error\_message*: Optional\[str]*[¶](#Excel.error_message "Permalink to this definition") The error string containing information from the Excel worker when available, None otherwise. * Return type `Optional`\[`str`] --- # viktor.external.external\_program ## ExternalProgram[​](/sdk/13/api/external/external-program/.md#_ExternalProgram "Direct link to ExternalProgram") * *class *viktor.external.external\_program.ExternalProgram(*queue\_name*, *version*)[¶](#ExternalProgram "Permalink to this definition") Bases: `ABC` Warning Do not use this class directly in an application! Base-class of an external analysis. * Parameters * **queue\_name** (`str`) – Name of the external integration. * **version** (`int`) – Version of the API between SDK <-> worker. - execute(*timeout=25*)[¶](#ExternalProgram.execute "Permalink to this definition") Run method to start an external analysis using a VIKTOR worker. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **timeout** (`int`) – Timeout period in seconds. * Raises * TimeoutError when timeout has been exceeded * ConnectionError if no worker installed or connected * LicenseError if no license is available * ExecutionError if the external program cannot execute with the provided inputs * Return type `None` --- # viktor.external.generic ## GenericAnalysis[​](/sdk/13/api/external/generic/.md#_GenericAnalysis "Direct link to GenericAnalysis") * *class *viktor.external.generic.GenericAnalysis(*files=None*, *executable\_key=None*, *output\_filenames=None*)[¶](#GenericAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") GenericAnalysis can be used to evaluate an executable on third-party infrastructure. The executable is expected to be blocking, i.e. if the executable is invoked from command prompt, it should wait until the executable is finished. For security purposes the executable that should be called has to be defined in the configuration file of the worker. Usage: ``` files = [ ('input1.txt', file1), ('input2.txt', file2) ] generic_analysis = GenericAnalysis(files=files, executable_key="someexecutable", output_filenames=["output.txt"]) generic_analysis.execute(timeout=60) output_file = generic_analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/13/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters * **files** (`Optional`\[`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]]) – Files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **executable\_key** (`Optional`\[`str`]) – The key of the executable that needs to be evaluated. This key should be present in the configuration file of the worker. * **output\_filenames** (`Optional`\[`List`\[`str`]]) – A list of filenames (including extension) that are to be transferred back to the SDK. This filename is relative to the working directory. At least one of the attributes above should be included in the call. * Raises **ValueError** – when no attribute is included in call. - get\_output\_file(*filename*, *\**, *as\_file=False*)[¶](#GenericAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#GenericAnalysis.get_output_file "viktor.external.generic.GenericAnalysis.get_output_file") afterwards. * Parameters * **filename** (`str`) – The name of the file (including extension) that you want to get. * **as\_file** (`bool`) – Return as BytesIO (default) or File * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.grasshopper Added in v14.8.0 --- # viktor.external.grlweap ## GRLWeapAnalysis[​](/sdk/13/api/external/grlweap/.md#_GRLWeapAnalysis "Direct link to GRLWeapAnalysis") * *class *viktor.external.grlweap.GRLWeapAnalysis(*input\_file*)[¶](#GRLWeapAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") GRLWeapAnalysis can be used to perform an analysis using GRLWeap on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#GRLWeapAnalysis.get_output_file "viktor.external.grlweap.GRLWeapAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` grlweap_analysis = GRLWeapAnalysis(input_file=gwt_file) grlweap_analysis.execute(timeout=10) result = grlweap_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – .gwt input file. - get\_output\_file(*\**, *as\_file=False*)[¶](#GRLWeapAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#GRLWeapAnalysis.get_output_file "viktor.external.grlweap.GRLWeapAnalysis.get_output_file") afterwards. * Parameters **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.idea ## IdeaRcsAnalysis[​](/sdk/13/api/external/idea/.md#_IdeaRcsAnalysis "Direct link to IdeaRcsAnalysis") * *class *viktor.external.idea\_rcs.idea\_rcs.IdeaRcsAnalysis(*input\_file*, *\**, *return\_result\_xml=None*, *return\_rcs\_file=None*)[¶](#IdeaRcsAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Can be used to perform an analysis using IDEA StatiCa RCS on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#IdeaRcsAnalysis.get_output_file "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis.get_output_file"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` idea_rcs_file = File.from_data("idea rcs input file content") idea_rcs_analysis = IdeaRcsAnalysis(input_file=idea_rcs_file) idea_rcs_analysis.execute(timeout=10) result = idea_rcs_analysis.get_output_file() ``` Exceptions which can be raised during calculation: > * [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters * **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – IDEA (Open)Model input XML file. * **return\_result\_xml** (`Optional`\[`bool`]) – Result .xml file will be available if set to True (default: True). * **return\_rcs\_file** (`Optional`\[`bool`]) – Input .ideaRcs file will be available if set to True (default: False). - get\_output\_file(*\**, *as\_file=False*)[¶](#IdeaRcsAnalysis.get_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. The file is only available when return\_result\_xml=True. [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * Returns * File (encoding=’utf-16’), if as\_file = True * BytesIO (encoding=’utf-16’), if as\_file = False (default) * get\_idea\_rcs\_file(*\**, *as\_file=False*)[¶](#IdeaRcsAnalysis.get_idea_rcs_file "Permalink to this definition") Method can be used to retrieve the .ideaRcs file which is converted from the (Open)Model input XML. The file is only available when return\_rcs\_file=True. [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * Returns * File, if as\_file = True * BytesIO, if as\_file = False (default) ## OpenModel[​](/sdk/13/api/external/idea/.md#_OpenModel "Direct link to OpenModel") * *class *viktor.external.idea\_rcs.idea\_rcs.OpenModel(*\**, *project\_data=None*, *code\_settings=None*)[¶](#OpenModel "Permalink to this definition") Bases: `_Model` Can be used to construct an IDEA-RCS model and generate its corresponding input XML file. This file can in turn be used as input of [`IdeaRcsAnalysis`](#IdeaRcsAnalysis "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis"). For a more elaborate example implementation, please see the guide. The OpenModel follows IDEA’s underlying API. Alternatively, you can use [`Model`](#Model "viktor.external.idea_rcs.idea_rcs.Model"). Warning Use this binding at own risk. Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Example usage: ``` # Initialize the model. model = OpenModel() # empty model, or optionally pass ProjectData and/or CodeSettings # Create the concrete section. mat = model.create_matconcrete_ec2(ConcreteMaterial.C12_15) cs = model.create_cross_section_parameter(name='cs', cross_section_type=CrossSectionType.RECT, material=mat, Width=2.0, Height=2.0) # Create the reinforced cross section. rcs = model.create_reinforced_cross_section(name='rcs', cross_section=cs) # Create bars (and stirrups) as desired mat_reinf = model.create_matreinforcement_ec2(ReinforcementMaterial.B_400A) bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): rcs.create_bar(coords, diameter, mat_reinf) # Create a CheckMember. member = model.create_check_member1d() # 'Assign' the CheckMember to a CheckSection with the previously defined reinforced section and add extremes. check_section = model.add_check_section(description='S 1', check_member=member, reinf_section=rcs) freq = LoadingSLS(ResultOfInternalForces(N=-100000, My=210000)) fund = LoadingULS(ResultOfInternalForces(N=-99999, My=200000)) check_section.create_extreme(frequent=freq, fundamental=fund) # 'Assign' the necessary additional data to the CheckMember. model.add_member_data_ec2(member, MemberType.BEAM_SLAB, TwoWaySlabType.SHELL_AS_PLATE) # Generate the input XML file. input_xml = model.generate_xml_input() ``` * Parameters * **project\_data** (`Optional`\[[`ProjectData`](/sdk/13/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData")]) – project\_data (default: IDEA-RCS default project\_data) * **code\_settings** (`Optional`\[[`CodeSettings`](/sdk/13/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings")]) – code and calculation settings (default: IDEA-RCS default settings) - project\_data[¶](#OpenModel.project_data "Permalink to this definition") * Return type [`ProjectData`](/sdk/13/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData") * code\_settings[¶](#OpenModel.code_settings "Permalink to this definition") * Return type [`CodeSettings`](/sdk/13/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings") - generate\_xml\_input(*\**, *as\_file=False*)[¶](#OpenModel.generate_xml_input "Permalink to this definition") Generates the input file XML representation of the IDEA-RCS model. Warning Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * create\_matconcrete\_ec2(*base\_material*, *name=None*, *\**, *e\_modulus=32800*, *g\_modulus=13667*, *poisson=0.2*, *unit\_mass=2500*, *specific\_heat=0.6*, *thermal\_expansion=1e-05*, *thermal\_conductivity=45*, *is\_default=False*, *order\_in\_code=1*, *thermal\_state=None*, *fck\_28=None*, *stone\_diameter=0.016*, *cement\_class=ConcCementClass.R*, *aggregate\_type=ConcAggregateType.QUARTZITE*, *diagram\_type=ConcDiagramType.PARABOLIC*, *silica\_fume=False*, *plain\_concrete\_diagram=False*, *dep\_params=None*)[¶](#OpenModel.create_matconcrete_ec2 "Permalink to this definition") Create a material concrete Ec2 object and add it to the model. * Parameters * **base\_material** ([`ConcreteMaterial`](/sdk/13/api/external/idea/.md#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")) – IDEA-RCS base material to start with. * **name** (`Optional`\[`str`]) – Name of the material (default: base\_material name). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 32800 MPa). * **g\_modulus** (`float`) – Shear modulus \[MPa] (default: 13667 MPa). * **poisson** (`float`) – Poisson’s ratio (default: 0.2). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 2500 kg/m3). * **specific\_heat** (`float`) – Specific heat capacity (default: 0.6). * **thermal\_expansion** (`float`) – Thermal expansion \[1/K] (default: 1e-05). * **thermal\_conductivity** (`float`) – Thermal conductivity (default: 45). * **is\_default** (`bool`) – True if material is default material in IDEA-RCS code (default: False). * **order\_in\_code** (`int`) – Order of this material in the IDEA-RCS code (default: 1). * **thermal\_state** (`Optional`\[[`ThermalState`](/sdk/13/api/external/idea/.md#ThermalState "viktor.external.idea_rcs.objects.ThermalState")]) – Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain curvatures (default: ThermalState()). * **fck\_28** (`Optional`\[`float`]) – Characteristic compressive cylinder strength of concrete at 28 days \[MPa] (default: base\_material fck). * **stone\_diameter** (`float`) – Aggregate size (default: 16 mm). * **cement\_class** ([`ConcCementClass`](/sdk/13/api/external/idea/.md#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")) – Cement class (default: R). * **aggregate\_type** ([`ConcAggregateType`](/sdk/13/api/external/idea/.md#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")) – Aggregate type (default: Quartzite). * **diagram\_type** ([`ConcDiagramType`](/sdk/13/api/external/idea/.md#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")) – Type of stress-strain diagram for ULS calculation (default: Parabolic). * **silica\_fume** (`bool`) – Contains silica fume (default: False) (EN 1992-2:2008-07 only). * **plain\_concrete\_diagram** (`bool`) – Stress strain diagram with tension part (default: False). * **dep\_params** (`Optional`\[[`ConcDependentParams`](/sdk/13/api/external/idea/.md#ConcDependentParams "viktor.external.idea_rcs.objects.ConcDependentParams")]) – Collection of a series of dependent parameters (see ConcDependentParams for more info). If None, values will be calculated based on ‘fck’ (default: None). * Return type [`MatConcreteEc2`](/sdk/13/api/external/idea/.md#MatConcreteEc2 "viktor.external.idea_rcs.objects.MatConcreteEc2") - create\_matreinforcement\_ec2(*base\_material*, *name=None*, *\**, *e\_modulus=200000*, *g\_modulus=83333*, *poisson=0.2*, *unit\_mass=7850*, *specific\_heat=0.6*, *thermal\_expansion=1e-05*, *thermal\_conductivity=45*, *is\_default=False*, *order\_in\_code=1*, *thermal\_state=None*, *bar\_surface=BarSurface.RIBBED*, *fyk=None*, *ftk\_by\_fyk=None*, *epsuk=None*, *ftk=None*, *class\_=ReinfClass.B*, *type\_=ReinfType.BARS*, *fabrication=ReinfFabrication.HOT\_ROLLED*, *diagram\_type=ReinfDiagramType.BILINEAR\_INCLINED*)[¶](#OpenModel.create_matreinforcement_ec2 "Permalink to this definition") Create a material reinforcement Ec2 object and add it to the model. * Parameters * **base\_material** ([`ReinforcementMaterial`](/sdk/13/api/external/idea/.md#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")) – IDEA-RCS base material to start with. * **name** (`Optional`\[`str`]) – Name of the material (default: base\_material name). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 200000 MPa). * **g\_modulus** (`float`) – Shear modulus \[MPa] (default: 83333 MPa). * **poisson** (`float`) – Poisson’s ratio (default: 0.2). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 7850 kg/m3). * **specific\_heat** (`float`) – Specific heat capacity (default: 0.6). * **thermal\_expansion** (`float`) – Thermal expansion \[1/K] (default: 1e-05). * **thermal\_conductivity** (`float`) – Thermal conductivity (default: 45). * **is\_default** (`bool`) – True if material is default material in IDEA-RCS code (default: False). * **order\_in\_code** (`int`) – Order of this material in the IDEA-RCS code (default: 1). * **thermal\_state** (`Optional`\[[`ThermalState`](/sdk/13/api/external/idea/.md#ThermalState "viktor.external.idea_rcs.objects.ThermalState")]) – Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain curvatures (default: ThermalState()). * **bar\_surface** ([`BarSurface`](/sdk/13/api/external/idea/.md#BarSurface "viktor.external.idea_rcs.objects.BarSurface")) – Bar surface (default: Ribbed). * **fyk** (`Optional`\[`float`]) – Characteristic yield strength of reinforcement (default: base\_material fyk). * **ftk\_by\_fyk** (`Optional`\[`float`]) – factor k = ratio ftk / fyk (default: base\_material k). * **epsuk** (`Optional`\[`float`]) – Characteristic strain of reinforcement at maximum load - εuk \[x 1e-4]. * **ftk** (`Optional`\[`float`]) – Characteristic tensile strength of reinforcement (default: base\_material ftk). * **class** – Class of reinforcement (default: B). * **type** – Type of reinforcement (default: Bars). * **fabrication** ([`ReinfFabrication`](/sdk/13/api/external/idea/.md#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")) – Fabrication of reinforcement (default: Hot rolled). * **diagram\_type** ([`ReinfDiagramType`](/sdk/13/api/external/idea/.md#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")) – Type of material diagram (default: Bilinear with an inclined top branch). * Return type [`MatReinforcementEc2`](/sdk/13/api/external/idea/.md#MatReinforcementEc2 "viktor.external.idea_rcs.objects.MatReinforcementEc2") * create\_cross\_section\_component(*name=None*)[¶](#OpenModel.create_cross_section_component "Permalink to this definition") Create a cross-section object defined by one or multiple components and add it to the model. * Parameters **name** (`Optional`\[`str`]) – Name of cross-section (default: ‘’). * Return type [`CrossSectionComponent`](/sdk/13/api/external/idea/.md#CrossSectionComponent "viktor.external.idea_rcs.objects.CrossSectionComponent") - create\_cross\_section\_parameter(*cross\_section\_type*, *material*, *name=None*, *\*\*parameters*)[¶](#OpenModel.create_cross_section_parameter "Permalink to this definition") Create a cross-section object defined by parameters and add it to the model. * Parameters * **cross\_section\_type** ([`CrossSectionType`](/sdk/13/api/external/idea/.md#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")) – Type of cross-section. * **material** ([`MatConcrete`](/sdk/13/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material (created by [`create_matconcrete_ec2()`](#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2")). * **name** (`Optional`\[`str`]) – Name of cross-section (default: ‘’). * **parameters** (`Any`) – keyword naming should correspond to chosen cross\_section\_type(!). The following combinations of cross\_section\_type and parameters can be used (see the IDEA StatiCa interface for the naming convention): * [`O`](/sdk/13/api/external/idea/.md#CrossSectionType.O "viktor.external.idea_rcs.objects.CrossSectionType.O"): D * [`RECT`](/sdk/13/api/external/idea/.md#CrossSectionType.RECT "viktor.external.idea_rcs.objects.CrossSectionType.RECT"): Width, Height * [`TRAPEZOID`](/sdk/13/api/external/idea/.md#CrossSectionType.TRAPEZOID "viktor.external.idea_rcs.objects.CrossSectionType.TRAPEZOID"): H, Bb, Bt * [`IGN`](/sdk/13/api/external/idea/.md#CrossSectionType.IGN "viktor.external.idea_rcs.objects.CrossSectionType.IGN"): H, Bh, Bs, Ts, Th, Tw * [`IGH`](/sdk/13/api/external/idea/.md#CrossSectionType.IGH "viktor.external.idea_rcs.objects.CrossSectionType.IGH"): H, Bh, Bs, Ts, Th, Tw, Bfh, Tfh * [`BEAM_SHAPE_I_HAUNCH_CHAMFER`](/sdk/13/api/external/idea/.md#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER "viktor.external.idea_rcs.objects.CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER"): Bbf, Hbf, Hbfh, Bw, H, Htfh, Htf, Btf, Bwh * [`TG`](/sdk/13/api/external/idea/.md#CrossSectionType.TG "viktor.external.idea_rcs.objects.CrossSectionType.TG"): Height, Width, TopFlangeWidth, WallWidth * [`TTFH`](/sdk/13/api/external/idea/.md#CrossSectionType.TTFH "viktor.external.idea_rcs.objects.CrossSectionType.TTFH"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch * [`TGREV`](/sdk/13/api/external/idea/.md#CrossSectionType.TGREV "viktor.external.idea_rcs.objects.CrossSectionType.TGREV"): Height, Width, TopFlangeWidth, WallWidth * [`TCHAMFER_1`](/sdk/13/api/external/idea/.md#CrossSectionType.TCHAMFER_1 "viktor.external.idea_rcs.objects.CrossSectionType.TCHAMFER_1"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch2, WallHaunch2 * [`TCHAMFER_2`](/sdk/13/api/external/idea/.md#CrossSectionType.TCHAMFER_2 "viktor.external.idea_rcs.objects.CrossSectionType.TCHAMFER_2"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch2, WallHaunch1, WallHaunch2 * [`TWH`](/sdk/13/api/external/idea/.md#CrossSectionType.TWH "viktor.external.idea_rcs.objects.CrossSectionType.TWH"): Height, Width, TopFlangeWidth, WallWidth, WallHaunch * [`TTFHREV`](/sdk/13/api/external/idea/.md#CrossSectionType.TTFHREV "viktor.external.idea_rcs.objects.CrossSectionType.TTFHREV"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch * [`TWHREV`](/sdk/13/api/external/idea/.md#CrossSectionType.TWHREV "viktor.external.idea_rcs.objects.CrossSectionType.TWHREV"): Height, Width, TopFlangeWidth, WallWidth, WallHaunch - Return type [`CrossSectionParameter`](/sdk/13/api/external/idea/.md#CrossSectionParameter "viktor.external.idea_rcs.objects.CrossSectionParameter") * create\_reinforced\_cross\_section(*cross\_section*, *name=None*)[¶](#OpenModel.create_reinforced_cross_section "Permalink to this definition") Create a reinforced cross-section object and add it to the model. * Parameters * **cross\_section** ([`CrossSection`](/sdk/13/api/external/idea/.md#CrossSection "viktor.external.idea_rcs.objects.CrossSection")) – Cross-section (created by [`create_cross_section_parameter()`](#OpenModel.create_cross_section_parameter "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_parameter") or [`create_cross_section_component()`](#OpenModel.create_cross_section_component "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_component")). * **name** (`Optional`\[`str`]) – Name of cross-section (default: ‘R{i}’). * Return type [`ReinforcedCrossSection`](/sdk/13/api/external/idea/.md#ReinforcedCrossSection "viktor.external.idea_rcs.objects.ReinforcedCrossSection") - create\_check\_member1d()[¶](#OpenModel.create_check_member1d "Permalink to this definition") Create a member 1D check, which can be used in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section") and [`add_member_data_ec2()`](#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2"). * Return type [`CheckMember1D`](/sdk/13/api/external/idea/.md#CheckMember1D "viktor.external.idea_rcs.objects.CheckMember1D") * add\_check\_section(*check\_member*, *reinf\_section*, *description=None*)[¶](#OpenModel.add_check_section "Permalink to this definition") Adds a single section check on the given CheckMember. Note that [`add_member_data_ec2()`](#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2") must be called subsequently. * Parameters * **check\_member** ([`CheckMember`](/sdk/13/api/external/idea/.md#CheckMember "viktor.external.idea_rcs.objects.CheckMember")) – CheckMember (created by [`create_check_member1d()`](#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d")). * **reinf\_section** ([`ReinforcedCrossSection`](/sdk/13/api/external/idea/.md#ReinforcedCrossSection "viktor.external.idea_rcs.objects.ReinforcedCrossSection")) – Reinforcement of cross-section (created by [`create_reinforced_cross_section()`](#OpenModel.create_reinforced_cross_section "viktor.external.idea_rcs.idea_rcs.OpenModel.create_reinforced_cross_section")). * **description** (`Optional`\[`str`]) – Description/name of the section (default: ‘S{i}’). * Return type [`CheckSection`](/sdk/13/api/external/idea/.md#CheckSection "viktor.external.idea_rcs.objects.CheckSection") - add\_member\_data\_ec2(*member*, *member\_type*, *two\_way\_slab\_type*, *\**, *calculation\_setup=None*, *coeff\_kx\_for\_wmax=None*, *exposure\_class\_data=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[¶](#OpenModel.add_member_data_ec2 "Permalink to this definition") Adds a concrete member Ec2 data to the model. * Parameters * **member** ([`CheckMember`](/sdk/13/api/external/idea/.md#CheckMember "viktor.external.idea_rcs.objects.CheckMember")) – CheckMember (created by [`create_check_member1d()`](#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d")). Should be previously added to a check section via [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **member\_type** ([`MemberType`](/sdk/13/api/external/idea/.md#MemberType "viktor.external.idea_rcs.objects.MemberType")) – Structural type of member. Must be a valid type corresponding to the reinf\_section assigned to the member in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **two\_way\_slab\_type** ([`TwoWaySlabType`](/sdk/13/api/external/idea/.md#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")) – Two way slab type. Must be a valid type corresponding to the reinf\_section assigned to the member in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **calculation\_setup** (`Optional`\[[`CalculationSetup`](/sdk/13/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")]) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **coeff\_kx\_for\_wmax** (`Optional`\[`float`]) – (Dutch annex only) Coefficient kx to increase limited concrete crack (default: 1.0). * **exposure\_class\_data** (`Optional`\[[`ExposureClassesDataEc2`](/sdk/13/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")]) – Exposure classes (default: no corrosion). * **creep\_coefficient** (`Optional`\[`float`]) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`Optional`\[`float`]) – Percentage of relative humidity (default: 65). * Return type `None` ## SectionPrototype1D[​](/sdk/13/api/external/idea/.md#_SectionPrototype1D "Direct link to SectionPrototype1D") * *class *viktor.external.idea\_rcs.idea\_rcs.SectionPrototype1D[¶](#SectionPrototype1D "Permalink to this definition") Bases: `_SectionPrototype`, `ABC` Abstract base class of all 1D (beam-like) section prototypes. ## RectSection[​](/sdk/13/api/external/idea/.md#_RectSection "Direct link to RectSection") * *class *viktor.external.idea\_rcs.idea\_rcs.RectSection(*width*, *height*)[¶](#RectSection "Permalink to this definition") Bases: [`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D") Rectangular section. The origin is located in the centroid of this section. * Parameters * **width** (`float`) – Width of the section. * **height** (`float`) – Height of the section. ## GeneralShape[​](/sdk/13/api/external/idea/.md#_GeneralShape "Direct link to GeneralShape") * *class *viktor.external.idea\_rcs.idea\_rcs.GeneralShape(*outline*, *\**, *openings=None*)[¶](#GeneralShape "Permalink to this definition") Bases: [`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D") General cross-section, defined by a set of coordinates. * Parameters * **outline** (`Sequence`\[`Tuple`\[`float`, `float`]]) – Vertices which define the outline of the section (y, z). A minimum of 3 vertices is required, the outline is automatically closed. * **openings** (`Optional`\[`Sequence`\[`Sequence`\[`Tuple`\[`float`, `float`]]]]) – One or multiple openings, defined by vertices (y, z). A minimum of 3 vertices per opening is required, the opening is automatically closed. ## Member[​](/sdk/13/api/external/idea/.md#_Member "Direct link to Member") * *class *viktor.external.idea\_rcs.idea\_rcs.Member(*rcs*, *check\_section*)[¶](#Member "Permalink to this definition") Base class of all member types. * *property *bars*: List\[[ReinforcedBar](/sdk/13/api/external/idea/.md#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")]*[¶](#Member.bars "Permalink to this definition") * Return type `List`\[[`ReinforcedBar`](/sdk/13/api/external/idea/.md#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")] - *property *stirrups*: List\[[Stirrup](/sdk/13/api/external/idea/.md#Stirrup "viktor.external.idea_rcs.objects.Stirrup")]*[¶](#Member.stirrups "Permalink to this definition") * Return type `List`\[[`Stirrup`](/sdk/13/api/external/idea/.md#Stirrup "viktor.external.idea_rcs.objects.Stirrup")] * *property *extremes*: List\[[CheckSectionExtreme](/sdk/13/api/external/idea/.md#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")]*[¶](#Member.extremes "Permalink to this definition") * Return type `List`\[[`CheckSectionExtreme`](/sdk/13/api/external/idea/.md#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")] - create\_bar(*coordinates*, *diameter*, *material*)[¶](#Member.create_bar "Permalink to this definition") Create a reinforced bar on the reinforced cross section. * Parameters * **coordinates** (`Tuple`\[`float`, `float`]) – (X, Y) coordinate of the bar \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](/sdk/13/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * Return type `None` * create\_bar\_layer(*\**, *origin*, *diameter*, *material*, *number\_of\_bars*, *delta\_y=None*, *delta\_z=None*)[¶](#Member.create_bar_layer "Permalink to this definition") Create multiple reinforced bars on the reinforced cross section, positioned on a line. * Parameters * **origin** (`Tuple`\[`float`, `float`]) – Origin point (Y, Z) \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](/sdk/13/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **number\_of\_bars** (`int`) – Number of bars (minimum of 2). * **delta\_y** (`Optional`\[`float`]) – Distance between origin bar and the last bar in y-direction \[m]. * **delta\_z** (`Optional`\[`float`]) – Distance between origin bar and the last bar in z-direction \[m]. * Return type `None` - create\_stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[¶](#Member.create_stirrup "Permalink to this definition") Create a stirrup on the reinforced cross section. * Parameters * **points** (`Sequence`\[`Union`\[`Tuple`\[`float`, `float`], `Tuple`\[`Tuple`\[`float`, `float`], `Tuple`\[`float`, `float`]]]]) – Sequence of (X, Y) coordinates \[m] of the stirrup vertices, connected by straight line segments. For arc-segments use ((X\_end, Y\_end), (X\_on\_arc, Y\_on\_arc)). * **diameter** (`float`) – Diameter of the stirrup \[m]. * **material** ([`MatReinforcement`](/sdk/13/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **distance** (`float`) – Longitudinal distance between stirrups \[m]. * **shear\_check** (`Optional`\[`bool`]) – Take stirrup into account in shear check (default: False). * **torsion\_check** (`Optional`\[`bool`]) – Take stirrup into account in torsion check (default: False). * **mandrel\_diameter\_factor** (`Optional`\[`float`]) – Inner diameter of mandrel as multiple of stirrup diameter \[-] (default: 1.0). * **anchorage\_length** (`Optional`\[`float`]) – Anchorage length \[m] (default: 0.0). * Return type `None` * create\_extreme(*\**, *accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*)[¶](#Member.create_extreme "Permalink to this definition") Create an extreme case with corresponding internal forces on the beam for checking. * Parameters * **accidental** (`Optional`\[[`LoadingULS`](/sdk/13/api/external/idea/.md#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")]) – Accidental loading. * **fatigue** (`Optional`\[[`FatigueLoading`](/sdk/13/api/external/idea/.md#FatigueLoading "viktor.external.idea_rcs.objects.FatigueLoading")]) – Fatigue loading. * **frequent** (`Optional`\[[`LoadingSLS`](/sdk/13/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Frequent loading. * **fundamental** (`Optional`\[[`LoadingULS`](/sdk/13/api/external/idea/.md#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")]) – Fundamental loading. * **characteristic** (`Optional`\[[`LoadingSLS`](/sdk/13/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Characteristic loading. * **quasi\_permanent** (`Optional`\[[`LoadingSLS`](/sdk/13/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Quasi-Permanent loading. * Return type `None` ## Beam[​](/sdk/13/api/external/idea/.md#_Beam "Direct link to Beam") * *class *viktor.external.idea\_rcs.idea\_rcs.Beam(*rcs*, *check\_section*)[¶](#Beam "Permalink to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_beam()`](#Model.create_beam "viktor.external.idea_rcs.idea_rcs.Model.create_beam"). ## CompressionMember[​](/sdk/13/api/external/idea/.md#_CompressionMember "Direct link to CompressionMember") * *class *viktor.external.idea\_rcs.idea\_rcs.CompressionMember(*rcs*, *check\_section*)[¶](#CompressionMember "Permalink to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_compression_member()`](#Model.create_compression_member "viktor.external.idea_rcs.idea_rcs.Model.create_compression_member"). ## OneWaySlab[​](/sdk/13/api/external/idea/.md#_OneWaySlab "Direct link to OneWaySlab") * *class *viktor.external.idea\_rcs.idea\_rcs.OneWaySlab(*rcs*, *check\_section*)[¶](#OneWaySlab "Permalink to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_one_way_slab()`](#Model.create_one_way_slab "viktor.external.idea_rcs.idea_rcs.Model.create_one_way_slab"). ## Model[​](/sdk/13/api/external/idea/.md#_Model "Direct link to Model") * *class *viktor.external.idea\_rcs.idea\_rcs.Model(*\**, *project\_data=None*, *code\_settings=None*)[¶](#Model "Permalink to this definition") Bases: `_Model` Can be used to construct an IDEA-RCS model and generate its corresponding input XML file. This file can in turn be used as input of [`IdeaRcsAnalysis`](#IdeaRcsAnalysis "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis"). For a more detailed elaboration, please see the guide. Alternatively, you can use [`OpenModel`](#OpenModel "viktor.external.idea_rcs.idea_rcs.OpenModel"). Warning Use this binding at own risk. Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The Model does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Example usage: ``` # Initialize the model. model = Model() # empty model, or optionally pass ProjectData and/or CodeSettings # Create the desired material(s). cs_mat = model.create_concrete_material(ConcreteMaterial.C12_15) mat_reinf = model.create_reinforcement_material(ReinforcementMaterial.B_400A) # Create a beam (or other type of member) to be checked. cross_section = RectSection(0.5, 1.0) beam = model.create_beam(cross_section, cs_mat) # Create bars (and stirrups) as desired bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): beam.create_bar(coords, diameter, mat_reinf) # Add extreme(s) freq = LoadingSLS(ResultOfInternalForces(N=-100000, My=210000)) fund = LoadingULS(ResultOfInternalForces(N=-99999, My=200000)) beam.create_extreme(frequent=freq, fundamental=fund) # Generate the input XML file. input_xml = model.generate_xml_input() ``` * Parameters * **project\_data** (`Optional`\[[`ProjectData`](/sdk/13/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData")]) – project\_data (default: IDEA-RCS default project\_data) * **code\_settings** (`Optional`\[[`CodeSettings`](/sdk/13/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings")]) – code and calculation settings (default: IDEA-RCS default settings) - project\_data[¶](#Model.project_data "Permalink to this definition") * Return type [`ProjectData`](/sdk/13/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData") * code\_settings[¶](#Model.code_settings "Permalink to this definition") * Return type [`CodeSettings`](/sdk/13/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings") - generate\_xml\_input(*\**, *as\_file=False*)[¶](#Model.generate_xml_input "Permalink to this definition") Generates the input file XML representation of the IDEA-RCS model. Warning Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * create\_concrete\_material(*base\_material*, *name=None*, *\**, *unit\_mass=2500*, *fck=None*, *stone\_diameter=0.016*, *cement\_class=ConcCementClass.R*, *aggregate\_type=ConcAggregateType.QUARTZITE*, *diagram\_type=ConcDiagramType.PARABOLIC*, *silica\_fume=False*, *plain\_concrete\_diagram=False*, *dep\_params=None*)[¶](#Model.create_concrete_material "Permalink to this definition") Create a concrete material, to be used in [`create_beam()`](#Model.create_beam "viktor.external.idea_rcs.idea_rcs.Model.create_beam") and similar methods. * Parameters * **base\_material** ([`ConcreteMaterial`](/sdk/13/api/external/idea/.md#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")) – IDEA-RCS base material to start with. * **name** (`Optional`\[`str`]) – Name of the material (default: base\_material name). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 2500 kg/m3). * **fck** (`Optional`\[`float`]) – Characteristic compressive cylinder strength of concrete at 28 days \[MPa] (default: base\_material fck). * **stone\_diameter** (`float`) – Aggregate size (default: 16 mm). * **cement\_class** ([`ConcCementClass`](/sdk/13/api/external/idea/.md#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")) – Cement class (default: R). * **aggregate\_type** ([`ConcAggregateType`](/sdk/13/api/external/idea/.md#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")) – Aggregate type (default: Quartzite). * **diagram\_type** ([`ConcDiagramType`](/sdk/13/api/external/idea/.md#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")) – Type of stress-strain diagram for ULS calculation (default: Parabolic). * **silica\_fume** (`bool`) – Contains silica fume (default: False) (EN 1992-2:2008-07 only). * **plain\_concrete\_diagram** (`bool`) – Stress strain diagram with tension part (default: False). * **dep\_params** (`Optional`\[[`ConcDependentParams`](/sdk/13/api/external/idea/.md#ConcDependentParams "viktor.external.idea_rcs.objects.ConcDependentParams")]) – Collection of a series of dependent parameters (see ConcDependentParams for more info). If None, values will be calculated based on ‘fck’ (default: None). * Return type [`MatConcreteEc2`](/sdk/13/api/external/idea/.md#MatConcreteEc2 "viktor.external.idea_rcs.objects.MatConcreteEc2") - create\_reinforcement\_material(*base\_material*, *name=None*, *\**, *unit\_mass=7850*, *e\_modulus=200000*, *fyk=None*, *ftk\_by\_fyk=None*, *epsuk=None*, *type\_=ReinfType.BARS*, *bar\_surface=BarSurface.RIBBED*, *class\_=ReinfClass.B*, *fabrication=ReinfFabrication.HOT\_ROLLED*, *diagram\_type=ReinfDiagramType.BILINEAR\_INCLINED*)[¶](#Model.create_reinforcement_material "Permalink to this definition") Create a reinforcement material, to be used in `create_reinforcement_bar()`. * Parameters * **base\_material** ([`ReinforcementMaterial`](/sdk/13/api/external/idea/.md#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")) – IDEA-RCS base material to start with. * **name** (`Optional`\[`str`]) – Name of the material (default: base\_material name). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 7850 kg/m3). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 200000 MPa). * **fyk** (`Optional`\[`float`]) – Characteristic yield strength of reinforcement (default: base\_material fyk). * **ftk\_by\_fyk** (`Optional`\[`float`]) – factor k = ratio ftk / fyk (default: base\_material k). * **epsuk** (`Optional`\[`float`]) – Characteristic strain of reinforcement at maximum load - εuk \[x 1e-4]. * **type** – Type of reinforcement (default: Bars). * **bar\_surface** ([`BarSurface`](/sdk/13/api/external/idea/.md#BarSurface "viktor.external.idea_rcs.objects.BarSurface")) – Bar surface (default: Ribbed). * **class** – Class of reinforcement (default: B). * **fabrication** ([`ReinfFabrication`](/sdk/13/api/external/idea/.md#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")) – Fabrication of reinforcement (default: Hot rolled). * **diagram\_type** ([`ReinfDiagramType`](/sdk/13/api/external/idea/.md#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")) – Type of material diagram (default: Bilinear with an inclined top branch). * Return type [`MatReinforcementEc2`](/sdk/13/api/external/idea/.md#MatReinforcementEc2 "viktor.external.idea_rcs.objects.MatReinforcementEc2") * create\_beam(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[¶](#Model.create_beam "Permalink to this definition") Create a beam section. * Parameters * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross section prototype. * **material** ([`MatConcrete`](/sdk/13/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** (`Optional`\[[`CalculationSetup`](/sdk/13/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")]) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`Optional`\[`str`]) – Name of the cross section (default: ‘S{i}’). * **rcs\_name** (`Optional`\[`str`]) – Name of the reinforced cross section (default: ‘R{i}’). * **exposure\_classes** (`Optional`\[[`ExposureClassesDataEc2`](/sdk/13/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")]) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`Optional`\[`float`]) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`Optional`\[`float`]) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`Optional`\[`float`]) – Percentage of relative humidity (default: 65). * Return type [`Beam`](#Beam "viktor.external.idea_rcs.idea_rcs.Beam") - create\_compression\_member(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[¶](#Model.create_compression_member "Permalink to this definition") Create a compression member section. * Parameters * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross section prototype. * **material** ([`MatConcrete`](/sdk/13/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** (`Optional`\[[`CalculationSetup`](/sdk/13/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")]) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`Optional`\[`str`]) – Name of the cross section (default: ‘S{i}’). * **rcs\_name** (`Optional`\[`str`]) – Name of the reinforced cross section (default: ‘R{i}’). * **exposure\_classes** (`Optional`\[[`ExposureClassesDataEc2`](/sdk/13/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")]) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`Optional`\[`float`]) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`Optional`\[`float`]) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`Optional`\[`float`]) – Percentage of relative humidity (default: 65). * Return type [`CompressionMember`](#CompressionMember "viktor.external.idea_rcs.idea_rcs.CompressionMember") * create\_one\_way\_slab(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[¶](#Model.create_one_way_slab "Permalink to this definition") Create a one-way slab member section. * Parameters * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross section prototype. * **material** ([`MatConcrete`](/sdk/13/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** (`Optional`\[[`CalculationSetup`](/sdk/13/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")]) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`Optional`\[`str`]) – Name of the cross section (default: ‘S{i}’). * **rcs\_name** (`Optional`\[`str`]) – Name of the reinforced cross section (default: ‘R{i}’). * **exposure\_classes** (`Optional`\[[`ExposureClassesDataEc2`](/sdk/13/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")]) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`Optional`\[`float`]) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`Optional`\[`float`]) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`Optional`\[`float`]) – Percentage of relative humidity (default: 65). * Return type [`OneWaySlab`](#OneWaySlab "viktor.external.idea_rcs.idea_rcs.OneWaySlab") ## RcsOutputFileParser[​](/sdk/13/api/external/idea/.md#_RcsOutputFileParser "Direct link to RcsOutputFileParser") * *class *viktor.external.idea\_rcs.idea\_rcs.RcsOutputFileParser(*xml\_file*)[¶](#RcsOutputFileParser "Permalink to this definition") Parser to extract results from an IDEA-RCS output file (.xml). Currently the following data can be extracted: > * [`capacity()`](#RcsOutputFileParser.SectionResult.capacity "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.capacity") > > * [`shear()`](#RcsOutputFileParser.SectionResult.shear "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.shear") > > * [`torsion()`](#RcsOutputFileParser.SectionResult.torsion "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.torsion") (new in v13.4.0) > > * [`interaction()`](#RcsOutputFileParser.SectionResult.interaction "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.interaction") (new in v13.4.0) > > * [`crack_width()`](#RcsOutputFileParser.SectionResult.crack_width "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.crack_width") > > * [`detailing()`](#RcsOutputFileParser.SectionResult.detailing "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.detailing") > > * [`stress_limitation()`](#RcsOutputFileParser.SectionResult.stress_limitation "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.stress_limitation") > > * [`fatigue()`](#RcsOutputFileParser.SectionResult.fatigue "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.fatigue") Example using [`File`](/sdk/13/api/core/.md#File "viktor.core.File"): ``` xml_file = idea_rcs_analysis.get_output_file(as_file=True) with xml_file.open_binary() as f: parser = RcsOutputFileParser(f) # loop through all sections for section in parser.section_results(): capacity_results = section.capacity() shear_results = section.shear() # or get results for a single section section_4 = parser.section_result(4) ... # or loop through all extremes within a section for extreme in section_4.extremes(): capacity = extreme['capacity'] ... ``` Example using BytesIO: ``` xml_file = idea_rcs_analysis.get_output_file() parser = RcsOutputFileParser(xml_file) for section in parser.section_results(): ... ``` * Parameters **xml\_file** (`BinaryIO`) – IDEA-RCS XML output file (.xml). - section\_result(*id\_*)[¶](#RcsOutputFileParser.section_result "Permalink to this definition") Retrieve the section result of the provided id. * Return type [`SectionResult`](#RcsOutputFileParser.SectionResult "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult") * section\_results()[¶](#RcsOutputFileParser.section_results "Permalink to this definition") Iterates through all section results. Usage: ``` for section in parser.section_results(): capacity_results = section.capacity() if section.id_ == 3: ... ``` * Return type `Iterator`\[[`SectionResult`](#RcsOutputFileParser.SectionResult "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult")] - *class *SectionResult(*id\_*, *element*)[¶](#RcsOutputFileParser.SectionResult "Permalink to this definition") Parsed result section, on which specific results can be retrieved. Do not instantiate this object directly, but retrieve it through [`RcsOutputFileParser.section_results()`](#RcsOutputFileParser.section_results "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.section_results"). * *property *id\_*: int*[¶](#RcsOutputFileParser.SectionResult.id_ "Permalink to this definition") Returns the ‘SectionId’ of current section. * Return type `int` - extremes()[¶](#RcsOutputFileParser.SectionResult.extremes "Permalink to this definition") Get all results combined per extreme for the current section. Returns a list of dictionaries in the following format: ``` [ { 'capacity': {...} | None, 'shear': {...} | None, 'torsion': {...} | None, # new in v13.4.0 'interaction': {...} | None, # new in v13.4.0 'crack_width': {...} | None, 'detailing': {...} | None, 'stress_limitation': {...} | None, 'fatigue': {...} | None, }, ... ] ``` * Return type `List`\[`dict`] * capacity()[¶](#RcsOutputFileParser.SectionResult.capacity "Permalink to this definition") Get the capacity results of all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Fu': { 'N': , 'Qy': , 'Qz': , 'Mx': , 'My': , 'Mz': }, 'Fu1': { ... # see 'Fu' } | None, # IDEA-RCS >= v10.1 only, else None 'Fu2': { ... # see 'Fu' } | None, # IDEA-RCS >= v10.1 only, else None 'CheckValue': , 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] - shear()[¶](#RcsOutputFileParser.SectionResult.shear "Permalink to this definition") Get the shear resistances for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ved': , 'Vrdc': , 'Vrd': , 'Vrdmax': , 'Vrdr': , 'Vrds': , 'CheckValue': , 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] * torsion()[¶](#RcsOutputFileParser.SectionResult.torsion "Permalink to this definition") New in v13.4.0 Get the torsion results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ted': , 'Trdc': , 'Trdmax': , 'Trds': , 'Trd': , 'CheckValue': , 'Result': } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] - interaction()[¶](#RcsOutputFileParser.SectionResult.interaction "Permalink to this definition") New in v13.4.0 Get the interaction results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ned': , 'Medy': , 'Medz': , 'Ved': , 'Ted': , 'CheckValue': , 'CheckValueShearAndTorsion': , 'CheckValueShearTorsionAndBending': , 'Result': } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] * crack\_width()[¶](#RcsOutputFileParser.SectionResult.crack_width "Permalink to this definition") Get the crack width (short/long) results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'short': { 'N': , 'My': , 'Mz': , 'W': , 'Wlim': , 'CheckValue': , 'Result': # new in v13.4.0 } | None, 'long': { ... # see 'short' } | None, } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] - detailing()[¶](#RcsOutputFileParser.SectionResult.detailing "Permalink to this definition") Get the unity checks of the longitudinal reinforcement and shear reinforcement for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'longitudinal': | None, 'shear': | None, 'CheckValue': , # new in v13.4.0 'CheckValueLongReinf': , # new in v13.4.0 'CheckValueShearReinf': , # new in v13.4.0 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] * stress\_limitation()[¶](#RcsOutputFileParser.SectionResult.stress_limitation "Permalink to this definition") Get the short- and long-term stress limitation results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Check_7_2_2_Concrete_fck': { # new in v13.4.0 'short': { 'Stress': | None, 'CheckValue': , 'Result': } | None, 'long': { ... # see 'short' } | None } | None, 'Check_7_2_3_Concrete_fck': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_7_2_5_Tendons_fpk': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_7_2_5_ReinforcementBars_fyk': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_5_10_3_2_Tendons': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_5_10_2_1_1_Tendons': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'short': { 'Check_7_2_2_Concrete_fck': | None, ... # see above for all keys } | None, 'long': { 'Check_7_2_2_Concrete_fck': | None, ... # see above for all keys } | None, } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] - fatigue()[¶](#RcsOutputFileParser.SectionResult.fatigue "Permalink to this definition") Get the fatigue results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'fatigue': { 'CheckValue': , 'DecisionMethod': , 'Result': # new in v13.4.0 }, 'shear': { 'max': { 'Ved': , 'Vrdc': , 'Vrd': , 'Vrdmax': , 'Vrdr': , 'Vrds': , 'CheckValue': , 'Result': # new in v13.4.0 }, 'min': { ... # see 'max' }, } } | None, ... ] ``` * Return type `List`\[`Optional`\[`dict`]] ## OutputFileParser[​](/sdk/13/api/external/idea/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.idea\_rcs.idea\_rcs.OutputFileParser(*xml\_file*)[¶](#OutputFileParser "Permalink to this definition") Helper class to extract results from a IDEA-RCS output file (.xml). Note, for very large result files we advise to make use of [`RcsOutputFileParser`](#RcsOutputFileParser "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser") instead. * Parameters **xml\_file** (`StringIO`) – valid IDEA-RCS XML output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘xml\_file’ can not be parsed (not a valid format). Example usage: ``` parser = OutputFileParser(xml_file) for section in parser.section_ids: capacity_results = parser.capacity_results(section) ... ``` In case you require results which are not supported, you can retrieve the raw results using the [`raw_results()`](#OutputFileParser.raw_results "viktor.external.idea_rcs.idea_rcs.OutputFileParser.raw_results") method. * *property *section\_ids*: List\[int]*[¶](#OutputFileParser.section_ids "Permalink to this definition") Get all section ids for which results are present in the result file. * Return type `List`\[`int`] - raw\_results()[¶](#OutputFileParser.raw_results "Permalink to this definition") Get the (complete) raw results in dict form. Can be used if results need to be extracted that are not supported by the available methods. * Return type `dict` * capacity\_results(*section\_id*)[¶](#OutputFileParser.capacity_results "Permalink to this definition") Get the result of applied internal forces of all extremes for the section with provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`capacity()`](#RcsOutputFileParser.SectionResult.capacity "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.capacity") for return format. * Return type `List`\[`Optional`\[`Dict`\[`str`, `Any`]]] - shear\_results(*section\_id*)[¶](#OutputFileParser.shear_results "Permalink to this definition") Get the shear resistances for all extremes for the section with provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`shear()`](#RcsOutputFileParser.SectionResult.shear "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.shear") for return format. * Return type `List`\[`Optional`\[`Dict`\[`str`, `Any`]]] * crack\_width\_results(*section\_id*)[¶](#OutputFileParser.crack_width_results "Permalink to this definition") Get the crack width (short/long) results for all extremes for the section with provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`crack_width()`](#RcsOutputFileParser.SectionResult.crack_width "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.crack_width") for return format. * Return type `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`Dict`\[`str`, `Any`]]]]] - detailing\_results(*section\_id*)[¶](#OutputFileParser.detailing_results "Permalink to this definition") Get the unity checks of the longitudinal reinforcement and shear reinforcement for all extremes for the section with provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`detailing()`](#RcsOutputFileParser.SectionResult.detailing "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.detailing") for return format. * Return type `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`float`]]]] * stress\_limitation\_results(*section\_id*)[¶](#OutputFileParser.stress_limitation_results "Permalink to this definition") Get the short- and long-term stress limitation results for all extremes for provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`stress_limitation()`](#RcsOutputFileParser.SectionResult.stress_limitation "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.stress_limitation") for return format. * Return type `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`float`]]]] - fatigue\_results(*section\_id*)[¶](#OutputFileParser.fatigue_results "Permalink to this definition") Get the fatigue results for all extremes for the provided ‘section\_id’. * Parameters **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises [**ParsingError**](/sdk/13/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. See [`fatigue()`](#RcsOutputFileParser.SectionResult.fatigue "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.fatigue") for return format. * Return type `List`\[`Optional`\[`dict`]] ## ConcreteMaterial[​](/sdk/13/api/external/idea/.md#_ConcreteMaterial "Direct link to ConcreteMaterial") * *class *viktor.external.idea\_rcs.objects.ConcreteMaterial(*value*)[¶](#ConcreteMaterial "Permalink to this definition") Bases: `Enum` An enumeration. * C12\_15*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 1*[¶](#ConcreteMaterial.C12_15 "Permalink to this definition") - C16\_20*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 2*[¶](#ConcreteMaterial.C16_20 "Permalink to this definition") * C20\_25*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 3*[¶](#ConcreteMaterial.C20_25 "Permalink to this definition") - C25\_30*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 4*[¶](#ConcreteMaterial.C25_30 "Permalink to this definition") * C30\_37*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 5*[¶](#ConcreteMaterial.C30_37 "Permalink to this definition") - C35\_45*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 6*[¶](#ConcreteMaterial.C35_45 "Permalink to this definition") * C40\_50*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 7*[¶](#ConcreteMaterial.C40_50 "Permalink to this definition") - C45\_55*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 8*[¶](#ConcreteMaterial.C45_55 "Permalink to this definition") * C50\_60*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 9*[¶](#ConcreteMaterial.C50_60 "Permalink to this definition") - C55\_67*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 10*[¶](#ConcreteMaterial.C55_67 "Permalink to this definition") * C60\_75*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 11*[¶](#ConcreteMaterial.C60_75 "Permalink to this definition") - C70\_85*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 12*[¶](#ConcreteMaterial.C70_85 "Permalink to this definition") * C80\_95*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 13*[¶](#ConcreteMaterial.C80_95 "Permalink to this definition") - C90\_105*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 14*[¶](#ConcreteMaterial.C90_105 "Permalink to this definition") * C100\_115*: [ConcreteMaterial](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 15*[¶](#ConcreteMaterial.C100_115 "Permalink to this definition") ## ReinforcementMaterial[​](/sdk/13/api/external/idea/.md#_ReinforcementMaterial "Direct link to ReinforcementMaterial") * *class *viktor.external.idea\_rcs.objects.ReinforcementMaterial(*value*)[¶](#ReinforcementMaterial "Permalink to this definition") Bases: `Enum` An enumeration. * B\_400A*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 1*[¶](#ReinforcementMaterial.B_400A "Permalink to this definition") - B\_500A*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 2*[¶](#ReinforcementMaterial.B_500A "Permalink to this definition") * B\_600A*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 3*[¶](#ReinforcementMaterial.B_600A "Permalink to this definition") - B\_400B*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 4*[¶](#ReinforcementMaterial.B_400B "Permalink to this definition") * B\_500B*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 5*[¶](#ReinforcementMaterial.B_500B "Permalink to this definition") - B\_600B*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 6*[¶](#ReinforcementMaterial.B_600B "Permalink to this definition") * B\_400C*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 7*[¶](#ReinforcementMaterial.B_400C "Permalink to this definition") - B\_500C*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 8*[¶](#ReinforcementMaterial.B_500C "Permalink to this definition") * B\_600C*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 9*[¶](#ReinforcementMaterial.B_600C "Permalink to this definition") - B\_550A*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 10*[¶](#ReinforcementMaterial.B_550A "Permalink to this definition") * B\_550B*: [ReinforcementMaterial](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 11*[¶](#ReinforcementMaterial.B_550B "Permalink to this definition") ## NationalAnnex[​](/sdk/13/api/external/idea/.md#_NationalAnnex "Direct link to NationalAnnex") * *class *viktor.external.idea\_rcs.objects.NationalAnnex(*value*)[¶](#NationalAnnex "Permalink to this definition") Bases: `Enum` An enumeration. * NO\_ANNEX*: [NationalAnnex](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'NoAnnex'*[¶](#NationalAnnex.NO_ANNEX "Permalink to this definition") - DUTCH*: [NationalAnnex](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'Dutch'*[¶](#NationalAnnex.DUTCH "Permalink to this definition") * BELGIUM*: [NationalAnnex](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'Belgian'*[¶](#NationalAnnex.BELGIUM "Permalink to this definition") ## ProjectData[​](/sdk/13/api/external/idea/.md#_ProjectData "Direct link to ProjectData") * *class *viktor.external.idea\_rcs.objects.ProjectData(*\**, *national\_annex=None*, *fatigue\_check=False*)[¶](#ProjectData "Permalink to this definition") Bases: `_OpenObject` Project data. * Parameters * **national\_annex** (`Optional`\[[`NationalAnnex`](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")]) – national annex (default: No national annex (EN)) * **fatigue\_check** (`bool`) – functionality - fatigue (default: false) ## EvaluationInteractionDiagram[​](/sdk/13/api/external/idea/.md#_EvaluationInteractionDiagram "Direct link to EvaluationInteractionDiagram") * *class *viktor.external.idea\_rcs.objects.EvaluationInteractionDiagram(*value*)[¶](#EvaluationInteractionDiagram "Permalink to this definition") Bases: `Enum` An enumeration. * NU\_MU\_MU*: [EvaluationInteractionDiagram](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 0*[¶](#EvaluationInteractionDiagram.NU_MU_MU "Permalink to this definition") - NU\_M\_M*: [EvaluationInteractionDiagram](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 1*[¶](#EvaluationInteractionDiagram.NU_M_M "Permalink to this definition") * N\_MU\_MU*: [EvaluationInteractionDiagram](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 2*[¶](#EvaluationInteractionDiagram.N_MU_MU "Permalink to this definition") ## NoResistanceConcreteTension1d[​](/sdk/13/api/external/idea/.md#_NoResistanceConcreteTension1d "Direct link to NoResistanceConcreteTension1d") * *class *viktor.external.idea\_rcs.objects.NoResistanceConcreteTension1d(*value*)[¶](#NoResistanceConcreteTension1d "Permalink to this definition") Bases: `Enum` An enumeration. * EXTREME*: [NoResistanceConcreteTension1d](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 0*[¶](#NoResistanceConcreteTension1d.EXTREME "Permalink to this definition") - SECTION*: [NoResistanceConcreteTension1d](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 1*[¶](#NoResistanceConcreteTension1d.SECTION "Permalink to this definition") * ALWAYS*: [NoResistanceConcreteTension1d](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 2*[¶](#NoResistanceConcreteTension1d.ALWAYS "Permalink to this definition") ## TypeSLSCalculation[​](/sdk/13/api/external/idea/.md#_TypeSLSCalculation "Direct link to TypeSLSCalculation") * *class *viktor.external.idea\_rcs.objects.TypeSLSCalculation(*value*)[¶](#TypeSLSCalculation "Permalink to this definition") Bases: `Enum` An enumeration. * BOTH*: [TypeSLSCalculation](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 0*[¶](#TypeSLSCalculation.BOTH "Permalink to this definition") - SHORT\_TERM*: [TypeSLSCalculation](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 1*[¶](#TypeSLSCalculation.SHORT_TERM "Permalink to this definition") * LONG\_TERM*: [TypeSLSCalculation](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 2*[¶](#TypeSLSCalculation.LONG_TERM "Permalink to this definition") ## CodeSettings[​](/sdk/13/api/external/idea/.md#_CodeSettings "Direct link to CodeSettings") * *class *viktor.external.idea\_rcs.objects.CodeSettings(*\**, *evaluation\_interaction\_diagram=None*, *theta=None*, *theta\_min=None*, *theta\_max=None*, *n\_cycles\_fatigue=None*, *no\_resistance\_concrete\_tension\_1d=None*, *type\_sls\_calculation=None*)[¶](#CodeSettings "Permalink to this definition") Bases: `_OpenObject` Code and calculation settings. * Parameters * **evaluation\_interaction\_diagram** (`Optional`\[[`EvaluationInteractionDiagram`](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")]) – evaluation of interaction diagram (default: NuMuMu) * **theta** (`Optional`\[`float`]) – angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **theta\_min** (`Optional`\[`float`]) – minimum angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **theta\_max** (`Optional`\[`float`]) – maximum angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **n\_cycles\_fatigue** (`Optional`\[`float`]) – number of fatigue cycles (\* 10⁶) (default: set by IDEA) * **no\_resistance\_concrete\_tension\_1d** (`Optional`\[[`NoResistanceConcreteTension1d`](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")]) – no resistance of concrete in tension - members 1D (default: Extreme) * **type\_sls\_calculation** (`Optional`\[[`TypeSLSCalculation`](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")]) – type of SLS calculation (default: Both) ## CheckMember[​](/sdk/13/api/external/idea/.md#_CheckMember "Direct link to CheckMember") * *class *viktor.external.idea\_rcs.objects.CheckMember(*id\_*)[¶](#CheckMember "Permalink to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all check members. ## CheckMember1D[​](/sdk/13/api/external/idea/.md#_CheckMember1D "Direct link to CheckMember1D") * *class *viktor.external.idea\_rcs.objects.CheckMember1D(*id\_*)[¶](#CheckMember1D "Permalink to this definition") Bases: [`CheckMember`](#CheckMember "viktor.external.idea_rcs.objects.CheckMember") Do not use this \_\_init\_\_ directly, but create the object by [`create_check_member1d()`](/sdk/13/api/external/idea/.md#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d"). ## ThermalStateType[​](/sdk/13/api/external/idea/.md#_ThermalStateType "Direct link to ThermalStateType") * *class *viktor.external.idea\_rcs.objects.ThermalStateType(*value*)[¶](#ThermalStateType "Permalink to this definition") Bases: `Enum` An enumeration. * NONE*: [ThermalStateType](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 0*[¶](#ThermalStateType.NONE "Permalink to this definition") - CODE*: [ThermalStateType](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 1*[¶](#ThermalStateType.CODE "Permalink to this definition") * USER*: [ThermalStateType](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 5*[¶](#ThermalStateType.USER "Permalink to this definition") ## ThermalState[​](/sdk/13/api/external/idea/.md#_ThermalState "Direct link to ThermalState") * *class *viktor.external.idea\_rcs.objects.ThermalState(*expansion=ThermalStateType.NONE*, *conductivity=ThermalStateType.NONE*, *specific\_heat=ThermalStateType.NONE*, *stress\_strain=ThermalStateType.NONE*, *strain=ThermalStateType.NONE*)[¶](#ThermalState "Permalink to this definition") Bases: `_OpenObject` Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain. * Parameters * **expansion** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal expansion curvature. * **conductivity** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal conductivity curvature. * **specific\_heat** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal specific heat curvature. * **stress\_strain** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal specific stress-strain curvature. * **strain** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal strain curvature. ## ReinfClass[​](/sdk/13/api/external/idea/.md#_ReinfClass "Direct link to ReinfClass") * *class *viktor.external.idea\_rcs.objects.ReinfClass(*value*)[¶](#ReinfClass "Permalink to this definition") Bases: `Enum` An enumeration. * A*: [ReinfClass](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 0*[¶](#ReinfClass.A "Permalink to this definition") - B*: [ReinfClass](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 1*[¶](#ReinfClass.B "Permalink to this definition") * C*: [ReinfClass](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 2*[¶](#ReinfClass.C "Permalink to this definition") ## ReinfType[​](/sdk/13/api/external/idea/.md#_ReinfType "Direct link to ReinfType") * *class *viktor.external.idea\_rcs.objects.ReinfType(*value*)[¶](#ReinfType "Permalink to this definition") Bases: `Enum` An enumeration. * BARS*: [ReinfType](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 0*[¶](#ReinfType.BARS "Permalink to this definition") - DECOILED\_RODS*: [ReinfType](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 1*[¶](#ReinfType.DECOILED_RODS "Permalink to this definition") * WIRE\_FABRICS*: [ReinfType](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 2*[¶](#ReinfType.WIRE_FABRICS "Permalink to this definition") - LATTICE\_GIRDERS*: [ReinfType](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 3*[¶](#ReinfType.LATTICE_GIRDERS "Permalink to this definition") ## BarSurface[​](/sdk/13/api/external/idea/.md#_BarSurface "Direct link to BarSurface") * *class *viktor.external.idea\_rcs.objects.BarSurface(*value*)[¶](#BarSurface "Permalink to this definition") Bases: `Enum` An enumeration. * SMOOTH*: [BarSurface](#BarSurface "viktor.external.idea_rcs.objects.BarSurface")** = 0*[¶](#BarSurface.SMOOTH "Permalink to this definition") - RIBBED*: [BarSurface](#BarSurface "viktor.external.idea_rcs.objects.BarSurface")** = 1*[¶](#BarSurface.RIBBED "Permalink to this definition") ## ReinfDiagramType[​](/sdk/13/api/external/idea/.md#_ReinfDiagramType "Direct link to ReinfDiagramType") * *class *viktor.external.idea\_rcs.objects.ReinfDiagramType(*value*)[¶](#ReinfDiagramType "Permalink to this definition") Bases: `Enum` An enumeration. * BILINEAR\_INCLINED*: [ReinfDiagramType](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 0*[¶](#ReinfDiagramType.BILINEAR_INCLINED "Permalink to this definition") - BILINEAR\_NOT\_INCLINED*: [ReinfDiagramType](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 1*[¶](#ReinfDiagramType.BILINEAR_NOT_INCLINED "Permalink to this definition") * USER*: [ReinfDiagramType](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 2*[¶](#ReinfDiagramType.USER "Permalink to this definition") ## ReinfFabrication[​](/sdk/13/api/external/idea/.md#_ReinfFabrication "Direct link to ReinfFabrication") * *class *viktor.external.idea\_rcs.objects.ReinfFabrication(*value*)[¶](#ReinfFabrication "Permalink to this definition") Bases: `Enum` An enumeration. * HOT\_ROLLED*: [ReinfFabrication](#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")** = 0*[¶](#ReinfFabrication.HOT_ROLLED "Permalink to this definition") - COLD\_WORKED*: [ReinfFabrication](#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")** = 1*[¶](#ReinfFabrication.COLD_WORKED "Permalink to this definition") ## MatReinforcement[​](/sdk/13/api/external/idea/.md#_MatReinforcement "Direct link to MatReinforcement") * *class *viktor.external.idea\_rcs.objects.MatReinforcement(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *bar\_surface*)[¶](#MatReinforcement "Permalink to this definition") Bases: `_Material`, `ABC` Abstract base class of all material reinforcements. ## MatReinforcementEc2[​](/sdk/13/api/external/idea/.md#_MatReinforcementEc2 "Direct link to MatReinforcementEc2") * *class *viktor.external.idea\_rcs.objects.MatReinforcementEc2(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *bar\_surface*, *fyk*, *ftk\_by\_fyk*, *epsuk*, *ftk*, *class\_*, *type\_*, *fabrication*, *diagram\_type*)[¶](#MatReinforcementEc2 "Permalink to this definition") Bases: [`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement") Do not use this \_\_init\_\_ directly, but create the object by [`create_matreinforcement_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2"). ## ConcDiagramType[​](/sdk/13/api/external/idea/.md#_ConcDiagramType "Direct link to ConcDiagramType") * *class *viktor.external.idea\_rcs.objects.ConcDiagramType(*value*)[¶](#ConcDiagramType "Permalink to this definition") Bases: `Enum` An enumeration. * BILINEAR*: [ConcDiagramType](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 0*[¶](#ConcDiagramType.BILINEAR "Permalink to this definition") - PARABOLIC*: [ConcDiagramType](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 1*[¶](#ConcDiagramType.PARABOLIC "Permalink to this definition") * USER*: [ConcDiagramType](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 2*[¶](#ConcDiagramType.USER "Permalink to this definition") ## ConcAggregateType[​](/sdk/13/api/external/idea/.md#_ConcAggregateType "Direct link to ConcAggregateType") * *class *viktor.external.idea\_rcs.objects.ConcAggregateType(*value*)[¶](#ConcAggregateType "Permalink to this definition") Bases: `Enum` An enumeration. * QUARTZITE*: [ConcAggregateType](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 0*[¶](#ConcAggregateType.QUARTZITE "Permalink to this definition") - LIMESTONE*: [ConcAggregateType](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 1*[¶](#ConcAggregateType.LIMESTONE "Permalink to this definition") * SANDSTONE*: [ConcAggregateType](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 2*[¶](#ConcAggregateType.SANDSTONE "Permalink to this definition") - BASALT*: [ConcAggregateType](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 3*[¶](#ConcAggregateType.BASALT "Permalink to this definition") ## ConcCementClass[​](/sdk/13/api/external/idea/.md#_ConcCementClass "Direct link to ConcCementClass") * *class *viktor.external.idea\_rcs.objects.ConcCementClass(*value*)[¶](#ConcCementClass "Permalink to this definition") Bases: `Enum` An enumeration. * S*: [ConcCementClass](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 0*[¶](#ConcCementClass.S "Permalink to this definition") - R*: [ConcCementClass](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 1*[¶](#ConcCementClass.R "Permalink to this definition") * N*: [ConcCementClass](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 2*[¶](#ConcCementClass.N "Permalink to this definition") ## MatConcrete[​](/sdk/13/api/external/idea/.md#_MatConcrete "Direct link to MatConcrete") * *class *viktor.external.idea\_rcs.objects.MatConcrete(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*)[¶](#MatConcrete "Permalink to this definition") Bases: `_Material`, `ABC` Abstract base class of all concrete materials. ## ConcDependentParams[​](/sdk/13/api/external/idea/.md#_ConcDependentParams "Direct link to ConcDependentParams") * *class *viktor.external.idea\_rcs.objects.ConcDependentParams(*E\_cm*, *eps\_c1*, *eps\_c2*, *eps\_c3*, *eps\_cu1*, *eps\_cu2*, *eps\_cu3*, *F\_ctm*, *F\_ctk\_0\_05*, *F\_ctk\_0\_95*, *n\_factor*, *F\_cm*)[¶](#ConcDependentParams "Permalink to this definition") Bases: `_OpenObject` Collection of all MatConcreteEc2 dependent parameters. * Parameters * **E\_cm** (`float`) – Secant modulus of elasticity of concrete \[MPa] * **eps\_c1** (`float`) – Compressive strain in the concrete - εc1 \[-] * **eps\_c2** (`float`) – Compressive strain in the concrete - εc2 \[-] * **eps\_c3** (`float`) – Compressive strain in the concrete - εc3 \[-] * **eps\_cu1** (`float`) – Ultimate compressive strain in the concrete - εcu1 \[-] * **eps\_cu2** (`float`) – Ultimate compressive strain in the concrete - εcu2 \[-] * **eps\_cu3** (`float`) – Ultimate compressive strain in the concrete - εcu3 \[-] * **F\_ctm** (`float`) – Mean value of axial tensile strength of concrete \[MPa] * **F\_ctk\_0\_05** (`float`) – Characteristic axial tensile strength of concrete 5% quantile \[MPa] * **F\_ctk\_0\_95** (`float`) – Characteristic axial tensile strength of concrete 95% quantile \[MPa] * **n\_factor** (`float`) – Coefficient n-factor - necessary parabolic part of stress-strain diagram - n \[-] * **F\_cm** (`float`) – Mean value of concrete cylinder compressive strength \[MPa] ## MatConcreteEc2[​](/sdk/13/api/external/idea/.md#_MatConcreteEc2 "Direct link to MatConcreteEc2") * *class *viktor.external.idea\_rcs.objects.MatConcreteEc2(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *fck*, *stone\_diameter*, *cement\_class*, *aggregate\_type*, *diagram\_type*, *silica\_fume*, *plain\_concrete\_diagram*, *dep\_params=None*)[¶](#MatConcreteEc2 "Permalink to this definition") Bases: [`MatConcrete`](#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete") Do not use this \_\_init\_\_ directly, but create the object by [`create_matconcrete_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2"). ## CrossSectionType[​](/sdk/13/api/external/idea/.md#_CrossSectionType "Direct link to CrossSectionType") * *class *viktor.external.idea\_rcs.objects.CrossSectionType(*value*)[¶](#CrossSectionType "Permalink to this definition") Bases: `Enum` An enumeration. * ONE\_COMPONENT\_CSS*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 0*[¶](#CrossSectionType.ONE_COMPONENT_CSS "Permalink to this definition") - ROLLED\_I*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 1*[¶](#CrossSectionType.ROLLED_I "Permalink to this definition") * ROLLED\_ANGLE*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 2*[¶](#CrossSectionType.ROLLED_ANGLE "Permalink to this definition") - ROLLED\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 3*[¶](#CrossSectionType.ROLLED_T "Permalink to this definition") * ROLLED\_U*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 4*[¶](#CrossSectionType.ROLLED_U "Permalink to this definition") - ROLLED\_CHS*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 5*[¶](#CrossSectionType.ROLLED_CHS "Permalink to this definition") * ROLLED\_RHS*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 6*[¶](#CrossSectionType.ROLLED_RHS "Permalink to this definition") - ROLLED\_DOUBLE\_UO*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 7*[¶](#CrossSectionType.ROLLED_DOUBLE_UO "Permalink to this definition") * ROLLED\_DOUBLE\_UC*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 8*[¶](#CrossSectionType.ROLLED_DOUBLE_UC "Permalink to this definition") - ROLLED\_DOUBLE\_LT*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 10*[¶](#CrossSectionType.ROLLED_DOUBLE_LT "Permalink to this definition") * ROLLED\_DOUBLE\_LU*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 11*[¶](#CrossSectionType.ROLLED_DOUBLE_LU "Permalink to this definition") - ROLLED\_TI*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 12*[¶](#CrossSectionType.ROLLED_TI "Permalink to this definition") * ROLLED\_I\_PAR*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 13*[¶](#CrossSectionType.ROLLED_I_PAR "Permalink to this definition") - ROLLED\_U\_PAR*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 14*[¶](#CrossSectionType.ROLLED_U_PAR "Permalink to this definition") * ROLLED\_L\_PAR*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 15*[¶](#CrossSectionType.ROLLED_L_PAR "Permalink to this definition") - BOX\_FL*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 16*[¶](#CrossSectionType.BOX_FL "Permalink to this definition") * BOX\_WEB*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 17*[¶](#CrossSectionType.BOX_WEB "Permalink to this definition") - BOX\_2I*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 18*[¶](#CrossSectionType.BOX_2I "Permalink to this definition") * BOX\_2U*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 19*[¶](#CrossSectionType.BOX_2U "Permalink to this definition") - BOX\_2U\_2PI*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 20*[¶](#CrossSectionType.BOX_2U_2PI "Permalink to this definition") * BOX\_2L*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 21*[¶](#CrossSectionType.BOX_2L "Permalink to this definition") - BOX\_4L*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 22*[¶](#CrossSectionType.BOX_4L "Permalink to this definition") * IW*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 23*[¶](#CrossSectionType.IW "Permalink to this definition") - IWN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 24*[¶](#CrossSectionType.IWN "Permalink to this definition") * TW*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 25*[¶](#CrossSectionType.TW "Permalink to this definition") - O*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 26*[¶](#CrossSectionType.O "Permalink to this definition") * RECT*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 27*[¶](#CrossSectionType.RECT "Permalink to this definition") - IGN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 28*[¶](#CrossSectionType.IGN "Permalink to this definition") * IGH*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 29*[¶](#CrossSectionType.IGH "Permalink to this definition") - TG*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 30*[¶](#CrossSectionType.TG "Permalink to this definition") * LG*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 31*[¶](#CrossSectionType.LG "Permalink to this definition") - LG\_MIRRORED*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 32*[¶](#CrossSectionType.LG_MIRRORED "Permalink to this definition") * UG*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 33*[¶](#CrossSectionType.UG "Permalink to this definition") - CHS\_G*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 34*[¶](#CrossSectionType.CHS_G "Permalink to this definition") * ZG*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 35*[¶](#CrossSectionType.ZG "Permalink to this definition") - RHS\_G*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 36*[¶](#CrossSectionType.RHS_G "Permalink to this definition") * OVAL*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 37*[¶](#CrossSectionType.OVAL "Permalink to this definition") - GENERAL*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 38*[¶](#CrossSectionType.GENERAL "Permalink to this definition") * ROLLED\_2I*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 39*[¶](#CrossSectionType.ROLLED_2I "Permalink to this definition") - TRAPEZOID*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 40*[¶](#CrossSectionType.TRAPEZOID "Permalink to this definition") * TTFH*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 41*[¶](#CrossSectionType.TTFH "Permalink to this definition") - TWH*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 42*[¶](#CrossSectionType.TWH "Permalink to this definition") * TGREV*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 43*[¶](#CrossSectionType.TGREV "Permalink to this definition") - TTFHREV*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 44*[¶](#CrossSectionType.TTFHREV "Permalink to this definition") * TWHREV*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 45*[¶](#CrossSectionType.TWHREV "Permalink to this definition") - TCHAMFER\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 46*[¶](#CrossSectionType.TCHAMFER_1 "Permalink to this definition") * TCHAMFER\_2*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 47*[¶](#CrossSectionType.TCHAMFER_2 "Permalink to this definition") - TT*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 48*[¶](#CrossSectionType.TT "Permalink to this definition") * TT1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 49*[¶](#CrossSectionType.TT1 "Permalink to this definition") - SG*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 50*[¶](#CrossSectionType.SG "Permalink to this definition") * GENERAL\_STEEL*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 51*[¶](#CrossSectionType.GENERAL_STEEL "Permalink to this definition") - GENERAL\_CONCRETE*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 52*[¶](#CrossSectionType.GENERAL_CONCRETE "Permalink to this definition") * COMPOSITE\_BEAM\_BOX*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 53*[¶](#CrossSectionType.COMPOSITE_BEAM_BOX "Permalink to this definition") - COMPOSITE\_BEAM\_BOX\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 54*[¶](#CrossSectionType.COMPOSITE_BEAM_BOX_1 "Permalink to this definition") * COMPOSITE\_BEAM\_IGEN\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 55*[¶](#CrossSectionType.COMPOSITE_BEAM_IGEN_T "Permalink to this definition") - COMPOSITE\_BEAM\_L\_LEFT*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 56*[¶](#CrossSectionType.COMPOSITE_BEAM_L_LEFT "Permalink to this definition") * COMPOSITE\_BEAM\_PLATE*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 57*[¶](#CrossSectionType.COMPOSITE_BEAM_PLATE "Permalink to this definition") - COMPOSITE\_BEAM\_R\_RES\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 58*[¶](#CrossSectionType.COMPOSITE_BEAM_R_RES_T "Permalink to this definition") * COMPOSITE\_BEAM\_R\_RES\_T\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 59*[¶](#CrossSectionType.COMPOSITE_BEAM_R_RES_T_1 "Permalink to this definition") - COMPOSITE\_BEAM\_R\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 60*[¶](#CrossSectionType.COMPOSITE_BEAM_R_T "Permalink to this definition") * COMPOSITE\_BEAM\_SHAPE\_CHAMF*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 61*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_CHAMF "Permalink to this definition") - COMPOSITE\_BEAM\_SHAPE\_CHAMF\_ASYM*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 62*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_CHAMF_ASYM "Permalink to this definition") * COMPOSITE\_BEAM\_SHAPE\_IGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 63*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_IGEN "Permalink to this definition") - COMPOSITE\_BEAM\_SHAPE\_I\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 64*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_I_T "Permalink to this definition") * COMPOSITE\_BEAM\_SHAPE\_I\_T\_ASYM*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 65*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_I_T_ASYM "Permalink to this definition") - COMPOSITE\_BEAM\_T\_LEFT*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 66*[¶](#CrossSectionType.COMPOSITE_BEAM_T_LEFT "Permalink to this definition") * COMPOSITE\_BEAM\_TRAPEZOID*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 67*[¶](#CrossSectionType.COMPOSITE_BEAM_TRAPEZOID "Permalink to this definition") - COMPOSITE\_BEAM\_TRES\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 68*[¶](#CrossSectionType.COMPOSITE_BEAM_TRES_T "Permalink to this definition") * COMPOSITE\_BEAM\_TREV*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 69*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV "Permalink to this definition") - COMPOSITE\_BEAM\_TREV\_RES\_I*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 70*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_I "Permalink to this definition") * COMPOSITE\_BEAM\_TREV\_RES\_I\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 71*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_I_1 "Permalink to this definition") - COMPOSITE\_BEAM\_TREV\_RES\_R*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 72*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_R "Permalink to this definition") * COMPOSITE\_BEAM\_TREV\_RES\_R\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 73*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_R_1 "Permalink to this definition") - COMPOSITE\_BEAM\_TREV\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 74*[¶](#CrossSectionType.COMPOSITE_BEAM_TREV_T "Permalink to this definition") * COMPOSITE\_BEAM\_SHAPE\_T\_T*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 75*[¶](#CrossSectionType.COMPOSITE_BEAM_SHAPE_T_T "Permalink to this definition") - BEAM\_SHAPE\_I\_HAUNCH\_CHAMFER*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 76*[¶](#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER "Permalink to this definition") * BEAM\_SHAPE\_I\_HAUNCH\_CHAMFER\_ASYM*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 77*[¶](#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER_ASYM "Permalink to this definition") - BEAM\_SHAPE\_REV\_U*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 78*[¶](#CrossSectionType.BEAM_SHAPE_REV_U "Permalink to this definition") * BEAM\_SHAPE\_BOX*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 79*[¶](#CrossSectionType.BEAM_SHAPE_BOX "Permalink to this definition") - BEAM\_SHAPE\_BOX\_1*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 80*[¶](#CrossSectionType.BEAM_SHAPE_BOX_1 "Permalink to this definition") * BEAM\_SHAPE\_TREV\_CHAMFER\_HAUNCH\_S*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 81*[¶](#CrossSectionType.BEAM_SHAPE_TREV_CHAMFER_HAUNCH_S "Permalink to this definition") - BEAM\_SHAPE\_TREV\_CHAMFER\_HAUNCH\_D*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 82*[¶](#CrossSectionType.BEAM_SHAPE_TREV_CHAMFER_HAUNCH_D "Permalink to this definition") * BEAM\_SHAPE\_IREV\_DEGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 83*[¶](#CrossSectionType.BEAM_SHAPE_IREV_DEGEN "Permalink to this definition") - BEAM\_SHAPE\_IREV\_DEGEN\_ADD*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 84*[¶](#CrossSectionType.BEAM_SHAPE_IREV_DEGEN_ADD "Permalink to this definition") * BEAM\_SHAPE\_TREV\_DEGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 85*[¶](#CrossSectionType.BEAM_SHAPE_TREV_DEGEN "Permalink to this definition") - BEAM\_SHAPE\_TREV\_DEGEN\_ADD*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 86*[¶](#CrossSectionType.BEAM_SHAPE_TREV_DEGEN_ADD "Permalink to this definition") * BEAM\_SHAPE\_Z\_DEGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 87*[¶](#CrossSectionType.BEAM_SHAPE_Z_DEGEN "Permalink to this definition") - BEAM\_SHAPE\_I\_Z\_DEGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 88*[¶](#CrossSectionType.BEAM_SHAPE_I_Z_DEGEN "Permalink to this definition") * BEAM\_SHAPE\_L\_DEGEN*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 89*[¶](#CrossSectionType.BEAM_SHAPE_L_DEGEN "Permalink to this definition") - CHS\_PAR*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 101*[¶](#CrossSectionType.CHS_PAR "Permalink to this definition") * UNIQUE\_NAME*: [CrossSectionType](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 1001*[¶](#CrossSectionType.UNIQUE_NAME "Permalink to this definition") ## CrossSection[​](/sdk/13/api/external/idea/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.idea\_rcs.objects.CrossSection(*id\_*, *name*)[¶](#CrossSection "Permalink to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all cross sections. ## CrossSectionParameter[​](/sdk/13/api/external/idea/.md#_CrossSectionParameter "Direct link to CrossSectionParameter") * *class *viktor.external.idea\_rcs.objects.CrossSectionParameter(*id\_*, *name*, *cross\_section\_type*, *material*, *\*\*parameters*)[¶](#CrossSectionParameter "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.idea_rcs.objects.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_section_parameter()`](/sdk/13/api/external/idea/.md#OpenModel.create_cross_section_parameter "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_parameter"). ## CrossSectionComponent[​](/sdk/13/api/external/idea/.md#_CrossSectionComponent "Direct link to CrossSectionComponent") * *class *viktor.external.idea\_rcs.objects.CrossSectionComponent(*id\_*, *name*)[¶](#CrossSectionComponent "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.idea_rcs.objects.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_section_component()`](/sdk/13/api/external/idea/.md#OpenModel.create_cross_section_component "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_component"). * create\_component(*outline*, *material*, *\**, *openings=None*)[¶](#CrossSectionComponent.create_component "Permalink to this definition") Create a component to build up the cross-section. * Parameters * **outline** (`Sequence`\[`Tuple`\[`float`, `float`]]) – Vertices which define the outline of the section (y, z). A minimum of 3 vertices is required, the outline is automatically closed. * **material** ([`MatConcrete`](#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material (created by [`create_matconcrete_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2")). * **openings** (`Optional`\[`Sequence`\[`Sequence`\[`Tuple`\[`float`, `float`]]]]) – One or multiple openings, defined by vertices (y, z). A minimum of 3 vertices per opening is required, the opening is automatically closed. * Return type `None` ## ReinforcedBar[​](/sdk/13/api/external/idea/.md#_ReinforcedBar "Direct link to ReinforcedBar") * *class *viktor.external.idea\_rcs.objects.ReinforcedBar(*coordinates*, *diameter*, *material*)[¶](#ReinforcedBar "Permalink to this definition") Bases: `_OpenObject` Do not use this \_\_init\_\_ directly, but create the object by [`ReinforcedCrossSection.create_bar()`](#ReinforcedCrossSection.create_bar "viktor.external.idea_rcs.objects.ReinforcedCrossSection.create_bar"). * *property *coordinates*: Tuple\[float, float]*[¶](#ReinforcedBar.coordinates "Permalink to this definition") * Return type `Tuple`\[`float`, `float`] - *property *diameter*: float*[¶](#ReinforcedBar.diameter "Permalink to this definition") * Return type `float` * *property *material\_id*: int*[¶](#ReinforcedBar.material_id "Permalink to this definition") * Return type `int` ## Stirrup[​](/sdk/13/api/external/idea/.md#_Stirrup "Direct link to Stirrup") * *class *viktor.external.idea\_rcs.objects.Stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[¶](#Stirrup "Permalink to this definition") Bases: `_OpenObject` Do not use this \_\_init\_\_ directly, but create the object by [`ReinforcedCrossSection.create_stirrup()`](#ReinforcedCrossSection.create_stirrup "viktor.external.idea_rcs.objects.ReinforcedCrossSection.create_stirrup"). * *property *points*: Sequence\[Union\[Tuple\[float, float], Tuple\[Tuple\[float, float], Tuple\[float, float]]]]*[¶](#Stirrup.points "Permalink to this definition") * Return type `Sequence`\[`Union`\[`Tuple`\[`float`, `float`], `Tuple`\[`Tuple`\[`float`, `float`], `Tuple`\[`float`, `float`]]]] - *property *material\_id*: int*[¶](#Stirrup.material_id "Permalink to this definition") * Return type `int` * *property *shear\_check*: bool*[¶](#Stirrup.shear_check "Permalink to this definition") * Return type `bool` - *property *torsion\_check*: bool*[¶](#Stirrup.torsion_check "Permalink to this definition") * Return type `bool` * *property *mandrel\_diameter\_factor*: float*[¶](#Stirrup.mandrel_diameter_factor "Permalink to this definition") * Return type `float` - *property *anchorage\_length*: float*[¶](#Stirrup.anchorage_length "Permalink to this definition") * Return type `float` ## ReinforcedCrossSection[​](/sdk/13/api/external/idea/.md#_ReinforcedCrossSection "Direct link to ReinforcedCrossSection") * *class *viktor.external.idea\_rcs.objects.ReinforcedCrossSection(*id\_*, *name*, *cross\_section*, *bars=None*, *stirrups=None*)[¶](#ReinforcedCrossSection "Permalink to this definition") Bases: `_OpenElementId` Do not use this \_\_init\_\_ directly, but create the object by [`create_reinforced_cross_section()`](/sdk/13/api/external/idea/.md#OpenModel.create_reinforced_cross_section "viktor.external.idea_rcs.idea_rcs.OpenModel.create_reinforced_cross_section"). * *property *bars*: List\[[ReinforcedBar](#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")]*[¶](#ReinforcedCrossSection.bars "Permalink to this definition") * Return type `List`\[[`ReinforcedBar`](#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")] - *property *stirrups*: List\[[Stirrup](#Stirrup "viktor.external.idea_rcs.objects.Stirrup")]*[¶](#ReinforcedCrossSection.stirrups "Permalink to this definition") * Return type `List`\[[`Stirrup`](#Stirrup "viktor.external.idea_rcs.objects.Stirrup")] * create\_bar(*coordinates*, *diameter*, *material*)[¶](#ReinforcedCrossSection.create_bar "Permalink to this definition") Create a reinforced bar on the reinforced cross section. * Parameters * **coordinates** (`Tuple`\[`float`, `float`]) – (X, Y) coordinate of the bar \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * Return type `None` - create\_bar\_layer(*\**, *origin*, *diameter*, *material*, *number\_of\_bars*, *delta\_y=None*, *delta\_z=None*)[¶](#ReinforcedCrossSection.create_bar_layer "Permalink to this definition") Create multiple reinforced bars on the reinforced cross section, positioned on a line. * Parameters * **origin** (`Tuple`\[`float`, `float`]) – Origin point (Y, Z) \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **number\_of\_bars** (`int`) – Number of bars (minimum of 2). * **delta\_y** (`Optional`\[`float`]) – Distance between origin bar and the last bar in y-direction \[m]. * **delta\_z** (`Optional`\[`float`]) – Distance between origin bar and the last bar in z-direction \[m]. * Return type `None` * create\_stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[¶](#ReinforcedCrossSection.create_stirrup "Permalink to this definition") Create a stirrup on the reinforced cross section. * Parameters * **points** (`Sequence`\[`Union`\[`Tuple`\[`float`, `float`], `Tuple`\[`Tuple`\[`float`, `float`], `Tuple`\[`float`, `float`]]]]) – Sequence of (X, Y) coordinates \[m] of the stirrup vertices, connected by straight line segments. For arc-segments use ((X\_end, Y\_end), (X\_on\_arc, Y\_on\_arc)). * **diameter** (`float`) – Diameter of the stirrup \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **distance** (`float`) – Longitudinal distance between stirrups \[m]. * **shear\_check** (`Optional`\[`bool`]) – Take stirrup into account in shear check (default: False). * **torsion\_check** (`Optional`\[`bool`]) – Take stirrup into account in torsion check (default: False). * **mandrel\_diameter\_factor** (`Optional`\[`float`]) – Inner diameter of mandrel as multiple of stirrup diameter \[-] (default: 1.0). * **anchorage\_length** (`Optional`\[`float`]) – Anchorage length \[m] (default: 0.0). * Return type `None` ## ResultOfInternalForces[​](/sdk/13/api/external/idea/.md#_ResultOfInternalForces "Direct link to ResultOfInternalForces") * *class *viktor.external.idea\_rcs.objects.ResultOfInternalForces(*N=0.0*, *Qy=0.0*, *Qz=0.0*, *Mx=0.0*, *My=0.0*, *Mz=0.0*)[¶](#ResultOfInternalForces "Permalink to this definition") Bases: `_OpenObject` Result of internal forces at a certain location. * Parameters * **N** (`float`) – Normal force (default: 0.0). * **Qy** (`float`) – Shear force in y direction (default: 0.0). * **Qz** (`float`) – Shear force in z direction (default: 0.0). * **Mx** (`float`) – Bending moment around x-axis (default: 0.0). * **My** (`float`) – Bending moment around y-axis (default: 0.0). * **Mz** (`float`) – Bending moment around z-axis (default: 0.0). ## LoadingULS[​](/sdk/13/api/external/idea/.md#_LoadingULS "Direct link to LoadingULS") * *class *viktor.external.idea\_rcs.objects.LoadingULS(*internal\_forces*, *internal\_forces\_second\_order=None*, *internal\_forces\_begin=None*, *internal\_forces\_end=None*, *internal\_forces\_imperfection=None*)[¶](#LoadingULS "Permalink to this definition") Bases: `_OpenObject` Loading ULS. * Parameters * **internal\_forces** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal force in section. * **internal\_forces\_second\_order** (`Optional`\[[`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")]) – Internal forces of 2nd order effect. * **internal\_forces\_begin** (`Optional`\[[`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")]) – Internal forces at the beginning. * **internal\_forces\_end** (`Optional`\[[`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")]) – Internal forces at the end. * **internal\_forces\_imperfection** (`Optional`\[[`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")]) – Internal forces of imperfection effect. ## LoadingSLS[​](/sdk/13/api/external/idea/.md#_LoadingSLS "Direct link to LoadingSLS") * *class *viktor.external.idea\_rcs.objects.LoadingSLS(*internal\_forces*, *internal\_forces\_imperfection=None*)[¶](#LoadingSLS "Permalink to this definition") Bases: `_OpenObject` Loading SLS. * Parameters * **internal\_forces** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal force in section. * **internal\_forces\_imperfection** (`Optional`\[[`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")]) – Internal forces of imperfection effect. ## FatigueLoading[​](/sdk/13/api/external/idea/.md#_FatigueLoading "Direct link to FatigueLoading") * *class *viktor.external.idea\_rcs.objects.FatigueLoading(*max\_loading*, *min\_loading*)[¶](#FatigueLoading "Permalink to this definition") Bases: `_OpenObject` Fatigue loading. * Parameters * **max\_loading** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Max. cyclic loading. * **min\_loading** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Min. cyclic loading. ## CheckSectionExtreme[​](/sdk/13/api/external/idea/.md#_CheckSectionExtreme "Direct link to CheckSectionExtreme") * *class *viktor.external.idea\_rcs.objects.CheckSectionExtreme(*accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*)[¶](#CheckSectionExtreme "Permalink to this definition") Bases: `_OpenObject` Abstract base class of all check section extremes. ## StandardCheckSectionExtreme[​](/sdk/13/api/external/idea/.md#_StandardCheckSectionExtreme "Direct link to StandardCheckSectionExtreme") * *class *viktor.external.idea\_rcs.objects.StandardCheckSectionExtreme(*\**, *accidental=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*, *fatigue=None*)[¶](#StandardCheckSectionExtreme "Permalink to this definition") Bases: [`CheckSectionExtreme`](#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme") Do not use this \_\_init\_\_ directly, but create the object by [`CheckSection.create_extreme()`](#CheckSection.create_extreme "viktor.external.idea_rcs.objects.CheckSection.create_extreme"). ## CheckSection[​](/sdk/13/api/external/idea/.md#_CheckSection "Direct link to CheckSection") * *class *viktor.external.idea\_rcs.objects.CheckSection(*id\_*, *description*, *check\_member*, *reinf\_section*, *extremes=None*)[¶](#CheckSection "Permalink to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all check sections. * *property *extremes*: List\[[CheckSectionExtreme](#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")]*[¶](#CheckSection.extremes "Permalink to this definition") * Return type `List`\[[`CheckSectionExtreme`](#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")] - create\_extreme(*\**, *accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*)[¶](#CheckSection.create_extreme "Permalink to this definition") Create an extreme case with corresponding internal forces on the section for checking. * Parameters * **accidental** (`Optional`\[[`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")]) – Accidental loading. * **fatigue** (`Optional`\[[`FatigueLoading`](#FatigueLoading "viktor.external.idea_rcs.objects.FatigueLoading")]) – Fatigue loading. * **frequent** (`Optional`\[[`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Frequent loading. * **fundamental** (`Optional`\[[`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")]) – Fundamental loading. * **characteristic** (`Optional`\[[`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Characteristic loading. * **quasi\_permanent** (`Optional`\[[`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")]) – Quasi-Permanent loading. * Return type `None` ## StandardCheckSection[​](/sdk/13/api/external/idea/.md#_StandardCheckSection "Direct link to StandardCheckSection") * *class *viktor.external.idea\_rcs.objects.StandardCheckSection(*id\_*, *description*, *check\_member*, *reinf\_section*, *extremes=None*)[¶](#StandardCheckSection "Permalink to this definition") Bases: [`CheckSection`](#CheckSection "viktor.external.idea_rcs.objects.CheckSection") Do not use this \_\_init\_\_ directly, but create the object by [`add_check_section()`](/sdk/13/api/external/idea/.md#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). ## MemberType[​](/sdk/13/api/external/idea/.md#_MemberType "Direct link to MemberType") * *class *viktor.external.idea\_rcs.objects.MemberType(*value*)[¶](#MemberType "Permalink to this definition") Bases: `Enum` An enumeration. * UNDEFINED*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 0*[¶](#MemberType.UNDEFINED "Permalink to this definition") - BEAM*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 1*[¶](#MemberType.BEAM "Permalink to this definition") * COLUMN*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 2*[¶](#MemberType.COLUMN "Permalink to this definition") - BEAM\_SLAB*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 4*[¶](#MemberType.BEAM_SLAB "Permalink to this definition") * HOLLOW\_CORE\_SLAB*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 8*[¶](#MemberType.HOLLOW_CORE_SLAB "Permalink to this definition") - TWO\_WAY\_SLAB*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 16*[¶](#MemberType.TWO_WAY_SLAB "Permalink to this definition") * PLATE*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 32*[¶](#MemberType.PLATE "Permalink to this definition") - WALL*: [MemberType](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 64*[¶](#MemberType.WALL "Permalink to this definition") ## TwoWaySlabType[​](/sdk/13/api/external/idea/.md#_TwoWaySlabType "Direct link to TwoWaySlabType") * *class *viktor.external.idea\_rcs.objects.TwoWaySlabType(*value*)[¶](#TwoWaySlabType "Permalink to this definition") Bases: `Enum` An enumeration. * SLAB*: [TwoWaySlabType](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 0*[¶](#TwoWaySlabType.SLAB "Permalink to this definition") - WALL*: [TwoWaySlabType](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 1*[¶](#TwoWaySlabType.WALL "Permalink to this definition") * DEEP\_BEAM*: [TwoWaySlabType](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 2*[¶](#TwoWaySlabType.DEEP_BEAM "Permalink to this definition") - SHELL\_AS\_PLATE*: [TwoWaySlabType](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 3*[¶](#TwoWaySlabType.SHELL_AS_PLATE "Permalink to this definition") * SHELL\_AS\_WALL*: [TwoWaySlabType](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 4*[¶](#TwoWaySlabType.SHELL_AS_WALL "Permalink to this definition") ## CalculationSetup[​](/sdk/13/api/external/idea/.md#_CalculationSetup "Direct link to CalculationSetup") * *class *viktor.external.idea\_rcs.objects.CalculationSetup(*\**, *uls\_response=None*, *uls\_diagram=None*, *uls\_shear=None*, *uls\_torsion=None*, *uls\_interaction=None*, *sls\_crack=None*, *sls\_stress\_limitation=None*, *sls\_stiffnesses=None*, *detailing=None*, *m\_n\_kappa\_diagram=None*, *fatigue=None*, *cross\_section\_characteristics=None*)[¶](#CalculationSetup "Permalink to this definition") Bases: `_OpenObject` Concrete calculation setup. * Parameters * **uls\_response** (`Optional`\[`bool`]) – Response N-M(-M) (default: False). * **uls\_diagram** (`Optional`\[`bool`]) – Capacity N-M(-M) (default: True). * **uls\_shear** (`Optional`\[`bool`]) – Shear (default: True). * **uls\_torsion** (`Optional`\[`bool`]) – Torsion (default: True). * **uls\_interaction** (`Optional`\[`bool`]) – Interaction (default: True). * **sls\_crack** (`Optional`\[`bool`]) – Crack width (default: True). * **sls\_stress\_limitation** (`Optional`\[`bool`]) – Stress limitation (default: True). * **sls\_stiffnesses** (`Optional`\[`bool`]) – Stiffnesses (default: False). * **detailing** (`Optional`\[`bool`]) – Detailing (default: True). * **m\_n\_kappa\_diagram** (`Optional`\[`bool`]) – M-N-κ diagram (default: False). * **fatigue** (`Optional`\[`bool`]) – Fatigue (default: True). * **cross\_section\_characteristics** (`Optional`\[`bool`]) – Cross section characteristics (default: IDEA-RCS default). ## ConcreteMemberData[​](/sdk/13/api/external/idea/.md#_ConcreteMemberData "Direct link to ConcreteMemberData") * *class *viktor.external.idea\_rcs.objects.ConcreteMemberData(*element*, *member\_type*, *two\_way\_slab\_type*, *calculation\_setup=None*)[¶](#ConcreteMemberData "Permalink to this definition") Bases: `_OpenObject`, `ABC` Abstract base class of all concrete member data. ## ExposureClassEc2Carbonation[​](/sdk/13/api/external/idea/.md#_ExposureClassEc2Carbonation "Direct link to ExposureClassEc2Carbonation") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2Carbonation(*value*)[¶](#ExposureClassEc2Carbonation "Permalink to this definition") Bases: `Enum` An enumeration. * XC1*: [ExposureClassEc2Carbonation](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 1*[¶](#ExposureClassEc2Carbonation.XC1 "Permalink to this definition") - XC2*: [ExposureClassEc2Carbonation](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 2*[¶](#ExposureClassEc2Carbonation.XC2 "Permalink to this definition") * XC3*: [ExposureClassEc2Carbonation](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 3*[¶](#ExposureClassEc2Carbonation.XC3 "Permalink to this definition") - XC4*: [ExposureClassEc2Carbonation](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 4*[¶](#ExposureClassEc2Carbonation.XC4 "Permalink to this definition") ## ExposureClassEc2Chlorides[​](/sdk/13/api/external/idea/.md#_ExposureClassEc2Chlorides "Direct link to ExposureClassEc2Chlorides") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2Chlorides(*value*)[¶](#ExposureClassEc2Chlorides "Permalink to this definition") Bases: `Enum` An enumeration. * XD1*: [ExposureClassEc2Chlorides](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 1*[¶](#ExposureClassEc2Chlorides.XD1 "Permalink to this definition") - XD2*: [ExposureClassEc2Chlorides](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 2*[¶](#ExposureClassEc2Chlorides.XD2 "Permalink to this definition") * XD3*: [ExposureClassEc2Chlorides](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 3*[¶](#ExposureClassEc2Chlorides.XD3 "Permalink to this definition") ## ExposureClassEc2ChloridesFromSea[​](/sdk/13/api/external/idea/.md#_ExposureClassEc2ChloridesFromSea "Direct link to ExposureClassEc2ChloridesFromSea") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2ChloridesFromSea(*value*)[¶](#ExposureClassEc2ChloridesFromSea "Permalink to this definition") Bases: `Enum` An enumeration. * XS1*: [ExposureClassEc2ChloridesFromSea](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 1*[¶](#ExposureClassEc2ChloridesFromSea.XS1 "Permalink to this definition") - XS2*: [ExposureClassEc2ChloridesFromSea](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 2*[¶](#ExposureClassEc2ChloridesFromSea.XS2 "Permalink to this definition") * XS3*: [ExposureClassEc2ChloridesFromSea](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 3*[¶](#ExposureClassEc2ChloridesFromSea.XS3 "Permalink to this definition") ## ExposureClassEc2FreezeAttack[​](/sdk/13/api/external/idea/.md#_ExposureClassEc2FreezeAttack "Direct link to ExposureClassEc2FreezeAttack") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2FreezeAttack(*value*)[¶](#ExposureClassEc2FreezeAttack "Permalink to this definition") Bases: `Enum` An enumeration. * XF1*: [ExposureClassEc2FreezeAttack](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 1*[¶](#ExposureClassEc2FreezeAttack.XF1 "Permalink to this definition") - XF2*: [ExposureClassEc2FreezeAttack](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 2*[¶](#ExposureClassEc2FreezeAttack.XF2 "Permalink to this definition") * XF3*: [ExposureClassEc2FreezeAttack](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 3*[¶](#ExposureClassEc2FreezeAttack.XF3 "Permalink to this definition") - XF4*: [ExposureClassEc2FreezeAttack](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 4*[¶](#ExposureClassEc2FreezeAttack.XF4 "Permalink to this definition") ## ExposureClassEc2ChemicalAttack[​](/sdk/13/api/external/idea/.md#_ExposureClassEc2ChemicalAttack "Direct link to ExposureClassEc2ChemicalAttack") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2ChemicalAttack(*value*)[¶](#ExposureClassEc2ChemicalAttack "Permalink to this definition") Bases: `Enum` An enumeration. * XA1*: [ExposureClassEc2ChemicalAttack](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 1*[¶](#ExposureClassEc2ChemicalAttack.XA1 "Permalink to this definition") - XA2*: [ExposureClassEc2ChemicalAttack](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 2*[¶](#ExposureClassEc2ChemicalAttack.XA2 "Permalink to this definition") * XA3*: [ExposureClassEc2ChemicalAttack](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 3*[¶](#ExposureClassEc2ChemicalAttack.XA3 "Permalink to this definition") ## ExposureClassesDataEc2[​](/sdk/13/api/external/idea/.md#_ExposureClassesDataEc2 "Direct link to ExposureClassesDataEc2") * *class *viktor.external.idea\_rcs.objects.ExposureClassesDataEc2(*\**, *carbonation=None*, *chlorides=None*, *chlorides\_from\_sea=None*, *freeze\_attack=None*, *chemical\_attack=None*)[¶](#ExposureClassesDataEc2 "Permalink to this definition") Bases: `_OpenObject` Exposure Classes Ec2. * Parameters * **carbonation** (`Optional`\[[`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")]) – Carbonation (default: None). * **chlorides** (`Optional`\[[`ExposureClassEc2Chlorides`](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")]) – Chlorides (default: None). * **chlorides\_from\_sea** (`Optional`\[[`ExposureClassEc2ChloridesFromSea`](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")]) – Chlorides from sea (default: None). * **freeze\_attack** (`Optional`\[[`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")]) – Freeze/Thaw Attack (default: None). * **chemical\_attack** (`Optional`\[[`ExposureClassEc2ChemicalAttack`](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")]) – Chemical Attack (default: None). ## ConcreteMemberDataEc2[​](/sdk/13/api/external/idea/.md#_ConcreteMemberDataEc2 "Direct link to ConcreteMemberDataEc2") * *class *viktor.external.idea\_rcs.objects.ConcreteMemberDataEc2(*element*, *member\_type*, *two\_way\_slab\_type*, *calculation\_setup=None*, *coeff\_kx\_for\_wmax=None*, *exposure\_class\_data=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[¶](#ConcreteMemberDataEc2 "Permalink to this definition") Bases: [`ConcreteMemberData`](#ConcreteMemberData "viktor.external.idea_rcs.objects.ConcreteMemberData") Do not use this \_\_init\_\_ directly, but create the object by [`add_member_data_ec2()`](/sdk/13/api/external/idea/.md#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2"). --- # viktor.external.matlab Added in v14.17.0 --- # viktor.external.plaxis Added in v14.17.0 --- # viktor.external.python Added in v14.17.0 --- # viktor.external.revit Added in v14.17.0 --- # viktor.external.rfem ## LoadingType[​](/sdk/13/api/external/rfem/.md#_LoadingType "Direct link to LoadingType") * *class *viktor.external.rfem.LoadingType(*value*)[¶](#LoadingType "Permalink to this definition") Bases: `Enum` An enumeration. * LOAD\_CASE*: [LoadingType](#LoadingType "viktor.external.rfem.LoadingType")** = 1*[¶](#LoadingType.LOAD_CASE "Permalink to this definition") - LOAD\_COMBINATION*: [LoadingType](#LoadingType "viktor.external.rfem.LoadingType")** = 2*[¶](#LoadingType.LOAD_COMBINATION "Permalink to this definition") ## RFEMAction[​](/sdk/13/api/external/rfem/.md#_RFEMAction "Direct link to RFEMAction") * *class *viktor.external.rfem.RFEMAction(*id\_*)[¶](#RFEMAction "Permalink to this definition") Bases: `ABC` Abstract base class of all RFEM action objects. ## EnergyOptimizationAction[​](/sdk/13/api/external/rfem/.md#_EnergyOptimizationAction "Direct link to EnergyOptimizationAction") * *class *viktor.external.rfem.EnergyOptimizationAction(*load\_cases*, *loading\_type=LoadingType.LOAD\_CASE*, *\**, *goal*, *accuracy*)[¶](#EnergyOptimizationAction "Permalink to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") * Performs an iterative analysis (consisting of a series of RFEM analyses) to solve for the magnitude of the 1st nodal load, such that the energy at that node (approximately) equals the ‘goal’. The iteration comes to a finish if the change in displacement at the node is lower than the specified ‘accuracy’. This is done for each of the load cases specified. - Parameters * **load\_cases** (`List`\[`int`]) – a list of load cases/combinations to do a energy optimization calculation for. None for all load cases/combinations (default: None). * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘load\_cases’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) * **goal** (`float`) – energy level \[Nm] for which the calculation tries to solve the 1st nodal load. Same goal is used for all load cases/combinations. * **accuracy** (`float`) – change in displacement \[m] of the node corresponding to the 1st nodal load at which the iteration will successfully return. A lower accuracy in general means more iterations. Same accuracy is used for all load cases/combinations. ## CopyNodalLoadAction[​](/sdk/13/api/external/rfem/.md#_CopyNodalLoadAction "Direct link to CopyNodalLoadAction") * *class *viktor.external.rfem.CopyNodalLoadAction(*copy\_from\_to*, *loading\_type=LoadingType.LOAD\_CASE*, *\**, *factor=1.0*)[¶](#CopyNodalLoadAction "Permalink to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") Copy the nodal load from one load case to the other, applying a factor on the magnitude. * Note: only the 1st nodal load is copied from and to each load case/combination, other loads are ignored. Make sure that at least 1 such nodal load exists in both the copy-from and copy-to load cases/combinations. - Parameters * **copy\_from\_to** (`List`\[`Tuple`\[`int`, `int`]]) – a list of load case/combination numbers to copy (from, to) * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘copy\_from\_to’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) * **factor** (`float`) – factor to be applied on the nodal load magnitude (default: 1.0) ## WriteResultsAction[​](/sdk/13/api/external/rfem/.md#_WriteResultsAction "Direct link to WriteResultsAction") * *class *viktor.external.rfem.WriteResultsAction(*load\_cases=None*, *loading\_type=LoadingType.LOAD\_CASE*)[¶](#WriteResultsAction "Permalink to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") Write all nodal deformations (X, Y, Z) and member internal forces (Location, My, Mz, Fy, Fz) for the model in current state, for each of the load cases/combinations requested, so that it is available in [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result"). * Parameters * **load\_cases** (`Optional`\[`List`\[`int`]]) – a list of load cases/combinations to write the results for. None for all load cases/combinations (default: None). * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘load\_cases’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) ## RFEMAnalysis[​](/sdk/13/api/external/rfem/.md#_RFEMAnalysis "Direct link to RFEMAnalysis") * *class *viktor.external.rfem.RFEMAnalysis(*rfx\_file*, *actions*)[¶](#RFEMAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") RFEMAnalysis can be used to perform an analysis with RFEM on third-party infrastructure. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the model call [`get_model()`](#RFEMAnalysis.get_model "viktor.external.rfem.RFEMAnalysis.get_model") and for results call [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result") for the desired load combination (only after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute")). Exceptions which can be raised during calculation: > * [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information Example usage: ``` # SLS sls_cases = [1, 2, 3] sls_optimization = EnergyOptimizationAction(sls_cases, goal=10000, accuracy=0.1) # goal = 10 kNm, accuracy = 10 cm # ALS als_cases = [4, 5, 6] als_optimization = EnergyOptimizationAction(als_cases, goal=15000, accuracy=0.1) # goal = 15 kNm, accuracy = 10 cm # ULS uls_cases = [7, 8, 9] uls_creation = CopyNodalLoadAction(list(zip(sls_cases, uls_cases)), factor=1.5) # ULS = SLS x 1.5 # Write action write_result_action = WriteResultsAction(sls_cases + als_cases + uls_cases) # or can be left empty = all cases actions = [sls_optimization, als_optimization, uls_creation, write_result_action] rfem_analysis = RFEMAnalysis(rfx_file=my_rfx_file, actions=actions) # my_rfx_file contains the desired load cases and nodal loads rfem_analysis.execute(timeout=300) model = rfem_analysis.get_model() result_lc1 = rfem_analysis.get_result(1) result_lc2 = rfem_analysis.get_result(2) ``` * Parameters * **rfx\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – RFEM input file * **actions** (`List`\[[`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction")]) – list of actions to be performed sequentially. Possible actions are: * [`EnergyOptimizationAction`](#EnergyOptimizationAction "viktor.external.rfem.EnergyOptimizationAction") * [`CopyNodalLoadAction`](#CopyNodalLoadAction "viktor.external.rfem.CopyNodalLoadAction") * [`WriteResultsAction`](#WriteResultsAction "viktor.external.rfem.WriteResultsAction") (required for [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result")) - get\_model(*\**, *as\_file=False*)[¶](#RFEMAnalysis.get_model "Permalink to this definition") Get the model that is returned after the RFEM analysis. * Parameters **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * get\_result(*load\_case*, *\**, *as\_file=False*)[¶](#RFEMAnalysis.get_result "Permalink to this definition") Get the nodal deformations (X, Y, Z) \[m] and member internal forces (Location \[m], My and Mz \[Nm], Fy and Fz \[N]) for a certain load case/combination number. * Parameters * **load\_case** (`int`) – number of the load case/combination to get the result for. A ‘WriteResultsAction’ must have been performed on the corresponding load case/combination to be available. * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] --- # viktor.external.robot ## RobotAnalysis[​](/sdk/13/api/external/robot/.md#_RobotAnalysis "Direct link to RobotAnalysis") * *class *viktor.external.robot.RobotAnalysis(*input\_file*, *\**, *return\_model=True*, *return\_results=True*, *requested\_results=None*)[¶](#RobotAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Perform an analysis using Autodesk Robot on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_results()`](#RobotAnalysis.get_results "viktor.external.robot.RobotAnalysis.get_results"), after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). The evaluated model file can be retrieved by calling [`get_model_file()`](#RobotAnalysis.get_model_file "viktor.external.robot.RobotAnalysis.get_model_file"). Usage: ``` robot_analysis = RobotAnalysis(input_file, return_model=True) robot_analysis.execute(timeout=10) results = robot_analysis.get_results() model_file = robot_analysis.get_model_file() ``` Exceptions which can be raised during calculation: > * [`ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters * **input\_file** ([`File`](/sdk/13/api/core/.md#File "viktor.core.File")) – Robot input file in STR format * **return\_results** (`bool`) – If True, an analysis will be run and the result file is returned. * **return\_model** (`bool`) – If True, the model file (.rtd) is returned. * **requested\_results** (`Optional`\[`dict`]) – (optional) Dictionary containing the requested results. If requested\_results is None and return\_results is True, the worker will return all results. For the allowed components see the Autodesk Robot SDK documentation. The dictionary should be formatted as follows: ``` { "bar_forces": List[string], "bar_displacements": List[string], "bar_stresses": List[string], "bar_deflections": List[string], "node_reactions": List[string], "node_displacements": List[string], } ``` * get\_model\_file()[¶](#RobotAnalysis.get_model_file "Permalink to this definition") Retrieve the model file (only if return\_model = True) in .rtd format. [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type `Optional`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")] - get\_results()[¶](#RobotAnalysis.get_results "Permalink to this definition") Retrieve the results (only if return\_results = True). `execute()` must be called first. The format of the returned dictionary is: ``` { 'bar_forces': { '1': { # case id '1': { # bar id '0.000000': { # positions 'FX': 26070.462297973572 # components } } } }, 'bar_displacements': { '1': { '1': { '0.000000': { 'RX': 0 } } } }, 'bar_stresses': { '1': { '1': { '0.000000': { 'FXSX': 19750.350225737555 } } } }, 'bar_deflections': { '1': { '1': { '0.000000': { 'PosUX': 0 } } } }, 'node_reactions': { '1': { # case id '1': { # node id 'FX': -9.89530235528946e-09 # components } } }, 'node_displacements': { '1': { '1': { 'RX': 0 } } } } ``` * Return type `Optional`\[`dict`] --- # viktor.external.sap2000 Added in v14.17.0 --- # viktor.external.scia ## CalcSetting[​](/sdk/13/api/external/scia/.md#_CalcSetting "Direct link to CalcSetting") * *class *viktor.external.scia.scia.CalcSetting(*value*)[¶](#CalcSetting "Permalink to this definition") Bases: `Enum` Enumeration of calculation settings: * NONE*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NONE'*[¶](#CalcSetting.NONE "Permalink to this definition") - NOC*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NOC'*[¶](#CalcSetting.NOC "Permalink to this definition") * LIN*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'LIN'*[¶](#CalcSetting.LIN "Permalink to this definition") - NEL*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NEL'*[¶](#CalcSetting.NEL "Permalink to this definition") * EIG*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'EIG'*[¶](#CalcSetting.EIG "Permalink to this definition") - STB*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'STB'*[¶](#CalcSetting.STB "Permalink to this definition") * INF*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'INF'*[¶](#CalcSetting.INF "Permalink to this definition") - MOB*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'MOB'*[¶](#CalcSetting.MOB "Permalink to this definition") * TDA*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'TDA'*[¶](#CalcSetting.TDA "Permalink to this definition") - SLN*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'SLN'*[¶](#CalcSetting.SLN "Permalink to this definition") * PHA*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'PHA'*[¶](#CalcSetting.PHA "Permalink to this definition") - NPH*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NPH'*[¶](#CalcSetting.NPH "Permalink to this definition") * CSS*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'CSS'*[¶](#CalcSetting.CSS "Permalink to this definition") - NST*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NST'*[¶](#CalcSetting.NST "Permalink to this definition") * TID*: [CalcSetting](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'TID'*[¶](#CalcSetting.TID "Permalink to this definition") ## ResultType[​](/sdk/13/api/external/scia/.md#_ResultType "Direct link to ResultType") * *class *viktor.external.scia.scia.ResultType(*value*)[¶](#ResultType "Permalink to this definition") Bases: `Enum` Enumeration of result types: * NONE*: [ResultType](#ResultType "viktor.external.scia.scia.ResultType")** = 'XML'*[¶](#ResultType.NONE "Permalink to this definition") - MODEL*: [ResultType](#ResultType "viktor.external.scia.scia.ResultType")** = 'MODEL'*[¶](#ResultType.MODEL "Permalink to this definition") * ENGINEERING\_REPORT*: [ResultType](#ResultType "viktor.external.scia.scia.ResultType")** = 'ENGINEERING\_REPORT'*[¶](#ResultType.ENGINEERING_REPORT "Permalink to this definition") ## SciaAnalysis[​](/sdk/13/api/external/scia/.md#_SciaAnalysis "Direct link to SciaAnalysis") * *class *viktor.external.scia.scia.SciaAnalysis(*input\_file*, *xml\_def\_file*, *scia\_model*, *calculation\_setting=CalcSetting.LIN*, *xml\_doc\_name='output'*, *\**, *result\_type=ResultType.MODEL*, *output\_document=''*)[¶](#SciaAnalysis "Permalink to this definition") Bases: [`ExternalProgram`](/sdk/13/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") SciaAnalysis can be used to perform an analysis using SCIA on a third-party worker. To start an analysis call the method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the output file call the method [`get_xml_output_file()`](#SciaAnalysis.get_xml_output_file "viktor.external.scia.scia.SciaAnalysis.get_xml_output_file") after [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` input_file = BytesIO("scia input file content".encode()) xml_def_file = BytesIO("scia xml def file content".encode()) scia_model = BytesIO("scia model content".encode()) scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model) scia_analysis.execute(timeout=600) xml_output_file = scia_analysis.get_xml_output_file() ``` Besides the output XML file, you can also retrieve the updated SCIA model. This is achieved using the result\_type: ``` scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model, result_type=ResultType.MODEL) scia_analysis.execute(timeout=600) updated_esa_file = scia_analysis.get_updated_esa_model() ``` or the Engineering Report: ``` scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model, result_type=ResultType.ENGINEERING_REPORT, output_document='report1') scia_analysis.execute(timeout=600) engineering_report = scia_analysis.get_engineering_report() ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/13/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/13/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters * **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – SCIA input .xml file. * **xml\_def\_file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – SCIA input .def file. * **scia\_model** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – SCIA .esa model. * **calculation\_setting** ([`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")) – Available calculation settings according to the documentation of ESA\_XML.exe: * NONE = without any recalculations * NOC = No calculation * LIN = Linear calculation (Delete all calculated results when exists) * NEL = Nonlinear calculation * CON = Nonlinear concrete calculation * EIG = Eigen frequencies calculation * STB = Stability calculation * INF = Influence lines calculation * MOB = Mobile loads calculation * TDA = TDA calculation * SLN = Soilin calculation * PHA = Phases calculation * NPH = Nonlinear phases * CSS = Recalculation of cross sections * NST = Nonlinear stability * TID = Test of input data - solver link only * **xml\_doc\_name** (`str`) – Name of XML IO document for export. * **result\_type** ([`ResultType`](#ResultType "viktor.external.scia.scia.ResultType")) – Type of output which should be returned besides the output.xml: * ResultType.NONE returns nothing * ResultType.MODEL returns the updated SCIA model (.esa) after calculation * ResultType.ENGINEERING\_REPORT returns the specified engineering report * **output\_document** (`str`) – Document name of the report which should be returned. This name should match the exact name of the report as defined in the .esa model. * Raises **ValueError** – if Engineering Report is selected as result\_type, but no output\_document is specified. - *static *get\_xml\_def\_name(*input\_file*)[¶](#SciaAnalysis.get_xml_def_name "Permalink to this definition") * Return type `str` * get\_xml\_output\_file(*as\_file=False*)[¶](#SciaAnalysis.get_xml_output_file "Permalink to this definition") Method can be used to retrieve the results generated by running an external analysis. This method returns the output XML file that is generated by SCIA. Make sure to call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_xml_output_file()`](#SciaAnalysis.get_xml_output_file "viktor.external.scia.scia.SciaAnalysis.get_xml_output_file") afterwards. * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * Returns * File, if as\_file = True * BytesIO, if as\_file = False (default) - get\_updated\_esa\_model(*as\_file=False*)[¶](#SciaAnalysis.get_updated_esa_model "Permalink to this definition") Method can be used to retrieve the updated SCIA model file (.esa), which contains the data that is read into the model while calling ESA\_XML.exe. Make sure to call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_updated_esa_model()`](#SciaAnalysis.get_updated_esa_model "viktor.external.scia.scia.SciaAnalysis.get_updated_esa_model") afterwards. * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * Returns * File, if as\_file = True * BytesIO, if as\_file = False (default) * get\_engineering\_report(*as\_file=False*)[¶](#SciaAnalysis.get_engineering_report "Permalink to this definition") Method can be used to retrieve the Engineering Report (.pdf). Make sure to call method [`execute()`](/sdk/13/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_engineering_report()`](#SciaAnalysis.get_engineering_report "viktor.external.scia.scia.SciaAnalysis.get_engineering_report") afterwards. * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`] * Returns * File, if as\_file = True * BytesIO, if as\_file = False (default) ## Model[​](/sdk/13/api/external/scia/.md#_Model "Direct link to Model") * *class *viktor.external.scia.scia.Model(*\**, *mesh\_setup=None*, *solver\_setup=None*, *project\_data=None*)[¶](#Model "Permalink to this definition") This Model can be used to construct a SCIA model and generate its corresponding input XML file. This file can in turn be used as input of [`SciaAnalysis`](#SciaAnalysis "viktor.external.scia.scia.SciaAnalysis"). For a more detailed elaboration, please see the tutorial. Example usage: ``` # Initialize the model model = Model() # Construct the geometry n1 = model.create_node('K:1', 0, 0, 0) n2 = model.create_node('K:2', 1, 0, 0) css = model.create_circular_cross_section('css', Material(123, 'some_material'), 100) beam = model.create_beam(n1, n2, css) #Construct the boundary conditions freedom = (PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID) model.create_point_support('Sn1', n1, PointSupport.Type.STANDARD, freedom, (0, 0, 0, 0, 0, 0), PointSupport.CSys.GLOBAL) # Construct a load combination load_group = model.create_load_group('LG1', LoadGroup.LoadOption.VARIABLE, LoadGroup.RelationOption.STANDARD, LoadGroup.LoadTypeOption.CAT_A) load_case = model.create_variable_load_case('LC1', 'My first load case', load_group, LoadCase.VariableLoadType.STATIC, LoadCase.Specification.STANDARD, LoadCase.Duration.SHORT) model.create_load_combination('C1', LoadCombination.Type.ENVELOPE_ULTIMATE, {load_case: 1}) # Generate the input XML file input_xml = model.generate_xml_input() ``` * Parameters * **mesh\_setup** (`Optional`\[[`MeshSetup`](/sdk/13/api/external/scia/.md#MeshSetup "viktor.external.scia.object.MeshSetup")]) – Optional mesh settings. * **solver\_setup** (`Optional`\[[`SolverSetup`](/sdk/13/api/external/scia/.md#SolverSetup "viktor.external.scia.object.SolverSetup")]) – Optional solver settings New in v13.1.0 . * **project\_data** (`Optional`\[[`ProjectData`](/sdk/13/api/external/scia/.md#ProjectData "viktor.external.scia.object.ProjectData")]) – Optional project settings New in v13.1.0 . - *property *layers*: Tuple\[[Layer](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer"), ...]*[¶](#Model.layers "Permalink to this definition") * Return type `Tuple`\[[`Layer`](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer"), `...`] * *property *concrete\_materials*: Tuple\[[Concrete](/sdk/13/api/external/scia/.md#Concrete "viktor.external.scia.object.Concrete"), ...]*[¶](#Model.concrete_materials "Permalink to this definition") * Return type `Tuple`\[[`Concrete`](/sdk/13/api/external/scia/.md#Concrete "viktor.external.scia.object.Concrete"), `...`] - *property *nonlinear\_functions*: Tuple\[[NonLinearFunction](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction"), ...]*[¶](#Model.nonlinear_functions "Permalink to this definition") * Return type `Tuple`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction"), `...`] * *property *subsoils*: Tuple\[[Subsoil](/sdk/13/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil"), ...]*[¶](#Model.subsoils "Permalink to this definition") * Return type `Tuple`\[[`Subsoil`](/sdk/13/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil"), `...`] - *property *orthotropy\_objects*: Tuple\[[Orthotropy](/sdk/13/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy"), ...]*[¶](#Model.orthotropy_objects "Permalink to this definition") * Return type `Tuple`\[[`Orthotropy`](/sdk/13/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy"), `...`] * *property *cross\_sections*: Tuple\[[CrossSection](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection"), ...]*[¶](#Model.cross_sections "Permalink to this definition") * Return type `Tuple`\[[`CrossSection`](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection"), `...`] - *property *nodes*: Tuple\[[Node](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node"), ...]*[¶](#Model.nodes "Permalink to this definition") * Return type `Tuple`\[[`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node"), `...`] * *property *beams*: Tuple\[[Beam](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam"), ...]*[¶](#Model.beams "Permalink to this definition") * Return type `Tuple`\[[`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam"), `...`] - *property *cross\_links*: Tuple\[[CrossLink](/sdk/13/api/external/scia/.md#CrossLink "viktor.external.scia.object.CrossLink"), ...]*[¶](#Model.cross_links "Permalink to this definition") New in v13.1.0 * Return type `Tuple`\[[`CrossLink`](/sdk/13/api/external/scia/.md#CrossLink "viktor.external.scia.object.CrossLink"), `...`] * *property *arbitrary\_profiles*: Tuple\[[ArbitraryProfile](/sdk/13/api/external/scia/.md#ArbitraryProfile "viktor.external.scia.object.ArbitraryProfile"), ...]*[¶](#Model.arbitrary_profiles "Permalink to this definition") * Return type `Tuple`\[[`ArbitraryProfile`](/sdk/13/api/external/scia/.md#ArbitraryProfile "viktor.external.scia.object.ArbitraryProfile"), `...`] - *property *hinges\_on\_beam*: Tuple\[[HingeOnBeam](/sdk/13/api/external/scia/.md#HingeOnBeam "viktor.external.scia.object.HingeOnBeam"), ...]*[¶](#Model.hinges_on_beam "Permalink to this definition") * Return type `Tuple`\[[`HingeOnBeam`](/sdk/13/api/external/scia/.md#HingeOnBeam "viktor.external.scia.object.HingeOnBeam"), `...`] * *property *hinges\_on\_plane*: Tuple\[[HingeOnPlane](/sdk/13/api/external/scia/.md#HingeOnPlane "viktor.external.scia.object.HingeOnPlane"), ...]*[¶](#Model.hinges_on_plane "Permalink to this definition") * Return type `Tuple`\[[`HingeOnPlane`](/sdk/13/api/external/scia/.md#HingeOnPlane "viktor.external.scia.object.HingeOnPlane"), `...`] - *property *sections\_on\_beam*: Tuple\[[SectionOnBeam](/sdk/13/api/external/scia/.md#SectionOnBeam "viktor.external.scia.object.SectionOnBeam"), ...]*[¶](#Model.sections_on_beam "Permalink to this definition") * Return type `Tuple`\[[`SectionOnBeam`](/sdk/13/api/external/scia/.md#SectionOnBeam "viktor.external.scia.object.SectionOnBeam"), `...`] * *property *sections\_on\_plane*: Tuple\[[SectionOnPlane](/sdk/13/api/external/scia/.md#SectionOnPlane "viktor.external.scia.object.SectionOnPlane"), ...]*[¶](#Model.sections_on_plane "Permalink to this definition") * Return type `Tuple`\[[`SectionOnPlane`](/sdk/13/api/external/scia/.md#SectionOnPlane "viktor.external.scia.object.SectionOnPlane"), `...`] - *property *planes*: Tuple\[[Plane](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), ...]*[¶](#Model.planes "Permalink to this definition") * Return type `Tuple`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `...`] * *property *open\_slabs*: Tuple\[[OpenSlab](/sdk/13/api/external/scia/.md#OpenSlab "viktor.external.scia.object.OpenSlab"), ...]*[¶](#Model.open_slabs "Permalink to this definition") * Return type `Tuple`\[[`OpenSlab`](/sdk/13/api/external/scia/.md#OpenSlab "viktor.external.scia.object.OpenSlab"), `...`] - *property *internal\_edges*: Tuple\[[InternalEdge](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge"), ...]*[¶](#Model.internal_edges "Permalink to this definition") * Return type `Tuple`\[[`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge"), `...`] * *property *rigid\_arms*: Tuple\[[RigidArm](/sdk/13/api/external/scia/.md#RigidArm "viktor.external.scia.object.RigidArm"), ...]*[¶](#Model.rigid_arms "Permalink to this definition") * Return type `Tuple`\[[`RigidArm`](/sdk/13/api/external/scia/.md#RigidArm "viktor.external.scia.object.RigidArm"), `...`] - *property *point\_supports*: Tuple\[[PointSupport](/sdk/13/api/external/scia/.md#PointSupport "viktor.external.scia.object.PointSupport"), ...]*[¶](#Model.point_supports "Permalink to this definition") * Return type `Tuple`\[[`PointSupport`](/sdk/13/api/external/scia/.md#PointSupport "viktor.external.scia.object.PointSupport"), `...`] * *property *point\_supports\_line*: Tuple\[[PointSupportLine](/sdk/13/api/external/scia/.md#PointSupportLine "viktor.external.scia.object.PointSupportLine"), ...]*[¶](#Model.point_supports_line "Permalink to this definition") * Return type `Tuple`\[[`PointSupportLine`](/sdk/13/api/external/scia/.md#PointSupportLine "viktor.external.scia.object.PointSupportLine"), `...`] - *property *line\_supports\_line*: Tuple\[[LineSupportLine](/sdk/13/api/external/scia/.md#LineSupportLine "viktor.external.scia.object.LineSupportLine"), ...]*[¶](#Model.line_supports_line "Permalink to this definition") * Return type `Tuple`\[[`LineSupportLine`](/sdk/13/api/external/scia/.md#LineSupportLine "viktor.external.scia.object.LineSupportLine"), `...`] * *property *line\_supports\_surface*: Tuple\[[LineSupportSurface](/sdk/13/api/external/scia/.md#LineSupportSurface "viktor.external.scia.object.LineSupportSurface"), ...]*[¶](#Model.line_supports_surface "Permalink to this definition") * Return type `Tuple`\[[`LineSupportSurface`](/sdk/13/api/external/scia/.md#LineSupportSurface "viktor.external.scia.object.LineSupportSurface"), `...`] - *property *surface\_supports*: Tuple\[[SurfaceSupportSurface](/sdk/13/api/external/scia/.md#SurfaceSupportSurface "viktor.external.scia.object.SurfaceSupportSurface"), ...]*[¶](#Model.surface_supports "Permalink to this definition") * Return type `Tuple`\[[`SurfaceSupportSurface`](/sdk/13/api/external/scia/.md#SurfaceSupportSurface "viktor.external.scia.object.SurfaceSupportSurface"), `...`] * *property *load\_cases*: Tuple\[[LoadCase](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), ...]*[¶](#Model.load_cases "Permalink to this definition") * Return type `Tuple`\[[`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), `...`] - *property *load\_groups*: Tuple\[[LoadGroup](/sdk/13/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup"), ...]*[¶](#Model.load_groups "Permalink to this definition") * Return type `Tuple`\[[`LoadGroup`](/sdk/13/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup"), `...`] * *property *load\_combinations*: Tuple\[[LoadCombination](/sdk/13/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination"), ...]*[¶](#Model.load_combinations "Permalink to this definition") * Return type `Tuple`\[[`LoadCombination`](/sdk/13/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination"), `...`] - *property *nonlinear\_load\_combinations*: Tuple\[[NonLinearLoadCombination](/sdk/13/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination"), ...]*[¶](#Model.nonlinear_load_combinations "Permalink to this definition") * Return type `Tuple`\[[`NonLinearLoadCombination`](/sdk/13/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination"), `...`] * *property *result\_classes*: Tuple\[[ResultClass](/sdk/13/api/external/scia/.md#ResultClass "viktor.external.scia.object.ResultClass"), ...]*[¶](#Model.result_classes "Permalink to this definition") * Return type `Tuple`\[[`ResultClass`](/sdk/13/api/external/scia/.md#ResultClass "viktor.external.scia.object.ResultClass"), `...`] - *property *point\_loads\_node*: Tuple\[[PointLoadNode](/sdk/13/api/external/scia/.md#PointLoadNode "viktor.external.scia.object.PointLoadNode"), ...]*[¶](#Model.point_loads_node "Permalink to this definition") * Return type `Tuple`\[[`PointLoadNode`](/sdk/13/api/external/scia/.md#PointLoadNode "viktor.external.scia.object.PointLoadNode"), `...`] * *property *point\_loads*: Tuple\[[PointLoad](/sdk/13/api/external/scia/.md#PointLoad "viktor.external.scia.object.PointLoad"), ...]*[¶](#Model.point_loads "Permalink to this definition") * Return type `Tuple`\[[`PointLoad`](/sdk/13/api/external/scia/.md#PointLoad "viktor.external.scia.object.PointLoad"), `...`] - *property *point\_moments\_node*: Tuple\[[PointMomentNode](/sdk/13/api/external/scia/.md#PointMomentNode "viktor.external.scia.object.PointMomentNode"), ...]*[¶](#Model.point_moments_node "Permalink to this definition") * Return type `Tuple`\[[`PointMomentNode`](/sdk/13/api/external/scia/.md#PointMomentNode "viktor.external.scia.object.PointMomentNode"), `...`] * *property *line\_loads*: Tuple\[[LineLoad](/sdk/13/api/external/scia/.md#LineLoad "viktor.external.scia.object.LineLoad"), ...]*[¶](#Model.line_loads "Permalink to this definition") * Return type `Tuple`\[[`LineLoad`](/sdk/13/api/external/scia/.md#LineLoad "viktor.external.scia.object.LineLoad"), `...`] - *property *line\_moments\_on\_beam*: Tuple\[[LineMomentOnBeam](/sdk/13/api/external/scia/.md#LineMomentOnBeam "viktor.external.scia.object.LineMomentOnBeam"), ...]*[¶](#Model.line_moments_on_beam "Permalink to this definition") * Return type `Tuple`\[[`LineMomentOnBeam`](/sdk/13/api/external/scia/.md#LineMomentOnBeam "viktor.external.scia.object.LineMomentOnBeam"), `...`] * *property *line\_moments\_on\_plane*: Tuple\[[LineMomentOnPlane](/sdk/13/api/external/scia/.md#LineMomentOnPlane "viktor.external.scia.object.LineMomentOnPlane"), ...]*[¶](#Model.line_moments_on_plane "Permalink to this definition") * Return type `Tuple`\[[`LineMomentOnPlane`](/sdk/13/api/external/scia/.md#LineMomentOnPlane "viktor.external.scia.object.LineMomentOnPlane"), `...`] - *property *line\_force\_surface\_list*: Tuple\[[LineForceSurface](/sdk/13/api/external/scia/.md#LineForceSurface "viktor.external.scia.object.LineForceSurface"), ...]*[¶](#Model.line_force_surface_list "Permalink to this definition") * Return type `Tuple`\[[`LineForceSurface`](/sdk/13/api/external/scia/.md#LineForceSurface "viktor.external.scia.object.LineForceSurface"), `...`] * *property *surface\_loads*: Tuple\[[SurfaceLoad](/sdk/13/api/external/scia/.md#SurfaceLoad "viktor.external.scia.object.SurfaceLoad"), ...]*[¶](#Model.surface_loads "Permalink to this definition") * Return type `Tuple`\[[`SurfaceLoad`](/sdk/13/api/external/scia/.md#SurfaceLoad "viktor.external.scia.object.SurfaceLoad"), `...`] - *property *thermal\_loads*: Tuple\[[ThermalLoad](/sdk/13/api/external/scia/.md#ThermalLoad "viktor.external.scia.object.ThermalLoad"), ...]*[¶](#Model.thermal_loads "Permalink to this definition") * Return type `Tuple`\[[`ThermalLoad`](/sdk/13/api/external/scia/.md#ThermalLoad "viktor.external.scia.object.ThermalLoad"), `...`] * *property *thermal\_surface\_loads*: Tuple\[[ThermalSurfaceLoad](/sdk/13/api/external/scia/.md#ThermalSurfaceLoad "viktor.external.scia.object.ThermalSurfaceLoad"), ...]*[¶](#Model.thermal_surface_loads "Permalink to this definition") * Return type `Tuple`\[[`ThermalSurfaceLoad`](/sdk/13/api/external/scia/.md#ThermalSurfaceLoad "viktor.external.scia.object.ThermalSurfaceLoad"), `...`] - *property *free\_surface\_loads*: Tuple\[[FreeSurfaceLoad](/sdk/13/api/external/scia/.md#FreeSurfaceLoad "viktor.external.scia.object.FreeSurfaceLoad"), ...]*[¶](#Model.free_surface_loads "Permalink to this definition") * Return type `Tuple`\[[`FreeSurfaceLoad`](/sdk/13/api/external/scia/.md#FreeSurfaceLoad "viktor.external.scia.object.FreeSurfaceLoad"), `...`] * *property *free\_line\_loads*: Tuple\[[FreeLineLoad](/sdk/13/api/external/scia/.md#FreeLineLoad "viktor.external.scia.object.FreeLineLoad"), ...]*[¶](#Model.free_line_loads "Permalink to this definition") * Return type `Tuple`\[[`FreeLineLoad`](/sdk/13/api/external/scia/.md#FreeLineLoad "viktor.external.scia.object.FreeLineLoad"), `...`] - *property *free\_point\_loads*: Tuple\[[FreePointLoad](/sdk/13/api/external/scia/.md#FreePointLoad "viktor.external.scia.object.FreePointLoad"), ...]*[¶](#Model.free_point_loads "Permalink to this definition") * Return type `Tuple`\[[`FreePointLoad`](/sdk/13/api/external/scia/.md#FreePointLoad "viktor.external.scia.object.FreePointLoad"), `...`] * *property *integration\_strips*: Tuple\[[IntegrationStrip](/sdk/13/api/external/scia/.md#IntegrationStrip "viktor.external.scia.object.IntegrationStrip"), ...]*[¶](#Model.integration_strips "Permalink to this definition") * Return type `Tuple`\[[`IntegrationStrip`](/sdk/13/api/external/scia/.md#IntegrationStrip "viktor.external.scia.object.IntegrationStrip"), `...`] - *property *mesh\_setup*: [MeshSetup](/sdk/13/api/external/scia/.md#MeshSetup "viktor.external.scia.object.MeshSetup")*[¶](#Model.mesh_setup "Permalink to this definition") * Return type [`MeshSetup`](/sdk/13/api/external/scia/.md#MeshSetup "viktor.external.scia.object.MeshSetup") * *property *solver\_setup*: [SolverSetup](/sdk/13/api/external/scia/.md#SolverSetup "viktor.external.scia.object.SolverSetup")*[¶](#Model.solver_setup "Permalink to this definition") New in v13.1.0 * Return type [`SolverSetup`](/sdk/13/api/external/scia/.md#SolverSetup "viktor.external.scia.object.SolverSetup") - *property *project\_data*: [ProjectData](/sdk/13/api/external/scia/.md#ProjectData "viktor.external.scia.object.ProjectData")*[¶](#Model.project_data "Permalink to this definition") New in v13.1.0 * Return type [`ProjectData`](/sdk/13/api/external/scia/.md#ProjectData "viktor.external.scia.object.ProjectData") * create\_layer(*name=None*, *\**, *comment=None*, *structural\_model\_only=None*, *current\_used\_activity=None*)[¶](#Model.create_layer "Permalink to this definition") Method to construct a layer. Duplicate layer names are not allowed. * Parameters * **name** (`Optional`\[`str`]) – name of the layer (default: ‘Layer{i}’) * **comment** (`Optional`\[`str`]) – optional comment * **structural\_model\_only** (`Optional`\[`bool`]) – when ‘True’, the layer is NOT taken into account for the calculation (default: False) * **current\_used\_activity** (`Optional`\[`bool`]) – defines if the layer is visible or not on the screen (default: True) * Return type [`Layer`](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer") - update\_concrete\_material(*object\_id*, *name*, *part*, *thermal\_expansion=None*, *unit\_mass=None*, *wet\_density=None*, *e\_modulus=None*, *poisson=None*, *g\_modulus=None*, *log\_decrement=None*, *specific\_heat=None*, *thermal\_conductivity=None*, *\**, *fck=None*)[¶](#Model.update_concrete_material "Permalink to this definition") This method can update specific properties of an already existing concrete material in the \*.esa model. * Parameters * **object\_id** (`int`) – id of the material in SCIA * **name** (`str`) – name which will be shown in SCIA * **part** ([`ECPart`](/sdk/13/api/external/scia/.md#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")) – enumeration of concrete types * **thermal\_expansion** (`Optional`\[`float`]) – thermal expansion in \[m/mK] * **unit\_mass** (`Optional`\[`float`]) – density in \[kg/m3] * **wet\_density** (`Optional`\[`float`]) – wet density in \[kg/m3] * **e\_modulus** (`Optional`\[`float`]) – Young’s modulus in \[Pa] * **poisson** (`Optional`\[`float`]) – Poisson ratio * **g\_modulus** (`Optional`\[`float`]) – shear modulus in \[Pa] * **log\_decrement** (`Optional`\[`float`]) – log. decrement * **specific\_heat** (`Optional`\[`float`]) – specific heat in \[J/kgK] * **thermal\_conductivity** (`Optional`\[`float`]) – thermal conductivity in \[W/mK] * **fck** (`Optional`\[`float`]) – characteristic compressive cylinder strength \[Pa] * Return type [`Concrete`](/sdk/13/api/external/scia/.md#Concrete "viktor.external.scia.object.Concrete") * create\_nonlinear\_function(*name*, *function\_type*, *positive\_end*, *negative\_end*, *impulse*)[¶](#Model.create_nonlinear_function "Permalink to this definition") Method to construct a non-linear function. * Parameters * **name** (`str`) – name of the function * **function\_type** ([`Type`](/sdk/13/api/external/scia/.md#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")) – type of function * **positive\_end** ([`Support`](/sdk/13/api/external/scia/.md#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")) – type of support at positive end * **negative\_end** ([`Support`](/sdk/13/api/external/scia/.md#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")) – type of support at negative end * **impulse** (`List`\[`Tuple`\[`float`, `float`]]) – impulse function X-Y values in \[m, N] (if function\_type = TRANSLATION), \[rad, Nm] (if function\_type = ROTATION), or \[m, Pa] (if function\_type = NONLINEAR\_SUBSOIL) * Return type [`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") - create\_subsoil(*name*, *\**, *stiffness*, *c1x=None*, *c1y=None*, *c1z=None*, *nonlinear\_function=None*, *c2x=None*, *c2y=None*, *is\_drained=None*, *water\_air\_in\_clay\_subgrade=None*, *specific\_weight=None*, *fi=None*, *sigma\_oc=None*, *c=None*, *cu=None*)[¶](#Model.create_subsoil "Permalink to this definition") Method to construct a subsoil. * Parameters * **name** (`str`) – name of the subsoil * **stiffness** (`float`) – stiffness c1z \[N/m3] * **c1x** (`Optional`\[`float`]) – stiffness c1x \[N/m3] (default: 50000000) * **c1y** (`Optional`\[`float`]) – stiffness c1y \[N/m3] (default: 50000000) * **c1z** (`Optional`\[[`C1z`](/sdk/13/api/external/scia/.md#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")]) – type for c1z (default: FLEXIBLE) * **nonlinear\_function** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – nonlinear function ([`create_nonlinear_function()`](#Model.create_nonlinear_function "viktor.external.scia.scia.Model.create_nonlinear_function")) (c1z = NONLINEAR\_FUNCTION only) * **c2x** (`Optional`\[`float`]) – \[N/m] * **c2y** (`Optional`\[`float`]) – \[N/m] * **is\_drained** (`Optional`\[`bool`]) – True for ‘drained’, False for ‘undrained’ (default: False) * **water\_air\_in\_clay\_subgrade** (`Optional`\[`bool`]) – (default: False) * **specific\_weight** (`Optional`\[`float`]) – specific weight \[kg/m3] (default: 0.0) * **fi** (`Optional`\[`float`]) – fi’ \[deg] (default: 0.0) * **sigma\_oc** (`Optional`\[`float`]) – sigma oc \[Pa] (default: 0.0) * **c** (`Optional`\[`float`]) – c’ \[Pa] (default: 0.0) * **cu** (`Optional`\[`float`]) – \[Pa] (default: 0.0) * Return type [`Subsoil`](/sdk/13/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil") * create\_orthotropy(*name*, *material*, *thickness*, *D11=None*, *D22=None*, *D12=None*, *D33=None*, *D44=None*, *D55=None*, *d11=None*, *d22=None*, *d12=None*, *d33=None*, *kxy=None*, *kyx=None*)[¶](#Model.create_orthotropy "Permalink to this definition") Method to construct a type of orthotropy. * Parameters * **name** (`str`) – name of the orthotropy * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material * **thickness** (`float`) – thickness of the plate / wall \[m] * **D11** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[Nm] * **D22** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[Nm] * **D12** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[Nm] * **D33** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[Nm] * **D44** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[N/m] * **D55** (`Optional`\[`float`]) – (plate) stiffness matrix parameter \[N/m] * **d11** (`Optional`\[`float`]) – (membrane) stiffness matrix parameter \[N/m] * **d22** (`Optional`\[`float`]) – (membrane) stiffness matrix parameter \[N/m] * **d12** (`Optional`\[`float`]) – (membrane) stiffness matrix parameter \[N/m] * **d33** (`Optional`\[`float`]) – (membrane) stiffness matrix parameter \[N/m] * **kxy** (`Optional`\[`float`]) – stiffness coefficient \[N/m] * **kyx** (`Optional`\[`float`]) – stiffness coefficient \[N/m] * Return type [`Orthotropy`](/sdk/13/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy") - create\_arbitrary\_profile\_span(*length*, *type\_of\_css*, *cross\_section\_start*, *cross\_section\_end*, *alignment*)[¶](#Model.create_arbitrary_profile_span "Permalink to this definition") Method to construct an arbitrary profile span, which is necessary to construct an arbitrary profile. * Parameters * **length** (`float`) – length of the span * **type\_of\_css** ([`TypeOfCss`](/sdk/13/api/external/scia/.md#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")) – enumeration of cross-section types * **cross\_section\_start** ([`CrossSection`](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object at the start point * **cross\_section\_end** ([`CrossSection`](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object at the end point * **alignment** ([`Alignment`](/sdk/13/api/external/scia/.md#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")) – enumeration of alignment types * Return type [`ArbitraryProfileSpan`](/sdk/13/api/external/scia/.md#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan") * create\_rectangular\_cross\_section(*name*, *material*, *width*, *height*)[¶](#Model.create_rectangular_cross_section "Permalink to this definition") Method to construct a rectangular cross-section. * Parameters * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **width** (`float`) – width of the cross-section in \[m] * **height** (`float`) – height of the cross-section in \[m] * Return type [`RectangularCrossSection`](/sdk/13/api/external/scia/.md#RectangularCrossSection "viktor.external.scia.object.RectangularCrossSection") - create\_circular\_cross\_section(*name*, *material*, *diameter*)[¶](#Model.create_circular_cross_section "Permalink to this definition") Method to construct a circular cross-section. * Parameters * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * Return type [`CircularCrossSection`](/sdk/13/api/external/scia/.md#CircularCrossSection "viktor.external.scia.object.CircularCrossSection") * create\_circular\_hollow\_cross\_section(*name*, *material*, *diameter*, *thickness*)[¶](#Model.create_circular_hollow_cross_section "Permalink to this definition") Method to construct a circular hollow cross-section. * Parameters * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * **thickness** (`float`) – thickness in \[m] * Return type [`CircularHollowCrossSection`](/sdk/13/api/external/scia/.md#CircularHollowCrossSection "viktor.external.scia.object.CircularHollowCrossSection") - create\_circular\_composed\_cross\_section(*name*, *material*, *material\_2*, *diameter*, *thickness*)[¶](#Model.create_circular_composed_cross_section "Permalink to this definition") Method to construct a circular cross-section, composed of two materials. * Parameters * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – outer material of the cross-section * **material\_2** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – inner material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * **thickness** (`float`) – thickness in \[m] * Return type [`CircularComposedCrossSection`](/sdk/13/api/external/scia/.md#CircularComposedCrossSection "viktor.external.scia.object.CircularComposedCrossSection") * create\_numerical\_cross\_section(*name*, *material*, *\**, *A=None*, *Ay=None*, *Az=None*, *AL=None*, *AD=None*, *cYUCS=None*, *cZUCS=None*, *alpha=None*, *Iy=None*, *Iz=None*, *Wely=None*, *Welz=None*, *Wply=None*, *Wplz=None*, *Mply\_plus=None*, *Mply\_min=None*, *Mplz\_plus=None*, *Mplz\_min=None*, *dy=None*, *dz=None*, *It=None*, *Iw=None*, *beta\_y=None*, *beta\_z=None*)[¶](#Model.create_numerical_cross_section "Permalink to this definition") Method to construct a numerical cross-section. * Parameters * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **A** (`Optional`\[`float`]) – cross-sectional area \[m²] * **Ay** (`Optional`\[`float`]) – shear area in y-direction \[m²] * **Az** (`Optional`\[`float`]) – shear area in z-direction \[m²] * **AL** (`Optional`\[`float`]) – circumference per unit length \[m²/m] * **AD** (`Optional`\[`float`]) – drying surface per unit length \[m²/m] * **cYUCS** (`Optional`\[`float`]) – centroid in y-direction of input axis system \[mm] * **cZUCS** (`Optional`\[`float`]) – centroid in z-direction of input axis system \[mm] * **alpha** (`Optional`\[`float`]) – rotation angle of axis system \[deg] * **Iy** (`Optional`\[`float`]) – moment of inertia about the y-axis \[m⁴] * **Iz** (`Optional`\[`float`]) – moment of inertia about the z-axis \[m⁴] * **Wely** (`Optional`\[`float`]) – elastic section modulus about the y-axis \[m³] * **Welz** (`Optional`\[`float`]) – elastic section modulus about the z-axis \[m³] * **Wply** (`Optional`\[`float`]) – plastic section modulus about the y-axis \[m³] * **Wplz** (`Optional`\[`float`]) – plastic section modulus about the z-axis \[m³] * **Mply\_plus** (`Optional`\[`float`]) – plastic moment about the y-axis for positive My moment \[Nm] * **Mply\_min** (`Optional`\[`float`]) – plastic moment about the y-axis for negative My moment \[Nm] * **Mplz\_plus** (`Optional`\[`float`]) – plastic moment about the z-axis for positive My moment \[Nm] * **Mplz\_min** (`Optional`\[`float`]) – plastic moment about the z-axis for negative My moment \[Nm] * **dy** (`Optional`\[`float`]) – shear center coordinate in y-axis, measured from centroid \[mm] * **dz** (`Optional`\[`float`]) – shear center coordinate in z-axis, measured from centroid \[mm] * **It** (`Optional`\[`float`]) – torsional constant \[m⁴] * **Iw** (`Optional`\[`float`]) – warping constant \[m⁶] * **beta\_y** (`Optional`\[`float`]) – mono-symmetry constant about the y-axis \[mm] * **beta\_z** (`Optional`\[`float`]) – mono-symmetry constant about the z-axis \[mm] * Return type [`NumericalCrossSection`](/sdk/13/api/external/scia/.md#NumericalCrossSection "viktor.external.scia.object.NumericalCrossSection") - create\_library\_cross\_section(*section*, *profile*, *material*, *\**, *name=None*)[¶](#Model.create_library_cross_section "Permalink to this definition") New in v13.1.0 Method to construct a cross-section that is part of the cross-section library. * Parameters * **section** ([`Section`](/sdk/13/api/external/scia/.md#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")) – section type (e.g. LibraryCrossSection.Section.I) * **profile** (`str`) – profile name including dimensions (e.g. “SHS30/30/2.0”) * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **name** (`Optional`\[`str`]) – name of the cross-section (default: ‘CS{i}’) * Return type [`LibraryCrossSection`](/sdk/13/api/external/scia/.md#LibraryCrossSection "viktor.external.scia.object.LibraryCrossSection") * create\_node(*name*, *x*, *y*, *z*)[¶](#Model.create_node "Permalink to this definition") Method to construct a node. * Parameters * **name** (`str`) – name which will be shown in SCIA * **x** (`float`) – X-coordinate in \[m] * **y** (`float`) – Y-coordinate in \[m] * **z** (`float`) – Z-coordinate in \[m] * Return type [`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node") - create\_beam(*begin\_node*, *end\_node*, *cross\_section*, *\**, *name=None*, *ez=None*, *lcs\_rotation=None*, *layer=None*)[¶](#Model.create_beam "Permalink to this definition") Method to construct a beam. * Parameters * **begin\_node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the start of the beam. * **end\_node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the end of the beam. * **cross\_section** ([`CrossSection`](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘B{i}’) * **ez** (`Optional`\[`float`]) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **lcs\_rotation** (`Optional`\[`float`]) – rotation of local coordinate system \[deg] (default: 0) * **layer** (`Optional`\[[`Layer`](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")]) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the beam will be added * Return type [`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam") * create\_cross\_link(*beam\_1*, *beam\_2*, *\**, *name=None*)[¶](#Model.create_cross_link "Permalink to this definition") New in v13.1.0 Method to construct a cross-link, connecting two beams. * Parameters * **beam\_1** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – first beam ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) * **beam\_2** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – second beam ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘CL{i}’) * Return type [`CrossLink`](/sdk/13/api/external/scia/.md#CrossLink "viktor.external.scia.object.CrossLink") - create\_arbitrary\_profile(*name*, *beam*, *c\_def*, *cross\_section*, *spans*)[¶](#Model.create_arbitrary_profile "Permalink to this definition") Method to construct an arbitrary profile. * Parameters * **name** (`str`) – name which will be shown in SCIA * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **c\_def** ([`CDef`](/sdk/13/api/external/scia/.md#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")) – enumeration of coordinate definition types * **cross\_section** ([`CrossSection`](/sdk/13/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object * **spans** (`List`\[[`ArbitraryProfileSpan`](/sdk/13/api/external/scia/.md#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan")]) – list of arbitrary profile span objects ([`create_arbitrary_profile_span()`](#Model.create_arbitrary_profile_span "viktor.external.scia.scia.Model.create_arbitrary_profile_span")). * Return type [`ArbitraryProfile`](/sdk/13/api/external/scia/.md#ArbitraryProfile "viktor.external.scia.object.ArbitraryProfile") * create\_hinge\_on\_beam(*beam*, *position*, *\**, *name=None*, *freedom\_ux=Freedom.RIGID*, *freedom\_uy=Freedom.RIGID*, *freedom\_uz=Freedom.RIGID*, *freedom\_fix=Freedom.RIGID*, *freedom\_fiy=Freedom.FREE*, *freedom\_fiz=Freedom.RIGID*, *stiffness\_ux=0*, *stiffness\_uy=0*, *stiffness\_uz=0*, *stiffness\_fix=0*, *stiffness\_fiy=0*, *stiffness\_fiz=0*)[¶](#Model.create_hinge_on_beam "Permalink to this definition") Create a hinge on a beam. * Parameters * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – Beam of appliance ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **position** ([`Position`](/sdk/13/api/external/scia/.md#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")) – Position of appliance. * **name** (`Optional`\[`str`]) – Name of the hinge (default: ‘H{i}’). * **freedom\_ux** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in ux (default: rigid). * **freedom\_uy** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in uy (default: rigid). * **freedom\_uz** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in uz (default: rigid). * **freedom\_fix** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fix (default: rigid). * **freedom\_fiy** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fiy (default: free). * **freedom\_fiz** ([`Freedom`](/sdk/13/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fiz (default: rigid). * **stiffness\_ux** (`float`) – Stiffness in ux \[N/m], only used if freedom in ux = flexible (default: 0.0). * **stiffness\_uy** (`float`) – Stiffness in uy \[N/m], only used if freedom in uy = flexible (default: 0.0). * **stiffness\_uz** (`float`) – Stiffness in uz \[N/m], only used if freedom in uz = flexible (default: 0.0). * **stiffness\_fix** (`float`) – Stiffness in fix \[Nm/rad], only used if freedom in fix = flexible (default: 0.0). * **stiffness\_fiy** (`float`) – Stiffness in fiy \[Nm/rad], only used if freedom in fiy = flexible (default: 0.0). * **stiffness\_fiz** (`float`) – Stiffness in fiz \[Nm/rad], only used if freedom in fiz = flexible (default: 0.0). * Return type [`HingeOnBeam`](/sdk/13/api/external/scia/.md#HingeOnBeam "viktor.external.scia.object.HingeOnBeam") - create\_section\_on\_beam(*name*, *beam*, *c\_def*, *position\_x*, *origin*, *repeat*, *delta\_x*)[¶](#Model.create_section_on_beam "Permalink to this definition") Method to construct a section on a beam, which can be used to receive calculation results on its position. * Parameters * **name** (`str`) – name which will be shown in SCIA * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **c\_def** ([`CDef`](/sdk/13/api/external/scia/.md#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")) – enumeration of coordinate definition types * **position\_x** (`float`) – position of the section on the beam * **origin** ([`Origin`](/sdk/13/api/external/scia/.md#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")) – enumeration of origin types * **repeat** (`int`) – number of section defined at the same time * **delta\_x** (`float`) – if repeat is greater than 1, this value defines the distance between individual sections * Return type [`SectionOnBeam`](/sdk/13/api/external/scia/.md#SectionOnBeam "viktor.external.scia.object.SectionOnBeam") * create\_section\_on\_plane(*point\_1*, *point\_2*, *\**, *name*, *draw=None*, *direction\_of\_cut=None*)[¶](#Model.create_section_on_plane "Permalink to this definition") Method to construct a section on a plane, which can be used to receive calculation results on its position. * Parameters * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the start position in \[m] * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the end position in \[m] * **name** (`str`) – name which will be shown in SCIA (default: SE{i}) * **draw** (`Optional`\[[`Draw`](/sdk/13/api/external/scia/.md#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")]) – defines the plane in which the section is drawn (default: Z\_DIRECTION) * **direction\_of\_cut** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – in-plane vector (x, y, z) which defines the direction of cut in \[m] (default: (0, 0, 1)) * Return type [`SectionOnPlane`](/sdk/13/api/external/scia/.md#SectionOnPlane "viktor.external.scia.object.SectionOnPlane") - create\_rigid\_arm(*name*, *master\_node*, *slave\_node*, *hinge\_on\_master*, *hinge\_on\_slave*)[¶](#Model.create_rigid_arm "Permalink to this definition") Method to construct a rigid arm. * Parameters * **name** (`str`) – name which will be shown in SCIA * **master\_node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **slave\_node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **hinge\_on\_master** (`bool`) – True to insert a hinge on the master node * **hinge\_on\_slave** (`bool`) – True to insert a hinge on the slave node * Return type [`RigidArm`](/sdk/13/api/external/scia/.md#RigidArm "viktor.external.scia.object.RigidArm") * create\_plane(*corner\_nodes*, *thickness*, *\**, *material*, *name=None*, *plane\_type=None*, *layer=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*)[¶](#Model.create_plane "Permalink to this definition") Method to construct a 2D member. * Parameters * **corner\_nodes** (`List`\[[`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of node objects located at the corners * **thickness** (`float`) – thickness of the plane in \[m] * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – `Material` of the plane * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘S{i}’) * **plane\_type** (`Optional`\[[`Type`](/sdk/13/api/external/scia/.md#Plane.Type "viktor.external.scia.object.Plane.Type")]) – enumeration of plane types (default: PLATE) * **layer** (`Optional`\[[`Layer`](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")]) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the plane will be added * **internal\_nodes** (`Optional`\[`List`\[[`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")]]) – list of internal node objects (default: None) * **swap\_orientation** (`Optional`\[`bool`]) – whereas to swap the plate orientation (default: False) * **lcs\_rotation** (`Optional`\[`float`]) – rotation of the local coordinate system \[deg] (default: 0.0) * **fem\_model** (`Optional`\[[`FEMModel`](/sdk/13/api/external/scia/.md#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")]) – FEM model to be used in the calculation (default: isotropic) * **orthotropy** (`Optional`\[[`Orthotropy`](/sdk/13/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy")]) – type of orthotropy (only for fem\_model = ORTHOTROPIC) * Return type [`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane") - create\_circular\_plane(*center\_node*, *diameter*, *thickness*, *\**, *material*, *axis=None*, *name=None*, *plane\_type=None*, *layer=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*)[¶](#Model.create_circular_plane "Permalink to this definition") Method to construct a circular 2D member. * Parameters * **center\_node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) located at the center of the plane * **diameter** (`float`) – diameter of the plane \[m] * **thickness** (`float`) – thickness of the plane \[m] * **material** ([`Material`](/sdk/13/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – `Material` of the plane * **axis** (`Union`\[[`Vector`](/sdk/13/api/geometry/.md#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`], `None`]) – axis direction (default: (0, 0, 1)) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘S{i}’) * **plane\_type** (`Optional`\[[`Type`](/sdk/13/api/external/scia/.md#Plane.Type "viktor.external.scia.object.Plane.Type")]) – enumeration of plane types (default: PLATE) * **layer** (`Optional`\[[`Layer`](/sdk/13/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")]) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the plane will be added * **internal\_nodes** (`Optional`\[`List`\[[`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")]]) – list of internal node objects (default: None) * **swap\_orientation** (`Optional`\[`bool`]) – whereas to swap the plate orientation (default: False) * **lcs\_rotation** (`Optional`\[`float`]) – rotation of the local coordinate system \[deg] (default: 0.0) * **fem\_model** (`Optional`\[[`FEMModel`](/sdk/13/api/external/scia/.md#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")]) – FEM model to be used in the calculation (default: isotropic) * **orthotropy** (`Optional`\[[`Orthotropy`](/sdk/13/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy")]) – type of orthotropy (only for fem\_model = ORTHOTROPIC) * Return type [`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane") * create\_open\_slab(*name*, *plane*, *corner\_nodes*)[¶](#Model.create_open_slab "Permalink to this definition") Method to construct an open slab in a 2D member. * Parameters * **name** (`str`) – name which will be shown in SCIA * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")). * **corner\_nodes** (`List`\[[`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of node objects located at the corners * Return type [`OpenSlab`](/sdk/13/api/external/scia/.md#OpenSlab "viktor.external.scia.object.OpenSlab") - create\_internal\_edge(*plane*, *node\_1*, *node\_2*, *\**, *name=None*)[¶](#Model.create_internal_edge "Permalink to this definition") Method to construct an internal edge in a 2D member. * Parameters * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) * **node\_1** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the start of the edge * **node\_2** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the end of the edge * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘ES{i}’) * Return type [`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge") * create\_integration\_strip(*plane*, *point\_1*, *point\_2*, *width*)[¶](#Model.create_integration_strip "Permalink to this definition") Method to construct an integration strip, which can be used to receive calculation results on its position. * Parameters * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")). * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the start position in \[m] * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the end position in \[m] * **width** (`float`) – width of the strip in \[m] * Return type [`IntegrationStrip`](/sdk/13/api/external/scia/.md#IntegrationStrip "viktor.external.scia.object.IntegrationStrip") - create\_point\_support(*name*, *node*, *spring\_type*, *freedom*, *stiffness*, *c\_sys*, *default\_size=0.2*, *\**, *angle=None*)[¶](#Model.create_point_support "Permalink to this definition") Method to construct a point support. * Parameters * **name** (`str`) – name which will be shown in SCIA * **node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) to which the support will be attached. * **spring\_type** ([`Type`](/sdk/13/api/external/scia/.md#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")) – enumeration of spring types * **freedom** (`Tuple`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/13/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")]) – tuple of component constraints in the order (X, Y, Z, Rx, Ry, Rz) * **stiffness** (`Tuple`\[`float`, `float`, `float`, `float`, `float`, `float`]) – tuple of component stiffness in the order (X, Y, Z, Rx, Ry, Rz) in \[N/m] * **c\_sys** ([`CSys`](/sdk/13/api/external/scia/.md#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")) – enumeration of coordinate system types * **default\_size** (`float`) – default size in \[m] * **angle** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – angle (Rx, Ry, Rz) \[deg] of the support around the respective global X-, Y- and Z-axis * Return type [`PointSupport`](/sdk/13/api/external/scia/.md#PointSupport "viktor.external.scia.object.PointSupport") * create\_point\_support\_on\_beam(*beam*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *default\_size=None*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *delta\_x=None*)[¶](#Model.create_point_support_on_beam "Permalink to this definition") Method to construct a point support on a beam. * Parameters * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the line support will be applied * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘Sb{i}’) * **x** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in X-direction (default: RIGID) * **stiffness\_x** (`Optional`\[`float`]) – stiffness in X-direction \[N/m] (only for x = FLEXIBLE) * **y** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in Y-direction (default: RIGID) * **stiffness\_y** (`Optional`\[`float`]) – stiffness in Y-direction \[N/m] (only for y = FLEXIBLE) * **z** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in Z-direction (default: RIGID) * **stiffness\_z** (`Optional`\[`float`]) – stiffness in Z-direction \[N/m] (only for z = FLEXIBLE) * **rx** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in X-rotation (default: RIGID) * **stiffness\_rx** (`Optional`\[`float`]) – stiffness in X-rotation \[Nm/rad] (only for rx = FLEXIBLE) * **ry** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in Y-rotation (default: RIGID) * **stiffness\_ry** (`Optional`\[`float`]) – stiffness in Y-rotation \[Nm/rad] (only for ry = FLEXIBLE) * **rz** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")]) – constraint type in Z-rotation (default: RIGID) * **stiffness\_rz** (`Optional`\[`float`]) – stiffness in Z-rotation \[Nm/rad] (only for rz = FLEXIBLE) * **default\_size** (`Optional`\[`float`]) – size of the support \[m] (default: 0.2) * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")]) – coordinate system (default: GLOBAL) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")]) – c\_def: coordinate definition (default: RELATIVE) * **position\_x** (`Optional`\[`float`]) – position of the load (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")]) – reference for position\_x (default: FROM\_START) * **repeat** (`Optional`\[`int`]) – number of uniformly distributed supports (default: 1) * **delta\_x** (`Optional`\[`float`]) – distance between supports (\[m] if c\_def = ABSOLUTE, else \[-]) (only for repeat > 1) * Return type [`PointSupportLine`](/sdk/13/api/external/scia/.md#PointSupportLine "viktor.external.scia.object.PointSupportLine") - create\_line\_support\_on\_beam(*beam*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *extent=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_line_support_on_beam "Permalink to this definition") Method to construct a line support on a beam. * Parameters * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the line support will be applied * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘Slb{i}’) * **x** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in X-direction (default: RIGID) * **stiffness\_x** (`Optional`\[`float`]) – stiffness in X-direction \[N/m2] (only for x = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_x** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in X-direction (only for x = NONLINEAR) * **y** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Y-direction (default: RIGID) * **stiffness\_y** (`Optional`\[`float`]) – stiffness in Y-direction \[N/m2] (only for y = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_y** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in Y-direction (only for y = NONLINEAR) * **z** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Z-direction (default: RIGID) * **stiffness\_z** (`Optional`\[`float`]) – stiffness in Z-direction \[N/m2] (only for z = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_z** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in Z-direction (only for z = NONLINEAR) * **rx** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in X-rotation (default: RIGID) * **stiffness\_rx** (`Optional`\[`float`]) – stiffness in X-rotation \[Nm/m/rad] (only for rx = FLEXIBLE | NONLINEAR) * **function\_rx** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in X-rotation (only for rx = NONLINEAR) * **ry** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Y-rotation (default: RIGID) * **stiffness\_ry** (`Optional`\[`float`]) – stiffness in Y-rotation \[Nm/m/rad] (only for ry = FLEXIBLE | NONLINEAR) * **function\_ry** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in Y-rotation (only for ry = NONLINEAR) * **rz** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Z-rotation (default: RIGID) * **stiffness\_rz** (`Optional`\[`float`]) – stiffness in Z-rotation \[Nm/m/rad] (only for rz = FLEXIBLE | NONLINEAR) * **function\_rz** (`Optional`\[[`NonLinearFunction`](/sdk/13/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]) – non-linear function in Z-rotation (only for rz = NONLINEAR) * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")]) – coordinate system (default: LOCAL) * **extent** (`Optional`\[[`Extent`](/sdk/13/api/external/scia/.md#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")]) – extension of support (default: FULL) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – start of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – end of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`LineSupportLine`](/sdk/13/api/external/scia/.md#LineSupportLine "viktor.external.scia.object.LineSupportLine") * create\_line\_support\_on\_plane(*edge*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_line_support_on_plane "Permalink to this definition") Method to construct a line support on a plane edge. * Parameters * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of the plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load should be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘Sle{i}’) * **x** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in X-direction (default: FREE) * **stiffness\_x** (`Optional`\[`float`]) – stiffness in X-direction \[N/m2] (only for x = FLEXIBLE) * **y** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Y-direction (default: FREE) * **stiffness\_y** (`Optional`\[`float`]) – stiffness in Y-direction \[N/m2] (only for y = FLEXIBLE) * **z** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Z-direction (default: FREE) * **stiffness\_z** (`Optional`\[`float`]) – stiffness in Z-direction \[N/m2] (only for z = FLEXIBLE) * **rx** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in X-rotation (default: FREE) * **stiffness\_rx** (`Optional`\[`float`]) – stiffness in X-rotation \[Nm/m/rad] (only for rx = FLEXIBLE) * **ry** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Y-rotation (default: FREE) * **stiffness\_ry** (`Optional`\[`float`]) – stiffness in Y-rotation \[Nm/m/rad] (only for ry = FLEXIBLE) * **rz** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]) – constraint type in Z-rotation (default: FREE) * **stiffness\_rz** (`Optional`\[`float`]) – stiffness in Z-rotation \[Nm/m/rad] (only for rz = FLEXIBLE) * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")]) – coordinate system (default: GLOBAL) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – start of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – end of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`LineSupportSurface`](/sdk/13/api/external/scia/.md#LineSupportSurface "viktor.external.scia.object.LineSupportSurface") - create\_surface\_support(*plane*, *subsoil*, *\**, *name=None*)[¶](#Model.create_surface_support "Permalink to this definition") Method to construct a surface support. * Parameters * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the support will be attached * **subsoil** ([`Subsoil`](/sdk/13/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil")) – subsoil object ([`create_subsoil()`](#Model.create_subsoil "viktor.external.scia.scia.Model.create_subsoil")) representing the support * **name** (`Optional`\[`str`]) – name which will be shown in SCIA * Return type [`SurfaceSupportSurface`](/sdk/13/api/external/scia/.md#SurfaceSupportSurface "viktor.external.scia.object.SurfaceSupportSurface") * create\_hinge\_on\_plane(*edge*, *\**, *name=None*, *ux=None*, *stiffness\_ux=None*, *uy=None*, *stiffness\_uy=None*, *uz=None*, *stiffness\_uz=None*, *fix=None*, *stiffness\_fix=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_hinge_on_plane "Permalink to this definition") Method to construct a hinge on a plane edge. * Parameters * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of a plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the hinge will be attached (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘L{i}’) * **ux** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")]) – Freedom in ux (default: RIGID). * **stiffness\_ux** (`Optional`\[`float`]) – Stiffness in ux \[N/m2], only used if freedom in ux = flexible (default: 0.0). * **uy** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")]) – Freedom in uy (default: RIGID). * **stiffness\_uy** (`Optional`\[`float`]) – Stiffness in uy \[N/m2], only used if freedom in uy = flexible (default: 0.0). * **uz** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")]) – Freedom in uz (default: RIGID). * **stiffness\_uz** (`Optional`\[`float`]) – Stiffness in uz \[N/m2], only used if freedom in uz = flexible (default: 0.0). * **fix** (`Optional`\[[`Freedom`](/sdk/13/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")]) – Freedom in fix (default: FREE). * **stiffness\_fix** (`Optional`\[`float`]) – Stiffness in fix \[Nm/m/rad], only used if freedom in fix = flexible (default: 0.0). * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`HingeOnPlane`](/sdk/13/api/external/scia/.md#HingeOnPlane "viktor.external.scia.object.HingeOnPlane") - create\_load\_group(*name*, *load\_option*, *relation=None*, *load\_type=None*)[¶](#Model.create_load_group "Permalink to this definition") Method to construct a load group. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_option** ([`LoadOption`](/sdk/13/api/external/scia/.md#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")) – enumeration of load option types * **relation** (`Optional`\[[`RelationOption`](/sdk/13/api/external/scia/.md#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")]) – enumeration of relation types * **load\_type** (`Optional`\[[`LoadTypeOption`](/sdk/13/api/external/scia/.md#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")]) – enumeration of load types * Return type [`LoadGroup`](/sdk/13/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup") * create\_permanent\_load\_case(*name*, *description*, *load\_group*, *load\_type*, *direction=None*, *primary\_effect=None*)[¶](#Model.create_permanent_load_case "Permalink to this definition") Method to construct a permanent load case. * Parameters * **name** (`str`) – name which will be shown in SCIA * **description** (`str`) – description which will be shown in SCIA * **load\_group** ([`LoadGroup`](/sdk/13/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup")) – load group object ([`create_load_group()`](#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group")) in which the load case should be placed. * **load\_type** ([`PermanentLoadType`](/sdk/13/api/external/scia/.md#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")) – permanent load types * **direction** (`Optional`\[[`Direction`](/sdk/13/api/external/scia/.md#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")]) – load direction in case of a *SELF\_WEIGHT* load type (default: NEG\_Z) * **primary\_effect** (`Optional`\[[`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")]) – previously created load case object in case the selected load type is *PRIMARY\_EFFECT* * Return type [`PermanentLoadCase`](/sdk/13/api/external/scia/.md#PermanentLoadCase "viktor.external.scia.object.PermanentLoadCase") - create\_variable\_load\_case(*name*, *description*, *load\_group*, *load\_type*, *specification=None*, *duration=None*, *primary\_effect=None*)[¶](#Model.create_variable_load_case "Permalink to this definition") Method to construct a variable load case. * Parameters * **name** (`str`) – name which will be shown in SCIA * **description** (`str`) – description which will be shown in SCIA * **load\_group** ([`LoadGroup`](/sdk/13/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup")) – load group object ([`create_load_group()`](#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group")) in which the load case should be placed. * **load\_type** ([`VariableLoadType`](/sdk/13/api/external/scia/.md#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")) – enumeration of variable load types * **specification** (`Optional`\[[`Specification`](/sdk/13/api/external/scia/.md#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")]) – enumeration of specification types * **duration** (`Optional`\[[`Duration`](/sdk/13/api/external/scia/.md#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")]) – enumeration of duration types * **primary\_effect** (`Optional`\[[`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")]) – previously created load case object in case the selected load type is *PRIMARY\_EFFECT* * Return type [`VariableLoadCase`](/sdk/13/api/external/scia/.md#VariableLoadCase "viktor.external.scia.object.VariableLoadCase") * create\_load\_combination(*name*, *load\_type*, *load\_cases*, *\**, *description=None*)[¶](#Model.create_load_combination "Permalink to this definition") Method to construct a load combination. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_type** ([`Type`](/sdk/13/api/external/scia/.md#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")) – enumeration of load types * **load\_cases** (`Dict`\[[`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), `float`]) – dictionary of previously created load case object(s) with corresponding coefficient * **description** (`Optional`\[`str`]) – description of the load combination New in v13.1.0 * Return type [`LoadCombination`](/sdk/13/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination") - create\_nonlinear\_load\_combination(*load\_type*, *load\_cases*, *\**, *name=None*, *description=None*)[¶](#Model.create_nonlinear_load_combination "Permalink to this definition") Create a non-linear load combination. * Parameters * **load\_type** ([`Type`](/sdk/13/api/external/scia/.md#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")) – type of combination * **load\_cases** (`Dict`\[[`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), `float`]) – dictionary of previously created load case object(s) with corresponding coefficient * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘NC{i}’) * **description** (`Optional`\[`str`]) – description of the load combination New in v13.1.0 * Return type [`NonLinearLoadCombination`](/sdk/13/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination") * create\_result\_class(*name*, *combinations=None*, *nonlinear\_combinations=None*)[¶](#Model.create_result_class "Permalink to this definition") Method to construct a result class. * Parameters * **name** (`str`) – name which will be shown in SCIA * **combinations** (`Optional`\[`List`\[[`LoadCombination`](/sdk/13/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination")]]) – list of load combination objects ([`create_load_combination()`](#Model.create_load_combination "viktor.external.scia.scia.Model.create_load_combination")) * **nonlinear\_combinations** (`Optional`\[`List`\[[`NonLinearLoadCombination`](/sdk/13/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination")]]) – list of nonlinear load combination objects ([`create_nonlinear_load_combination()`](#Model.create_nonlinear_load_combination "viktor.external.scia.scia.Model.create_nonlinear_load_combination")) * Return type [`ResultClass`](/sdk/13/api/external/scia/.md#ResultClass "viktor.external.scia.object.ResultClass") - create\_point\_load\_node(*node*, *load\_case*, *load*, *\**, *name=None*, *direction=None*, *c\_sys=None*, *angle=None*)[¶](#Model.create_point_load_node "Permalink to this definition") Method to construct a point load in a node. * Parameters * **node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) on which the load should be applied * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **load** (`float`) – magnitude of the load in \[N] * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘F{i}’) * **direction** (`Optional`\[[`Direction`](/sdk/13/api/external/scia/.md#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")]) – direction of the load (default: Z) * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")]) – coordinate system (default: global) * **angle** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – angle (Rx, Ry, Rz) \[deg] of the load around the respective global X-, Y- and Z-axis * Return type [`PointLoadNode`](/sdk/13/api/external/scia/.md#PointLoadNode "viktor.external.scia.object.PointLoadNode") * create\_point\_load(*name*, *load\_case*, *beam*, *direction*, *load\_type*, *load\_value*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *ey=None*, *ez=None*, *\**, *angle=None*)[¶](#Model.create_point_load "Permalink to this definition") Method to construct a point load on a beam. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")) – enumeration of directions * **load\_type** ([`Type`](/sdk/13/api/external/scia/.md#PointLoad.Type "viktor.external.scia.object.PointLoad.Type")) – enumeration of load types * **load\_value** (`float`) – magnitude of the load in \[N] * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")]) – enumeration of coordinate system types (default: global) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")]) – enumeration of coordinate definition types (default: relative) * **position\_x** (`Optional`\[`float`]) – position of the load (default: 0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")]) – enumeration of origin types (default: from start) * **repeat** (`Optional`\[`int`]) – number of loads acting on the beam, distributed uniformly (default: 1) * **ey** (`Optional`\[`float`]) – eccentricity in Y-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **ez** (`Optional`\[`float`]) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **angle** (`Optional`\[`Tuple`\[`float`, `float`, `float`]]) – angle (Rx, Ry, Rz) \[deg] of the load around the respective X-, Y- and Z-axis (default: 0) * Return type [`PointLoad`](/sdk/13/api/external/scia/.md#PointLoad "viktor.external.scia.object.PointLoad") - create\_point\_moment\_node(*node*, *load\_case*, *load*, *direction*, *name=None*, *c\_sys=CSys.GLOBAL*)[¶](#Model.create_point_moment_node "Permalink to this definition") Create a point moment on an existing node. * Parameters * **node** ([`Node`](/sdk/13/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – Node of appliance ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – Previously created load case of appliance. * **load** (`float`) – Magnitude of the load \[Nm]. * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")) – Direction of the load. * **name** (`Optional`\[`str`]) – Name of the load in SCIA (default: ‘M{i}’). * **c\_sys** ([`CSys`](/sdk/13/api/external/scia/.md#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")) – Coordinate system (default: global). * Return type [`PointMomentNode`](/sdk/13/api/external/scia/.md#PointMomentNode "viktor.external.scia.object.PointMomentNode") * create\_line\_load(*name*, *load\_case*, *beam*, *load\_type*, *distribution*, *load\_start*, *load\_end*, *direction*, *position\_start*, *position\_end*, *c\_def*, *c\_sys*, *origin*, *ey*, *ez*)[¶](#Model.create_line_load "Permalink to this definition") Method to construct a line load on a beam. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **load\_type** ([`Type`](/sdk/13/api/external/scia/.md#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")) – enumeration of load types * **distribution** ([`Distribution`](/sdk/13/api/external/scia/.md#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")) – enumeration of distribution options * **load\_start** (`float`) – magnitude of the load at the start point in \[N] * **load\_end** (`float`) – magnitude of the load at the end point in \[N] * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")) – enumeration of directions * **position\_start** (`float`) – position of the start point on the beam in \[m] * **position\_end** (`float`) – position of the end point on the beam in \[m] * **c\_def** ([`CDef`](/sdk/13/api/external/scia/.md#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")) – enumeration of coordinate definition types * **c\_sys** ([`CSys`](/sdk/13/api/external/scia/.md#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")) – enumeration of coordinate system types * **origin** ([`Origin`](/sdk/13/api/external/scia/.md#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")) – enumeration of origin types * **ey** (`float`) – eccentricity in Y-direction w\.r.t. the beam’s center line in \[m] * **ez** (`float`) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] * Return type [`LineLoad`](/sdk/13/api/external/scia/.md#LineLoad "viktor.external.scia.object.LineLoad") - create\_line\_moment\_on\_beam(*beam*, *load\_case*, *m1*, *m2=None*, *\**, *name=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_line_moment_on_beam "Permalink to this definition") Method to construct a line moment on a beam. * Parameters * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **m1** (`float`) – magnitude of the moment \[Nm/m] on point 1 * **m2** (`Optional`\[`float`]) – magnitude of the moment \[Nm/m] on point 2. None for uniform load (with magnitude m1) (default: None) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘LM{i}’) * **direction** (`Optional`\[[`Direction`](/sdk/13/api/external/scia/.md#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")]) – direction of the moment (default: Z) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – position of p1 along the beam with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – position of p2 along the beam with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`LineMomentOnBeam`](/sdk/13/api/external/scia/.md#LineMomentOnBeam "viktor.external.scia.object.LineMomentOnBeam") * create\_line\_moment\_on\_plane(*edge*, *m1*, *m2=None*, *\**, *load\_case*, *name=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_line_moment_on_plane "Permalink to this definition") Method to construct a line moment on a plane edge. * Parameters * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of the plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load should be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **m1** (`float`) – magnitude of the moment \[Nm/m] on point 1 * **m2** (`Optional`\[`float`]) – magnitude of the moment \[Nm/m] on point 2. None for uniform load (with magnitude m1) (default: None) * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘LMS{i}’) * **direction** (`Optional`\[[`Direction`](/sdk/13/api/external/scia/.md#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")]) – direction of the moment (default: Z) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`LineMomentOnPlane`](/sdk/13/api/external/scia/.md#LineMomentOnPlane "viktor.external.scia.object.LineMomentOnPlane") - create\_line\_load\_on\_plane(*edge*, *p1*, *p2=None*, *\**, *load\_case*, *direction=None*, *name=None*, *location=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#Model.create_line_load_on_plane "Permalink to this definition") Method to construct a line load on a plane edge. * Parameters * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/13/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of a plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load will be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **p1** (`float`) – magnitude of the load \[N/m] on point 1 * **p2** (`Optional`\[`float`]) – magnitude of the load \[N/m] on point 2. None for uniform load (with magnitude p1) (default: None) * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **direction** (`Optional`\[[`Direction`](/sdk/13/api/external/scia/.md#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")]) – direction of the load (default: Z) * **name** (`Optional`\[`str`]) – name which will be shown in SCIA (default: ‘LFS{i}’) * **location** (`Optional`\[[`Location`](/sdk/13/api/external/scia/.md#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")]) – location type (default: LENGTH) * **c\_sys** (`Optional`\[[`CSys`](/sdk/13/api/external/scia/.md#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")]) – coordinate system (default: LOCAL) * **c\_def** (`Optional`\[[`CDef`](/sdk/13/api/external/scia/.md#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")]) – coordinate definition (default: RELATIVE) * **position\_x1** (`Optional`\[`float`]) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`Optional`\[`float`]) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** (`Optional`\[[`Origin`](/sdk/13/api/external/scia/.md#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")]) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type [`LineForceSurface`](/sdk/13/api/external/scia/.md#LineForceSurface "viktor.external.scia.object.LineForceSurface") * create\_surface\_load(*name*, *load\_case*, *plane*, *direction*, *load\_type*, *load\_value*, *c\_sys*, *location*)[¶](#Model.create_surface_load "Permalink to this definition") Method to construct a surface load on a plane. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the load should be applied * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")) – enumeration of directions * **load\_type** ([`Type`](/sdk/13/api/external/scia/.md#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")) – enumeration of load types * **load\_value** (`float`) – magnitude of the load in \[N] * **c\_sys** ([`CSys`](/sdk/13/api/external/scia/.md#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")) – enumeration of coordinate system types * **location** ([`Location`](/sdk/13/api/external/scia/.md#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")) – enumeration of location options * Return type [`SurfaceLoad`](/sdk/13/api/external/scia/.md#SurfaceLoad "viktor.external.scia.object.SurfaceLoad") - create\_thermal\_load(*name*, *load\_case*, *beam*, *distribution*, *delta*, *left\_delta*, *right\_delta*, *top\_delta*, *bottom\_delta*, *position\_start*, *position\_end*, *c\_def*, *origin*)[¶](#Model.create_thermal_load "Permalink to this definition") Method to construct a temperature load on a beam. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/13/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **distribution** ([`Distribution`](/sdk/13/api/external/scia/.md#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")) – enumeration of distribution options * **delta** (`float`) – temperature difference in case of a *CONSTANT* distribution * **left\_delta** (`float`) – temperature difference in +Y direction * **right\_delta** (`float`) – temperature difference in -Y direction * **top\_delta** (`float`) – temperature difference in +Z direction * **bottom\_delta** (`float`) – temperature difference in -Z direction * **position\_start** (`float`) – position of the start point on the beam in \[m] * **position\_end** (`float`) – position of the end point on the beam in \[m] * **c\_def** ([`CDef`](/sdk/13/api/external/scia/.md#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")) – enumeration of coordinate definition types * **origin** ([`Origin`](/sdk/13/api/external/scia/.md#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")) – enumeration of origin types * Return type [`ThermalLoad`](/sdk/13/api/external/scia/.md#ThermalLoad "viktor.external.scia.object.ThermalLoad") * create\_thermal\_surface\_load(*name*, *load\_case*, *plane*, *delta=None*, *top\_delta=None*, *bottom\_delta=None*)[¶](#Model.create_thermal_surface_load "Permalink to this definition") Method to construct a temperature load on a plane. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **plane** ([`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the load should be applied * **delta** (`Optional`\[`float`]) – temperature difference in case of a constant distribution * **top\_delta** (`Optional`\[`float`]) – temperature difference in +Z direction * **bottom\_delta** (`Optional`\[`float`]) – temperature difference in -Z direction * Return type [`ThermalSurfaceLoad`](/sdk/13/api/external/scia/.md#ThermalSurfaceLoad "viktor.external.scia.object.ThermalSurfaceLoad") - create\_free\_surface\_load(*name*, *load\_case*, *direction*, *q1*, *q2=None*, *q3=None*, *points=None*, *\**, *distribution=None*, *selection=None*)[¶](#Model.create_free_surface_load "Permalink to this definition") Method to construct a free surface load. Note: can only be defined in XY-plane. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – direction of the load * **q1** (`float`) – magnitude of the load in the first point in \[N] * **q2** (`Optional`\[`float`]) – magnitude of the load in the second point in \[N] (distribution = DIR\_X | DIR\_Y | POINTS only) * **q3** (`Optional`\[`float`]) – magnitude of the load in the third point in \[N] (distribution = POINTS only) * **points** (`Optional`\[`List`\[`Tuple`\[`float`, `float`]]]) – list of XY coordinates (at least 3). If distribution = DIR\_X | DIR\_Y: q1 and q2 are applied to points\[0] and points\[1] respectively. If distribution = POINTS: q1, q2 and q3 are applied to points\[0], points\[1] and points\[2] respectively. * **distribution** (`Optional`\[[`Distribution`](/sdk/13/api/external/scia/.md#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")]) – distribution of the load (default: POINTS) * **selection** (`Optional`\[`List`\[[`Plane`](/sdk/13/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")]]) – selection of 1 or more planes ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to generate the load on (default: select = auto) * Return type [`FreeSurfaceLoad`](/sdk/13/api/external/scia/.md#FreeSurfaceLoad "viktor.external.scia.object.FreeSurfaceLoad") * create\_free\_line\_load(*name*, *load\_case*, *point\_1*, *point\_2*, *direction*, *magnitude\_1*, *magnitude\_2*)[¶](#Model.create_free_line_load "Permalink to this definition") Method to construct a free line load. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **point\_1** (`Tuple`\[`float`, `float`]) – XY coordinate of the first point * **point\_2** (`Tuple`\[`float`, `float`]) – XY coordinate of the second point * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – enumeration of direction options * **magnitude\_1** (`float`) – magnitude of the load in point\_1 in \[N] * **magnitude\_2** (`float`) – magnitude of the load in point\_2 in \[N] * Return type [`FreeLineLoad`](/sdk/13/api/external/scia/.md#FreeLineLoad "viktor.external.scia.object.FreeLineLoad") - create\_free\_point\_load(*name*, *load\_case*, *direction*, *magnitude*, *position*)[¶](#Model.create_free_point_load "Permalink to this definition") Method to construct a free point load. * Parameters * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/13/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **direction** ([`Direction`](/sdk/13/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – enumeration of direction options * **magnitude** (`float`) – magnitude of the load in \[N] * **position** (`Tuple`\[`float`, `float`]) – XY coordinate of the load * Return type [`FreePointLoad`](/sdk/13/api/external/scia/.md#FreePointLoad "viktor.external.scia.object.FreePointLoad") * generate\_xml\_input(*as\_file=False*)[¶](#Model.generate_xml_input "Permalink to this definition") Returns the input file XML representation of the SCIA model and corresponding .def file. Note This method needs to be mocked in (automated) unit and integration tests. * Return type `Union`\[`Tuple`\[`BytesIO`, `BytesIO`], `Tuple`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File"), [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]] * Returns * File if as\_file = True * BytesIO if as\_file = False (default) ## OutputFileParser[​](/sdk/13/api/external/scia/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.scia.scia.OutputFileParser[¶](#OutputFileParser "Permalink to this definition") Helper class to extract results from a SCIA output file (.xml). Example using BytesIO: ``` xml_output_file = scia_analysis.get_xml_output_file() result_table = OutputFileParser.get_result(xml_output_file, 'Reactions') another_result_table = OutputFileParser.get_result(xml_output_file, '2D internal forces') ``` Example using [`File`](/sdk/13/api/core/.md#File "viktor.core.File"): ``` xml_output_file = scia_analysis.get_xml_output_file(as_file=True) with xml_output_file.open_binary() as f: result_table = OutputFileParser.get_result(f, 'Reactions') another_result_table = OutputFileParser.get_result(f, '2D internal forces') ``` * *classmethod *get\_result(*file*, *table\_name*, *\**, *parent=None*)[¶](#OutputFileParser.get_result "Permalink to this definition") Retrieve the results of an output XML by ‘table\_name’. This corresponds to the ‘name’ attribute that is found in the XML table, e.g. “Result classes - UGT” in the example below: ``` ``` In case indenting has been used in the SCIA I/O doc, multiple tables with the name ‘table\_name’ will be found. A parent name can be specified as input to account for this indenting (up to 1 indent level). If indenting is used but no parent name is specified, this method will return the first ‘table\_name’ table it can find. * Parameters * **file** (`BinaryIO`) – SCIA output file (.xml). * **table\_name** (`str`) – Name of the result table to be extracted from the output XML. * **parent** (`Optional`\[`str`]) – Name of the parent, e.g. a result class. - :raises [`viktor.errors.SciaParsingError`](/sdk/13/api/errors/.md#SciaParsingError "viktor.errors.SciaParsingError"): * if table ‘table\_name’ could not be found in the provided output file * if no results were found in the XML table ‘table\_name’ * Return type `Dict`\[`str`, `dict`] ## Layer[​](/sdk/13/api/external/scia/.md#_Layer "Direct link to Layer") * *class *viktor.external.scia.object.Layer(*object\_id*, *name*, *comment=None*, *structural\_model\_only=None*, *current\_used\_activity=None*)[¶](#Layer "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_layer()`](/sdk/13/api/external/scia/.md#Model.create_layer "viktor.external.scia.scia.Model.create_layer") ## Material[​](/sdk/13/api/external/scia/.md#_Material "Direct link to Material") * *class *viktor.external.scia.object.Material(*object\_id*, *name*)[¶](#Material "Permalink to this definition") Bases: `_SciaObject` Reference to an existing material in the .esa template file in which the xml input file will be loaded. * Parameters * **object\_id** (`int`) – ID of the existing material. * **name** (`str`) – name of the existing material. ## NonLinearFunction[​](/sdk/13/api/external/scia/.md#_NonLinearFunction "Direct link to NonLinearFunction") * *class *viktor.external.scia.object.NonLinearFunction(*object\_id*, *name*, *function\_type*, *positive\_end*, *negative\_end*, *impulse*)[¶](#NonLinearFunction "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_nonlinear_function()`](/sdk/13/api/external/scia/.md#Model.create_nonlinear_function "viktor.external.scia.scia.Model.create_nonlinear_function") * *class *Type(*value*)[¶](#NonLinearFunction.Type "Permalink to this definition") Bases: `Enum` An enumeration. * TRANSLATION*: [Type](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 0*[¶](#NonLinearFunction.Type.TRANSLATION "Permalink to this definition") - ROTATION*: [Type](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 1*[¶](#NonLinearFunction.Type.ROTATION "Permalink to this definition") * NONLINEAR\_SUBSOIL*: [Type](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 2*[¶](#NonLinearFunction.Type.NONLINEAR_SUBSOIL "Permalink to this definition") - *class *Support(*value*)[¶](#NonLinearFunction.Support "Permalink to this definition") Bases: `Enum` An enumeration. * RIGID*: [Support](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 0*[¶](#NonLinearFunction.Support.RIGID "Permalink to this definition") - FREE*: [Support](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 1*[¶](#NonLinearFunction.Support.FREE "Permalink to this definition") * FLEXIBLE*: [Support](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 2*[¶](#NonLinearFunction.Support.FLEXIBLE "Permalink to this definition") * *property *impulse*: List\[Tuple\[float, float]]*[¶](#NonLinearFunction.impulse "Permalink to this definition") * Return type `List`\[`Tuple`\[`float`, `float`]] ## Subsoil[​](/sdk/13/api/external/scia/.md#_Subsoil "Direct link to Subsoil") * *class *viktor.external.scia.object.Subsoil(*object\_id*, *name*, *stiffness*, *c1x=None*, *c1y=None*, *c1z=None*, *nonlinear\_function=None*, *c2x=None*, *c2y=None*, *is\_drained=None*, *water\_air\_in\_clay\_subgrade=None*, *specific\_weight=None*, *fi=None*, *sigma\_oc=None*, *c=None*, *cu=None*)[¶](#Subsoil "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_subsoil()`](/sdk/13/api/external/scia/.md#Model.create_subsoil "viktor.external.scia.scia.Model.create_subsoil") * *class *C1z(*value*)[¶](#Subsoil.C1z "Permalink to this definition") Bases: `Enum` An enumeration. * FLEXIBLE*: [C1z](#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")** = 0*[¶](#Subsoil.C1z.FLEXIBLE "Permalink to this definition") - NONLINEAR\_FUNCTION*: [C1z](#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")** = 1*[¶](#Subsoil.C1z.NONLINEAR_FUNCTION "Permalink to this definition") - *property *nonlinear\_function*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#Subsoil.nonlinear_function "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] ## Orthotropy[​](/sdk/13/api/external/scia/.md#_Orthotropy "Direct link to Orthotropy") * *class *viktor.external.scia.object.Orthotropy(*object\_id*, *name*, *material*, *thickness*, *D11=None*, *D22=None*, *D12=None*, *D33=None*, *D44=None*, *D55=None*, *d11=None*, *d22=None*, *d12=None*, *d33=None*, *kxy=None*, *kyx=None*)[¶](#Orthotropy "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_orthotropy()`](/sdk/13/api/external/scia/.md#Model.create_orthotropy "viktor.external.scia.scia.Model.create_orthotropy") ## CrossSection[​](/sdk/13/api/external/scia/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.scia.object.CrossSection(*object\_id*, *name*, *material*)[¶](#CrossSection "Permalink to this definition") Bases: `_SciaObject`, `ABC` Abstract base class of all cross sections. ## RectangularCrossSection[​](/sdk/13/api/external/scia/.md#_RectangularCrossSection "Direct link to RectangularCrossSection") * *class *viktor.external.scia.object.RectangularCrossSection(*object\_id*, *name*, *material*, *width*, *height*)[¶](#RectangularCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_rectangular_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_rectangular_cross_section "viktor.external.scia.scia.Model.create_rectangular_cross_section") ## CircularCrossSection[​](/sdk/13/api/external/scia/.md#_CircularCrossSection "Direct link to CircularCrossSection") * *class *viktor.external.scia.object.CircularCrossSection(*object\_id*, *name*, *material*, *diameter*)[¶](#CircularCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_circular_cross_section "viktor.external.scia.scia.Model.create_circular_cross_section") ## CircularHollowCrossSection[​](/sdk/13/api/external/scia/.md#_CircularHollowCrossSection "Direct link to CircularHollowCrossSection") * *class *viktor.external.scia.object.CircularHollowCrossSection(*object\_id*, *name*, *material*, *diameter*, *thickness*)[¶](#CircularHollowCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_hollow_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_circular_hollow_cross_section "viktor.external.scia.scia.Model.create_circular_hollow_cross_section") ## ComposedCrossSection[​](/sdk/13/api/external/scia/.md#_ComposedCrossSection "Direct link to ComposedCrossSection") * *class *viktor.external.scia.object.ComposedCrossSection(*object\_id*, *name*, *material*, *material\_2*)[¶](#ComposedCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection"), `ABC` Abstract base class of all cross sections, composed of two materials. ## CircularComposedCrossSection[​](/sdk/13/api/external/scia/.md#_CircularComposedCrossSection "Direct link to CircularComposedCrossSection") * *class *viktor.external.scia.object.CircularComposedCrossSection(*object\_id*, *name*, *material*, *material\_2*, *diameter*, *thickness*)[¶](#CircularComposedCrossSection "Permalink to this definition") Bases: [`ComposedCrossSection`](#ComposedCrossSection "viktor.external.scia.object.ComposedCrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_composed_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_circular_composed_cross_section "viktor.external.scia.scia.Model.create_circular_composed_cross_section") ## NumericalCrossSection[​](/sdk/13/api/external/scia/.md#_NumericalCrossSection "Direct link to NumericalCrossSection") * *class *viktor.external.scia.object.NumericalCrossSection(*object\_id*, *name*, *material*, *\**, *A=None*, *Ay=None*, *Az=None*, *AL=None*, *AD=None*, *cYUCS=None*, *cZUCS=None*, *alpha=None*, *Iy=None*, *Iz=None*, *Wely=None*, *Welz=None*, *Wply=None*, *Wplz=None*, *Mply\_plus=None*, *Mply\_min=None*, *Mplz\_plus=None*, *Mplz\_min=None*, *dy=None*, *dz=None*, *It=None*, *Iw=None*, *beta\_y=None*, *beta\_z=None*)[¶](#NumericalCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_numerical_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_numerical_cross_section "viktor.external.scia.scia.Model.create_numerical_cross_section") ## LibraryCrossSection[​](/sdk/13/api/external/scia/.md#_LibraryCrossSection "Direct link to LibraryCrossSection") * *class *viktor.external.scia.object.LibraryCrossSection(*object\_id*, *name*, *material*, *section*, *profile*)[¶](#LibraryCrossSection "Permalink to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_library_cross_section()`](/sdk/13/api/external/scia/.md#Model.create_library_cross_section "viktor.external.scia.scia.Model.create_library_cross_section") * *class *Section(*value*)[¶](#LibraryCrossSection.Section "Permalink to this definition") Bases: `Enum` An enumeration. * I*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 1*[¶](#LibraryCrossSection.Section.I "Permalink to this definition") - RECTANGULAR\_HOLLOW*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 2*[¶](#LibraryCrossSection.Section.RECTANGULAR_HOLLOW "Permalink to this definition") * CIRCULAR\_HOLLOW*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 3*[¶](#LibraryCrossSection.Section.CIRCULAR_HOLLOW "Permalink to this definition") - L*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 4*[¶](#LibraryCrossSection.Section.L "Permalink to this definition") * CHANNEL*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 5*[¶](#LibraryCrossSection.Section.CHANNEL "Permalink to this definition") - T*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 6*[¶](#LibraryCrossSection.Section.T "Permalink to this definition") * FULL\_RECTANGULAR*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 7*[¶](#LibraryCrossSection.Section.FULL_RECTANGULAR "Permalink to this definition") - FULL\_CIRCULAR*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 11*[¶](#LibraryCrossSection.Section.FULL_CIRCULAR "Permalink to this definition") * ASYMMETRIC\_I*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 101*[¶](#LibraryCrossSection.Section.ASYMMETRIC_I "Permalink to this definition") - ROLLED\_Z*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 102*[¶](#LibraryCrossSection.Section.ROLLED_Z "Permalink to this definition") * GENERAL\_COLD\_FORMED*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 110*[¶](#LibraryCrossSection.Section.GENERAL_COLD_FORMED "Permalink to this definition") - COLD\_FORMED\_ANGLE*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 111*[¶](#LibraryCrossSection.Section.COLD_FORMED_ANGLE "Permalink to this definition") * COLD\_FORMED\_CHANNEL*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 112*[¶](#LibraryCrossSection.Section.COLD_FORMED_CHANNEL "Permalink to this definition") - COLD\_FORMED\_Z*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 113*[¶](#LibraryCrossSection.Section.COLD_FORMED_Z "Permalink to this definition") * COLD\_FORMED\_C*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 114*[¶](#LibraryCrossSection.Section.COLD_FORMED_C "Permalink to this definition") - COLD\_FORMED\_OMEGA*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 115*[¶](#LibraryCrossSection.Section.COLD_FORMED_OMEGA "Permalink to this definition") * COLD\_FORMED\_C\_EAVES\_BEAM*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 116*[¶](#LibraryCrossSection.Section.COLD_FORMED_C_EAVES_BEAM "Permalink to this definition") - COLD\_FORMED\_C\_PLUS*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 117*[¶](#LibraryCrossSection.Section.COLD_FORMED_C_PLUS "Permalink to this definition") * COLD\_FORMED\_ZED*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 118*[¶](#LibraryCrossSection.Section.COLD_FORMED_ZED "Permalink to this definition") - COLD\_FORMED\_ZED\_ASYMMETRIC\_LIPS*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 119*[¶](#LibraryCrossSection.Section.COLD_FORMED_ZED_ASYMMETRIC_LIPS "Permalink to this definition") * COLD\_FORMED\_ZED\_INCLINED\_LIP*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 120*[¶](#LibraryCrossSection.Section.COLD_FORMED_ZED_INCLINED_LIP "Permalink to this definition") - COLD\_FORMED\_SIGMA*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 121*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA "Permalink to this definition") * COLD\_FORMED\_SIGMA\_STIFFENED*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 122*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_STIFFENED "Permalink to this definition") - COLD\_FORMED\_SIGMA\_PLUS*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 123*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_PLUS "Permalink to this definition") * COLD\_FORMED\_SIGMA\_EAVES\_BEAM*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 124*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_EAVES_BEAM "Permalink to this definition") - COLD\_FORMED\_SIGMA\_PLUS\_EAVES\_BEAM*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 125*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_PLUS_EAVES_BEAM "Permalink to this definition") * COLD\_FORMED\_ZED\_BOTH\_LIPS\_INCLINED*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 126*[¶](#LibraryCrossSection.Section.COLD_FORMED_ZED_BOTH_LIPS_INCLINED "Permalink to this definition") - COLD\_FORMED\_I\_PLUS*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 127*[¶](#LibraryCrossSection.Section.COLD_FORMED_I_PLUS "Permalink to this definition") * COLD\_FORMED\_IS\_PLUS*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 128*[¶](#LibraryCrossSection.Section.COLD_FORMED_IS_PLUS "Permalink to this definition") - COLD\_FORMED\_SIGMA\_ASYMMETRIC*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 129*[¶](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_ASYMMETRIC "Permalink to this definition") * COLD\_FORMED\_2C*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 130*[¶](#LibraryCrossSection.Section.COLD_FORMED_2C "Permalink to this definition") - RAIL\_TYPE\_KA*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 150*[¶](#LibraryCrossSection.Section.RAIL_TYPE_KA "Permalink to this definition") * RAIL\_TYPE\_KF*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 151*[¶](#LibraryCrossSection.Section.RAIL_TYPE_KF "Permalink to this definition") - RAIL\_TYPE\_KG*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 152*[¶](#LibraryCrossSection.Section.RAIL_TYPE_KG "Permalink to this definition") * SFB*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 153*[¶](#LibraryCrossSection.Section.SFB "Permalink to this definition") - IFBA*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 154*[¶](#LibraryCrossSection.Section.IFBA "Permalink to this definition") * IFBB*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 155*[¶](#LibraryCrossSection.Section.IFBB "Permalink to this definition") - THQ*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 156*[¶](#LibraryCrossSection.Section.THQ "Permalink to this definition") * VIRTUAL\_JOIST*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 160*[¶](#LibraryCrossSection.Section.VIRTUAL_JOIST "Permalink to this definition") - MINUS\_L*: [Section](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 1002*[¶](#LibraryCrossSection.Section.MINUS_L "Permalink to this definition") ## Node[​](/sdk/13/api/external/scia/.md#_Node "Direct link to Node") * *class *viktor.external.scia.object.Node(*object\_id*, *name*, *x*, *y*, *z*)[¶](#Node "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_node()`](/sdk/13/api/external/scia/.md#Model.create_node "viktor.external.scia.scia.Model.create_node") ## Beam[​](/sdk/13/api/external/scia/.md#_Beam "Direct link to Beam") * *class *viktor.external.scia.object.Beam(*object\_id*, *name*, *begin\_node*, *end\_node*, *cross\_section*, *ez=None*, *lcs\_rotation=None*, *layer=None*)[¶](#Beam "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_beam()`](/sdk/13/api/external/scia/.md#Model.create_beam "viktor.external.scia.scia.Model.create_beam") * *property *begin\_node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#Beam.begin_node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") - *property *end\_node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#Beam.end_node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") * *property *cross\_section*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[¶](#Beam.cross_section "Permalink to this definition") * Return type [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") - *property *ez*: float*[¶](#Beam.ez "Permalink to this definition") * Return type `float` ## CrossLink[​](/sdk/13/api/external/scia/.md#_CrossLink "Direct link to CrossLink") * *class *viktor.external.scia.object.CrossLink(*object\_id*, *name*, *beam\_1*, *beam\_2*)[¶](#CrossLink "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_link()`](/sdk/13/api/external/scia/.md#Model.create_cross_link "viktor.external.scia.scia.Model.create_cross_link") ## ArbitraryProfileSpan[​](/sdk/13/api/external/scia/.md#_ArbitraryProfileSpan "Direct link to ArbitraryProfileSpan") * *class *viktor.external.scia.object.ArbitraryProfileSpan(*length*, *type\_of\_css*, *cross\_section\_start*, *cross\_section\_end*, *alignment*)[¶](#ArbitraryProfileSpan "Permalink to this definition") Do not use this \_\_init\_\_ directly, but create the object by [`create_arbitrary_profile_span()`](/sdk/13/api/external/scia/.md#Model.create_arbitrary_profile_span "viktor.external.scia.scia.Model.create_arbitrary_profile_span") * *class *TypeOfCss(*value*)[¶](#ArbitraryProfileSpan.TypeOfCss "Permalink to this definition") Bases: `Enum` * **PRISMATIC** - The cross-section of the span is constant. * **PARAM\_HAUNCH** - A standard haunch is inserted into the span. * **TWO\_CSS** - Two cross-sections corresponding to the two end-points of the span are defined. The cross-section varies over the span from one section to the other. - PRISMATIC*: [TypeOfCss](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 0*[¶](#ArbitraryProfileSpan.TypeOfCss.PRISMATIC "Permalink to this definition") * PARAM\_HAUNCH*: [TypeOfCss](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 1*[¶](#ArbitraryProfileSpan.TypeOfCss.PARAM_HAUNCH "Permalink to this definition") - TWO\_CSS*: [TypeOfCss](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 2*[¶](#ArbitraryProfileSpan.TypeOfCss.TWO_CSS "Permalink to this definition") - *class *Alignment(*value*)[¶](#ArbitraryProfileSpan.Alignment "Permalink to this definition") Bases: `Enum` * **DEFAULT** - see “Default” at * **CENTER\_LINE** - see “Centre line” at * **TOP\_SURFACE** - see “Top surface” at * **BOTTOM\_SURFACE** - see “Bottom surface” at * **LEFT\_SURFACE** - see “Left surface” at * **RIGHT\_SURFACE** - see “Right surface” at * **TOP\_LEFT** - * **TOP\_RIGHT** - * **BOTTOM\_LEFT** - * **BOTTOM\_RIGHT** - - DEFAULT*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 0*[¶](#ArbitraryProfileSpan.Alignment.DEFAULT "Permalink to this definition") * CENTER\_LINE*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 1*[¶](#ArbitraryProfileSpan.Alignment.CENTER_LINE "Permalink to this definition") - TOP\_SURFACE*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 2*[¶](#ArbitraryProfileSpan.Alignment.TOP_SURFACE "Permalink to this definition") * BOTTOM\_SURFACE*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 3*[¶](#ArbitraryProfileSpan.Alignment.BOTTOM_SURFACE "Permalink to this definition") - LEFT\_SURFACE*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 4*[¶](#ArbitraryProfileSpan.Alignment.LEFT_SURFACE "Permalink to this definition") * RIGHT\_SURFACE*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 5*[¶](#ArbitraryProfileSpan.Alignment.RIGHT_SURFACE "Permalink to this definition") - TOP\_LEFT*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 6*[¶](#ArbitraryProfileSpan.Alignment.TOP_LEFT "Permalink to this definition") * TOP\_RIGHT*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 7*[¶](#ArbitraryProfileSpan.Alignment.TOP_RIGHT "Permalink to this definition") - BOTTOM\_LEFT*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 8*[¶](#ArbitraryProfileSpan.Alignment.BOTTOM_LEFT "Permalink to this definition") * BOTTOM\_RIGHT*: [Alignment](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 9*[¶](#ArbitraryProfileSpan.Alignment.BOTTOM_RIGHT "Permalink to this definition") * *property *cross\_section\_start*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[¶](#ArbitraryProfileSpan.cross_section_start "Permalink to this definition") * Return type [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") - *property *cross\_section\_end*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[¶](#ArbitraryProfileSpan.cross_section_end "Permalink to this definition") * Return type [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") ## ArbitraryProfile[​](/sdk/13/api/external/scia/.md#_ArbitraryProfile "Direct link to ArbitraryProfile") * *class *viktor.external.scia.object.ArbitraryProfile(*object\_id*, *name*, *beam*, *c\_def*, *cross\_section*, *spans*)[¶](#ArbitraryProfile "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_arbitrary_profile()`](/sdk/13/api/external/scia/.md#Model.create_arbitrary_profile "viktor.external.scia.scia.Model.create_arbitrary_profile") * *class *CDef(*value*)[¶](#ArbitraryProfile.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute * **RELATIVE** - relative - ABSOLUTE*: [CDef](#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")** = 0*[¶](#ArbitraryProfile.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")** = 1*[¶](#ArbitraryProfile.CDef.RELATIVE "Permalink to this definition") - *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#ArbitraryProfile.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") * *property *cross\_section*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[¶](#ArbitraryProfile.cross_section "Permalink to this definition") * Return type [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") - *property *spans*: List\[[ArbitraryProfileSpan](#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan")]*[¶](#ArbitraryProfile.spans "Permalink to this definition") * Return type `List`\[[`ArbitraryProfileSpan`](#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan")] ## HingeOnBeam[​](/sdk/13/api/external/scia/.md#_HingeOnBeam "Direct link to HingeOnBeam") * *class *viktor.external.scia.object.HingeOnBeam(*object\_id*, *name*, *beam*, *position*, *freedom\_ux=Freedom.FREE*, *freedom\_uy=Freedom.FREE*, *freedom\_uz=Freedom.FREE*, *freedom\_fix=Freedom.FREE*, *freedom\_fiy=Freedom.FREE*, *freedom\_fiz=Freedom.FREE*, *stiffness\_ux=0*, *stiffness\_uy=0*, *stiffness\_uz=0*, *stiffness\_fix=0*, *stiffness\_fiy=0*, *stiffness\_fiz=0*)[¶](#HingeOnBeam "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_hinge_on_beam()`](/sdk/13/api/external/scia/.md#Model.create_hinge_on_beam "viktor.external.scia.scia.Model.create_hinge_on_beam"). * *class *Position(*value*)[¶](#HingeOnBeam.Position "Permalink to this definition") Bases: `Enum` An enumeration. * BEGIN*: [Position](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 0*[¶](#HingeOnBeam.Position.BEGIN "Permalink to this definition") - END*: [Position](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 1*[¶](#HingeOnBeam.Position.END "Permalink to this definition") * BOTH*: [Position](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 2*[¶](#HingeOnBeam.Position.BOTH "Permalink to this definition") - *class *Freedom(*value*)[¶](#HingeOnBeam.Freedom "Permalink to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FREE*: [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 0*[¶](#HingeOnBeam.Freedom.FREE "Permalink to this definition") * RIGID*: [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 1*[¶](#HingeOnBeam.Freedom.RIGID "Permalink to this definition") - FLEXIBLE*: [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 2*[¶](#HingeOnBeam.Freedom.FLEXIBLE "Permalink to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#HingeOnBeam.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") - *property *freedom*: Tuple\[[Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")]*[¶](#HingeOnBeam.freedom "Permalink to this definition") ux, uy, uz, fix, fiy, fiz * Return type `Tuple`\[[`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")] * *property *stiffness*: Tuple\[float, float, float, float, float, float]*[¶](#HingeOnBeam.stiffness "Permalink to this definition") ux, uy, uz, fix, fiy, fiz * Return type `Tuple`\[`float`, `float`, `float`, `float`, `float`, `float`] ## HingeOnPlane[​](/sdk/13/api/external/scia/.md#_HingeOnPlane "Direct link to HingeOnPlane") * *class *viktor.external.scia.object.HingeOnPlane(*object\_id*, *name*, *edge*, *ux=None*, *stiffness\_ux=None*, *uy=None*, *stiffness\_uy=None*, *uz=None*, *stiffness\_uz=None*, *fix=None*, *stiffness\_fix=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#HingeOnPlane "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_hinge_on_plane()`](/sdk/13/api/external/scia/.md#Model.create_hinge_on_plane "viktor.external.scia.scia.Model.create_hinge_on_plane"). * *class *CDef(*value*)[¶](#HingeOnPlane.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")** = 0*[¶](#HingeOnPlane.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")** = 1*[¶](#HingeOnPlane.CDef.RELATIVE "Permalink to this definition") - *class *Freedom(*value*)[¶](#HingeOnPlane.Freedom "Permalink to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FREE*: [Freedom](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 0*[¶](#HingeOnPlane.Freedom.FREE "Permalink to this definition") * RIGID*: [Freedom](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 1*[¶](#HingeOnPlane.Freedom.RIGID "Permalink to this definition") - FLEXIBLE*: [Freedom](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 2*[¶](#HingeOnPlane.Freedom.FLEXIBLE "Permalink to this definition") * *class *Origin(*value*)[¶](#HingeOnPlane.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_START*: [Origin](#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")** = 0*[¶](#HingeOnPlane.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")** = 1*[¶](#HingeOnPlane.Origin.FROM_END "Permalink to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#HingeOnPlane.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") ## Plane[​](/sdk/13/api/external/scia/.md#_Plane "Direct link to Plane") * *class *viktor.external.scia.object.Plane(*object\_id*, *name*, *thickness*, *material*, *\**, *plane\_type=None*, *layer=None*, *corner\_nodes=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*, *center\_node=None*, *vertex\_node=None*, *axis=None*)[¶](#Plane "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_plane()`](/sdk/13/api/external/scia/.md#Model.create_plane "viktor.external.scia.scia.Model.create_plane") or [`create_circular_plane()`](/sdk/13/api/external/scia/.md#Model.create_circular_plane "viktor.external.scia.scia.Model.create_circular_plane") * *class *FEMModel(*value*)[¶](#Plane.FEMModel "Permalink to this definition") Bases: `Enum` An enumeration. * ISOTROPIC*: [FEMModel](#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")** = 0*[¶](#Plane.FEMModel.ISOTROPIC "Permalink to this definition") - ORTHOTROPIC*: [FEMModel](#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")** = 1*[¶](#Plane.FEMModel.ORTHOTROPIC "Permalink to this definition") - *class *Type(*value*)[¶](#Plane.Type "Permalink to this definition") Bases: `Enum` * **PLATE** - A standard plate is a planar 2D member with an arbitrary number of edges that may be straight or curved. * **WALL** - A wall is a vertical 2D member whose base is either straight or curved. * **SHELL** - Shells are defined by border lines (i.e. border curves). The shape of the shell can be defined by four, three or two curves / straight lines. - PLATE*: [Type](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 0*[¶](#Plane.Type.PLATE "Permalink to this definition") * WALL*: [Type](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 1*[¶](#Plane.Type.WALL "Permalink to this definition") - SHELL*: [Type](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 2*[¶](#Plane.Type.SHELL "Permalink to this definition") * *property *corner\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[¶](#Plane.corner_nodes "Permalink to this definition") * Return type `List`\[[`Node`](#Node "viktor.external.scia.object.Node")] - *property *internal\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[¶](#Plane.internal_nodes "Permalink to this definition") * Return type `List`\[[`Node`](#Node "viktor.external.scia.object.Node")] * *property *swap\_orientation*: bool*[¶](#Plane.swap_orientation "Permalink to this definition") * Return type `bool` - *property *lcs\_rotation*: float*[¶](#Plane.lcs_rotation "Permalink to this definition") * Return type `float` ## LineSupport[​](/sdk/13/api/external/scia/.md#_LineSupport "Direct link to LineSupport") * *class *viktor.external.scia.object.LineSupport(*object\_id*, *name*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineSupport "Permalink to this definition") Bases: `_SciaObject`, `ABC` Abstract base class of all line supports. * *class *Constraint(*value*)[¶](#LineSupport.Constraint "Permalink to this definition") Bases: `Enum` An enumeration. * FIXED*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 0*[¶](#LineSupport.Constraint.FIXED "Permalink to this definition") - HINGED*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 1*[¶](#LineSupport.Constraint.HINGED "Permalink to this definition") * SLIDING*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 2*[¶](#LineSupport.Constraint.SLIDING "Permalink to this definition") - CUSTOM*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 3*[¶](#LineSupport.Constraint.CUSTOM "Permalink to this definition") - *class *Type(*value*)[¶](#LineSupport.Type "Permalink to this definition") Bases: `Enum` An enumeration. * LINE*: [Type](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 0*[¶](#LineSupport.Type.LINE "Permalink to this definition") - FOUNDATION\_STRIP*: [Type](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 1*[¶](#LineSupport.Type.FOUNDATION_STRIP "Permalink to this definition") * WALL*: [Type](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 2*[¶](#LineSupport.Type.WALL "Permalink to this definition") * *class *Freedom(*value*)[¶](#LineSupport.Freedom "Permalink to this definition") Bases: `Enum` An enumeration. * FREE*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 0*[¶](#LineSupport.Freedom.FREE "Permalink to this definition") - RIGID*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 1*[¶](#LineSupport.Freedom.RIGID "Permalink to this definition") * FLEXIBLE*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 2*[¶](#LineSupport.Freedom.FLEXIBLE "Permalink to this definition") - RIGID\_PRESS\_ONLY*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 3*[¶](#LineSupport.Freedom.RIGID_PRESS_ONLY "Permalink to this definition") * RIGID\_TENSION\_ONLY*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 4*[¶](#LineSupport.Freedom.RIGID_TENSION_ONLY "Permalink to this definition") - FLEXIBLE\_PRESS\_ONLY*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 5*[¶](#LineSupport.Freedom.FLEXIBLE_PRESS_ONLY "Permalink to this definition") * FLEXIBLE\_TENSION\_ONLY*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 6*[¶](#LineSupport.Freedom.FLEXIBLE_TENSION_ONLY "Permalink to this definition") - NONLINEAR*: [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 7*[¶](#LineSupport.Freedom.NONLINEAR "Permalink to this definition") - *class *CSys(*value*)[¶](#LineSupport.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")** = 0*[¶](#LineSupport.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")** = 1*[¶](#LineSupport.CSys.LOCAL "Permalink to this definition") * *class *CDef(*value*)[¶](#LineSupport.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")** = 0*[¶](#LineSupport.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")** = 1*[¶](#LineSupport.CDef.RELATIVE "Permalink to this definition") - *class *Extent(*value*)[¶](#LineSupport.Extent "Permalink to this definition") Bases: `Enum` * **FULL** - support across the full length * **SPAN** - support across a span - FULL*: [Extent](#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")** = 0*[¶](#LineSupport.Extent.FULL "Permalink to this definition") * SPAN*: [Extent](#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")** = 1*[¶](#LineSupport.Extent.SPAN "Permalink to this definition") * *class *Origin(*value*)[¶](#LineSupport.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")** = 0*[¶](#LineSupport.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")** = 1*[¶](#LineSupport.Origin.FROM_END "Permalink to this definition") - *property *constraint*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")*[¶](#LineSupport.constraint "Permalink to this definition") * Return type [`Constraint`](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint") * *property *freedom*: Tuple\[[Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]*[¶](#LineSupport.freedom "Permalink to this definition") * Return type `Tuple`\[[`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")] - *property *stiffness*: Tuple\[Optional\[float], Optional\[float], Optional\[float], Optional\[float], Optional\[float], Optional\[float]]*[¶](#LineSupport.stiffness "Permalink to this definition") * Return type `Tuple`\[`Optional`\[`float`], `Optional`\[`float`], `Optional`\[`float`], `Optional`\[`float`], `Optional`\[`float`], `Optional`\[`float`]] * *property *function\_x*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_x "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] - *property *function\_y*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_y "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] * *property *function\_z*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_z "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] - *property *function\_rx*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_rx "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] * *property *function\_ry*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_ry "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] - *property *function\_rz*: Optional\[[NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")]*[¶](#LineSupport.function_rz "Permalink to this definition") * Return type `Optional`\[[`NonLinearFunction`](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")] ## LineSupportLine[​](/sdk/13/api/external/scia/.md#_LineSupportLine "Direct link to LineSupportLine") * *class *viktor.external.scia.object.LineSupportLine(*object\_id*, *name*, *beam*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *extent=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineSupportLine "Permalink to this definition") Bases: [`LineSupport`](#LineSupport "viktor.external.scia.object.LineSupport") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_support_on_beam()`](/sdk/13/api/external/scia/.md#Model.create_line_support_on_beam "viktor.external.scia.scia.Model.create_line_support_on_beam") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#LineSupportLine.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") - *property *spring\_type*: [Type](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")*[¶](#LineSupportLine.spring_type "Permalink to this definition") * Return type [`Type`](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type") ## LineSupportSurface[​](/sdk/13/api/external/scia/.md#_LineSupportSurface "Direct link to LineSupportSurface") * *class *viktor.external.scia.object.LineSupportSurface(*object\_id*, *name*, *edge*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineSupportSurface "Permalink to this definition") Bases: [`LineSupport`](#LineSupport "viktor.external.scia.object.LineSupport") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_support_on_plane()`](/sdk/13/api/external/scia/.md#Model.create_line_support_on_plane "viktor.external.scia.scia.Model.create_line_support_on_plane") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#LineSupportSurface.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") ## SurfaceSupportSurface[​](/sdk/13/api/external/scia/.md#_SurfaceSupportSurface "Direct link to SurfaceSupportSurface") * *class *viktor.external.scia.object.SurfaceSupportSurface(*object\_id*, *name*, *plane*, *subsoil*)[¶](#SurfaceSupportSurface "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_surface_support()`](/sdk/13/api/external/scia/.md#Model.create_surface_support "viktor.external.scia.scia.Model.create_surface_support") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#SurfaceSupportSurface.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") - *property *subsoil*: [Subsoil](#Subsoil "viktor.external.scia.object.Subsoil")*[¶](#SurfaceSupportSurface.subsoil "Permalink to this definition") * Return type [`Subsoil`](#Subsoil "viktor.external.scia.object.Subsoil") ## OpenSlab[​](/sdk/13/api/external/scia/.md#_OpenSlab "Direct link to OpenSlab") * *class *viktor.external.scia.object.OpenSlab(*object\_id*, *name*, *plane*, *corner\_nodes*)[¶](#OpenSlab "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_open_slab()`](/sdk/13/api/external/scia/.md#Model.create_open_slab "viktor.external.scia.scia.Model.create_open_slab") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#OpenSlab.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") - *property *corner\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[¶](#OpenSlab.corner_nodes "Permalink to this definition") * Return type `List`\[[`Node`](#Node "viktor.external.scia.object.Node")] ## InternalEdge[​](/sdk/13/api/external/scia/.md#_InternalEdge "Direct link to InternalEdge") * *class *viktor.external.scia.object.InternalEdge(*object\_id*, *name*, *plane*, *node\_1*, *node\_2*)[¶](#InternalEdge "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_internal_edge()`](/sdk/13/api/external/scia/.md#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#InternalEdge.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") - *property *node\_1*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#InternalEdge.node_1 "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") * *property *node\_2*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#InternalEdge.node_2 "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") ## PointSupport[​](/sdk/13/api/external/scia/.md#_PointSupport "Direct link to PointSupport") * *class *viktor.external.scia.object.PointSupport(*object\_id*, *name*, *node*, *spring\_type*, *freedom*, *stiffness*, *c\_sys*, *default\_size=0.2*, *angle=None*)[¶](#PointSupport "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_point_support()`](/sdk/13/api/external/scia/.md#Model.create_point_support "viktor.external.scia.scia.Model.create_point_support") * *class *Constraint(*value*)[¶](#PointSupport.Constraint "Permalink to this definition") Bases: `Enum` An enumeration. * FIXED*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 0*[¶](#PointSupport.Constraint.FIXED "Permalink to this definition") - HINGED*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 1*[¶](#PointSupport.Constraint.HINGED "Permalink to this definition") * SLIDING*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 2*[¶](#PointSupport.Constraint.SLIDING "Permalink to this definition") - CUSTOM*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 3*[¶](#PointSupport.Constraint.CUSTOM "Permalink to this definition") - *class *Type(*value*)[¶](#PointSupport.Type "Permalink to this definition") Bases: `Enum` An enumeration. * STANDARD*: [Type](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 0*[¶](#PointSupport.Type.STANDARD "Permalink to this definition") - PAD\_FOUNDATION*: [Type](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 1*[¶](#PointSupport.Type.PAD_FOUNDATION "Permalink to this definition") * COLUMN*: [Type](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 2*[¶](#PointSupport.Type.COLUMN "Permalink to this definition") * *class *Freedom(*value*)[¶](#PointSupport.Freedom "Permalink to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FREE*: [Freedom](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 0*[¶](#PointSupport.Freedom.FREE "Permalink to this definition") * RIGID*: [Freedom](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 1*[¶](#PointSupport.Freedom.RIGID "Permalink to this definition") - FLEXIBLE*: [Freedom](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 2*[¶](#PointSupport.Freedom.FLEXIBLE "Permalink to this definition") - *class *CSys(*value*)[¶](#PointSupport.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")** = 0*[¶](#PointSupport.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")** = 1*[¶](#PointSupport.CSys.LOCAL "Permalink to this definition") * *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#PointSupport.node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") - *property *constraint*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")*[¶](#PointSupport.constraint "Permalink to this definition") * Return type [`Constraint`](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint") ## PointSupportLine[​](/sdk/13/api/external/scia/.md#_PointSupportLine "Direct link to PointSupportLine") * *class *viktor.external.scia.object.PointSupportLine(*object\_id*, *name*, *beam*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *default\_size=None*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *delta\_x=None*)[¶](#PointSupportLine "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_point_support_on_beam()`](/sdk/13/api/external/scia/.md#Model.create_point_support_on_beam "viktor.external.scia.scia.Model.create_point_support_on_beam") * *class *Freedom(*value*)[¶](#PointSupportLine.Freedom "Permalink to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FREE*: [Freedom](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 0*[¶](#PointSupportLine.Freedom.FREE "Permalink to this definition") * RIGID*: [Freedom](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 1*[¶](#PointSupportLine.Freedom.RIGID "Permalink to this definition") - FLEXIBLE*: [Freedom](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 2*[¶](#PointSupportLine.Freedom.FLEXIBLE "Permalink to this definition") - *class *CSys(*value*)[¶](#PointSupportLine.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")** = 0*[¶](#PointSupportLine.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")** = 1*[¶](#PointSupportLine.CSys.LOCAL "Permalink to this definition") * *class *CDef(*value*)[¶](#PointSupportLine.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")** = 0*[¶](#PointSupportLine.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")** = 1*[¶](#PointSupportLine.CDef.RELATIVE "Permalink to this definition") - *class *Origin(*value*)[¶](#PointSupportLine.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")** = 0*[¶](#PointSupportLine.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")** = 1*[¶](#PointSupportLine.Origin.FROM_END "Permalink to this definition") ## RigidArm[​](/sdk/13/api/external/scia/.md#_RigidArm "Direct link to RigidArm") * *class *viktor.external.scia.object.RigidArm(*object\_id*, *name*, *master\_node*, *slave\_node*, *hinge\_on\_master*, *hinge\_on\_slave*)[¶](#RigidArm "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_rigid_arm()`](/sdk/13/api/external/scia/.md#Model.create_rigid_arm "viktor.external.scia.scia.Model.create_rigid_arm") * *property *master\_node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#RigidArm.master_node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") - *property *slave\_node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#RigidArm.slave_node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") ## SectionOnBeam[​](/sdk/13/api/external/scia/.md#_SectionOnBeam "Direct link to SectionOnBeam") * *class *viktor.external.scia.object.SectionOnBeam(*object\_id*, *name*, *beam*, *c\_def*, *position\_x*, *origin*, *repeat*, *delta\_x*)[¶](#SectionOnBeam "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_section_on_beam()`](/sdk/13/api/external/scia/.md#Model.create_section_on_beam "viktor.external.scia.scia.Model.create_section_on_beam") * *class *CDef(*value*)[¶](#SectionOnBeam.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")** = 0*[¶](#SectionOnBeam.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")** = 1*[¶](#SectionOnBeam.CDef.RELATIVE "Permalink to this definition") - *class *Origin(*value*)[¶](#SectionOnBeam.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")** = 0*[¶](#SectionOnBeam.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")** = 1*[¶](#SectionOnBeam.Origin.FROM_END "Permalink to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#SectionOnBeam.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") ## LoadGroup[​](/sdk/13/api/external/scia/.md#_LoadGroup "Direct link to LoadGroup") * *class *viktor.external.scia.object.LoadGroup(*object\_id*, *name*, *load\_option*, *relation=None*, *load\_type=None*)[¶](#LoadGroup "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_load_group()`](/sdk/13/api/external/scia/.md#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group") * *class *LoadOption(*value*)[¶](#LoadGroup.LoadOption "Permalink to this definition") Bases: `Enum` An enumeration. * PERMANENT*: [LoadOption](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 0*[¶](#LoadGroup.LoadOption.PERMANENT "Permalink to this definition") - VARIABLE*: [LoadOption](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 1*[¶](#LoadGroup.LoadOption.VARIABLE "Permalink to this definition") * ACCIDENTAL*: [LoadOption](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 2*[¶](#LoadGroup.LoadOption.ACCIDENTAL "Permalink to this definition") - SEISMIC*: [LoadOption](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 3*[¶](#LoadGroup.LoadOption.SEISMIC "Permalink to this definition") - *class *RelationOption(*value*)[¶](#LoadGroup.RelationOption "Permalink to this definition") Bases: `Enum` An enumeration. * STANDARD*: [RelationOption](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 0*[¶](#LoadGroup.RelationOption.STANDARD "Permalink to this definition") - EXCLUSIVE*: [RelationOption](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 1*[¶](#LoadGroup.RelationOption.EXCLUSIVE "Permalink to this definition") * TOGETHER*: [RelationOption](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 2*[¶](#LoadGroup.RelationOption.TOGETHER "Permalink to this definition") * *class *LoadTypeOption(*value*)[¶](#LoadGroup.LoadTypeOption "Permalink to this definition") Bases: `Enum` * **CAT\_A** - Domestic * **CAT\_B** - Offices * **CAT\_C** - Congregation * **CAT\_D** - Shopping * **CAT\_E** - Storage * **CAT\_F** - Vehicle <30kN * **CAT\_G** - Vehicle >30kN * **CAT\_H** - Roofs * **SNOW** - Snow * **WIND** - Wind * **TEMPERATURE** - Temperature * **RAIN\_WATER** - Rain water * **CONSTRUCTION\_LOADS** - Construction loads - CAT\_A*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 0*[¶](#LoadGroup.LoadTypeOption.CAT_A "Permalink to this definition") * CAT\_B*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 1*[¶](#LoadGroup.LoadTypeOption.CAT_B "Permalink to this definition") - CAT\_C*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 2*[¶](#LoadGroup.LoadTypeOption.CAT_C "Permalink to this definition") * CAT\_D*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 3*[¶](#LoadGroup.LoadTypeOption.CAT_D "Permalink to this definition") - CAT\_E*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 4*[¶](#LoadGroup.LoadTypeOption.CAT_E "Permalink to this definition") * CAT\_F*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 5*[¶](#LoadGroup.LoadTypeOption.CAT_F "Permalink to this definition") - CAT\_G*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 6*[¶](#LoadGroup.LoadTypeOption.CAT_G "Permalink to this definition") * CAT\_H*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 7*[¶](#LoadGroup.LoadTypeOption.CAT_H "Permalink to this definition") - SNOW*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 8*[¶](#LoadGroup.LoadTypeOption.SNOW "Permalink to this definition") * WIND*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 11*[¶](#LoadGroup.LoadTypeOption.WIND "Permalink to this definition") - TEMPERATURE*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 12*[¶](#LoadGroup.LoadTypeOption.TEMPERATURE "Permalink to this definition") * RAIN\_WATER*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 20*[¶](#LoadGroup.LoadTypeOption.RAIN_WATER "Permalink to this definition") - CONSTRUCTION\_LOADS*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 21*[¶](#LoadGroup.LoadTypeOption.CONSTRUCTION_LOADS "Permalink to this definition") - *property *relation*: Optional\[[RelationOption](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")]*[¶](#LoadGroup.relation "Permalink to this definition") * Return type `Optional`\[[`RelationOption`](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")] * *property *load\_type*: Optional\[[LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")]*[¶](#LoadGroup.load_type "Permalink to this definition") * Return type `Optional`\[[`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")] ## LoadCase[​](/sdk/13/api/external/scia/.md#_LoadCase "Direct link to LoadCase") * *class *viktor.external.scia.object.LoadCase(*object\_id*, *name*, *description*, *action\_type*, *load\_group*)[¶](#LoadCase "Permalink to this definition") Bases: `ABC`, `_SciaObject` Abstract base class of all load cases. * *class *ActionType(*value*)[¶](#LoadCase.ActionType "Permalink to this definition") Bases: `Enum` An enumeration. * PERMANENT*: [ActionType](#LoadCase.ActionType "viktor.external.scia.object.LoadCase.ActionType")** = 0*[¶](#LoadCase.ActionType.PERMANENT "Permalink to this definition") - VARIABLE*: [ActionType](#LoadCase.ActionType "viktor.external.scia.object.LoadCase.ActionType")** = 1*[¶](#LoadCase.ActionType.VARIABLE "Permalink to this definition") - *class *PermanentLoadType(*value*)[¶](#LoadCase.PermanentLoadType "Permalink to this definition") Bases: `Enum` An enumeration. * SELF\_WEIGHT*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 0*[¶](#LoadCase.PermanentLoadType.SELF_WEIGHT "Permalink to this definition") - STANDARD*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 1*[¶](#LoadCase.PermanentLoadType.STANDARD "Permalink to this definition") * PRIMARY\_EFFECT*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 2*[¶](#LoadCase.PermanentLoadType.PRIMARY_EFFECT "Permalink to this definition") * *class *VariableLoadType(*value*)[¶](#LoadCase.VariableLoadType "Permalink to this definition") Bases: `Enum` An enumeration. * STATIC*: [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")** = 0*[¶](#LoadCase.VariableLoadType.STATIC "Permalink to this definition") - PRIMARY\_EFFECT*: [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")** = 1*[¶](#LoadCase.VariableLoadType.PRIMARY_EFFECT "Permalink to this definition") - *class *Specification(*value*)[¶](#LoadCase.Specification "Permalink to this definition") Bases: `Enum` An enumeration. * STANDARD*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 100*[¶](#LoadCase.Specification.STANDARD "Permalink to this definition") - TEMPERATURE*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 101*[¶](#LoadCase.Specification.TEMPERATURE "Permalink to this definition") * STATIC\_WIND*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 102*[¶](#LoadCase.Specification.STATIC_WIND "Permalink to this definition") - EARTHQUAKE*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 103*[¶](#LoadCase.Specification.EARTHQUAKE "Permalink to this definition") * SNOW*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 104*[¶](#LoadCase.Specification.SNOW "Permalink to this definition") * *class *Duration(*value*)[¶](#LoadCase.Duration "Permalink to this definition") Bases: `Enum` An enumeration. * LONG*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 0*[¶](#LoadCase.Duration.LONG "Permalink to this definition") - MEDIUM*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 1*[¶](#LoadCase.Duration.MEDIUM "Permalink to this definition") * SHORT*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 2*[¶](#LoadCase.Duration.SHORT "Permalink to this definition") - INSTANTANEOUS*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 3*[¶](#LoadCase.Duration.INSTANTANEOUS "Permalink to this definition") - *class *Direction(*value*)[¶](#LoadCase.Direction "Permalink to this definition") Bases: `Enum` * **NEG\_Z** - -Z * **POS\_Z** - +Z * **NEG\_Y** - -Y * **POS\_Y** - +Y * **NEG\_X** - -X * **POS\_X** - +X - NEG\_Z*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 0*[¶](#LoadCase.Direction.NEG_Z "Permalink to this definition") * POS\_Z*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 1*[¶](#LoadCase.Direction.POS_Z "Permalink to this definition") - NEG\_Y*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 2*[¶](#LoadCase.Direction.NEG_Y "Permalink to this definition") * POS\_Y*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 3*[¶](#LoadCase.Direction.POS_Y "Permalink to this definition") - NEG\_X*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 4*[¶](#LoadCase.Direction.NEG_X "Permalink to this definition") * POS\_X*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 5*[¶](#LoadCase.Direction.POS_X "Permalink to this definition") * *property *load\_group*: [LoadGroup](#LoadGroup "viktor.external.scia.object.LoadGroup")*[¶](#LoadCase.load_group "Permalink to this definition") * Return type [`LoadGroup`](#LoadGroup "viktor.external.scia.object.LoadGroup") - *abstract property *load\_type*: Union\[[PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType"), [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")]*[¶](#LoadCase.load_type "Permalink to this definition") * Return type `Union`\[[`PermanentLoadType`](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType"), [`VariableLoadType`](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")] * *abstract property *direction*: Optional\[[Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")]*[¶](#LoadCase.direction "Permalink to this definition") * Return type `Optional`\[[`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")] - *abstract property *specification*: Optional\[[Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")]*[¶](#LoadCase.specification "Permalink to this definition") * Return type `Optional`\[[`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")] * *abstract property *duration*: Optional\[[Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")]*[¶](#LoadCase.duration "Permalink to this definition") * Return type `Optional`\[[`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")] - *abstract property *master*: Optional\[str]*[¶](#LoadCase.master "Permalink to this definition") * Return type `Optional`\[`str`] * *abstract property *primary\_effect*: Optional\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")]*[¶](#LoadCase.primary_effect "Permalink to this definition") * Return type `Optional`\[[`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase")] ## PermanentLoadCase[​](/sdk/13/api/external/scia/.md#_PermanentLoadCase "Direct link to PermanentLoadCase") * *class *viktor.external.scia.object.PermanentLoadCase(*object\_id*, *name*, *description*, *load\_group*, *load\_type*, *direction=None*, *primary\_effect=None*)[¶](#PermanentLoadCase "Permalink to this definition") Bases: [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") Do not use this \_\_init\_\_ directly, but create the object by [`create_permanent_load_case()`](/sdk/13/api/external/scia/.md#Model.create_permanent_load_case "viktor.external.scia.scia.Model.create_permanent_load_case") * *property *load\_type*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")*[¶](#PermanentLoadCase.load_type "Permalink to this definition") * Return type [`PermanentLoadType`](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType") - *property *direction*: Optional\[[Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")]*[¶](#PermanentLoadCase.direction "Permalink to this definition") * Return type `Optional`\[[`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")] * *property *specification*: None*[¶](#PermanentLoadCase.specification "Permalink to this definition") * Return type `None` - *property *duration*: None*[¶](#PermanentLoadCase.duration "Permalink to this definition") * Return type `None` * *property *master*: None*[¶](#PermanentLoadCase.master "Permalink to this definition") * Return type `None` - *property *primary\_effect*: Optional\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")]*[¶](#PermanentLoadCase.primary_effect "Permalink to this definition") * Return type `Optional`\[[`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase")] ## VariableLoadCase[​](/sdk/13/api/external/scia/.md#_VariableLoadCase "Direct link to VariableLoadCase") * *class *viktor.external.scia.object.VariableLoadCase(*object\_id*, *name*, *description*, *load\_group*, *load\_type*, *specification=None*, *duration=None*, *primary\_effect=None*, *master=None*)[¶](#VariableLoadCase "Permalink to this definition") Bases: [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") Do not use this \_\_init\_\_ directly, but create the object by [`create_variable_load_case()`](/sdk/13/api/external/scia/.md#Model.create_variable_load_case "viktor.external.scia.scia.Model.create_variable_load_case") * *property *load\_type*: [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")*[¶](#VariableLoadCase.load_type "Permalink to this definition") * Return type [`VariableLoadType`](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType") - *property *master*: Optional\[str]*[¶](#VariableLoadCase.master "Permalink to this definition") * Return type `Optional`\[`str`] * *property *specification*: Optional\[[Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")]*[¶](#VariableLoadCase.specification "Permalink to this definition") * Return type `Optional`\[[`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")] - *property *duration*: Optional\[[Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")]*[¶](#VariableLoadCase.duration "Permalink to this definition") * Return type `Optional`\[[`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")] * *property *direction*: None*[¶](#VariableLoadCase.direction "Permalink to this definition") * Return type `None` - *property *primary\_effect*: Optional\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")]*[¶](#VariableLoadCase.primary_effect "Permalink to this definition") * Return type `Optional`\[[`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase")] ## LoadCombination[​](/sdk/13/api/external/scia/.md#_LoadCombination "Direct link to LoadCombination") * *class *viktor.external.scia.object.LoadCombination(*object\_id*, *name*, *combination\_type*, *load\_cases*, *\**, *description=None*)[¶](#LoadCombination "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_load_combination()`](/sdk/13/api/external/scia/.md#Model.create_load_combination "viktor.external.scia.scia.Model.create_load_combination") * *class *Type(*value*)[¶](#LoadCombination.Type "Permalink to this definition") Bases: `Enum` * **ENVELOPE\_ULTIMATE** - Envelope - ultimate * **ENVELOPE\_SERVICEABILITY** - Envelope - serviceability * **LINEAR\_ULTIMATE** - Linear - ultimate * **LINEAR\_SERVICEABILITY** - Linear - serviceability * **EN\_ULS\_SET\_B** - EN-ULS (STR/GEO) Set B * **EN\_ACC\_ONE** - EN-Accidental 1 * **EN\_ACC\_TWO** - EN-Accidental 2 * **EN\_SEISMIC** - EN-Seismic * **EN\_SLS\_CHAR** - EN-SLS Characteristic * **EN\_SLS\_FREQ** - EN-SLS Frequent * **EN\_SLS\_QUASI** - EN-SLS Quasi-permanent * **EN\_ULS\_SET\_C** - EN-ULS (STR/GEO) Set C - ENVELOPE\_ULTIMATE*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 0*[¶](#LoadCombination.Type.ENVELOPE_ULTIMATE "Permalink to this definition") * ENVELOPE\_SERVICEABILITY*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 1*[¶](#LoadCombination.Type.ENVELOPE_SERVICEABILITY "Permalink to this definition") - LINEAR\_ULTIMATE*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 2*[¶](#LoadCombination.Type.LINEAR_ULTIMATE "Permalink to this definition") * LINEAR\_SERVICEABILITY*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 3*[¶](#LoadCombination.Type.LINEAR_SERVICEABILITY "Permalink to this definition") - EN\_ULS\_SET\_B*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 4*[¶](#LoadCombination.Type.EN_ULS_SET_B "Permalink to this definition") * EN\_ACC\_ONE*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 5*[¶](#LoadCombination.Type.EN_ACC_ONE "Permalink to this definition") - EN\_ACC\_TWO*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 6*[¶](#LoadCombination.Type.EN_ACC_TWO "Permalink to this definition") * EN\_SEISMIC*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 7*[¶](#LoadCombination.Type.EN_SEISMIC "Permalink to this definition") - EN\_SLS\_CHAR*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 8*[¶](#LoadCombination.Type.EN_SLS_CHAR "Permalink to this definition") * EN\_SLS\_FREQ*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 9*[¶](#LoadCombination.Type.EN_SLS_FREQ "Permalink to this definition") - EN\_SLS\_QUASI*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 10*[¶](#LoadCombination.Type.EN_SLS_QUASI "Permalink to this definition") * EN\_ULS\_SET\_C*: [Type](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 11*[¶](#LoadCombination.Type.EN_ULS_SET_C "Permalink to this definition") - *property *load\_cases*: Dict\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase"), float]*[¶](#LoadCombination.load_cases "Permalink to this definition") * Return type `Dict`\[[`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase"), `float`] ## NonLinearLoadCombination[​](/sdk/13/api/external/scia/.md#_NonLinearLoadCombination "Direct link to NonLinearLoadCombination") * *class *viktor.external.scia.object.NonLinearLoadCombination(*object\_id*, *name*, *combination\_type*, *load\_cases*, *\**, *description=None*)[¶](#NonLinearLoadCombination "Permalink to this definition") Bases: `_SciaObject` * Do not use this \_\_init\_\_ directly, but create the object by [`create_nonlinear_load_combination()`](/sdk/13/api/external/scia/.md#Model.create_nonlinear_load_combination "viktor.external.scia.scia.Model.create_nonlinear_load_combination") - *class *Type(*value*)[¶](#NonLinearLoadCombination.Type "Permalink to this definition") Bases: `Enum` An enumeration. * ULTIMATE*: [Type](#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")** = 0*[¶](#NonLinearLoadCombination.Type.ULTIMATE "Permalink to this definition") - SERVICEABILITY*: [Type](#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")** = 1*[¶](#NonLinearLoadCombination.Type.SERVICEABILITY "Permalink to this definition") * *property *load\_cases*: Dict\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase"), float]*[¶](#NonLinearLoadCombination.load_cases "Permalink to this definition") * Return type `Dict`\[[`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase"), `float`] ## ResultClass[​](/sdk/13/api/external/scia/.md#_ResultClass "Direct link to ResultClass") * *class *viktor.external.scia.object.ResultClass(*object\_id*, *name*, *combinations*, *nonlinear\_combinations*)[¶](#ResultClass "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_result_class()`](/sdk/13/api/external/scia/.md#Model.create_result_class "viktor.external.scia.scia.Model.create_result_class") * *property *combinations*: List\[[LoadCombination](#LoadCombination "viktor.external.scia.object.LoadCombination")]*[¶](#ResultClass.combinations "Permalink to this definition") * Return type `List`\[[`LoadCombination`](#LoadCombination "viktor.external.scia.object.LoadCombination")] - *property *nonlinear\_combinations*: List\[[NonLinearLoadCombination](#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination")]*[¶](#ResultClass.nonlinear_combinations "Permalink to this definition") * Return type `List`\[[`NonLinearLoadCombination`](#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination")] ## IntegrationStrip[​](/sdk/13/api/external/scia/.md#_IntegrationStrip "Direct link to IntegrationStrip") * *class *viktor.external.scia.object.IntegrationStrip(*object\_id*, *name*, *plane*, *point\_1*, *point\_2*, *width*, *effective\_width\_geometry=\_EffectiveWidthGeometry.CONSTANT\_SYMMETRIC*, *effective\_width\_definition=\_EffectiveWidthDefinition.WIDTH*)[¶](#IntegrationStrip "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_integration_strip()`](/sdk/13/api/external/scia/.md#Model.create_integration_strip "viktor.external.scia.scia.Model.create_integration_strip") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#IntegrationStrip.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") ## SectionOnPlane[​](/sdk/13/api/external/scia/.md#_SectionOnPlane "Direct link to SectionOnPlane") * *class *viktor.external.scia.object.SectionOnPlane(*object\_id*, *name*, *point\_1*, *point\_2*, *draw=None*, *direction\_of\_cut=None*)[¶](#SectionOnPlane "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_section_on_plane()`](/sdk/13/api/external/scia/.md#Model.create_section_on_plane "viktor.external.scia.scia.Model.create_section_on_plane") * *class *Draw(*value*)[¶](#SectionOnPlane.Draw "Permalink to this definition") Bases: `Enum` An enumeration. * UPRIGHT\_TO\_ELEMENT*: [Draw](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 0*[¶](#SectionOnPlane.Draw.UPRIGHT_TO_ELEMENT "Permalink to this definition") - ELEMENT\_PLANE*: [Draw](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 1*[¶](#SectionOnPlane.Draw.ELEMENT_PLANE "Permalink to this definition") * X\_DIRECTION*: [Draw](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 2*[¶](#SectionOnPlane.Draw.X_DIRECTION "Permalink to this definition") - Y\_DIRECTION*: [Draw](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 3*[¶](#SectionOnPlane.Draw.Y_DIRECTION "Permalink to this definition") * Z\_DIRECTION*: [Draw](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 4*[¶](#SectionOnPlane.Draw.Z_DIRECTION "Permalink to this definition") ## ProjectData[​](/sdk/13/api/external/scia/.md#_ProjectData "Direct link to ProjectData") * *class *viktor.external.scia.object.ProjectData(*\**, *name=None*, *part=None*, *description=None*, *author=None*, *date=None*)[¶](#ProjectData "Permalink to this definition") Bases: `_SciaObject` New in v13.1.0 Basic project data. * Parameters * **name** (`Optional`\[`str`]) – Project name (default: as defined in ESA model) * **part** (`Optional`\[`str`]) – Project part name (default: as defined in ESA model) * **description** (`Optional`\[`str`]) – Project description (default: as defined in ESA model) * **author** (`Optional`\[`str`]) – Name of the author (default: as defined in ESA model) * **date** (`Optional`\[`str`]) – Date of the last modification (default: as defined in ESA model) ## MeshSetup[​](/sdk/13/api/external/scia/.md#_MeshSetup "Direct link to MeshSetup") * *class *viktor.external.scia.object.MeshSetup(*\**, *average\_1d=1.0*, *average\_2d=1.0*, *division\_2d\_1d=50*)[¶](#MeshSetup "Permalink to this definition") Bases: `_SciaObject` Mesh settings parameters. * Parameters * **average\_1d** (`float`) – Average size of cables, tendons, elements on subsoil, nonlinear soil spring \[m] (default: 1.0). * **average\_2d** (`float`) – Average size of 2d element/curved element \[m] (default: 1.0). * **division\_2d\_1d** (`int`) – Division for 2D-1D upgrade (default: 50). ## SolverSetup[​](/sdk/13/api/external/scia/.md#_SolverSetup "Direct link to SolverSetup") * *class *viktor.external.scia.object.SolverSetup(*\**, *neglect\_shear\_force\_deformation=None*, *bending\_theory=None*, *solver\_type=None*, *number\_of\_sections=None*, *reinforcement\_coefficient=None*)[¶](#SolverSetup "Permalink to this definition") Bases: `_SciaObject` New in v13.1.0 Solver setup. * Parameters * **neglect\_shear\_force\_deformation** (`Optional`\[`bool`]) – Neglect shear force deformation (default: as defined in ESA model) * **bending\_theory** (`Optional`\[`str`]) – Bending theory of plate/shell analysis (‘mindlin’ | ‘kirchhoff’) (default: as defined in ESA model) * **solver\_type** (`Optional`\[`str`]) – Type of solver (‘direct’ | ‘iterative’) (default: as defined in ESA model) * **number\_of\_sections** (`Optional`\[`float`]) – Number of sections on average member (default: as defined in ESA model) * **reinforcement\_coefficient** (`Optional`\[`float`]) – Coefficient for reinforcement (default: as defined in ESA model) ## Concrete[​](/sdk/13/api/external/scia/.md#_Concrete "Direct link to Concrete") * *class *viktor.external.scia.object.Concrete(*object\_id*, *name*, *part*, *thermal\_expansion=None*, *unit\_mass=None*, *wet\_density=None*, *e\_modulus=None*, *poisson=None*, *g\_modulus=None*, *log\_decrement=None*, *specific\_heat=None*, *thermal\_conductivity=None*, *\**, *fck=None*)[¶](#Concrete "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`update_concrete_material()`](/sdk/13/api/external/scia/.md#Model.update_concrete_material "viktor.external.scia.scia.Model.update_concrete_material") * *class *ECPart(*value*)[¶](#Concrete.ECPart "Permalink to this definition") Bases: `Enum` * **GENERAL** - concrete EN 1992-1-1 * **BRIDGES** - concrete EN 1992-2 - GENERAL*: [ECPart](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")** = 0*[¶](#Concrete.ECPart.GENERAL "Permalink to this definition") * BRIDGES*: [ECPart](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")** = 1*[¶](#Concrete.ECPart.BRIDGES "Permalink to this definition") - *property *ec\_part*: [ECPart](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")*[¶](#Concrete.ec_part "Permalink to this definition") * Return type [`ECPart`](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart") ## FreeLoad[​](/sdk/13/api/external/scia/.md#_FreeLoad "Direct link to FreeLoad") * *class *viktor.external.scia.object.FreeLoad(*object\_id*, *name*, *load\_case*, *direction*, *select*, *validity=None*, *load\_type=None*, *c\_sys=None*)[¶](#FreeLoad "Permalink to this definition") Bases: `_SciaObject`, `ABC` Abstract base class of all free loads. * Do not use this \_\_init\_\_ directly, but create the object by [`create_free_point_load()`](/sdk/13/api/external/scia/.md#Model.create_free_point_load "viktor.external.scia.scia.Model.create_free_point_load"), [`create_free_line_load()`](/sdk/13/api/external/scia/.md#Model.create_free_line_load "viktor.external.scia.scia.Model.create_free_line_load") or [`create_free_surface_load()`](/sdk/13/api/external/scia/.md#Model.create_free_surface_load "viktor.external.scia.scia.Model.create_free_surface_load") - *class *Direction(*value*)[¶](#FreeLoad.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 0*[¶](#FreeLoad.Direction.X "Permalink to this definition") - Y*: [Direction](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 1*[¶](#FreeLoad.Direction.Y "Permalink to this definition") * Z*: [Direction](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 2*[¶](#FreeLoad.Direction.Z "Permalink to this definition") * *class *Select(*value*)[¶](#FreeLoad.Select "Permalink to this definition") Bases: `Enum` An enumeration. * AUTO*: [Select](#FreeLoad.Select "viktor.external.scia.object.FreeLoad.Select")** = 0*[¶](#FreeLoad.Select.AUTO "Permalink to this definition") - SELECT*: [Select](#FreeLoad.Select "viktor.external.scia.object.FreeLoad.Select")** = 1*[¶](#FreeLoad.Select.SELECT "Permalink to this definition") - *class *Type(*value*)[¶](#FreeLoad.Type "Permalink to this definition") Bases: `Enum` An enumeration. * FORCE*: [Type](#FreeLoad.Type "viktor.external.scia.object.FreeLoad.Type")** = 0*[¶](#FreeLoad.Type.FORCE "Permalink to this definition") * *class *Validity(*value*)[¶](#FreeLoad.Validity "Permalink to this definition") Bases: `Enum` An enumeration. * ALL*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 0*[¶](#FreeLoad.Validity.ALL "Permalink to this definition") - NEG\_Z*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 1*[¶](#FreeLoad.Validity.NEG_Z "Permalink to this definition") * POS\_Z*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 2*[¶](#FreeLoad.Validity.POS_Z "Permalink to this definition") - FROM\_TO*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 3*[¶](#FreeLoad.Validity.FROM_TO "Permalink to this definition") * ZERO\_Z*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 4*[¶](#FreeLoad.Validity.ZERO_Z "Permalink to this definition") - NEG\_Z\_INCL\_ZERO*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 5*[¶](#FreeLoad.Validity.NEG_Z_INCL_ZERO "Permalink to this definition") * POS\_Z\_INCL\_ZERO*: [Validity](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 6*[¶](#FreeLoad.Validity.POS_Z_INCL_ZERO "Permalink to this definition") - *class *CSys(*value*)[¶](#FreeLoad.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 0*[¶](#FreeLoad.CSys.GLOBAL "Permalink to this definition") - MEMBER\_LCS*: [CSys](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 1*[¶](#FreeLoad.CSys.MEMBER_LCS "Permalink to this definition") * LOAD\_LCS*: [CSys](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 2*[¶](#FreeLoad.CSys.LOAD_LCS "Permalink to this definition") * *class *Location(*value*)[¶](#FreeLoad.Location "Permalink to this definition") Bases: `Enum` An enumeration. * LENGTH*: [Location](#FreeLoad.Location "viktor.external.scia.object.FreeLoad.Location")** = 0*[¶](#FreeLoad.Location.LENGTH "Permalink to this definition") - PROJECTION*: [Location](#FreeLoad.Location "viktor.external.scia.object.FreeLoad.Location")** = 1*[¶](#FreeLoad.Location.PROJECTION "Permalink to this definition") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#FreeLoad.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## FreeLineLoad[​](/sdk/13/api/external/scia/.md#_FreeLineLoad "Direct link to FreeLineLoad") * *class *viktor.external.scia.object.FreeLineLoad(*object\_id*, *name*, *load\_case*, *point\_1*, *point\_2*, *direction*, *magnitude\_1*, *magnitude\_2*, *distribution=Distribution.TRAPEZOIDAL*, *validity=Validity.ALL*, *load\_type=Type.FORCE*, *select=Select.AUTO*, *system=CSys.GLOBAL*, *location=Location.LENGTH*)[¶](#FreeLineLoad "Permalink to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_line_load()`](/sdk/13/api/external/scia/.md#Model.create_free_line_load "viktor.external.scia.scia.Model.create_free_line_load") * *class *Distribution(*value*)[¶](#FreeLineLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * UNIFORM*: [Distribution](#FreeLineLoad.Distribution "viktor.external.scia.object.FreeLineLoad.Distribution")** = 0*[¶](#FreeLineLoad.Distribution.UNIFORM "Permalink to this definition") - TRAPEZOIDAL*: [Distribution](#FreeLineLoad.Distribution "viktor.external.scia.object.FreeLineLoad.Distribution")** = 1*[¶](#FreeLineLoad.Distribution.TRAPEZOIDAL "Permalink to this definition") ## FreePointLoad[​](/sdk/13/api/external/scia/.md#_FreePointLoad "Direct link to FreePointLoad") * *class *viktor.external.scia.object.FreePointLoad(*object\_id*, *name*, *load\_case*, *direction*, *magnitude*, *position*, *load\_type=Type.FORCE*, *validity=Validity.ALL*, *select=Select.AUTO*, *system=CSys.GLOBAL*)[¶](#FreePointLoad "Permalink to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_point_load()`](/sdk/13/api/external/scia/.md#Model.create_free_point_load "viktor.external.scia.scia.Model.create_free_point_load") ## FreeSurfaceLoad[​](/sdk/13/api/external/scia/.md#_FreeSurfaceLoad "Direct link to FreeSurfaceLoad") * *class *viktor.external.scia.object.FreeSurfaceLoad(*object\_id*, *name*, *load\_case*, *direction*, *q1*, *q2=None*, *q3=None*, *points=None*, *distribution=None*, *load\_type=None*, *validity=None*, *system=None*, *location=None*, *selection=None*)[¶](#FreeSurfaceLoad "Permalink to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_surface_load()`](/sdk/13/api/external/scia/.md#Model.create_free_surface_load "viktor.external.scia.scia.Model.create_free_surface_load") * *class *Distribution(*value*)[¶](#FreeSurfaceLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * UNIFORM*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 0*[¶](#FreeSurfaceLoad.Distribution.UNIFORM "Permalink to this definition") - DIR\_X*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 1*[¶](#FreeSurfaceLoad.Distribution.DIR_X "Permalink to this definition") * DIR\_Y*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 2*[¶](#FreeSurfaceLoad.Distribution.DIR_Y "Permalink to this definition") - POINTS*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 3*[¶](#FreeSurfaceLoad.Distribution.POINTS "Permalink to this definition") - *property *q2*: Optional\[float]*[¶](#FreeSurfaceLoad.q2 "Permalink to this definition") * Return type `Optional`\[`float`] * *property *q3*: Optional\[float]*[¶](#FreeSurfaceLoad.q3 "Permalink to this definition") * Return type `Optional`\[`float`] - *property *points*: Optional\[List\[Tuple\[float, float]]]*[¶](#FreeSurfaceLoad.points "Permalink to this definition") * Return type `Optional`\[`List`\[`Tuple`\[`float`, `float`]]] * *property *distribution*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")*[¶](#FreeSurfaceLoad.distribution "Permalink to this definition") * Return type [`Distribution`](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution") - *property *selection*: Optional\[List\[[Plane](#Plane "viktor.external.scia.object.Plane")]]*[¶](#FreeSurfaceLoad.selection "Permalink to this definition") * Return type `Optional`\[`List`\[[`Plane`](#Plane "viktor.external.scia.object.Plane")]] ## LineLoad[​](/sdk/13/api/external/scia/.md#_LineLoad "Direct link to LineLoad") * *class *viktor.external.scia.object.LineLoad(*object\_id*, *name*, *load\_case*, *beam*, *load\_type*, *distribution*, *load\_start*, *load\_end*, *direction*, *c\_sys*, *position\_start*, *position\_end*, *c\_def*, *origin*, *ey*, *ez*)[¶](#LineLoad "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_line_load()`](/sdk/13/api/external/scia/.md#Model.create_line_load "viktor.external.scia.scia.Model.create_line_load") * *class *CSys(*value*)[¶](#LineLoad.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")** = 0*[¶](#LineLoad.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")** = 1*[¶](#LineLoad.CSys.LOCAL "Permalink to this definition") - *class *CDef(*value*)[¶](#LineLoad.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")** = 0*[¶](#LineLoad.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")** = 1*[¶](#LineLoad.CDef.RELATIVE "Permalink to this definition") * *class *Direction(*value*)[¶](#LineLoad.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 0*[¶](#LineLoad.Direction.X "Permalink to this definition") - Y*: [Direction](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 1*[¶](#LineLoad.Direction.Y "Permalink to this definition") * Z*: [Direction](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 2*[¶](#LineLoad.Direction.Z "Permalink to this definition") - *class *Distribution(*value*)[¶](#LineLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * UNIFORM*: [Distribution](#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")** = 0*[¶](#LineLoad.Distribution.UNIFORM "Permalink to this definition") - TRAPEZOIDAL*: [Distribution](#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")** = 1*[¶](#LineLoad.Distribution.TRAPEZOIDAL "Permalink to this definition") * *class *Origin(*value*)[¶](#LineLoad.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")** = 0*[¶](#LineLoad.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")** = 1*[¶](#LineLoad.Origin.FROM_END "Permalink to this definition") - *class *Type(*value*)[¶](#LineLoad.Type "Permalink to this definition") Bases: `Enum` An enumeration. * FORCE*: [Type](#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")** = 0*[¶](#LineLoad.Type.FORCE "Permalink to this definition") - SELF\_WEIGHT*: [Type](#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")** = 1*[¶](#LineLoad.Type.SELF_WEIGHT "Permalink to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#LineLoad.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#LineLoad.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## LineMomentOnBeam[​](/sdk/13/api/external/scia/.md#_LineMomentOnBeam "Direct link to LineMomentOnBeam") * *class *viktor.external.scia.object.LineMomentOnBeam(*object\_id*, *name*, *beam*, *load\_case*, *m1*, *m2=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineMomentOnBeam "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_line_moment_on_beam()`](/sdk/13/api/external/scia/.md#Model.create_line_moment_on_beam "viktor.external.scia.scia.Model.create_line_moment_on_beam"). * *class *CDef(*value*)[¶](#LineMomentOnBeam.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")** = 0*[¶](#LineMomentOnBeam.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")** = 1*[¶](#LineMomentOnBeam.CDef.RELATIVE "Permalink to this definition") - *class *Direction(*value*)[¶](#LineMomentOnBeam.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 0*[¶](#LineMomentOnBeam.Direction.X "Permalink to this definition") - Y*: [Direction](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 1*[¶](#LineMomentOnBeam.Direction.Y "Permalink to this definition") * Z*: [Direction](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 2*[¶](#LineMomentOnBeam.Direction.Z "Permalink to this definition") * *class *Origin(*value*)[¶](#LineMomentOnBeam.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")** = 0*[¶](#LineMomentOnBeam.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")** = 1*[¶](#LineMomentOnBeam.Origin.FROM_END "Permalink to this definition") ## LineMomentOnPlane[​](/sdk/13/api/external/scia/.md#_LineMomentOnPlane "Direct link to LineMomentOnPlane") * *class *viktor.external.scia.object.LineMomentOnPlane(*object\_id*, *name*, *edge*, *load\_case*, *m1*, *m2=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineMomentOnPlane "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_line_moment_on_plane()`](/sdk/13/api/external/scia/.md#Model.create_line_moment_on_plane "viktor.external.scia.scia.Model.create_line_moment_on_plane"). * *class *CDef(*value*)[¶](#LineMomentOnPlane.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")** = 0*[¶](#LineMomentOnPlane.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")** = 1*[¶](#LineMomentOnPlane.CDef.RELATIVE "Permalink to this definition") - *class *Direction(*value*)[¶](#LineMomentOnPlane.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 0*[¶](#LineMomentOnPlane.Direction.X "Permalink to this definition") - Y*: [Direction](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 1*[¶](#LineMomentOnPlane.Direction.Y "Permalink to this definition") * Z*: [Direction](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 2*[¶](#LineMomentOnPlane.Direction.Z "Permalink to this definition") * *class *Origin(*value*)[¶](#LineMomentOnPlane.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_START*: [Origin](#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")** = 0*[¶](#LineMomentOnPlane.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")** = 1*[¶](#LineMomentOnPlane.Origin.FROM_END "Permalink to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#LineMomentOnPlane.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") ## LineForceSurface[​](/sdk/13/api/external/scia/.md#_LineForceSurface "Direct link to LineForceSurface") * *class *viktor.external.scia.object.LineForceSurface(*object\_id*, *name*, *edge*, *load\_case*, *p1*, *p2=None*, *direction=None*, *location=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[¶](#LineForceSurface "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_line_load_on_plane()`](/sdk/13/api/external/scia/.md#Model.create_line_load_on_plane "viktor.external.scia.scia.Model.create_line_load_on_plane") * *class *CSys(*value*)[¶](#LineForceSurface.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")** = 0*[¶](#LineForceSurface.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")** = 1*[¶](#LineForceSurface.CSys.LOCAL "Permalink to this definition") - *class *Direction(*value*)[¶](#LineForceSurface.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 0*[¶](#LineForceSurface.Direction.X "Permalink to this definition") - Y*: [Direction](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 1*[¶](#LineForceSurface.Direction.Y "Permalink to this definition") * Z*: [Direction](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 2*[¶](#LineForceSurface.Direction.Z "Permalink to this definition") * *class *Distribution(*value*)[¶](#LineForceSurface.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * UNIFORM*: [Distribution](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")** = 0*[¶](#LineForceSurface.Distribution.UNIFORM "Permalink to this definition") - TRAPEZOIDAL*: [Distribution](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")** = 1*[¶](#LineForceSurface.Distribution.TRAPEZOIDAL "Permalink to this definition") - *class *Location(*value*)[¶](#LineForceSurface.Location "Permalink to this definition") Bases: `Enum` An enumeration. * LENGTH*: [Location](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")** = 0*[¶](#LineForceSurface.Location.LENGTH "Permalink to this definition") - PROJECTION*: [Location](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")** = 1*[¶](#LineForceSurface.Location.PROJECTION "Permalink to this definition") * *class *CDef(*value*)[¶](#LineForceSurface.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")** = 0*[¶](#LineForceSurface.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")** = 1*[¶](#LineForceSurface.CDef.RELATIVE "Permalink to this definition") - *class *Origin(*value*)[¶](#LineForceSurface.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_START*: [Origin](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")** = 0*[¶](#LineForceSurface.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")** = 1*[¶](#LineForceSurface.Origin.FROM_END "Permalink to this definition") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#LineForceSurface.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#LineForceSurface.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") * *property *c\_sys*: [CSys](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")*[¶](#LineForceSurface.c_sys "Permalink to this definition") * Return type [`CSys`](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys") - *property *location*: [Location](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")*[¶](#LineForceSurface.location "Permalink to this definition") * Return type [`Location`](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location") * *property *distribution*: [Distribution](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")*[¶](#LineForceSurface.distribution "Permalink to this definition") * Return type [`Distribution`](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution") - *property *c\_def*: [CDef](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")*[¶](#LineForceSurface.c_def "Permalink to this definition") * Return type [`CDef`](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef") * *property *position\_x1*: Optional\[float]*[¶](#LineForceSurface.position_x1 "Permalink to this definition") * Return type `Optional`\[`float`] - *property *position\_x2*: Optional\[float]*[¶](#LineForceSurface.position_x2 "Permalink to this definition") * Return type `Optional`\[`float`] * *property *origin*: [Origin](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")*[¶](#LineForceSurface.origin "Permalink to this definition") * Return type [`Origin`](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin") ## PointLoadNode[​](/sdk/13/api/external/scia/.md#_PointLoadNode "Direct link to PointLoadNode") * *class *viktor.external.scia.object.PointLoadNode(*object\_id*, *name*, *node*, *load\_case*, *load*, *direction=None*, *c\_sys=None*, *angle=None*)[¶](#PointLoadNode "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_point_load_node()`](/sdk/13/api/external/scia/.md#Model.create_point_load_node "viktor.external.scia.scia.Model.create_point_load_node") * *class *CSys(*value*)[¶](#PointLoadNode.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")** = 0*[¶](#PointLoadNode.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")** = 1*[¶](#PointLoadNode.CSys.LOCAL "Permalink to this definition") - *class *Direction(*value*)[¶](#PointLoadNode.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 0*[¶](#PointLoadNode.Direction.X "Permalink to this definition") - Y*: [Direction](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 1*[¶](#PointLoadNode.Direction.Y "Permalink to this definition") * Z*: [Direction](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 2*[¶](#PointLoadNode.Direction.Z "Permalink to this definition") * *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#PointLoadNode.node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#PointLoadNode.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## PointLoad[​](/sdk/13/api/external/scia/.md#_PointLoad "Direct link to PointLoad") * *class *viktor.external.scia.object.PointLoad(*object\_id*, *name*, *load\_case*, *beam*, *direction*, *load\_type*, *load\_value*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *ey=None*, *ez=None*, *\**, *angle=None*)[¶](#PointLoad "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_point_load()`](/sdk/13/api/external/scia/.md#Model.create_point_load "viktor.external.scia.scia.Model.create_point_load") * *class *CSys(*value*)[¶](#PointLoad.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")** = 0*[¶](#PointLoad.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")** = 1*[¶](#PointLoad.CSys.LOCAL "Permalink to this definition") - *class *CDef(*value*)[¶](#PointLoad.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")** = 0*[¶](#PointLoad.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")** = 1*[¶](#PointLoad.CDef.RELATIVE "Permalink to this definition") * *class *Direction(*value*)[¶](#PointLoad.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 0*[¶](#PointLoad.Direction.X "Permalink to this definition") - Y*: [Direction](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 1*[¶](#PointLoad.Direction.Y "Permalink to this definition") * Z*: [Direction](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 2*[¶](#PointLoad.Direction.Z "Permalink to this definition") - *class *Distribution(*value*)[¶](#PointLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * UNIFORM*: [Distribution](#PointLoad.Distribution "viktor.external.scia.object.PointLoad.Distribution")** = 0*[¶](#PointLoad.Distribution.UNIFORM "Permalink to this definition") - TRAPEZOIDAL*: [Distribution](#PointLoad.Distribution "viktor.external.scia.object.PointLoad.Distribution")** = 1*[¶](#PointLoad.Distribution.TRAPEZOIDAL "Permalink to this definition") * *class *Origin(*value*)[¶](#PointLoad.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")** = 0*[¶](#PointLoad.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")** = 1*[¶](#PointLoad.Origin.FROM_END "Permalink to this definition") - *class *Type(*value*)[¶](#PointLoad.Type "Permalink to this definition") Bases: `Enum` An enumeration. * FORCE*: [Type](#PointLoad.Type "viktor.external.scia.object.PointLoad.Type")** = 0*[¶](#PointLoad.Type.FORCE "Permalink to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#PointLoad.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#PointLoad.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## PointMomentNode[​](/sdk/13/api/external/scia/.md#_PointMomentNode "Direct link to PointMomentNode") * *class *viktor.external.scia.object.PointMomentNode(*object\_id*, *name*, *node*, *load\_case*, *load*, *direction*, *c\_sys*)[¶](#PointMomentNode "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_point_moment_node()`](/sdk/13/api/external/scia/.md#Model.create_point_moment_node "viktor.external.scia.scia.Model.create_point_moment_node"). * *class *CSys(*value*)[¶](#PointMomentNode.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")** = 0*[¶](#PointMomentNode.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")** = 1*[¶](#PointMomentNode.CSys.LOCAL "Permalink to this definition") - *class *Direction(*value*)[¶](#PointMomentNode.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 0*[¶](#PointMomentNode.Direction.X "Permalink to this definition") - Y*: [Direction](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 1*[¶](#PointMomentNode.Direction.Y "Permalink to this definition") * Z*: [Direction](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 2*[¶](#PointMomentNode.Direction.Z "Permalink to this definition") * *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[¶](#PointMomentNode.node "Permalink to this definition") * Return type [`Node`](#Node "viktor.external.scia.object.Node") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#PointMomentNode.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## SurfaceLoad[​](/sdk/13/api/external/scia/.md#_SurfaceLoad "Direct link to SurfaceLoad") * *class *viktor.external.scia.object.SurfaceLoad(*object\_id*, *name*, *load\_case*, *plane*, *direction*, *load\_type*, *load\_value*, *c\_sys*, *location*)[¶](#SurfaceLoad "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_surface_load()`](/sdk/13/api/external/scia/.md#Model.create_surface_load "viktor.external.scia.scia.Model.create_surface_load") * *class *Direction(*value*)[¶](#SurfaceLoad.Direction "Permalink to this definition") Bases: `Enum` An enumeration. * X*: [Direction](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 0*[¶](#SurfaceLoad.Direction.X "Permalink to this definition") - Y*: [Direction](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 1*[¶](#SurfaceLoad.Direction.Y "Permalink to this definition") * Z*: [Direction](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 2*[¶](#SurfaceLoad.Direction.Z "Permalink to this definition") - *class *Type(*value*)[¶](#SurfaceLoad.Type "Permalink to this definition") Bases: `Enum` An enumeration. * FORCE*: [Type](#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")** = 0*[¶](#SurfaceLoad.Type.FORCE "Permalink to this definition") - SELF\_WEIGHT*: [Type](#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")** = 1*[¶](#SurfaceLoad.Type.SELF_WEIGHT "Permalink to this definition") * *class *CSys(*value*)[¶](#SurfaceLoad.CSys "Permalink to this definition") Bases: `Enum` An enumeration. * GLOBAL*: [CSys](#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")** = 0*[¶](#SurfaceLoad.CSys.GLOBAL "Permalink to this definition") - LOCAL*: [CSys](#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")** = 1*[¶](#SurfaceLoad.CSys.LOCAL "Permalink to this definition") - *class *Location(*value*)[¶](#SurfaceLoad.Location "Permalink to this definition") Bases: `Enum` An enumeration. * LENGTH*: [Location](#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")** = 0*[¶](#SurfaceLoad.Location.LENGTH "Permalink to this definition") - PROJECTION*: [Location](#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")** = 1*[¶](#SurfaceLoad.Location.PROJECTION "Permalink to this definition") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[¶](#SurfaceLoad.plane "Permalink to this definition") * Return type [`Plane`](#Plane "viktor.external.scia.object.Plane") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#SurfaceLoad.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## ThermalLoad[​](/sdk/13/api/external/scia/.md#_ThermalLoad "Direct link to ThermalLoad") * *class *viktor.external.scia.object.ThermalLoad(*object\_id*, *name*, *load\_case*, *beam*, *distribution*, *delta*, *left\_delta*, *right\_delta*, *top\_delta*, *bottom\_delta*, *position\_start*, *position\_end*, *c\_def*, *origin*)[¶](#ThermalLoad "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_thermal_load()`](/sdk/13/api/external/scia/.md#Model.create_thermal_load "viktor.external.scia.scia.Model.create_thermal_load") * *class *Distribution(*value*)[¶](#ThermalLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * CONSTANT*: [Distribution](#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")** = 0*[¶](#ThermalLoad.Distribution.CONSTANT "Permalink to this definition") - LINEAR*: [Distribution](#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")** = 1*[¶](#ThermalLoad.Distribution.LINEAR "Permalink to this definition") - *class *CDef(*value*)[¶](#ThermalLoad.CDef "Permalink to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [CDef](#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")** = 0*[¶](#ThermalLoad.CDef.ABSOLUTE "Permalink to this definition") * RELATIVE*: [CDef](#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")** = 1*[¶](#ThermalLoad.CDef.RELATIVE "Permalink to this definition") * *class *Origin(*value*)[¶](#ThermalLoad.Origin "Permalink to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_START*: [Origin](#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")** = 0*[¶](#ThermalLoad.Origin.FROM_START "Permalink to this definition") * FROM\_END*: [Origin](#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")** = 1*[¶](#ThermalLoad.Origin.FROM_END "Permalink to this definition") - *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[¶](#ThermalLoad.beam "Permalink to this definition") * Return type [`Beam`](#Beam "viktor.external.scia.object.Beam") * *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[¶](#ThermalLoad.load_case "Permalink to this definition") * Return type [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") ## ThermalSurfaceLoad[​](/sdk/13/api/external/scia/.md#_ThermalSurfaceLoad "Direct link to ThermalSurfaceLoad") * *class *viktor.external.scia.object.ThermalSurfaceLoad(*object\_id*, *name*, *load\_case*, *plane*, *delta=None*, *top\_delta=None*, *bottom\_delta=None*)[¶](#ThermalSurfaceLoad "Permalink to this definition") Bases: `_SciaObject` Do not use this \_\_init\_\_ directly, but create the object by [`create_thermal_surface_load()`](/sdk/13/api/external/scia/.md#Model.create_thermal_surface_load "viktor.external.scia.scia.Model.create_thermal_surface_load") * *class *Distribution(*value*)[¶](#ThermalSurfaceLoad.Distribution "Permalink to this definition") Bases: `Enum` An enumeration. * CONSTANT*: [Distribution](#ThermalSurfaceLoad.Distribution "viktor.external.scia.object.ThermalSurfaceLoad.Distribution")** = 0*[¶](#ThermalSurfaceLoad.Distribution.CONSTANT "Permalink to this definition") - LINEAR*: [Distribution](#ThermalSurfaceLoad.Distribution "viktor.external.scia.object.ThermalSurfaceLoad.Distribution")** = 1*[¶](#ThermalSurfaceLoad.Distribution.LINEAR "Permalink to this definition") --- # viktor.external.spreadsheet ## NamedInputCell[​](/sdk/13/api/external/spreadsheet/.md#_NamedInputCell "Direct link to NamedInputCell") * *class *viktor.external.spreadsheet.NamedInputCell(*name*, *value*)[¶](#NamedInputCell "Permalink to this definition") Bases: `_NamedCellBaseClass` Class for defining a named cell in which a value must be inserted. * Parameters * **name** (`str`) – name of the cell. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. - serialize(*convert\_value\_to\_str=False*)[¶](#NamedInputCell.serialize "Permalink to this definition") * Parameters **convert\_value\_to\_str** (`bool`) – convert value to str. Necessary when NamedInputCell is used in coupled Excel program (only old workers). * Return type `dict` * serialize\_for\_fill\_spreadsheet()[¶](#NamedInputCell.serialize_for_fill_spreadsheet "Permalink to this definition") * Return type `dict` ## SpreadsheetCalculationInput[​](/sdk/13/api/external/spreadsheet/.md#_SpreadsheetCalculationInput "Direct link to SpreadsheetCalculationInput") * *class *viktor.external.spreadsheet.SpreadsheetCalculationInput(*name*, *value*)[¶](#SpreadsheetCalculationInput "Permalink to this definition") Bases: [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell") This class is subclassed from NamedInputCell because the same functionality is needed. * Parameters * **name** (`str`) – name of the cell. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. ## NamedOutputCell[​](/sdk/13/api/external/spreadsheet/.md#_NamedOutputCell "Direct link to NamedOutputCell") * *class *viktor.external.spreadsheet.NamedOutputCell(*name*)[¶](#NamedOutputCell "Permalink to this definition") Bases: `_NamedCellBaseClass` Class for defining named cells of which the output is desired. Example usage: ``` named_cell = NamedOutputCell('my_name') excel = Excel(template, named_output_cells=[named_cell]) excel.execute() my_desired_value = named_cell.result ``` * *property *result*: Any*[¶](#NamedOutputCell.result "Permalink to this definition") Property that returns the result of this cell. May be called after Excel has been executed. * Return type `Any` * Returns the result of this cell after excel execution - equals(*named\_cell\_result*)[¶](#NamedOutputCell.equals "Permalink to this definition") * Return type `bool` * serialize()[¶](#NamedOutputCell.serialize "Permalink to this definition") * Return type `dict` ## DirectInputCell[​](/sdk/13/api/external/spreadsheet/.md#_DirectInputCell "Direct link to DirectInputCell") * *class *viktor.external.spreadsheet.DirectInputCell(*sheet\_name*, *column*, *row*, *value*)[¶](#DirectInputCell "Permalink to this definition") Bases: `_DirectCellBaseClass` Class for defining a direct cell in which a value must be inserted If a rectangular block of data has to be inserted, use [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange") for more efficiency. * Parameters * **sheet\_name** (`str`) – name of the sheet in which the cell is present. * **column** (`str`) – target column. * **row** (`int`) – target row. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. - serialize(*convert\_value\_to\_str=False*)[¶](#DirectInputCell.serialize "Permalink to this definition") * Parameters **convert\_value\_to\_str** (`bool`) – convert value to str. Necessary when DirectInputCell is used in coupled Excel program (only old workers). * Return type `dict` ## DirectOutputCell[​](/sdk/13/api/external/spreadsheet/.md#_DirectOutputCell "Direct link to DirectOutputCell") * *class *viktor.external.spreadsheet.DirectOutputCell(*sheet\_name*, *column*, *row*)[¶](#DirectOutputCell "Permalink to this definition") Bases: `_DirectCellBaseClass` Class for defining a direct cell of which an output is desired. Example usage: ``` direct_cell = DirectOutputCell('sheet_name', 'G', 3) excel = Excel(template, direct_output_cells=[direct_cell]) excel.execute() my_desired_value = direct_cell.result ``` * *property *result*: Any*[¶](#DirectOutputCell.result "Permalink to this definition") * Return type `Any` - equals(*direct\_cell\_result*)[¶](#DirectOutputCell.equals "Permalink to this definition") * Return type `bool` * serialize()[¶](#DirectOutputCell.serialize "Permalink to this definition") * Return type `dict` ## InputCellRange[​](/sdk/13/api/external/spreadsheet/.md#_InputCellRange "Direct link to InputCellRange") * *class *viktor.external.spreadsheet.InputCellRange(*sheet\_name*, *left\_column*, *top\_row*, *data*)[¶](#InputCellRange "Permalink to this definition") Convenience object to define a range of cells in row- and/or column direction. For single cells, use [`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell") Example: ``` data = [ [1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], ] cell_range = InputCellRange('Sheet1', left_column='B', top_row=3, data=data) ``` This produces the following sheet: > | | | | | | | > | - | - | - | - | - | - | > | | A | B | C | D | E | > | 1 | | | | | | > | 2 | | | | | | > | 3 | | 1 | 2 | 3 | | > | 4 | | 4 | 5 | 6 | | > | 5 | | a | b | c | | > | 6 | | | | | | * Parameters * **sheet\_name** (`str`) – name of the sheet in which the data is inserted * **left\_column** (`str`) – column letter of the top left target of the data * **top\_row** (`int`) – row number of the top left target of the data * **data** (`List`\[`List`\[`Union`\[`float`, `str`]]]) – content which is filled in the cell range. the nested list structure should be rectangular (each list should have the same length) and not empty. - serialize()[¶](#InputCellRange.serialize "Permalink to this definition") * Return type `dict` ## stringify\_value[​](/sdk/13/api/external/spreadsheet/.md#_stringify_value "Direct link to stringify_value") * viktor.external.spreadsheet.stringify\_value(*value*)[¶](#stringify_value "Permalink to this definition") Function that will create the correct string representation of python data types, in order for ‘value’ to be inserted in Excel correctly. * Parameters **value** (`Union`\[`bool`, `int`, `str`, `float`]) – the value to be stringified. * Return type `str` * Returns a string representation of value. ## SpreadsheetResult[​](/sdk/13/api/external/spreadsheet/.md#_SpreadsheetResult "Direct link to SpreadsheetResult") * *class *viktor.external.spreadsheet.SpreadsheetResult(*\**, *values=None*, *file\_content=None*)[¶](#SpreadsheetResult "Permalink to this definition") Wrapper around results obtained from spreadsheet services * *property *values*: dict*[¶](#SpreadsheetResult.values "Permalink to this definition") * Return type `dict` - *property *file\_content*: bytes*[¶](#SpreadsheetResult.file_content "Permalink to this definition") * Return type `bytes` * get\_value(*name*)[¶](#SpreadsheetResult.get_value "Permalink to this definition") * Return type `Any` ## SpreadsheetCalculation[​](/sdk/13/api/external/spreadsheet/.md#_SpreadsheetCalculation "Direct link to SpreadsheetCalculation") * *class *viktor.external.spreadsheet.SpreadsheetCalculation(*file*, *inputs*)[¶](#SpreadsheetCalculation "Permalink to this definition") Using a spreadsheet for calculations, inserting inputs and reading outputs. This spreadsheet should not contain macros. See the excel module for spreadsheet calculations with macros. Example usage: ``` inputs = [ SpreadsheetCalculationInput('x', 1), SpreadsheetCalculationInput('y', 2), ] spreadsheet = SpreadsheetCalculation(spreadsheet, inputs) result = spreadsheet.evaluate(include_filled_file=False) values = result.values ``` * Parameters **file** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – spreadsheet file - *classmethod *from\_path(*file\_path*, *inputs*)[¶](#SpreadsheetCalculation.from_path "Permalink to this definition") * Parameters * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **inputs** (`List`\[[`SpreadsheetCalculationInput`](#SpreadsheetCalculationInput "viktor.external.spreadsheet.SpreadsheetCalculationInput")]) – * Return type [`SpreadsheetCalculation`](#SpreadsheetCalculation "viktor.external.spreadsheet.SpreadsheetCalculation") * evaluate(*include\_filled\_file=False*)[¶](#SpreadsheetCalculation.evaluate "Permalink to this definition") This function enters the values provided into the input tab of the sheet. The sheet evaluates the input and returns a dictionary containing key value pairs of the result parameters Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **include\_filled\_file** (`bool`) – when True, the SpreadsheetResult will contain the filled in spreadsheet. * Return type [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") - *property *result*: [SpreadsheetResult](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult")*[¶](#SpreadsheetCalculation.result "Permalink to this definition") * Return type [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") ## SpreadsheetTemplate[​](/sdk/13/api/external/spreadsheet/.md#_SpreadsheetTemplate "Direct link to SpreadsheetTemplate") * *class *viktor.external.spreadsheet.SpreadsheetTemplate(*file*, *input\_cells*)[¶](#SpreadsheetTemplate "Permalink to this definition") Note Prefer to use the function [`render_spreadsheet()`](#render_spreadsheet "viktor.external.spreadsheet.render_spreadsheet") instead. Fill spreadsheet with values/text. This can be done both with direct cells (e.g. A2), or named cells. Example usage: ``` cells = [ DirectInputCell('sheet1', 'A', 1, 5), NamedInputCell('named_cell_1', 'text_to_be_placed'), ] template = SpreadsheetTemplate(template, cells) result = template.render() filled_template = result.file_content ``` * Parameters * **file** (`BytesIO`) – BytesIO object of the spreadsheet * **input\_cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – The cells to fill the file with. - *classmethod *from\_path(*file\_path*, *input\_cells*)[¶](#SpreadsheetTemplate.from_path "Permalink to this definition") * Parameters * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **input\_cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – The cells to fill the file with * Return type [`SpreadsheetTemplate`](#SpreadsheetTemplate "viktor.external.spreadsheet.SpreadsheetTemplate") * render()[¶](#SpreadsheetTemplate.render "Permalink to this definition") This function renders the SpreadsheetTemplate with cells. It returns a SpreadsheetResult object of the filled template. * Return type [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") * Returns a SpreadsheetResult object containing the filled template - *property *result*: [SpreadsheetResult](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult")*[¶](#SpreadsheetTemplate.result "Permalink to this definition") * Return type [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") ## render\_spreadsheet[​](/sdk/13/api/external/spreadsheet/.md#_render_spreadsheet "Direct link to render_spreadsheet") * viktor.external.spreadsheet.render\_spreadsheet(*template*, *cells*)[¶](#render_spreadsheet "Permalink to this definition") Fill spreadsheet with values/text. This can be done both with direct cells (e.g. A2), or named cells. Example usage: ``` cells = [ DirectInputCell('sheet1', 'A', 1, 5), NamedInputCell('named_cell_1', 'text_to_be_placed'), ] template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.xlsx' with open(template_path, 'rb') as template: filled_spreadsheet = render_spreadsheet(template, cells) ``` * Parameters * **template** (`BinaryIO`) – spreadsheet template file * **cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – cells to fill the template with * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing the rendered spreadsheet --- # viktor.external.tekla Added in v14.17.0 --- # viktor.external.word ## WordFileComponent[​](/sdk/13/api/external/word/.md#_WordFileComponent "Direct link to WordFileComponent") * *class *viktor.external.word.WordFileComponent(*identifier*)[¶](#WordFileComponent "Permalink to this definition") Bases: `ABC` Abstract base class for specific word file components, such as tags, images… ## WordFileTag[​](/sdk/13/api/external/word/.md#_WordFileTag "Direct link to WordFileTag") * *class *viktor.external.word.WordFileTag(*identifier*, *value*)[¶](#WordFileTag "Permalink to this definition") Bases: [`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent") Add a value in a Word file template by tag. * Parameters * **identifier** (`str`) – used to find the location in the template * **value** (`object`) – what needs to be placed at tag location ## WordFileImage[​](/sdk/13/api/external/word/.md#_WordFileImage "Direct link to WordFileImage") * *class *viktor.external.word.WordFileImage(*file*, *identifier*, *width=None*, *height=None*)[¶](#WordFileImage "Permalink to this definition") Bases: [`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent") Add an image in a Word file template. When neither width or height is provided, the original size is used. When only one is provided, the other is scaled. When both are provided, both are used and the original aspect ratio might be changed. * Parameters * **file** (`BinaryIO`) – image to be placed at the tag location * **identifier** (`str`) – used to find the location in the template * **width** (`Optional`\[`int`]) – optional parameter for sizing. in Pt * **height** (`Optional`\[`int`]) – optional parameter for sizing. in Pt - *classmethod *from\_path(*file\_path*, *identifier*, *width=None*, *height=None*)[¶](#WordFileImage.from_path "Permalink to this definition") Create a WordFileImage from an image defined by its file path. * Return type [`WordFileImage`](#WordFileImage "viktor.external.word.WordFileImage") ## WordFileResult[​](/sdk/13/api/external/word/.md#_WordFileResult "Direct link to WordFileResult") * *class *viktor.external.word.WordFileResult(*\**, *file\_content=None*)[¶](#WordFileResult "Permalink to this definition") * *property *file\_content*: bytes*[¶](#WordFileResult.file_content "Permalink to this definition") * Return type `bytes` ## WordFileTemplate[​](/sdk/13/api/external/word/.md#_WordFileTemplate "Direct link to WordFileTemplate") * *class *viktor.external.word.WordFileTemplate(*file*, *components*)[¶](#WordFileTemplate "Permalink to this definition") Note Prefer to use the function [`render_word_file()`](#render_word_file "viktor.external.word.render_word_file") instead. Fill wordfile template with components (e.g. text, image). Note that the template file should be a BytesIO object of a .docx file (not .doc). Example usage: ``` >>> file = BytesIO(b'file') >>> image = BytesIO(b'image') >>> >>> tags = [ >>> WordFileTag('x', 1), >>> WordFileTag('y', 2), >>> WordFileImage(image, 'fig_tag', width=300), >>> ] >>> word_file_template = WordFileTemplate(file, tags) >>> result = word_file_template.render() >>> word_file = result.file_content ``` * Parameters * **file** (`BytesIO`) – BytesIO object of the Word template * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – items that need to be inserted in the template - *classmethod *from\_path(*file\_path*, *components*)[¶](#WordFileTemplate.from_path "Permalink to this definition") * Parameters * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – items that need to be inserted in the template * Return type [`WordFileTemplate`](#WordFileTemplate "viktor.external.word.WordFileTemplate") * render()[¶](#WordFileTemplate.render "Permalink to this definition") This function renders the docx template and returns the resulting file. Note This method needs to be mocked in (automated) unit and integration tests. * Return type [`WordFileResult`](#WordFileResult "viktor.external.word.WordFileResult") - *property *result*: [WordFileResult](#WordFileResult "viktor.external.word.WordFileResult")*[¶](#WordFileTemplate.result "Permalink to this definition") * Return type [`WordFileResult`](#WordFileResult "viktor.external.word.WordFileResult") ## render\_word\_file[​](/sdk/13/api/external/word/.md#_render_word_file "Direct link to render_word_file") * viktor.external.word.render\_word\_file(*template*, *components*)[¶](#render_word_file "Permalink to this definition") Fill Word file with components (e.g. text, image). Example usage: ``` components = [ WordFileTag('x', 1), WordFileImage(image, 'fig_tag', width=300), ] template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.docx' with open(template_path, 'rb') as template: word_file = render_word_file(template, components) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **template** (`BinaryIO`) – Word file template of type .docx (not .doc) * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – components to fill the template with * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing the rendered Word file * Raises [`viktor.errors.WordFileError`](/sdk/13/api/errors/.md#WordFileError "viktor.errors.WordFileError") when rendering fails --- # viktor.geo ## RobertsonMethod[​](/sdk/13/api/geo/.md#_RobertsonMethod "Direct link to RobertsonMethod") * *class *viktor.geo.RobertsonMethod(*soil\_properties*)[¶](#RobertsonMethod "Permalink to this definition") Bases: `_ClassificationMethod` Class to pass Robertson specific properties such as soil\_properties. Every list element at least requires a ‘name’ key that specifies the RobertsonZone. It is important that ‘name’ key matches with hardcoded RobertsonZone.name property. There are 9 Robertson zones and 1 Robertson zone unknown that can be specified By default, the colors as defined in (red, green, blue) for each zone are as shown in this figure: [![/\_images/robertson\_colors.png](/_images/robertson_colors.png)](/_images/robertson_colors.png) Example: ``` soil_properties = [ {'name': 'Robertson zone unknown', 'extra_property1': 1, 'extra_property2': 2}, {'name': 'Robertson zone 1', 'extra_property1': 3, 'extra_property2': 4}, ] method = RobertsonMethod(soil_properties) ``` * Parameters **soil\_properties** (`List`\[`dict`]) – dictionary with soil properties - get\_method\_params()[¶](#RobertsonMethod.get_method_params "Permalink to this definition") * Return type `dict` ## TableMethod[​](/sdk/13/api/geo/.md#_TableMethod "Direct link to TableMethod") * *class *viktor.geo.TableMethod(*qualification\_table*, *ground\_water\_level*)[¶](#TableMethod "Permalink to this definition") Bases: `_ClassificationMethod` Class to pass TableMethod specific properties, such as a qualification\_table and ground\_water\_level. The qualification\_table is a list of dictionaries, containing for each user-specified soil type the accompanying qualification parameters (and possibly additional material properties). The required fields for each row are: > * name > > * color in r, g, b Also required fields, but can also be (partly) empty: > * qc\_min > > * qc\_max > > * qc\_norm\_min > > * qc\_norm\_max > > * rf\_min > > * rf\_max > > * gamma\_dry\_min > > * gamma\_dry\_max > > * gamma\_wet\_min > > * gamma\_wet\_max For more information about qc\_norm (qc\_normalized), see table 2.b in in NEN 9997-1+C1:2012, point g specifically. Besides the qualification table, a ground\_water\_level has to be provided as well, which is used to determine if gamma\_dry or gamma\_wet should be used to calculate qc\_norm for each entry in the GEF file. Example: ``` qualification_table = [ {'name': 'Peat', 'color': '166,42,42', 'qc_min': 0, 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 8, 'rf_max': '', 'gamma_dry_min': 10, 'gamma_wet_min': 10, }, {'name': 'Clay', 'color': '125,180,116', 'qc_min': '', 'qc_max': 2, 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 1, 'rf_max': 8, 'gamma_dry_min': 20, 'gamma_wet_min': 22, }, {'name': 'Loam', 'color': '125,150,116', 'qc_min': 2, 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 1, 'rf_max': 8, 'gamma_dry_min': 20, 'gamma_wet_min': 22, }, {'name': 'Sand', 'color': '239,255,12', 'qc_min': '', 'qc_max': '', 'qc_norm_min': 22, 'qc_norm_max': '', 'rf_min': 0, 'rf_max': 1, 'gamma_dry_min': 24, 'gamma_wet_min': 26, }, {'name': 'Gravel', 'color': '255,255,128', 'qc_min': '', 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': 22, 'rf_min': 0, 'rf_max': 1, 'gamma_dry_min': 24, 'gamma_wet_min': 26, } ] ground_water_level = -4.63 method = TableMethod(qualification_table, ground_water_level) ``` * Parameters * **ground\_water\_level** (`float`) – Ground water level is used to compute qc\_norm using either gamma\_dry or gamma\_wet * **qualification\_table** (`List`\[`dict`]) – List containing rows defining a soil - get\_qualification\_table\_plot(*fileformat*)[¶](#TableMethod.get_qualification_table_plot "Permalink to this definition") Use this method to obtain a plot of the qualification table. On the x axis the Rf values are plotted, on the y axis Qc values are shown. Each line, representing a soil, is shown as an area in this plot. This allows for easy inspection of the qualification rules, showing areas of the plot that might still be empty, or soil areas that overlap (in which case the area on top will be chosen). Use the fileformat argument to specify if the result should be a BytesIO containing pdf or png bytes or a StringIO containing svg data * Parameters **fileformat** (`str`) – specify if required fileformat is pdf, png or svg * Return type `Union`\[`BytesIO`, `StringIO`] * Returns qualification table plot as either BytesIO (‘pdf’ or ‘png’) or StringIO (‘svg’) object * get\_method\_params()[¶](#TableMethod.get_method_params "Permalink to this definition") * Return type `dict` ## NormalizedSoilBehaviourTypeIndexMethod[​](/sdk/13/api/geo/.md#_NormalizedSoilBehaviourTypeIndexMethod "Direct link to NormalizedSoilBehaviourTypeIndexMethod") * *class *viktor.geo.NormalizedSoilBehaviourTypeIndexMethod(*ic\_table*, *ground\_water\_level*, *specific\_weight\_soil*, *resolution=None*)[¶](#NormalizedSoilBehaviourTypeIndexMethod "Permalink to this definition") Bases: `_ClassificationMethod` Class to classify soil based on the normalized soil behaviour type index Example: ``` ic_table = [ {'name': 'Sand', 'color': '0, 50, 255', 'ic_min': 0, 'ic_max': 3.5}, {'name': 'Clay', 'color': '80, 70, 25', 'ic_min': 3.5, 'cone_factor': 20}, ] ground_water_level = 0 specific_weight_soil = 17 method = NormalizedSoilBehaviourTypeIndexMethod(ic_table, ground_water_level, specific_weight_soil) ``` This method uses the assumption that the specific weight of all the soil layers is the same, this is a simplification. It is possible to calculate the specific weight from qc values. * Parameters * **ic\_table** (`List`\[`dict`]) – Table with soil types that correspond to Ic values. Keys: name, ic\_min, ic\_max, color, cone\_factor * **ground\_water\_level** (`float`) – Ground water level used to compute qc\_norm * **specific\_weight\_soil** (`float`) – Specific weight of soil in kN/m^3 used to calculate sigma’ * **resolution** (`Optional`\[`float`]) – Resolution of the classification in m; if None classify each line of data - get\_method\_params()[¶](#NormalizedSoilBehaviourTypeIndexMethod.get_method_params "Permalink to this definition") * Return type `dict` ## GEFData[​](/sdk/13/api/geo/.md#_GEFData "Direct link to GEFData") * *class *viktor.geo.GEFData(*gef\_dict*)[¶](#GEFData "Permalink to this definition") Initialize GEFData object to simplify working with GEF data. Every GEF has different header fields, and therefore only a limited amount of fields is compulsory. All other header fields are also added as attribute. Compulsory header fields are: > * name > > * ground\_level\_wrt\_reference Other header fields might be compulsory for methods on the object (e.g. get\_cone\_visualization). See docstring of the specific method for needed headers. The following measurement\_data fields are also compulsory and are implicitly parsed from the file (do NOT need to be specified explicitly): > * elevation > > * qc > > * Rf Examples of optional attributes from header are: > * height\_system > > * project\_name > > * project\_id > > * gef\_file\_date > > * gef\_version\_number > > * x\_y\_coordinates > > * coordinate\_system > > * excavation\_depth > > * measurement\_standard > > * surface\_area\_quotient\_tip > > * water\_level > > * cone\_tip\_area > > * cone\_type Measurement\_data fields that are optional are: > * u2 > > * fs > > * penetration\_length > > * corrected\_depth > > * inclination > > * inclination\_n\_s > > * inclination\_e\_w Example implementation to create GEFData object: ``` from viktor.core import ViktorController, ParamsFromFile from viktor.geo import GEFFile, GEFData class GEFFileController(ViktorController): ... @ParamsFromFile(file_types=['.gef']) def process_file(self, file, **kwargs) -> dict: file_content = file.getvalue(encoding="ISO-8859-1") gef_file = GEFFile(file_content) gef_data_object = gef_file.parse(additional_columns=['elevation', 'qc', 'Rf', 'fs', 'u2'], return_gef_data_obj=True) gef_dict = gef_data_object.serialize() return {'gef_dict': gef_dict} def get_gef_content_from_database(self) -> GEFData: # API call to right entity return GEFData(gef_file_entity.last_saved_params['gef_dict']) ``` * Parameters **gef\_dict** (`Union`\[`dict`, `Munch`]) – dictionary with \[‘headers’] and \[‘measurement\_data’] keys - classify(*method*, *return\_soil\_layout\_obj=True*)[¶](#GEFData.classify "Permalink to this definition") Create SoilLayout object or dictionary by classifying the GEF measurement data, using either the Robertson method or a qualification table method. **RobertsonMethod** This method requires the GEFData object to at least contain the measurement data ‘corrected\_depth’. See [`GEFData`](#GEFData "viktor.geo.GEFData") for all possible measurement data columns. ``` from viktor.geo import RobertsonMethod soil_properties = [ {'name': 'Robertson zone unknown', 'extra_property1': 1, 'extra_property2': 2}, {'name': 'Robertson zone 1', 'extra_property1': 3, 'extra_property2': 4}, ] classification_method = RobertsonMethod(soil_properties) soil_layout_dict = gef_data.classify(method=classification_method, return_soil_layout_obj=False) ``` **TableMethod** For this method a qualification table has to be provided by the user, for example through a VIKTOR editor. Please refer to the docstring of [`TableMethod`](#TableMethod "viktor.geo.TableMethod") for the structure of this table. This table is usually controlled on a project-wide level, so in a parent entity. On the controller of the GEF file, you can use the API to retrieve the table content and pass it to the TableMethod: ``` from viktor.api_v1 import API api = API() parent_entity = api.get_entity(entity_id).parent() parent_params = parent.last_saved_params qualification_table = parent_params['material_properties'] ground_water_level = parent_params['ground_water_level'] classification_method = TableMethod(qualification_table, ground_water_level) soil_layout_obj = gef_data.classify(method=classification_method, return_soil_layout_obj=False) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **method** (`_ClassificationMethod`) – Specifies which method should be used for qualification: TableMethod | RobertsonMethod | NormalizedSoilBehaviourTypeIndexMethod. * **return\_soil\_layout\_obj** (`bool`) – Flag to return SoilLayout object or dictionary * Return type `Union`\[`dict`, [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")] * Returns SoilLayout object or dictionary (=SoilLayout.serialize()) * serialize()[¶](#GEFData.serialize "Permalink to this definition") * Return type `Union`\[`dict`, `Munch`] - get\_cone\_visualization(*axes*)[¶](#GEFData.get_cone_visualization "Permalink to this definition") Modify (clean/empty) ‘axes’ input argument to plot cone resistance (with pore pressure if present in GEF data). * Parameters **axes** (`Axes`) – Axes object that will be modified. The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference > > * ground\_level\_wrt\_reference > > * height\_system Example usage: ``` import matplotlib.pyplot as plt # Create main figure fig = plt.figure(figsize=(8.27, 11.69)) # Define contour (rectangle) for cone visualization, and create Axes object that can be modified by # functions rect_cone = [0.1, 0.1, 0.4, 0.9] # [left, bottom, width, height] cone_axes = plt.axes(rect_cone) # Modify created Axes objects self.gef_data.get_cone_visualization(cone_axes) # Convert to SVG for visualization svg_data = StringIO() fig.savefig(svg_data, format='svg', bbox_inches='tight', pad_inches=0.8) plt.close() gef_visualisation_data = svg_data.getvalue() ``` * Return type `None` * get\_resistance\_visualization(*axes*)[¶](#GEFData.get_resistance_visualization "Permalink to this definition") Modify (clean/empty) ‘axes’ input argument to plot resistance number. * Parameters **axes** (`Axes`) – Axes object that will be modified. The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference > > * ground\_level\_wrt\_reference Example usage: ``` import matplotlib.pyplot as plt # Create main figure fig = plt.figure(figsize=(8.27, 11.69)) # Define contour (rectangle) for resistance number visualization, and create Axes object that can be # modified by functions rect_resistance = [0.1, 0.1, 0.4, 0.9] # [left, bottom, width, height] resistance_axes = plt.axes(rect_resistance) # Modify created Axes objects self.gef_data.get_resistance_visualization(resistance_axes) # Convert to SVG for visualization svg_data = StringIO() fig.savefig(svg_data, format='svg', bbox_inches='tight', pad_inches=0.8) plt.close() gef_visualisation_data = svg_data.getvalue() ``` * Return type `None` - get\_plotted\_denotation\_large\_qc\_values(*axes*, *x\_loc\_text*)[¶](#GEFData.get_plotted_denotation_large_qc_values "Permalink to this definition") Can be used to add text labels with the maximum qc value of a layer that exceeds the maximum value of the x-axis. * Parameters * **axes** (`Axes`) – Axes object that will be modified. * **x\_loc\_text** (`float`) – Maximum qc value. The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference An example is shown below where the figure is capped at a maximum qc of 30 MPa (hence x\_loc\_text=30). [![/\_images/gefdata\_plot\_large\_qc.svg](/_images/gefdata_plot_large_qc.svg)](/_images/gefdata_plot_large_qc.svg) * Return type `None` ## GEFFile[​](/sdk/13/api/geo/.md#_GEFFile "Direct link to GEFFile") * *class *viktor.geo.GEFFile(*file\_content*)[¶](#GEFFile "Permalink to this definition") * *classmethod *from\_file(*file\_path*, *encoding='ISO-8859-1'*)[¶](#GEFFile.from_file "Permalink to this definition") * Return type [`GEFFile`](#GEFFile "viktor.geo.GEFFile") - parse(*additional\_columns=None*, *verbose=True*, *return\_gef\_data\_obj=True*)[¶](#GEFFile.parse "Permalink to this definition") Parse GEFFile, and return information from GEF in dict with \[‘headers’] and \[‘measurement data’] sub-dicts or a GEFData object. Example implementation: ``` from viktor.core import ViktorController, ParamsFromFile from viktor.geo import GEFFile, GEFData class GEFFileController(ViktorController): ... @ParamsFromFile(file_types=['.gef']) def process_file(self, file, **kwargs) -> dict: file_content = file.getvalue(encoding="ISO-8859-1") gef_file = GEFFile(file_content) gef_data_obj = gef_file.parse(additional_columns=['fs', 'u2'], return_gef_data_obj=True) soil_properties = [ {'name': Robertson zone unknown, 'extra_property1': 1, 'extra_property2': 2}, {'name': Robertson zone 1, 'extra_property1': 3, 'extra_property2': 4}, ] soil_layout_dict = gef_data_obj.classify(method=RobertsonMethod(soil_properties), return_soil_layout_obj=False) parsed_dict = gef_data_obj.serialize() parsed_dict['soils'] = soil_layout_dict return parsed_dict ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **additional\_columns** (`Optional`\[`List`\[`str`]]) – In order for a GEF file to be of use in VIKTOR, three columns are required: * elevation (corrected depth with respect to a specified datum) * qc (tip pressure as measured) * Rf (friction number, either measured or computed using qc and fs) These three columns will always be parsed and returned, additional columns can be parsed as well. Possible columns to request are: * ”penetration\_length” * ”corrected\_depth” * ”fs” * ”u2” (for more accuracy when qualifying layers using Robertson method) * ”inclination” * ”inclination\_n\_s” * ”inclination\_e\_w” * **verbose** (`bool`) – Boolean specifying if parsing should output warnings or work in silence * **return\_gef\_data\_obj** (`bool`) – Boolean to return GEFData or dictionary * Return type `Union`\[`dict`, [`GEFData`](#GEFData "viktor.geo.GEFData")] * Returns dictionary with GEF parameters or GEFData object with GEF parameters as attributes ## gef\_visualization[​](/sdk/13/api/geo/.md#_gef_visualization "Direct link to gef_visualization") * viktor.geo.gef\_visualization(*gef\_data*, *soil\_layout\_original*, *soil\_layout\_user*, *\**, *as\_file=False*)[¶](#gef_visualization "Permalink to this definition") Standard visualization for GEF File. Example usage: ``` class Controller(ViktorController): ... @ImageView("GEF plot", duration_guess=2) def visualize(self, params, **kwargs): gef_data = ... soil_layout_original = ... soil_layout_user = ... svg_image = gef_visualization(gef_data, soil_layout_original, soil_layout_user) return ImageResult(svg_image) ``` * Parameters * **gef\_data** ([`GEFData`](#GEFData "viktor.geo.GEFData")) – GEFData object to be visualized * **soil\_layout\_original** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) – SoilLayout from GEFData. Layers must be sorted from top to bottom. * **soil\_layout\_user** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) – SoilLayout that is filtered/modified by user. Layers must be sorted from top to bottom. * **as\_file** (`bool`) – return as str (default) or File New in v13.5.0 * Return type `Union`\[`str`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] * Returns SVG image file ## Soil[​](/sdk/13/api/geo/.md#_Soil "Direct link to Soil") * *class *viktor.geo.Soil(*name*, *color*, *properties=None*)[¶](#Soil "Permalink to this definition") Set name and color of Soil material. Extra properties can be added with dictionary, and keys are added as attribute via ‘munchify’. They are accessible as self.properties.{extra\_property\_name} * Parameters * **name** (`str`) – * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – color of soil used in plots * **properties** (`Union`\[`dict`, `Munch`, `None`]) – dict with optional extra parameters to be added to Soil - *classmethod *from\_dict(*d*)[¶](#Soil.from_dict "Permalink to this definition") * Return type [`Soil`](#Soil "viktor.geo.Soil") * *property *color*: [Color](/sdk/13/api/core/.md#Color "viktor.core.Color")*[¶](#Soil.color "Permalink to this definition") * Return type [`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color") - update\_properties(*properties*)[¶](#Soil.update_properties "Permalink to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type `None` * serialize()[¶](#Soil.serialize "Permalink to this definition") Serialize Soil in following dictionary structure: ``` { 'name', 'color', 'properties': { (..extra_properties..) }, } ``` * Return type `dict` * Returns dictionary with all properties of Soil ## UndefinedSoil[​](/sdk/13/api/geo/.md#_UndefinedSoil "Direct link to UndefinedSoil") * *class *viktor.geo.UndefinedSoil[¶](#UndefinedSoil "Permalink to this definition") Bases: [`Soil`](#Soil "viktor.geo.Soil") Set name and color of Soil material. Extra properties can be added with dictionary, and keys are added as attribute via ‘munchify’. They are accessible as self.properties.{extra\_property\_name} * Parameters * **name** – * **color** – color of soil used in plots * **properties** – dict with optional extra parameters to be added to Soil ## PiezoLine[​](/sdk/13/api/geo/.md#_PiezoLine "Direct link to PiezoLine") * *class *viktor.geo.PiezoLine(*points*, *phreatic=False*)[¶](#PiezoLine "Permalink to this definition") Bases: [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline") Class to represent a Piezo line. Essentially, this is a polyline with a flag added to mark the phreatic polyline. * Parameters * **points** (`List`\[[`Point`](/sdk/13/api/geometry/.md#Point "viktor.geometry.Point")]) – points of the polyline * **phreatic** (`bool`) – mark the phreatic waterline - serialize()[¶](#PiezoLine.serialize "Permalink to this definition") Return a json serializable dict of form: ``` [ {'x': point_1.x, 'y': point_1.y}, {'x': point_2.x, 'y': point_2.y} ] ``` * Return type `dict` * *classmethod *from\_dict(*piezo\_line\_dict*)[¶](#PiezoLine.from_dict "Permalink to this definition") * Return type [`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine") - *classmethod *from\_lines(*lines*, *phreatic=False*)[¶](#PiezoLine.from_lines "Permalink to this definition") create a polyline object from a list of lines the end of one line must always coincide with the start of the next * Parameters * **lines** (`List`\[`Union`\[[`Line`](/sdk/13/api/geometry/.md#Line "viktor.geometry.Line"), [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")]]) – * **phreatic** (`bool`) – * Return type [`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine") ## SoilLayer[​](/sdk/13/api/geo/.md#_SoilLayer "Direct link to SoilLayer") * *class *viktor.geo.SoilLayer(*soil*, *top\_of\_layer*, *bottom\_of\_layer*, *properties=None*)[¶](#SoilLayer "Permalink to this definition") Create a SoilLayer to be used in SoilLayout * Parameters * **soil** ([`Soil`](#Soil "viktor.geo.Soil")) – Type of soil * **top\_of\_layer** (`float`) – Top of layer * **bottom\_of\_layer** (`float`) – Bottom of layer * **properties** (`Union`\[`dict`, `Munch`, `None`]) – dict with optional extra parameters to be added to SoilLayer - *classmethod *from\_dict(*soil\_layer\_dict*)[¶](#SoilLayer.from_dict "Permalink to this definition") * Return type [`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer") * *property *thickness*: float*[¶](#SoilLayer.thickness "Permalink to this definition") * Return type `float` - serialize()[¶](#SoilLayer.serialize "Permalink to this definition") Serialize SoilLayer in following dictionary structure: ``` { 'soil', 'top_of_layer', 'bottom_of_layer', } ``` * Return type `dict` * Returns dictionary with properties of SoilLayer * update\_soil\_properties(*properties*)[¶](#SoilLayer.update_soil_properties "Permalink to this definition") * Return type `None` - update\_properties(*properties*)[¶](#SoilLayer.update_properties "Permalink to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type `None` ## SoilLayer2D[​](/sdk/13/api/geo/.md#_SoilLayer2D "Direct link to SoilLayer2D") * *class *viktor.geo.SoilLayer2D(*soil*, *top\_profile*, *bottom\_profile*, *properties=None*, *piezo\_line\_top=None*, *piezo\_line\_bottom=None*)[¶](#SoilLayer2D "Permalink to this definition") A 2D representation of a soil layer A Soil layer 2d always consists of a soil and a top and bottom profile Optionally, properties and top and bottom pl lines can be added Top and bottom profiles need to be monotonic ascending in x-direction Top and bottom profiles need to have identical start x and end x coordinates. These will become the left and right boundaries Top and bottom profiles can overlap, but not intersect. The layer can have one or multiple ranges with zero thickness, but the top profile may never lie below the bottom profile * Parameters * **soil** ([`Soil`](#Soil "viktor.geo.Soil")) – * **top\_profile** ([`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – * **bottom\_profile** ([`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – * **properties** (`Union`\[`dict`, `Munch`, `None`]) – * **piezo\_line\_top** (`Optional`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]) – * **piezo\_line\_bottom** (`Optional`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]) – - serialize()[¶](#SoilLayer2D.serialize "Permalink to this definition") Serialize SoilLayer in following dictionary structure: ``` { 'soil': Soil 'top_profile': Polyline 'bottom_profile': Polyline 'piezo_line_top': serialized PiezoLine 'piezo_line_bottom': serialized PiezoLine 'properties': Dict } ``` * Return type `dict` * Returns dictionary with properties of SoilLayer * *classmethod *from\_dict(*soil\_layer\_dict*)[¶](#SoilLayer2D.from_dict "Permalink to this definition") Instantiates a SoilLayer2D from the provided soil layer data. dict structure: ``` { 'soil': serialized Soil 'top_profile': serialized Polyline 'bottom_profile': serialized Polyline 'piezo_line_top': serialized PiezoLine 'piezo_line_bottom': serialized PiezoLine 'properties': Dict } ``` * Parameters **soil\_layer\_dict** (`Union`\[`dict`, `Munch`]) – Soil layer data. * Return type [`SoilLayer2D`](#SoilLayer2D "viktor.geo.SoilLayer2D") - *property *left\_boundary*: float*[¶](#SoilLayer2D.left_boundary "Permalink to this definition") * Return type `float` * *property *right\_boundary*: float*[¶](#SoilLayer2D.right_boundary "Permalink to this definition") * Return type `float` - update\_soil\_properties(*properties*)[¶](#SoilLayer2D.update_soil_properties "Permalink to this definition") Replace the current soil properties dict with a new one * Parameters **properties** (`Union`\[`dict`, `Munch`]) – * Return type `None` * Returns * update\_properties(*properties*)[¶](#SoilLayer2D.update_properties "Permalink to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type `None` * Returns - polygons()[¶](#SoilLayer2D.polygons "Permalink to this definition") Generate a list of polygons representing this soil layer. For every region of this soil layout that has a non-zero thickness, a polygon is generated. * Return type `List`\[[`Polygon`](/sdk/13/api/geometry/.md#Polygon "viktor.geometry.Polygon")] * visualize\_geometry(*visualize\_border=False*, *opacity=1*, *material=None*)[¶](#SoilLayer2D.visualize_geometry "Permalink to this definition") Returns the visualization elements (group, labels) of the SoilLayer2D which can be used in a GeometryView. * Parameters * **visualize\_border** (`bool`) – visualize the border surrounding this soil layout with an extra line. * **opacity** (`float`) – float between 0 (transparent) - 1 (opaque) * **material** (`Optional`\[[`Material`](/sdk/13/api/geometry/.md#Material "viktor.geometry.Material")]) – optional material to be applied on the geometry. * Return type `Tuple`\[[`Group`](/sdk/13/api/geometry/.md#Group "viktor.geometry.Group"), `List`\[[`Label`](/sdk/13/api/views/.md#Label "viktor.views.Label")]] - height\_at\_x(*x*)[¶](#SoilLayer2D.height_at_x "Permalink to this definition") Returns the height at a specific x location. If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters **x** (`float`) – The x-coordinate where the height is requested. * Return type `float` * Returns The height at the x-coordinate location. * top\_y\_coordinate(*x*)[¶](#SoilLayer2D.top_y_coordinate "Permalink to this definition") Determine the y-coordinate along the top boundary, belonging to the x value used as input If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters **x** (`float`) – The x-coordinate where the height is requested. * Return type `float` * Returns The y-coordinate of the top at the x-coordinate location. - bottom\_y\_coordinate(*x*)[¶](#SoilLayer2D.bottom_y_coordinate "Permalink to this definition") Determine the y-coordinate along the bottom boundary, belonging to the x value used as input If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters **x** (`float`) – The x-coordinate where the height is requested. * Return type `float` * Returns The y-coordinate of the top at the x-coordinate location. ## SoilLayout[​](/sdk/13/api/geo/.md#_SoilLayout "Direct link to SoilLayout") * *class *viktor.geo.SoilLayout(*soil\_layers*)[¶](#SoilLayout "Permalink to this definition") Aggregation object of SoilLayer * Parameters **soil\_layers** (`List`\[[`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")]) – list of SoilLayer objects - *classmethod *from\_dict(*soil\_layout\_dict*)[¶](#SoilLayout.from_dict "Permalink to this definition") Create SoilLayout with dictionary from SoilLayout.serialize(). Useful when SoilLayout needs to be created from dictionary from the database. Example usage: ``` class Controller(ViktorController): ... def get_soil_layout_from_database(self) -> SoilLayout: # API call to entity that stores complete SoilLayout layout_dict = entity.last_saved_params['layout_dict'] soil_layout = SoilLayout.from_dict(layout_dict) return soil_layout ``` * Parameters **soil\_layout\_dict** (`Union`\[`Dict`\[`str`, `List`], `Munch`]) – dictionary with same structure as SoilLayout.serialize() * Return type [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") * update\_soil\_properties(*df*)[¶](#SoilLayout.update_soil_properties "Permalink to this definition") Update SoilLayout with Soil properties * Parameters **df** (`DataFrame`) – dataframe with soil properties by name (must at least have column ‘name’). * Return type `None` * Returns - serialize()[¶](#SoilLayout.serialize "Permalink to this definition") Serialize SoilLayout to dict (e.g. to store in database). The structure of dict is: ``` { 'layers': [...] } ``` * Return type `dict` * get\_visualization(*axes*)[¶](#SoilLayout.get_visualization "Permalink to this definition") Modify (clean/empty) ‘axes’ input argument to plot SoilLayout structure. Layers must be sorted from top to bottom. * Parameters **axes** (`Axes`) – Axes object that will be modified * Return type `None` - *property *top*: float*[¶](#SoilLayout.top "Permalink to this definition") Height level of the top of the layout. * Return type `float` * *property *bottom*: float*[¶](#SoilLayout.bottom "Permalink to this definition") Height level of the bottom of the layout. * Return type `float` - *property *number\_of\_layers*: int*[¶](#SoilLayout.number_of_layers "Permalink to this definition") Number of layers * Return type `int` * update\_layers()[¶](#SoilLayout.update_layers "Permalink to this definition") Merges adjacent layers that have the same soil type. The merged layer is assigned the average value of each SoilLayer’s individual properties. This average is calculated in ratio to the thickness of the layers. After merging layer depths are corrected by going from top to bottom and setting each bottom\_of\_layer equal to top\_of\_layer of next SoilLayer Example layer 1 has thickness 10 and for property A a value of 5 layer 2 has thickness 40 and for property A a value of 2 Resulting layer will have thickness 50, and property A = (10 \* 5 + 40 \* 2) / (10 + 40) = 2.6 * Return type `None` - append(*layer*)[¶](#SoilLayout.append "Permalink to this definition") Add a layer to the bottom of the classification * Parameters **layer** ([`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")) – SoilLayer instance * Return type `None` * filter\_layers\_on\_thickness(*min\_layer\_thickness*, *merge\_adjacent\_same\_soil\_layers=False*)[¶](#SoilLayout.filter_layers_on_thickness "Permalink to this definition") Collects layers that are thinner than min\_layer\_thickness in groups, and replaces them by one of two things: > * If the group is thinner than min\_layer\_thickness, it is removed from the soil layout and the layer above it is elongated to fill the gap. See explanation figure, situation A. > > * If the group is equal to or thicker than min\_layer\_thickness, a new layer with Soil and properties of the most dominant (based cumulative thickness) soiltype occurring within this block of layers that was replaced by the new layer. See explanation figure, situation B. After all replacements have been made, if merge\_adjacent\_same\_soil\_layers is specified as True (default is False), `_merge_adjacent_same_soil_layers()` is called, which merges adjacent soil layers that have the same soiltype and have the same set of parameters. Note that this merging results in a new layer that has the average value for all soil layer properties present in the layers that were merged. See the docstring of `_merge_adjacent_same_soil_layers()` for more detailed information about how this is done. * Parameters * **min\_layer\_thickness** (`float`) – Minimum thickness * **merge\_adjacent\_same\_soil\_layers** (`bool`) – Try to merge adjacent layers that have the same soil type Note: this method alters the instance! [![/\_images/soil\_layout\_filtering\_explanation.svg](/_images/soil_layout_filtering_explanation.svg)](/_images/soil_layout_filtering_explanation.svg) * Return type [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") - filter\_unique\_soils()[¶](#SoilLayout.filter_unique_soils "Permalink to this definition") * Return type `List`\[[`Soil`](#Soil "viktor.geo.Soil")] ## PositionalSoilLayout[​](/sdk/13/api/geo/.md#_PositionalSoilLayout "Direct link to PositionalSoilLayout") * *class *viktor.geo.PositionalSoilLayout(*x*, *soil\_layers*)[¶](#PositionalSoilLayout "Permalink to this definition") Bases: [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") A subclass of SoilLayout that adds an x location. This can be useful to generate a Soil Layout 2D Generate a positional soil layout from an x location and a list of soil layers * Parameters * **x** (`float`) – * **soil\_layers** (`List`\[[`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")]) – - *classmethod *from\_dict(*positional\_soil\_layout\_dict*)[¶](#PositionalSoilLayout.from_dict "Permalink to this definition") Instantiates a PositionalSoilLayout from the provided soil layout data. * Parameters **positional\_soil\_layout\_dict** (`Union`\[`dict`, `Munch`]) – Soil layout data. * Return type [`PositionalSoilLayout`](#PositionalSoilLayout "viktor.geo.PositionalSoilLayout") * serialize()[¶](#PositionalSoilLayout.serialize "Permalink to this definition") Generate a JSON serializable dict from this positional soil layout. * Return type `dict` ## SoilLayout2D[​](/sdk/13/api/geo/.md#_SoilLayout2D "Direct link to SoilLayout2D") * *class *viktor.geo.SoilLayout2D(*soil\_layers*, *piezo\_lines=None*)[¶](#SoilLayout2D "Permalink to this definition") A 2D representation of a soil body build up from layers. A Soil Layout 2D basically consists of the following elements: * A list of soil layers: objects of the class SoilLayer2D * A list of piezo lines * A left and right boundary * A top and bottom profile Left and right boundaries, as well as top and bottom profiles, are automatically taken from the given soil layers The following requirements are to be met: * Each soil layer has to stretch all the way from the left boundary to the right boundary * The layers have to be stacked starting from bottom to top * There can be no holes in the soil layout 2d, meaning that the top profile of a previous layer always has to be identical to the bottom profile of the next layer * A layer can have zero thickness over (part of) the width of the soil layout 2d * All soil layers and piezo lines have to exactly identical ranges in x direction, meaning that they all range exactly from left boundary to right boundary A SoilLayout2D will have roughly the following shape, with each layer containing it’s own soil and soil properties: ``` | xxxxxxxxxx | |xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| | | | | | xxxxxxxx | |xxxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxxxxx| | xxx xxxxxx | | xxx | | | | | |xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxx| | xxxxxxxxxxxxxxxxxx | | | | xxxxxxxxxxxxxxx | |xxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| ``` The SoilLayout2D class is immutable. Any methods that alter or change properties of the class will return a new instance. * Parameters * **soil\_layers** (`List`\[[`SoilLayer2D`](#SoilLayer2D "viktor.geo.SoilLayer2D")]) – an ordered dict of 2D soil layers. Starting from the bottom layer * **piezo\_lines** (`Optional`\[`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]]) – list of piezo lines - *classmethod *from\_positional\_soil\_layouts(*positional\_soil\_layouts*, *top\_profile*, *piezo\_lines=None*)[¶](#SoilLayout2D.from_positional_soil_layouts "Permalink to this definition") Instantiate a soil layout 2d from multiple 1d soil layouts combined with x locations and a ground profile all 1d soil layouts should have the same layers in the same order. Variation in height and thickness are possible the top profile has to be monotonic ascending in x direction * Parameters * **positional\_soil\_layouts** (`List`\[[`PositionalSoilLayout`](#PositionalSoilLayout "viktor.geo.PositionalSoilLayout")]) – 1d soil layouts with x locations * **top\_profile** ([`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – a polyline representing the ground level * **piezo\_lines** (`Optional`\[`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]]) – list of piezo lines * Return type [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") * *classmethod *from\_single\_soil\_layout(*soil\_layout*, *left\_boundary*, *right\_boundary*, *top\_profile*, *piezo\_lines=None*)[¶](#SoilLayout2D.from_single_soil_layout "Permalink to this definition") A special case when a 1D soil layout is stretched in the 2D plane. This class method will create a 2D layout with horizontal layers and a top\_profile. * Parameters * **soil\_layout** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) – * **top\_profile** ([`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – * **left\_boundary** (`float`) – * **right\_boundary** (`float`) – * **piezo\_lines** (`Optional`\[`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]]) – * Return type [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") - *classmethod *combine\_soil\_layouts\_2d(*\*soil\_layouts\_2d*)[¶](#SoilLayout2D.combine_soil_layouts_2d "Permalink to this definition") Combine multiple SoilLayout2D’s in into one big SoilLayout2D All given soil layouts need to connect seemlessly, so that the resulting SoilLayout2D fullfills the requirement that it has got no holes and the top and bottom profile are monotonic ascending in x direction All layers will be continued (with zero thickness) to the new right and left boundaries * Parameters **soil\_layouts\_2d** ([`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D")) – * Return type [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") * Returns POSSIBLE COMBINATIONS: combining a left and a right soil layout 2d ``` _____________________ | |_______________________ | | | |-------------------|----------------------| | | | |___________________|----------------------| | | |______________________| ``` combining a top and bottom soil layout 2d ``` _____________________ | | |-------------------| | | |___________________|______________ | | |--------------------------| |__________________________| ``` combining n soil layouts, as long as there are no holes in the resulting soil layout, and it is possible to keep all layer profiles monotonic ascending in x-directions ``` _____________________ | |_______________________ | | | |-------------------|----------------------| | | | |___________________|______________________| | | |-------------------| |___________________| ``` IMPOSSIBLE COMBINATIONS: soillayouts without seem ``` _____________________ | | ________________________ | | | | |-------------------| |----------------------| | | | | |___________________| |----------------------| | | |______________________| ``` overlapping soil layouts ``` _____________________ | ________|_______________ | | | | |-----------|-------| | | |-------|--------------| |___________|_______| | | | |______________________| ``` the resulting soil layout does contain layers with profiles that are not monotonic ascending in x-direction ``` _____________________ | |_______________________ | | | |-------------------| | | |----------------------| |___________________| | | | ________|______________________| | | |-------------------| |___________________| ``` * *classmethod *from\_dict(*soil\_layout\_2d\_dict*)[¶](#SoilLayout2D.from_dict "Permalink to this definition") Create SoilLayout2D with dictionary from SoilLayout2D.serialize(). Useful when SoilLayout2D needs to be created from dictionary from the database. Example usage: ``` class Controller(ViktorController): ... def get_interpolated_soil_layout_from_database(self) -> SoilLayout2D: # API call to entity that stores complete SoilLayout2D layout_dict = entity.last_saved_params['layout_dict'] interpolated_soil_layout = SoilLayout2D.from_dict(layout_dict) return interpolated_soil_layout ``` * Parameters **soil\_layout\_2d\_dict** (`Union`\[`dict`, `Munch`]) – dictionary with same structure as SoilLayout2D.serialize() * Return type [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") - serialize()[¶](#SoilLayout2D.serialize "Permalink to this definition") Serialize to dict (e.g. to store in database). The structure of dict is: ``` {'layers': [layer.serialize} for layer in self.layers, 'piezo_lines': [line.serialize() for line in self.piezo_lines]} ``` * Return type `dict` * Returns dictionary with structure above * *property *top\_profile*: [Polyline](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")*[¶](#SoilLayout2D.top_profile "Permalink to this definition") top profile of the soil layout: Polyline * Type return * Return type [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline") - *property *bottom\_profile*: [Polyline](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")*[¶](#SoilLayout2D.bottom_profile "Permalink to this definition") bottom profile of the soil layout: Polyline * Type return * Return type [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline") * visualize\_geometry(*visualize\_border=False*, *opacity=1*)[¶](#SoilLayout2D.visualize_geometry "Permalink to this definition") Returns the visualization elements (group, labels) of the SoilLayout2D which can be used in a GeometryView. * Parameters * **visualize\_border** (`bool`) – visualize the border surrounding this soil layout with an extra line. * **opacity** (`float`) – float between 0 (transparent) - 1 (opaque) * Return type `Tuple`\[[`Group`](/sdk/13/api/geometry/.md#Group "viktor.geometry.Group"), `List`\[[`Label`](/sdk/13/api/views/.md#Label "viktor.views.Label")]] - split(*\*split\_lines*)[¶](#SoilLayout2D.split "Permalink to this definition") Split the soil layout by given polylines. Each split line has to: > * have a start and end point that lies outside of this soil layout > > * intersect the soil layout in at least one region > > * be monotonic ascending in x-direction Split lines are allowed to cross each other one or multiple times. Examples: Single split line ``` ___________ ___________ ___________ ____________ | / | | / / | | / | ==> | / / | |-------/-------------| |-------/ /-------------| |______/______________| |______/ /______________| ``` Single split line with multiple intersections ``` /\ ___________/__\________ _______________________ | / \ | | / \ | | / \ | ==> | / \ | |-------/--------\----| |-------/ ____ \----| |______/__________\___| |______/ / \ \___| / \ / \ /--------\ /__________\ ``` Two crossing split lines ``` ____ ______ ____ ___________ _______ \ / ____________ | \ / | | \ \/ / | | \/ | ==> | \ / | |-------/\------------| |-------/ \------------| |______/__\___________| |______/ /\ \___________| /__\ ``` * Parameters **split\_lines** ([`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – a list of polylines * Return type `List`\[[`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D")] * get\_left\_boundary\_polyline()[¶](#SoilLayout2D.get_left_boundary_polyline "Permalink to this definition") Get the polyline describing the left boundary This will always be a straight boundary This will contain a point on every boundary between layers * Return type [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline") * Returns Polyline - get\_right\_boundary\_polyline()[¶](#SoilLayout2D.get_right_boundary_polyline "Permalink to this definition") Get the polyline describing the right boundary This will always be a straight boundary This will contain a point on every boundary between layers * Return type [`Polyline`](/sdk/13/api/geometry/.md#Polyline "viktor.geometry.Polyline") * Returns Polyline --- # viktor.geometry ## Vector[​](/sdk/13/api/geometry/.md#_Vector "Direct link to Vector") * *class *viktor.geometry.Vector(*x*, *y*, *z=0*)[¶](#Vector "Permalink to this definition") A 3-dimensional vector in space. The following operations are supported: * Negation > ``` > v1 = Vector(1, 2, 3) > v2 = -v1 # results in Vector(-1, -2, -3) > ``` * Addition > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > v3 = v1 + v2 # results in Vector(2, 4, 6) > ``` * Subtraction > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > v3 = v1 - v2 # results in Vector(0, 0, 0) > ``` * (reverse) Multiplication > ``` > v1 = Vector(1, 2, 3) > v2 = v1 * 3 # results in Vector(3, 6, 9) > v3 = 3 * v1 # results in Vector(3, 6, 9) > ``` * Dot product > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > res = v1.dot(v2) # results in 14 > ``` * Cross product > ``` > v1 = Vector(1, 0, 0) > v2 = Vector(0, 1, 0) > v3 = v1.cross(v2) # results in Vector(0, 0, 1) > ``` - Parameters * **x** (`float`) – X-coordinate. * **y** (`float`) – Y-coordinate. * **z** (`float`) – Z-coordinate (default: 0). * *property *squared\_magnitude*: float*[¶](#Vector.squared_magnitude "Permalink to this definition") Vector magnitude without square root; faster than magnitude. * Return type `float` - *property *magnitude*: float*[¶](#Vector.magnitude "Permalink to this definition") Magnitude of the Vector. * Return type `float` * *property *coordinates*: Tuple\[float, float, float]*[¶](#Vector.coordinates "Permalink to this definition") Coordinates of the Vector as tuple (X, Y, Z). * Return type `Tuple`\[`float`, `float`, `float`] - normalize()[¶](#Vector.normalize "Permalink to this definition") Return the normalized vector (with unit-length). * Raises **ValueError** – if vector is a null-vector. * Return type [`Vector`](#Vector "viktor.geometry.Vector") * dot(*other*)[¶](#Vector.dot "Permalink to this definition") Scalar product of two vectors. * Parameters **other** ([`Vector`](#Vector "viktor.geometry.Vector")) – Second Vector * Return type `float` - cross(*other*)[¶](#Vector.cross "Permalink to this definition") Vector product of two vectors. * Parameters **other** ([`Vector`](#Vector "viktor.geometry.Vector")) – Second Vector * Return type [`Vector`](#Vector "viktor.geometry.Vector") ## Material[​](/sdk/13/api/geometry/.md#_Material "Direct link to Material") * *class *viktor.geometry.Material(*name*, *density=None*, *price=None*, *\**, *threejs\_type='MeshStandardMaterial'*, *threejs\_roughness=0.7*, *threejs\_metalness=0.8*, *threejs\_opacity=1.0*, *color=Color(221, 221, 221)*)[¶](#Material "Permalink to this definition") * Parameters * **name** (`str`) – * **density** (`Optional`\[`float`]) – * **price** (`Optional`\[`float`]) – * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – * **threejs\_type** (`str`) – legacy, not used anymore * **threejs\_roughness** (`float`) – Between 0 - 1 where closer to 1 gives the material a rough texture. * **threejs\_metalness** (`float`) – Between 0 - 1 where closer to 1 gives the material a shiny metal look. * **threejs\_opacity** (`float`) – Between 0 - 1 where closer to 0 makes the material less visible. - *property *name*: str*[¶](#Material.name "Permalink to this definition") * Return type `str` * *property *density*: Optional\[float]*[¶](#Material.density "Permalink to this definition") * Return type `Optional`\[`float`] - *property *price*: Optional\[float]*[¶](#Material.price "Permalink to this definition") * Return type `Optional`\[`float`] ## TransformableObject[​](/sdk/13/api/geometry/.md#_TransformableObject "Direct link to TransformableObject") * *class *viktor.geometry.TransformableObject[¶](#TransformableObject "Permalink to this definition") Bases: `ABC` * translate(*translation\_vector*)[¶](#TransformableObject.translate "Permalink to this definition") Translate an object along a translation vector. * Parameters **translation\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which translation is to be performed. * Return type [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") - rotate(*angle*, *direction*, *point=None*)[¶](#TransformableObject.rotate "Permalink to this definition") Rotate an object along an axis (direction) by an angle. Direction will follow right hand rule. * Parameters * **angle** (`float`) – Angle of desired rotation in radians. * **direction** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which rotation is to be performed. * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`], `None`]) – Point through which the rotation vector runs. * Return type [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * mirror(*point*, *normal*)[¶](#TransformableObject.mirror "Permalink to this definition") Mirror an object on a plane defined by a point and normal vector. * Parameters * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point within the mirror plane. * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Normal vector of the mirror plane. * Return type [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") - scale(*scaling\_vector*)[¶](#TransformableObject.scale "Permalink to this definition") Scale an object along a scaling vector. * Parameters **scaling\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which scaling is to be performed. * Return type [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") ## Group[​](/sdk/13/api/geometry/.md#_Group "Direct link to Group") * *class *viktor.geometry.Group(*objects*)[¶](#Group "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * Parameters **objects** (`Sequence`\[[`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")]) – Objects that are part of the group. - add(*objects*)[¶](#Group.add "Permalink to this definition") * Return type `None` * *property *children*: List\[[TransformableObject](#TransformableObject "viktor.geometry.TransformableObject")]*[¶](#Group.children "Permalink to this definition") * Return type `List`\[[`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")] - duplicate()[¶](#Group.duplicate "Permalink to this definition") * Return type [`Group`](#Group "viktor.geometry.Group") ## Point[​](/sdk/13/api/geometry/.md#_Point "Direct link to Point") * *class *viktor.geometry.Point(*x*, *y*, *z=0*)[¶](#Point "Permalink to this definition") This class represents a point object, which is instantiated by means of 3-dimensional coordinates X, Y, and Z. It forms a basis of many structural 2D and 3D objects. Example usage: ``` p1 = Point(1, 2) # create a 2D point p1.z # 0 p2 = Point(1, 2, 3) # create a 3D point p1.z # 3 ``` * Parameters * **x** (`float`) – X-coordinate. * **y** (`float`) – Y-coordinate. * **z** (`float`) – (optional) Z-coordinate, defaults to 0. * Raises **TypeError** – if the point is instantiated with a None value. - *property *x*: float*[¶](#Point.x "Permalink to this definition") X-coordinate. * Return type `float` * *property *y*: float*[¶](#Point.y "Permalink to this definition") Y-coordinate. * Return type `float` - *property *z*: float*[¶](#Point.z "Permalink to this definition") Z-coordinate. * Return type `float` * *property *coordinates*: numpy.ndarray*[¶](#Point.coordinates "Permalink to this definition") Coordinates of the Point as array (X, Y, Z). * Return type `ndarray` - copy()[¶](#Point.copy "Permalink to this definition") Returns a deep copy of the object. * Return type [`Point`](#Point "viktor.geometry.Point") * coincides\_with(*other*)[¶](#Point.coincides_with "Permalink to this definition") Given another Point object, this method determines whether the two points coincide. * Return type `bool` - vector\_to(*point*)[¶](#Point.vector_to "Permalink to this definition") Vector pointing from self to point. Example usage: ``` p1 = Point(1, 2, 3) p2 = Point(0, 0, 0) # origin v = p1.vector_to(p2) # vector from p1 to the origin v = p1.vector_to((0, 0, 0)) # short notation ``` * Return type [`Vector`](#Vector "viktor.geometry.Vector") * get\_local\_coordinates(*local\_origin*, *spherical=False*)[¶](#Point.get_local_coordinates "Permalink to this definition") Method to determine the local coordinates of the current Point with respect to a ‘local origin’. * Return type `ndarray` ## Line[​](/sdk/13/api/geometry/.md#_Line "Direct link to Line") * *class *viktor.geometry.Line(*start\_point*, *end\_point*, *\**, *color=Color(0, 0, 0)*)[¶](#Line "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * Parameters * **start\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Start point of the line (cannot coincide with end\_point). * **end\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – End point of the line (cannot coincide with start\_point). * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . - *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Line.start_point "Permalink to this definition") * Return type [`Point`](#Point "viktor.geometry.Point") * *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Line.end_point "Permalink to this definition") * Return type [`Point`](#Point "viktor.geometry.Point") - *property *length*: float*[¶](#Line.length "Permalink to this definition") * Return type `float` * direction(*normalize=True*)[¶](#Line.direction "Permalink to this definition") Direction vector between start and end point. * Return type [`Vector`](#Vector "viktor.geometry.Vector") - collinear(*point*)[¶](#Line.collinear "Permalink to this definition") True if point is collinear (in line) with Line, else False. * Return type `bool` * project\_point(*point*)[¶](#Line.project_point "Permalink to this definition") Project the point on the (unbounded) line. * Return type [`Point`](#Point "viktor.geometry.Point") - distance\_to\_point(*point*)[¶](#Line.distance_to_point "Permalink to this definition") Calculate the (minimal) distance from the given point to the (unbounded) line. * Return type `float` * *property *length\_vector*: numpy.ndarray*[¶](#Line.length_vector "Permalink to this definition") * Return type `ndarray` - *property *unit\_vector*: numpy.ndarray*[¶](#Line.unit_vector "Permalink to this definition") * Return type `ndarray` * *property *horizontal*: bool*[¶](#Line.horizontal "Permalink to this definition") * Return type `bool` - *property *vertical*: bool*[¶](#Line.vertical "Permalink to this definition") * Return type `bool` * revolve(*\**, *material=None*, *\*\*kwargs*)[¶](#Line.revolve "Permalink to this definition") Revolve line around y-axis, only possible for lines in x-y plane. * Parameters **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material * Raises **NotImplementedError** – when line is not in x-y plane * Return type [`LineRevolve`](#LineRevolve "viktor.geometry.LineRevolve") - get\_line\_function\_parameters()[¶](#Line.get_line_function_parameters "Permalink to this definition") Get parameters for y=ax+b definition of a line. * Return type `Tuple`\[`float`, `float`] * Returns (a, b) or (nan, nan) if line is vertical * find\_overlap(*other*, *inclusive=False*)[¶](#Line.find_overlap "Permalink to this definition") Find the overlapping part of this line with another line. The returned value depends on the situation: * None, if no overlap is found or the two lines are not parallel * Point, if an overlap is found with length equal to 0 * Line, if an overlap is found with length larger than 0 - Parameters * **other** ([`Line`](#Line "viktor.geometry.Line")) – Other Line object * **inclusive** (`bool`) – True to treat overlapping points as overlap - Return type `Union`\[[`Point`](#Point "viktor.geometry.Point"), [`Line`](#Line "viktor.geometry.Line"), `None`] ## calculate\_intersection\_bounded\_line\_with\_y[​](/sdk/13/api/geometry/.md#_calculate_intersection_bounded_line_with_y "Direct link to calculate_intersection_bounded_line_with_y") * viktor.geometry.calculate\_intersection\_bounded\_line\_with\_y(*line*, *y\_intersection*)[¶](#calculate_intersection_bounded_line_with_y "Permalink to this definition") Calculate x intersection between two points and y value. Return None if no intersection is found. ``` Returns x: Returns None: o / y-----/--- y--------- /: o / : / o x o ``` * Parameters * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object. * **y\_intersection** (`float`) – y-value of the intersection line. * Return type `Optional`\[`float`] ## calculate\_intersection\_extended\_line\_with\_y[​](/sdk/13/api/geometry/.md#_calculate_intersection_extended_line_with_y "Direct link to calculate_intersection_extended_line_with_y") * viktor.geometry.calculate\_intersection\_extended\_line\_with\_y(*line*, *y\_intersection*)[¶](#calculate_intersection_extended_line_with_y "Permalink to this definition") Calculates the intersection x value of a line at a given y value. ``` Returns x: Returns x: o / y-----/--- y---------- /: o: / : / : o x o x ``` * Parameters * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object. * **y\_intersection** (`float`) – y-value of the intersection line. * Return type `float` ## line\_is\_horizontal[​](/sdk/13/api/geometry/.md#_line_is_horizontal "Direct link to line_is_horizontal") * viktor.geometry.line\_is\_horizontal(*line*)[¶](#line_is_horizontal "Permalink to this definition") Returns True if line is horizontal. * Return type `bool` ## line\_is\_vertical[​](/sdk/13/api/geometry/.md#_line_is_vertical "Direct link to line_is_vertical") * viktor.geometry.line\_is\_vertical(*line*)[¶](#line_is_vertical "Permalink to this definition") Returns True if line is vertical. * Return type `bool` ## x\_between\_bounds[​](/sdk/13/api/geometry/.md#_x_between_bounds "Direct link to x_between_bounds") * viktor.geometry.x\_between\_bounds(*x*, *x1*, *x2*, *inclusive=True*)[¶](#x_between_bounds "Permalink to this definition") Method checks whether the x value is between the bounds x1 and x2. * Parameters * **x** (`float`) – x-value to be evaluated. * **x1** (`float`) – Lower bound. * **x2** (`float`) – Upper bound. * **inclusive** (`bool`) – If set to True, this method will also return True when the x value is equal to either x1 or x2. * Return type `bool` ## y\_between\_bounds[​](/sdk/13/api/geometry/.md#_y_between_bounds "Direct link to y_between_bounds") * viktor.geometry.y\_between\_bounds(*y*, *y1*, *y2*, *inclusive=True*)[¶](#y_between_bounds "Permalink to this definition") Method checks whether the y value is between the bounds y1 and y2. * Parameters * **y** (`float`) – y-value to be evaluated. * **y1** (`float`) – Lower bound. * **y2** (`float`) – Upper bound. * **inclusive** (`bool`) – If set to True, this method will also return True when the y value is equal to either y1 or y2. * Return type `bool` ## point\_is\_on\_bounded\_line[​](/sdk/13/api/geometry/.md#_point_is_on_bounded_line "Direct link to point_is_on_bounded_line") * viktor.geometry.point\_is\_on\_bounded\_line(*point*, *line*, *inclusive=True*)[¶](#point_is_on_bounded_line "Permalink to this definition") Check whether a given Point object is within the ends of a Line. * Parameters * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point to be evaluated. * **line** (`Union`\[[`Line`](#Line "viktor.geometry.Line"), `Tuple`\[`Tuple`\[`float`, `float`, `float`], `Tuple`\[`float`, `float`, `float`]]]) – Line object. * **inclusive** (`bool`) – If True, this method will also return True when the point is located on one of the line ends. * Return type `bool` ## calculate\_intersection\_extended\_line\_with\_x[​](/sdk/13/api/geometry/.md#_calculate_intersection_extended_line_with_x "Direct link to calculate_intersection_extended_line_with_x") * viktor.geometry.calculate\_intersection\_extended\_line\_with\_x(*line*, *x*)[¶](#calculate_intersection_extended_line_with_x "Permalink to this definition") Returns the point at which a given line intersects a vertical axis at position x. ``` Returns P(x, y): Returns P(x, y): o / y-----P--- y-----P---- /: o: / : / : o x o x ``` * Parameters * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line to be evaluated. * **x** (`float`) – x-value of the intersection line. * Return type [`Point`](#Point "viktor.geometry.Point") ## get\_line\_function\_parameters[​](/sdk/13/api/geometry/.md#_get_line_function_parameters "Direct link to get_line_function_parameters") * viktor.geometry.get\_line\_function\_parameters(*line*)[¶](#get_line_function_parameters "Permalink to this definition") Returns the line function parameters (a, b) of a line (y = ax + b). * Return type `Tuple`\[`float`, `float`] ## calculate\_intersection\_extended\_lines[​](/sdk/13/api/geometry/.md#_calculate_intersection_extended_lines "Direct link to calculate_intersection_extended_lines") * viktor.geometry.calculate\_intersection\_extended\_lines(*extended\_line1*, *extended\_line2*)[¶](#calculate_intersection_extended_lines "Permalink to this definition") Calculate intersection between two lines defined by start/end points. The lines are assumed to extend infinitely: bounds are not taken account. Returns None if lines are parallel (i.e. no intersection exists). ``` Returns P(x, y): Returns P(x, y): Returns None: o / o-----P---o o--o P o-----o / o / / o--o o o ``` * Parameters * **extended\_line1** ([`Line`](#Line "viktor.geometry.Line")) – First Line object. * **extended\_line2** ([`Line`](#Line "viktor.geometry.Line")) – Second Line object. * Return type `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## calculate\_intersection\_bounded\_line\_extended\_line[​](/sdk/13/api/geometry/.md#_calculate_intersection_bounded_line_extended_line "Direct link to calculate_intersection_bounded_line_extended_line") * viktor.geometry.calculate\_intersection\_bounded\_line\_extended\_line(*bounded\_line*, *extended\_line*, *inclusive=True*)[¶](#calculate_intersection_bounded_line_extended_line "Permalink to this definition") Calculate intersection between line with fixed endpoints and line which is indefinitely extended. * Parameters * **bounded\_line** ([`Line`](#Line "viktor.geometry.Line")) – Bounded Line object. * **extended\_line** ([`Line`](#Line "viktor.geometry.Line")) – Extended Line object. * **inclusive** (`bool`) – If set to True, this method will also check for end points that are located on one of the line ends. * Return type `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## calculate\_intersection\_bounded\_lines[​](/sdk/13/api/geometry/.md#_calculate_intersection_bounded_lines "Direct link to calculate_intersection_bounded_lines") * viktor.geometry.calculate\_intersection\_bounded\_lines(*bounded\_line1*, *bounded\_line2*, *inclusive=True*)[¶](#calculate_intersection_bounded_lines "Permalink to this definition") Calculate intersection between two lines with fixed endpoints (2D only, Z-coordinate is ignored!). * Parameters * **bounded\_line1** ([`Line`](#Line "viktor.geometry.Line")) – First bounded Line object. * **bounded\_line2** ([`Line`](#Line "viktor.geometry.Line")) – Second bounded Line object. * **inclusive** (`bool`) – If set to True, intersections on the endpoint will also be taken into account. * Return type `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## Revolve[​](/sdk/13/api/geometry/.md#_Revolve "Direct link to Revolve") * *class *viktor.geometry.Revolve(*\*args*, *rotation\_angle=None*, *material=None*, *\*\*kwargs*)[¶](#Revolve "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject"), `ABC` Abstract base class of a revolved object. * *abstract property *surface\_area*: float*[¶](#Revolve.surface_area "Permalink to this definition") * Return type `float` - *abstract property *inner\_volume*: float*[¶](#Revolve.inner_volume "Permalink to this definition") * Return type `float` * *property *thickness*: float*[¶](#Revolve.thickness "Permalink to this definition") * Return type `float` - *property *mass*: float*[¶](#Revolve.mass "Permalink to this definition") Calculates the mass of the object as rho \* area \* thickness, with rho the density of the Material. * Return type `float` ## LineRevolve[​](/sdk/13/api/geometry/.md#_LineRevolve "Direct link to LineRevolve") * *class *viktor.geometry.LineRevolve(*line*, *\*args*, *material=None*, *\*\*kwargs*)[¶](#LineRevolve "Permalink to this definition") Bases: [`Revolve`](#Revolve "viktor.geometry.Revolve") Returns a revolved object of a Line around the global y-axis. An example revolve of a line between the point (1, 1, 0) and (3, 2, 0) is shown below, with the line object shown in black. ``` line = Line(Point(1, 1, 0), Point(3, 2, 0)) line_rev = LineRevolve(line) ``` [![/\_images/line-revolve.png](/_images/line-revolve.png)](/_images/line-revolve.png) * Parameters * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object which is to be revolved. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material - *property *line*: [Line](#Line "viktor.geometry.Line")*[¶](#LineRevolve.line "Permalink to this definition") * Return type [`Line`](#Line "viktor.geometry.Line") * *property *uuid*: UUID*[¶](#LineRevolve.uuid "Permalink to this definition") * Return type `UUID` - *property *height*: float*[¶](#LineRevolve.height "Permalink to this definition") * Return type `float` * *property *surface\_area*: float*[¶](#LineRevolve.surface_area "Permalink to this definition") Returns the total exterior area of the revolved object. * Return type `float` - *property *inner\_volume*: float*[¶](#LineRevolve.inner_volume "Permalink to this definition") Returns the inner volume of the revolved object. This method will only return a value if the defined Line meets the following conditions: > * it should NOT be horizontal, i.e. y\_start != y\_end > > * it should be defined in positive y-direction, i.e. y\_start < y\_end * Return type `float` ## Arc[​](/sdk/13/api/geometry/.md#_Arc "Direct link to Arc") * *class *viktor.geometry.Arc(*centre\_point*, *start\_point*, *end\_point*, *short\_arc=True*, *\**, *n\_segments=30*, *color=Color(0, 0, 0)*)[¶](#Arc "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Creates a constant radius arc in the xy plane. Clockwise rotation creates an outward surface. * Parameters * **centre\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. * **start\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. Should have the same distance to centre\_point as end\_point. * **end\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. Should have the same distance to centre\_point as start\_point. * **short\_arc** (`bool`) – Angle of arc smaller than pi if True, larger than pi if False. * **n\_segments** (`int`) – Number of discrete segments of the arc (default: 30) New in v13.5.0 . * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . - *property *radius*: float*[¶](#Arc.radius "Permalink to this definition") * Return type `float` * *property *centre\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Arc.centre_point "Permalink to this definition") * Return type [`Point`](#Point "viktor.geometry.Point") - *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Arc.start_point "Permalink to this definition") * Return type [`Point`](#Point "viktor.geometry.Point") * *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Arc.end_point "Permalink to this definition") * Return type [`Point`](#Point "viktor.geometry.Point") - *property *n\_segments*: int*[¶](#Arc.n_segments "Permalink to this definition") * Return type `int` * *property *theta1\_theta2*: Tuple\[float, float]*[¶](#Arc.theta1_theta2 "Permalink to this definition") Angles of the end (theta1) and start (theta2) points with respect to the x-axis in radians. * Return type `Tuple`\[`float`, `float`] - *property *theta1*: float*[¶](#Arc.theta1 "Permalink to this definition") Angle of the end point with respect to the x-axis in radians. * Return type `float` * *property *theta2*: float*[¶](#Arc.theta2 "Permalink to this definition") Angle of the start point with respect to the x-axis in radians. * Return type `float` - *property *short\_arc*: bool*[¶](#Arc.short_arc "Permalink to this definition") * Return type `bool` * *property *angle*: float*[¶](#Arc.angle "Permalink to this definition") Absolute angle of the arc in radians, which is the difference between theta1 and theta2. * Return type `float` - *property *length*: float*[¶](#Arc.length "Permalink to this definition") Arc length. * Return type `float` * discretize(*num=2*)[¶](#Arc.discretize "Permalink to this definition") Returns a discrete representation of the arc, as a list of Point objects. The amount of points can be specified using ‘num’, which should be larger than 1. * Return type `List`\[[`Point`](#Point "viktor.geometry.Point")] - revolve(*\**, *rotation\_angle=None*, *material=None*, *\*\*kwargs*)[¶](#Arc.revolve "Permalink to this definition") Returns an ArcRevolve object, revolved around the global y-axis. * Parameters * **rotation\_angle** (`Optional`\[`float`]) – Angle of the revolved object according to the right-hand-rule, with the start of the rotation in positive z-direction. Angle in radians. If not specified, 2 pi will be used. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material * Return type [`ArcRevolve`](#ArcRevolve "viktor.geometry.ArcRevolve") ## ArcRevolve[​](/sdk/13/api/geometry/.md#_ArcRevolve "Direct link to ArcRevolve") * *class *viktor.geometry.ArcRevolve(*arc*, *\*args*, *rotation\_angle=None*, *material=None*, *\*\*kwargs*)[¶](#ArcRevolve "Permalink to this definition") Bases: [`Revolve`](#Revolve "viktor.geometry.Revolve") Returns a revolved object of an arc around the global y-axis. In the example below, rotation\_angle is equal to pi / 3: [![/\_images/arc-revolve.png](/_images/arc-revolve.png)](/_images/arc-revolve.png) * Parameters * **arc** ([`Arc`](#Arc "viktor.geometry.Arc")) – Arc object. * **rotation\_angle** (`Optional`\[`float`]) – Angle of the revolved object according to the right-hand-rule, with the start of the rotation in positive z-direction. Angle in radians. If not specified, 2 pi will be used. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material - *property *arc*: [Arc](#Arc "viktor.geometry.Arc")*[¶](#ArcRevolve.arc "Permalink to this definition") [`Arc`](#Arc "viktor.geometry.Arc") * Return type [`Arc`](#Arc "viktor.geometry.Arc") * *property *uuid*: str*[¶](#ArcRevolve.uuid "Permalink to this definition") * Return type `str` - *property *surface\_area*: float*[¶](#ArcRevolve.surface_area "Permalink to this definition") Total exterior area of the object. * Return type `float` * *property *inner\_volume*: float*[¶](#ArcRevolve.inner_volume "Permalink to this definition") Returns the inner volume of the revolved object. This method will only return a value if the defined Arc meets the following conditions: > * it should be short, i.e. short\_arc=True > > * the start- and end-point are located on the same side w\.r.t. the y-axis of the center-point of the Arc > > * it is defined in clockwise direction * Return type `float` - *property *height*: float*[¶](#ArcRevolve.height "Permalink to this definition") Height of the object. * Return type `float` ## Triangle[​](/sdk/13/api/geometry/.md#_Triangle "Direct link to Triangle") * *class *viktor.geometry.Triangle(*point1*, *point2*, *point3*)[¶](#Triangle "Permalink to this definition") Creates a Triangle object from 3D vertices. * Parameters * **point1** ([`Point`](#Point "viktor.geometry.Point")) – First vertex. * **point2** ([`Point`](#Point "viktor.geometry.Point")) – Second vertex. * **point3** ([`Point`](#Point "viktor.geometry.Point")) – Third vertex. - area()[¶](#Triangle.area "Permalink to this definition") Returns the area of the triangle. * Return type `float` * *property *centroid*: Tuple\[float, float, float]*[¶](#Triangle.centroid "Permalink to this definition") Returns the centroid (X, Y, Z) of the triangle. * Return type `Tuple`\[`float`, `float`, `float`] - *property *moment\_of\_inertia*: Tuple\[float, float]*[¶](#Triangle.moment_of_inertia "Permalink to this definition") Returns the moment of inertia (Ix, Iy) (only in x-y plane). * Return type `Tuple`\[`float`, `float`] ## CartesianAxes[​](/sdk/13/api/geometry/.md#_CartesianAxes "Direct link to CartesianAxes") * *class *viktor.geometry.CartesianAxes(*origin=Point(0.000e+00, 0.000e+00, 0.000e+00)*, *axis\_length=1*, *axis\_diameter=0.05*)[¶](#CartesianAxes "Permalink to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Helper visualisation object to show positive x (red), y (green) and z (blue) axes. [![/\_images/cartesian-axes.png](/_images/cartesian-axes.png)](/_images/cartesian-axes.png) * Parameters * **origin** ([`Point`](#Point "viktor.geometry.Point")) – Coordinates of the origin. * **axis\_length** (`float`) – Length of the axes. * **axis\_diameter** (`float`) – Diameter of the axes. ## RDWGSConverter[​](/sdk/13/api/geometry/.md#_RDWGSConverter "Direct link to RDWGSConverter") * *class *viktor.geometry.RDWGSConverter[¶](#RDWGSConverter "Permalink to this definition") Class that provides functions to translate latitude and longitude coordinates between the WGS system and RD system. The RD coordinate system is a cartesian coordinate system that is frequently used for in civil engineering to describe locations in the Netherlands. The origin is located in france, so that for all of the Netherlands, both x (m) and y (m) values are positive and y is always larger then x. The domain in which the RD coordinate system is valid is: * x: \[-7000, 300000] * y: \[289000, 629000] About the RD coordinate system: * X0* = 155000*[¶](#RDWGSConverter.X0 "Permalink to this definition") - Y0* = 463000*[¶](#RDWGSConverter.Y0 "Permalink to this definition") * phi0* = 52.1551744*[¶](#RDWGSConverter.phi0 "Permalink to this definition") - lam0* = 5.38720621*[¶](#RDWGSConverter.lam0 "Permalink to this definition") * *static *from\_rd\_to\_wgs(*coords*)[¶](#RDWGSConverter.from_rd_to_wgs "Permalink to this definition") Convert RD coordinates (x, y) to WGS coordinates \[latitude, longitude]. ``` lat, lon = RDWGSConverter.from_rd_to_wgs((100000, 400000)) ``` * Parameters **coords** (`Tuple`\[`float`, `float`]) – RD coordinates (x, y) * Return type `List`\[`float`] - *static *from\_wgs\_to\_rd(*coords*)[¶](#RDWGSConverter.from_wgs_to_rd "Permalink to this definition") Convert WGS coordinates (latitude, longitude) to RD coordinates \[x, y]. ``` x, y = RDWGSConverter.from_wgs_to_rd((51.58622, 4.59360)) ``` * Parameters **coords** (`Tuple`\[`float`, `float`]) – WGS coordinates (latitude, longitude) * Return type `List`\[`float`] ## spherical\_to\_cartesian[​](/sdk/13/api/geometry/.md#_spherical_to_cartesian "Direct link to spherical_to_cartesian") * viktor.geometry.spherical\_to\_cartesian(*spherical\_coordinates*)[¶](#spherical_to_cartesian "Permalink to this definition") Using ISO/physical convention: * Parameters **spherical\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Spherical coordinates (r, theta, phi). * Return type `ndarray` * Returns Cartesian coordinates (x, y, z). ## cartesian\_to\_spherical[​](/sdk/13/api/geometry/.md#_cartesian_to_spherical "Direct link to cartesian_to_spherical") * viktor.geometry.cartesian\_to\_spherical(*cartesian\_coordinates*)[¶](#cartesian_to_spherical "Permalink to this definition") Using ISO/physical convention: * Parameters **cartesian\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cartesian coordinates (x, y, z). * Return type `ndarray` * Returns Spherical coordinates (r, theta, phi). ## cylindrical\_to\_cartesian[​](/sdk/13/api/geometry/.md#_cylindrical_to_cartesian "Direct link to cylindrical_to_cartesian") * viktor.geometry.cylindrical\_to\_cartesian(*cylindrical\_coordinates*)[¶](#cylindrical_to_cartesian "Permalink to this definition") Using ISO convention: Reference plane is former Cartesian xy-plane and cylindrical axis is the Cartesian z-axis. * Parameters **cylindrical\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cylindrical coordinates (rho, phi, z). * Return type `ndarray` * Returns Cartesian coordinates (x, y, z). ## cartesian\_to\_cylindrical[​](/sdk/13/api/geometry/.md#_cartesian_to_cylindrical "Direct link to cartesian_to_cylindrical") * viktor.geometry.cartesian\_to\_cylindrical(*cartesian\_coordinates*)[¶](#cartesian_to_cylindrical "Permalink to this definition") Using ISO convention: Reference plane is former Cartesian xy-plane and cylindrical axis is the Cartesian z-axis. * Parameters **cartesian\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cartesian coordinates (x, y, z). * Return type `ndarray` * Returns Cylindrical coordinates (rho, phi, z) with phi between -pi and +pi. ## Extrusion[​](/sdk/13/api/geometry/.md#_Extrusion "Direct link to Extrusion") * *class *viktor.geometry.Extrusion(*profile*, *line*, *profile\_rotation=0*, *\**, *material=None*)[¶](#Extrusion "Permalink to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Extruded object from a given set of points, which is called the profile. This profile should meet the following requirements: > * start point should be added at the end for closed profile > > * points should be defined in z=0 plane > > * circumference should be defined clockwise Note that the profile is defined with respect to the start point of the Line object, i.e. the profile is defined in the local coordinate system. An example is given below of two extrusions with the same dimensions. Their corresponding Line objects are also visualized. The extrusion have the following profile: ``` # black box profile_b = [ Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1), Point(1, 1), ] box_b = Extrusion(profile_b, Line(Point(4, 1, 0), Point(4, 1, 1))) # yellow box profile_y = [ Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5), Point(0.5, -0.5), Point(-0.5, -0.5), ] box_y = Extrusion(profile_y, Line(Point(2, 2, 0), Point(2, 2, 1))) ``` [![/\_images/extrusion-profile.png](/_images/extrusion-profile.png)](/_images/extrusion-profile.png) * Parameters * **profile** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Coordinates of cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material - *property *profile*: List\[[Point](#Point "viktor.geometry.Point")]*[¶](#Extrusion.profile "Permalink to this definition") * Return type `List`\[[`Point`](#Point "viktor.geometry.Point")] * *property *material*: [Material](#Material "viktor.geometry.Material")*[¶](#Extrusion.material "Permalink to this definition") * Return type [`Material`](#Material "viktor.geometry.Material") - *property *line*: [Line](#Line "viktor.geometry.Line")*[¶](#Extrusion.line "Permalink to this definition") * Return type [`Line`](#Line "viktor.geometry.Line") * *property *length*: float*[¶](#Extrusion.length "Permalink to this definition") * Return type `float` ## ArcExtrusion[​](/sdk/13/api/geometry/.md#_ArcExtrusion "Direct link to ArcExtrusion") * *class *viktor.geometry.ArcExtrusion(*profile*, *arc*, *profile\_rotation=0*, *n\_segments=50*, *\**, *material=None*)[¶](#ArcExtrusion "Permalink to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Given an Arc and a cross-section of the extrusion, a discretized Extrusion object is returned. The coordinates of the profile are defined with respect to the Arc and have a LOCAL coordinate system: > * z-axis is in direction of the arc from start to end. > > * x-axis is in positive global z-axis. > > * y-axis follows from the right-hand-rule. Rotation of the profile is about the axis according to the right-hand-rule with LOCAL z-axis (see definition above). Example: ``` profile = [ Point(1, 1), Point(1, 2), Point(3, 2), Point(3, 1), Point(1, 1), ] arc = Arc(Point(1, 1, 0), Point(3, 1, 0), Point(1, 3, 0)) arc_ext = ArcExtrusion(profile, arc, profile_rotation=10, n_segments=10) ``` This will result in the following visualization, where the Arc itself is also shown in the xy plane: [![/\_images/arc-extrusion.png](/_images/arc-extrusion.png)](/_images/arc-extrusion.png) * Parameters * **profile** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Coordinates of cross-section. * **arc** ([`Arc`](#Arc "viktor.geometry.Arc")) – An Arc object is used to define the direction of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around its local Z-axis in degrees. * **n\_segments** (`int`) – Number of discrete segments of the arc, which is 50 by default. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material ## CircularExtrusion[​](/sdk/13/api/geometry/.md#_CircularExtrusion "Direct link to CircularExtrusion") * *class *viktor.geometry.CircularExtrusion(*diameter*, *line*, *\**, *shell\_thickness=None*, *open\_ends=False*, *material=None*)[¶](#CircularExtrusion "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") This class is used to construct an extrusion which has a circular base, e.g. a circular foundation pile. * Parameters * **diameter** (`float`) – Outer diameter of the cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object along which the circular cross-section is extruded. * **shell\_thickness** (`Optional`\[`float`]) – Optional shell thickness. None for solid (default: None) New in v13.6.0 . * **open\_ends** (`bool`) – Deprecated, please use ‘shell\_thickness’ instead. Note that ‘open\_ends’ takes precedence over ‘shell\_thickness’. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – Optional material. - *property *line*: [Line](#Line "viktor.geometry.Line")*[¶](#CircularExtrusion.line "Permalink to this definition") * Return type [`Line`](#Line "viktor.geometry.Line") * *property *length*: float*[¶](#CircularExtrusion.length "Permalink to this definition") * Return type `float` - *property *diameter*: float*[¶](#CircularExtrusion.diameter "Permalink to this definition") * Return type `float` * *property *radius*: float*[¶](#CircularExtrusion.radius "Permalink to this definition") * Return type `float` - *property *shell\_thickness*: Optional\[float]*[¶](#CircularExtrusion.shell_thickness "Permalink to this definition") * Return type `Optional`\[`float`] * *property *cross\_sectional\_area*: float*[¶](#CircularExtrusion.cross_sectional_area "Permalink to this definition") * Return type `float` ## RectangularExtrusion[​](/sdk/13/api/geometry/.md#_RectangularExtrusion "Direct link to RectangularExtrusion") * *class *viktor.geometry.RectangularExtrusion(*width*, *height*, *line*, *profile\_rotation=0*, *\**, *material=None*)[¶](#RectangularExtrusion "Permalink to this definition") Bases: [`Extrusion`](#Extrusion "viktor.geometry.Extrusion") Extruded object from a given set of points, which is called the profile. This profile should meet the following requirements: > * start point should be added at the end for closed profile > > * points should be defined in z=0 plane > > * circumference should be defined clockwise Note that the profile is defined with respect to the start point of the Line object, i.e. the profile is defined in the local coordinate system. An example is given below of two extrusions with the same dimensions. Their corresponding Line objects are also visualized. The extrusion have the following profile: ``` # black box profile_b = [ Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1), Point(1, 1), ] box_b = Extrusion(profile_b, Line(Point(4, 1, 0), Point(4, 1, 1))) # yellow box profile_y = [ Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5), Point(0.5, -0.5), Point(-0.5, -0.5), ] box_y = Extrusion(profile_y, Line(Point(2, 2, 0), Point(2, 2, 1))) ``` [![/\_images/extrusion-profile.png](/_images/extrusion-profile.png)](/_images/extrusion-profile.png) * Parameters * **profile** – Coordinates of cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material - *property *width*: float*[¶](#RectangularExtrusion.width "Permalink to this definition") Width of the extrusion. * Return type `float` * *property *height*: float*[¶](#RectangularExtrusion.height "Permalink to this definition") Height of the extrusion. * Return type `float` - *property *cross\_sectional\_area*: float*[¶](#RectangularExtrusion.cross_sectional_area "Permalink to this definition") Returns the area of the cross-section (width x height). * Return type `float` * *property *inner\_volume*: float*[¶](#RectangularExtrusion.inner_volume "Permalink to this definition") Returns the inner volume of the extruded object. * Return type `float` ## SquareBeam[​](/sdk/13/api/geometry/.md#_SquareBeam "Direct link to SquareBeam") * *class *viktor.geometry.SquareBeam(*length\_x*, *length\_y*, *length\_z*, *\**, *material=None*)[¶](#SquareBeam "Permalink to this definition") Bases: [`RectangularExtrusion`](#RectangularExtrusion "viktor.geometry.RectangularExtrusion") High level object to create a rectangular beam object around the origin. The centroid of the beam is located at the origin (0, 0, 0). * Parameters * **length\_x** (`float`) – Width of the extrusion in x-direction. * **length\_y** (`float`) – Length of the extrusion in y-direction. * **length\_z** (`float`) – Height of the extrusion in z-direction. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material ## points\_are\_coplanar[​](/sdk/13/api/geometry/.md#_points_are_coplanar "Direct link to points_are_coplanar") * viktor.geometry.points\_are\_coplanar(*points*)[¶](#points_are_coplanar "Permalink to this definition") Determine whether all given points are coplanar (are on a two-dimensional plane). * Parameters **points** (`Sequence`\[`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]]) – points to be evaluated (min. 3). Example usage: ``` points = [[Point(0, 3, 1), Point(0, 5, 1), Point(2, 3, 4), Point(2, 5, 4)]] coplanar = points_are_coplanar(points) coplanar = points_are_coplanar([(0, 3, 1), (0, 5, 1), (2, 3, 4), (2, 5, 4)]) ``` * Return type `bool` ## lines\_in\_same\_plane[​](/sdk/13/api/geometry/.md#_lines_in_same_plane "Direct link to lines_in_same_plane") * viktor.geometry.lines\_in\_same\_plane(*line1*, *line2*)[¶](#lines_in_same_plane "Permalink to this definition") Method to determine whether two Line objects are located in a shared plane and hence are coplanar. * Parameters * **line1** ([`Line`](#Line "viktor.geometry.Line")) – First line object. * **line2** ([`Line`](#Line "viktor.geometry.Line")) – Second line object. * Return type `bool` ## calculate\_distance\_vector[​](/sdk/13/api/geometry/.md#_calculate_distance_vector "Direct link to calculate_distance_vector") * viktor.geometry.calculate\_distance\_vector(*start\_point*, *end\_point*)[¶](#calculate_distance_vector "Permalink to this definition") Calculates the distance between start and end point in the direction start -> end. * Parameters * **start\_point** ([`Point`](#Point "viktor.geometry.Point")) – Start position of the distance vector. * **end\_point** ([`Point`](#Point "viktor.geometry.Point")) – End position of the distance vector. * Return type `ndarray` ## convert\_points\_for\_lathe[​](/sdk/13/api/geometry/.md#_convert_points_for_lathe "Direct link to convert_points_for_lathe") * viktor.geometry.convert\_points\_for\_lathe(*points*)[¶](#convert_points_for_lathe "Permalink to this definition") Method can be used to convert Point objects to lists of dictionaries in the format: {‘x’: point.x, ‘y’: point.y} * Parameters **points** (`Sequence`\[[`Point`](#Point "viktor.geometry.Point")]) – Point objects. * Return type `List`\[`dict`] ## translation\_matrix[​](/sdk/13/api/geometry/.md#_translation_matrix "Direct link to translation_matrix") * viktor.geometry.translation\_matrix(*direction*)[¶](#translation_matrix "Permalink to this definition") Returns the translation matrix that corresponds to a give direction vector (3D). * Parameters **direction** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Direction vector of the translation. * Return type `ndarray` ## scaling\_matrix[​](/sdk/13/api/geometry/.md#_scaling_matrix "Direct link to scaling_matrix") * viktor.geometry.scaling\_matrix(*scaling\_vector*)[¶](#scaling_matrix "Permalink to this definition") Returns the scaling matrix that corresponds to a given scaling vector (3D). * Parameters **scaling\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Three-dimensional scaling vector. * Return type `ndarray` ## rotation\_matrix[​](/sdk/13/api/geometry/.md#_rotation_matrix "Direct link to rotation_matrix") * viktor.geometry.rotation\_matrix(*angle*, *direction*, *point=None*)[¶](#rotation_matrix "Permalink to this definition") Returns the rotation matrix that corresponds to a rotation about an axis defined by a point and direction. Angle in radians, direction in accordance to right-hand rule. Example: ``` R = rotation_matrix(pi/2, [0, 0, 1], [1, 0, 0]) np.allclose(np.dot(R, [0, 0, 0, 1]), [1, -1, 0, 1]) # True ``` * Return type `ndarray` ## reflection\_matrix[​](/sdk/13/api/geometry/.md#_reflection_matrix "Direct link to reflection_matrix") * viktor.geometry.reflection\_matrix(*point*, *normal*)[¶](#reflection_matrix "Permalink to this definition") Returns the reflection matrix to mirror at a plane defined by a point and a normal vector. * Parameters * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point object. * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Normal vector of the mirror plane. * Return type `ndarray` ## unit\_vector[​](/sdk/13/api/geometry/.md#_unit_vector "Direct link to unit_vector") * viktor.geometry.unit\_vector(*data*, *axis=None*, *out=None*)[¶](#unit_vector "Permalink to this definition") Returns the unit vector of a given vector. * Return type `ndarray` ## mirror\_object[​](/sdk/13/api/geometry/.md#_mirror_object "Direct link to mirror_object") * viktor.geometry.mirror\_object(*obj*, *point*, *normal*)[¶](#mirror_object "Permalink to this definition") Function that mirrors an object through a plane. The plane is defined by a point and a normal vector. The return is a copy of the original object, mirrored over the specified plane. * Parameters * **obj** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – Object that is to be mirrored * **point** ([`Point`](#Point "viktor.geometry.Point")) – Point object on the desired mirror plane * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector that denotes a normal vector of the desired mirror plane. * Return type [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") ## volume\_cone[​](/sdk/13/api/geometry/.md#_volume_cone "Direct link to volume_cone") * viktor.geometry.volume\_cone(*r*, *h*)[¶](#volume_cone "Permalink to this definition") Calculates the volume of a cone. * Parameters * **r** (`float`) – Radius of the base. * **h** (`float`) – Height of the cone. * Return type `float` ## surface\_cone\_without\_base[​](/sdk/13/api/geometry/.md#_surface_cone_without_base "Direct link to surface_cone_without_base") * viktor.geometry.surface\_cone\_without\_base(*r*, *h*)[¶](#surface_cone_without_base "Permalink to this definition") Calculates the exterior surface of the cone, excluding the area of the circular base. * Parameters * **r** (`float`) – Radius of the base. * **h** (`float`) – Height of the cone. * Return type `float` ## surface\_area\_dome[​](/sdk/13/api/geometry/.md#_surface_area_dome "Direct link to surface_area_dome") * viktor.geometry.surface\_area\_dome(*theta1*, *theta2*, *r*, *R*)[¶](#surface_area_dome "Permalink to this definition") Computes the surface area of a dome (arc-revolve). * Parameters * **theta1** (`float`) – Starting angle of arc in radians. * **theta2** (`float`) – Ending angle of arc in radians. * **r** (`float`) – Radius of arc. * **R** (`float`) – Distance from centre of arc to rotation line. * Return type `float` * Returns surface area of arc-revolve. ## hex\_to\_rgb[​](/sdk/13/api/geometry/.md#_hex_to_rgb "Direct link to hex_to_rgb") * viktor.geometry.hex\_to\_rgb(*value*)[¶](#hex_to_rgb "Permalink to this definition") Return (red, green, blue) for the color given as #rrggbb. * Return type `Tuple`\[`int`, `...`] ## rgb\_to\_hex[​](/sdk/13/api/geometry/.md#_rgb_to_hex "Direct link to rgb_to_hex") * viktor.geometry.rgb\_to\_hex(*red*, *green*, *blue*, *include\_hashtag=True*)[¶](#rgb_to_hex "Permalink to this definition") Return color as #rrggbb for the given color values. * Return type `str` ## circumference\_is\_clockwise[​](/sdk/13/api/geometry/.md#_circumference_is_clockwise "Direct link to circumference_is_clockwise") * viktor.geometry.circumference\_is\_clockwise(*circumference*)[¶](#circumference_is_clockwise "Permalink to this definition") * Method determines the direction of a set of points, and returns: * True if the circumference is clockwise * False if the circumference is counter-clockwise - Parameters **circumference** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Circumference in x,y-plane. - Return type `bool` ## add\_point[​](/sdk/13/api/geometry/.md#_add_point "Direct link to add_point") * viktor.geometry.add\_point(*unique\_points*, *point*)[¶](#add_point "Permalink to this definition") Adds a Point object to a unique list of Point objects. The point is only added when not already present in the list. * Parameters * **unique\_points** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – List of point objects. * **point** ([`Point`](#Point "viktor.geometry.Point")) – Point object which has to be added. * Return type `Tuple`\[`List`\[[`Point`](#Point "viktor.geometry.Point")], `int`] ## get\_vertices\_faces[​](/sdk/13/api/geometry/.md#_get_vertices_faces "Direct link to get_vertices_faces") * viktor.geometry.get\_vertices\_faces(*triangles*)[¶](#get_vertices_faces "Permalink to this definition") Returns the vertices and faces of a list of Triangle objects. * Parameters **triangles** (`List`\[[`Triangle`](#Triangle "viktor.geometry.Triangle")]) – List of triangle objects. * Return type `Tuple`\[`list`, `list`] ## find\_overlap[​](/sdk/13/api/geometry/.md#_find_overlap "Direct link to find_overlap") * viktor.geometry.find\_overlap(*region\_a*, *region\_b*, *inclusive=False*)[¶](#find_overlap "Permalink to this definition") Given to regions with upper and lower boundary, check if there is overlap and if so return a tuple with the overlap found The direction of the given regions does not matter: (1, 2) will be handled exactly the same as (2, 1) The returned Tuple will always be in ascending order Example usage: ``` find_overlap((2, 4), (3, 5)) -> (3, 4) find_overlap((4, 2), (5, 3)) -> (3, 4) find_overlap((2, 3), (3, 4)) -> None find_overlap((2, 3), (3, 4), inclusive=True) -> (3, 3) ``` * Parameters * **region\_a** (`Tuple`\[`float`, `float`]) – Tuple of values of the first region. * **region\_b** (`Tuple`\[`float`, `float`]) – Tuple of values of the second region. * **inclusive** (`bool`) – A flag to decide whether a point overlap is counted as overlap or not. * Return type `Optional`\[`Tuple`\[`float`, `float`]] * Returns A tuple with upper and lower bounds of the overlapping region, or None. ## Pattern[​](/sdk/13/api/geometry/.md#_Pattern "Direct link to Pattern") * *class *viktor.geometry.Pattern(*base\_object*, *duplicate\_translation\_list*)[¶](#Pattern "Permalink to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Instantiates a pattern based on a base object and several duplicates, each translated by an input vector. * Parameters * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **duplicate\_translation\_list** (`List`\[`List`\[`float`]]) – a list of translation vectors, each of which generates a duplicate ## LinearPattern[​](/sdk/13/api/geometry/.md#_LinearPattern "Direct link to LinearPattern") * *class *viktor.geometry.LinearPattern(*base\_object*, *direction*, *number\_of\_elements*, *spacing*)[¶](#LinearPattern "Permalink to this definition") Bases: [`Pattern`](#Pattern "viktor.geometry.Pattern") Instantiates a linear, evenly spaced, pattern along a single direction. * Parameters * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **direction** (`List`\[`float`]) – a unit vector specifying in which direction the pattern propagates * **number\_of\_elements** (`int`) – total amount of elements in the pattern, including the base object * **spacing** (`float`) – the applied spacing ## BidirectionalPattern[​](/sdk/13/api/geometry/.md#_BidirectionalPattern "Direct link to BidirectionalPattern") * *class *viktor.geometry.BidirectionalPattern(*base\_object*, *direction\_1*, *direction\_2*, *number\_of\_elements\_1*, *number\_of\_elements\_2*, *spacing\_1*, *spacing\_2*)[¶](#BidirectionalPattern "Permalink to this definition") Bases: [`Pattern`](#Pattern "viktor.geometry.Pattern") Instantiates a two-dimensional pattern, evenly spaced in two separate directions * Parameters * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **direction\_1** (`List`\[`float`]) – a unit vector specifying the first direction * **direction\_2** (`List`\[`float`]) – a unit vector specifying the second direction * **number\_of\_elements\_1** (`int`) – total amount of elements along direction 1 * **number\_of\_elements\_2** (`int`) – total amount of elements along direction 2 * **spacing\_1** (`float`) – the applied spacing in direction 1 * **spacing\_2** (`float`) – the applied spacing in direction 2 ## Polygon[​](/sdk/13/api/geometry/.md#_Polygon "Direct link to Polygon") * *class *viktor.geometry.Polygon(*points*, *\**, *surface\_orientation=False*, *material=None*, *skip\_duplicate\_vertices\_check=False*)[¶](#Polygon "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") 2D closed polygon without holes in x-y plane. * Parameters * **points** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – profile is automatically closed, do not add start point at the end. only the x and y coordinates are considered. left hand rule around circumference determines surface direction * **surface\_orientation** (`bool`) – * if True, the left hand rule around circumference determines surface direction * if False, surface always in +z direction * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material * **skip\_duplicate\_vertices\_check** (`bool`) – if True, duplicate vertices are not filtered on serialization of the triangles. This may boost performance (default: False). * Raises **ValueError** – * if less than 3 points are provided. * if points contains duplicates. * if points form a polygon with self-intersecting lines. * if points are all collinear. - has\_clockwise\_circumference()[¶](#Polygon.has_clockwise_circumference "Permalink to this definition") * Method determines the direction of the input points, and returns: * True if the circumference is clockwise * False if the circumference is counter-clockwise - Return type `bool` * *property *cross\_sectional\_area*: float*[¶](#Polygon.cross_sectional_area "Permalink to this definition") * Return type `float` - *property *centroid*: Tuple\[float, float]*[¶](#Polygon.centroid "Permalink to this definition") Returns the centroid (X, Y) of the polygon. * Return type `Tuple`\[`float`, `float`] * *property *moment\_of\_inertia*: Tuple\[float, float]*[¶](#Polygon.moment_of_inertia "Permalink to this definition") Returns the moment of inertia (Ix, Iy) in xy-plane. * Return type `Tuple`\[`float`, `float`] - extrude(*line*, *\**, *profile\_rotation=0*, *material=None*)[¶](#Polygon.extrude "Permalink to this definition") Extrude the Polygon in the direction of the given line. Polygon must be defined in clockwise direction. * Parameters * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material * Raises **ValueError** – if polygon is defined in anti-clockwise direction * Return type [`Extrusion`](#Extrusion "viktor.geometry.Extrusion") ## Polyline[​](/sdk/13/api/geometry/.md#_Polyline "Direct link to Polyline") * *class *viktor.geometry.Polyline(*points*, *\**, *color=Color(0, 0, 0)*)[¶](#Polyline "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Representation of a polyline made up of multiple straight line segments. This class is immutable, meaning that all functions that perform changes on a polyline will return a mutated copy of the original polyline. * Parameters * **points** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – List of points, which may contain duplicate points. Note that when calling the individual lines of the polyline, duplicate points are filtered (i.e. zero-length lines are omitted). * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . - *property *points*: List\[[Point](#Point "viktor.geometry.Point")]*[¶](#Polyline.points "Permalink to this definition") * Return type `List`\[[`Point`](#Point "viktor.geometry.Point")] * *classmethod *from\_lines(*lines*)[¶](#Polyline.from_lines "Permalink to this definition") Create a polyline object from a list of lines. The end of one line must always coincide with the start of the next line. * Parameters **lines** (`Sequence`\[[`Line`](#Line "viktor.geometry.Line")]) – Sequence of lines * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") - is\_equal\_to(*other*)[¶](#Polyline.is_equal_to "Permalink to this definition") Check if all points in this polyline coincide with all points of another polyline * Parameters **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – Other polyline * Return type `bool` * *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Polyline.start_point "Permalink to this definition") First point in polyline.points * Return type [`Point`](#Point "viktor.geometry.Point") - *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[¶](#Polyline.end_point "Permalink to this definition") Last point in polyline.points * Return type [`Point`](#Point "viktor.geometry.Point") * *property *lines*: List\[[Line](#Line "viktor.geometry.Line")]*[¶](#Polyline.lines "Permalink to this definition") A list of lines connecting all polyline points. Lines between coincident points are skipped. * Return type `List`\[[`Line`](#Line "viktor.geometry.Line")] - *property *x\_min*: Optional\[float]*[¶](#Polyline.x_min "Permalink to this definition") The lowest x-coordinate present within this polyline. * Return type `Optional`\[`float`] * *property *x\_max*: Optional\[float]*[¶](#Polyline.x_max "Permalink to this definition") The highest x-coordinate present within this polyline. * Return type `Optional`\[`float`] - *property *y\_min*: Optional\[float]*[¶](#Polyline.y_min "Permalink to this definition") The lowest y-coordinate present within this polyline. * Return type `Optional`\[`float`] * *property *y\_max*: Optional\[float]*[¶](#Polyline.y_max "Permalink to this definition") The highest y-coordinate present within this polyline. * Return type `Optional`\[`float`] - *property *z\_min*: Optional\[float]*[¶](#Polyline.z_min "Permalink to this definition") The lowest z-coordinate present within this polyline. * Return type `Optional`\[`float`] * *property *z\_max*: Optional\[float]*[¶](#Polyline.z_max "Permalink to this definition") The highest z-coordinate present within this polyline. * Return type `Optional`\[`float`] - get\_reversed\_polyline()[¶](#Polyline.get_reversed_polyline "Permalink to this definition") Returns a polyline that is the reverse of this one. * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") * serialize()[¶](#Polyline.serialize "Permalink to this definition") Return a json serializable dict of form: ``` [ {'x': point_1.x, 'y': point_1.y}, {'x': point_2.x, 'y': point_2.y} ] ``` * Return type `List`\[`dict`] - filter\_duplicate\_points()[¶](#Polyline.filter_duplicate_points "Permalink to this definition") Returns a new Polyline object. If two consecutive points in this polyline coincide, the second point will be omitted * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") * is\_monotonic\_ascending\_x(*strict=True*)[¶](#Polyline.is_monotonic_ascending_x "Permalink to this definition") Check if the x coordinates of the points of this polyline are ascending. * Parameters **strict** (`bool`) – when set to false, equal x coordinates are accepted between points * Return type `bool` - is\_monotonic\_ascending\_y(*strict=True*)[¶](#Polyline.is_monotonic_ascending_y "Permalink to this definition") Check if the y coordinates of the points of this polyline are ascending * Parameters **strict** (`bool`) – when set to false, equal y coordinates are accepted between points * Return type `bool` * intersections\_with\_polyline(*other\_polyline*)[¶](#Polyline.intersections_with_polyline "Permalink to this definition") Find all intersections with another polyline and return them ordered according to the direction of this polyline If the polylines are partly parallel, the start and end points of the parallel section will be returned as intersections. If one of the polylines is a subset of the other, or the two lines are completely parallel, no intersections will be found. * Parameters **other\_polyline** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – * Return type `List`\[[`Point`](#Point "viktor.geometry.Point")] - intersections\_with\_x\_location(*x*)[¶](#Polyline.intersections_with_x_location "Permalink to this definition") Find all intersections of this polyline with a given x location. Ordered from start to end of this polyline. If this line is partly vertical, the start and end points of the vertical section will be returned as an intersection. If this line is completely vertical, no intersections will be found. * Parameters **x** (`float`) – * Return type `List`\[[`Point`](#Point "viktor.geometry.Point")] * point\_is\_on\_polyline(*point*)[¶](#Polyline.point_is_on_polyline "Permalink to this definition") Check if a given point lies on this polyline * Parameters **point** ([`Point`](#Point "viktor.geometry.Point")) – * Return type `bool` - get\_polyline\_between(*start\_point*, *end\_point*, *inclusive=False*)[¶](#Polyline.get_polyline_between "Permalink to this definition") Given two points that both lie on a polyline, return the polyline that lies between those two points start\_point has to lie before end\_point on this polyline. If the given start point lies after the given end point on this polyline, an empty polyline will be returned. If the two given points are identical, it depends on the inclusive flag whether a polyline containing that point once, or an empty polyline will be returned. * Parameters * **start\_point** ([`Point`](#Point "viktor.geometry.Point")) – * **end\_point** ([`Point`](#Point "viktor.geometry.Point")) – * **inclusive** (`bool`) – if true, the start and the end points will be added to the returned list * Raises **ValueError** – when one of the two given points does not lie on this polyline * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") * find\_overlaps(*other*)[¶](#Polyline.find_overlaps "Permalink to this definition") Find all overlapping regions of this polyline with another polyline. The returned overlapping regions will all point in the direction of this line. The overlap polylines will contain all points of both polylines, even if they only occur in one of the lines. If no overlaps are found, an empty list will be returned. * Parameters **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – * Return type `List`\[[`Polyline`](#Polyline "viktor.geometry.Polyline")] - combine\_with(*other*)[¶](#Polyline.combine_with "Permalink to this definition") Given two polylines that have at least one point in common and together form one line without any side branches, combine those two polylines. The combined line will contain all points of both polylines. * Parameters **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") * split(*point*)[¶](#Polyline.split "Permalink to this definition") return the two separate parts of this polyline before and after the given point. * Parameters **point** ([`Point`](#Point "viktor.geometry.Point")) – * Raises **ValueError** – if the provided point does not lie on this polyline. * Return type `Tuple`\[[`Polyline`](#Polyline "viktor.geometry.Polyline"), [`Polyline`](#Polyline "viktor.geometry.Polyline")] - *classmethod *get\_lowest\_or\_highest\_profile\_x(*profile\_1*, *profile\_2*, *lowest*)[¶](#Polyline.get_lowest_or_highest_profile_x "Permalink to this definition") Given two polylines with n intersections, return a third polyline that will always follow the lowest (or highest) of the two lines the x locations of the points of the two polylines should be not descending (lines from left to right or vertical) the returned polyline will only cover the overlapping range in x coordinates. If one of the profiles is an empty polyline, an empty polyline will be returned. examples: ``` /----------------| / /-------|-------------------- profile_1: ----------------\ / / | \ / / |_____________________________ profile_2: -------------\-/ / \_________/ get_lowest_or_highest_profile_x(cls, profile_1, profile_2, lowest=True) will return: /-------| / | / |____________________ result: -------------\ / \_________/ ``` Note that only the overlapping region of the two profiles is returned! * Parameters * **profile\_1** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – * **profile\_2** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – * **lowest** (`bool`) – switch to decide whether to return highest or lowest profile Currently, this implementation is exclusive. Meaning that vertical line parts that lie on the start or end of the overlap region in x are not taken into account. * Return type [`Polyline`](#Polyline "viktor.geometry.Polyline") ## Cone[​](/sdk/13/api/geometry/.md#_Cone "Direct link to Cone") * *class *viktor.geometry.Cone(*diameter*, *height*, *\**, *origin=None*, *orientation=None*, *material=None*)[¶](#Cone "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Creates a cone object. * Parameters * **diameter** (`float`) – Diameter of the circular base surface. * **height** (`float`) – Height from base to tip. * **origin** (`Optional`\[[`Point`](#Point "viktor.geometry.Point")]) – Optional location of the centroid of the base surface (default: Point(0, 0, 0)). * **orientation** (`Optional`\[[`Vector`](#Vector "viktor.geometry.Vector")]) – Optional orientation from origin to the tip (default: Vector(0, 0, 1)). * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – Optional material. - *classmethod *from\_line(*diameter*, *line*, *\**, *material=None*)[¶](#Cone.from_line "Permalink to this definition") Create a Cone object by a given base diameter and line. * Parameters * **diameter** (`float`) – Diameter of the circular base surface. * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line from base to top of the cone. The start point of the line represents the location of the center of the base, and the end point represents the tip of the cone. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – Optional material. * Return type [`Cone`](#Cone "viktor.geometry.Cone") ## Sphere[​](/sdk/13/api/geometry/.md#_Sphere "Direct link to Sphere") * *class *viktor.geometry.Sphere(*centre\_point*, *radius*, *width\_segments=30*, *height\_segments=30*, *material=None*)[¶](#Sphere "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") This class can be used to construct a spherical object around the specified coordinate. The smoothness of the edges can be altered by setting width\_segments and height\_segments. In the example below both the default smoothness of 30 (left) and a rough sphere with 5 segments (right) is shown: [![/\_images/sphere.png](/_images/sphere.png)](/_images/sphere.png) * Parameters * **centre\_point** ([`Point`](#Point "viktor.geometry.Point")) – Center point of the sphere. * **radius** (`float`) – Radius of the sphere. * **width\_segments** (`float`) – Sets the smoothness in xz-plane. * **height\_segments** (`float`) – Sets the smoothness in yz-plane. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – Optionally a custom material can be set. - diameter()[¶](#Sphere.diameter "Permalink to this definition") * Return type `float` * circumference()[¶](#Sphere.circumference "Permalink to this definition") * Return type `float` - surface\_area()[¶](#Sphere.surface_area "Permalink to this definition") * Return type `float` * volume()[¶](#Sphere.volume "Permalink to this definition") * Return type `float` ## Torus[​](/sdk/13/api/geometry/.md#_Torus "Direct link to Torus") * *class *viktor.geometry.Torus(*radius\_cross\_section*, *radius\_rotation\_axis*, *rotation\_angle=6.283185307179586*, *\**, *material=None*)[¶](#Torus "Permalink to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Create a torus object * Parameters * **radius\_cross\_section** (`float`) – * **radius\_rotation\_axis** (`float`) – measured from central axis to centre of cross-section. * **rotation\_angle** (`float`) – optional argument to control how large of a torus section you want. 2pi for complete torus * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material - *property *inner\_volume*: float*[¶](#Torus.inner_volume "Permalink to this definition") * Return type `float` * *property *material*: [Material](#Material "viktor.geometry.Material")*[¶](#Torus.material "Permalink to this definition") * Return type [`Material`](#Material "viktor.geometry.Material") ## TriangleAssembly[​](/sdk/13/api/geometry/.md#_TriangleAssembly "Direct link to TriangleAssembly") * *class *viktor.geometry.TriangleAssembly(*triangles*, *\**, *material=None*, *skip\_duplicate\_vertices\_check=False*)[¶](#TriangleAssembly "Permalink to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Fundamental visualisation geometry, built up from triangles. Right hand rule on triangle circumference determines the surface direction. * Parameters * **triangles** (`List`\[[`Triangle`](#Triangle "viktor.geometry.Triangle")]) – Triangles of the assembly. * **material** (`Optional`\[[`Material`](#Material "viktor.geometry.Material")]) – optional material. * **skip\_duplicate\_vertices\_check** (`bool`) – if True, duplicate vertices are not filtered on serialization of the triangles. This may boost performance (default: False). ## GeoPoint[​](/sdk/13/api/geometry/.md#_GeoPoint "Direct link to GeoPoint") * *class *viktor.geometry.GeoPoint(*lat*, *lon*)[¶](#GeoPoint "Permalink to this definition") Geographical point on the Earth’s surface described by a latitude / longitude coordinate pair. This object can be created directly, or will be returned in the params when using a [`GeoPointField`](/sdk/13/api/parametrization/.md#GeoPointField "viktor.parametrization.GeoPointField"). * Parameters * **lat** (`float`) – Latitude, between -90 and 90 degrees. * **lon** (`float`) – Longitude, between -180 and 180 degrees. - *classmethod *from\_rd(*coords*)[¶](#GeoPoint.from_rd "Permalink to this definition") Instantiates a GeoPoint from the provided RD coordinates. * Parameters **coords** (`Tuple`\[`float`, `float`]) – RD coordinates (x, y). * Return type [`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint") * *property *rd*: Tuple\[float, float]*[¶](#GeoPoint.rd "Permalink to this definition") RD representation (x, y) of the GeoPoint. * Return type `Tuple`\[`float`, `float`] ## GeoPolyline[​](/sdk/13/api/geometry/.md#_GeoPolyline "Direct link to GeoPolyline") * *class *viktor.geometry.GeoPolyline(*\*points*)[¶](#GeoPolyline "Permalink to this definition") Geographical polyline on the Earth’s surface described by a list of [`GeoPoints`](#GeoPoint "viktor.geometry.GeoPoint"). This object can be created directly, or will be returned in the params when using a [`GeoPolylineField`](/sdk/13/api/parametrization/.md#GeoPolylineField "viktor.parametrization.GeoPolylineField"). * Parameters **points** ([`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")) – Geo points (minimum 2). - *property *points*: List\[[GeoPoint](#GeoPoint "viktor.geometry.GeoPoint")]*[¶](#GeoPolyline.points "Permalink to this definition") * Return type `List`\[[`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")] ## GeoPolygon[​](/sdk/13/api/geometry/.md#_GeoPolygon "Direct link to GeoPolygon") * *class *viktor.geometry.GeoPolygon(*\*points*)[¶](#GeoPolygon "Permalink to this definition") Geographical polygon on the Earth’s surface described by a list of [`GeoPoints`](#GeoPoint "viktor.geometry.GeoPoint"). This object can be created directly, or will be returned in the params when using a [`GeoPolygonField`](/sdk/13/api/parametrization/.md#GeoPolygonField "viktor.parametrization.GeoPolygonField"). * Parameters **points** ([`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")) – Geo points (minimum 3). The profile is automatically closed, so it is not necessary to add the start point at the end. - *property *points*: List\[[GeoPoint](#GeoPoint "viktor.geometry.GeoPoint")]*[¶](#GeoPolygon.points "Permalink to this definition") * Return type `List`\[[`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")] --- # viktor.parametrization ## Interaction[​](/sdk/13/api/parametrization/.md#_Interaction "Direct link to Interaction") * *class *viktor.parametrization.Interaction(*view*, *selection=None*)[¶](#Interaction "Permalink to this definition") Bases: `ABC` * Parameters * **view** (`str`) – method name of the view to be interacted with. * **selection** (`Optional`\[`Sequence`\[`str`]]) – only features/objects within selected interaction groups can be interacted with. Interaction groups can be created on the view result (e.g. `MapResult`) using ‘interaction\_groups’. None, to enable interaction with all features/objects with ‘identifier’ assigned, ignoring interaction groups (default: None). ## MapSelectInteraction[​](/sdk/13/api/parametrization/.md#_MapSelectInteraction "Direct link to MapSelectInteraction") * *class *viktor.parametrization.MapSelectInteraction(*view*, *\**, *selection=None*, *min\_select=1*, *max\_select=None*)[¶](#MapSelectInteraction "Permalink to this definition") Bases: [`Interaction`](#Interaction "viktor.parametrization.Interaction") New in v13.2.0 Interaction for the selection of feature(s) in a map view. See [`Interaction`](#Interaction "viktor.parametrization.Interaction") for parameters. Additional parameters: * Parameters * **min\_select** (`int`) – minimum number of features a user must select (>=1). * **max\_select** (`Optional`\[`int`]) – maximum number of features a user may select. None for no limit (default: None). Example: ``` button = ActionButton(..., interaction=MapSelectInteraction('my_map_view', selection=['points'])) ``` ## DownloadButton[​](/sdk/13/api/parametrization/.md#_DownloadButton "Direct link to DownloadButton") * *class *viktor.parametrization.DownloadButton(*ui\_name*, *method*, *longpoll=False*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[¶](#DownloadButton "Permalink to this definition") Bases: `_ActionButton` Action button which can be pressed to download a result to a file. Example usage: ``` # in parametrization: download_btn = DownloadButton("Download file", "get_download_result", longpoll=True) # in controller: def get_download_result(self, params, **kwargs): return DownloadResult(file_content='file_content', file_name='some_file.txt') ``` * Parameters * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – Set this to True if the action button has to remain available for users that do not have permission to make any changes in the editor. This gives such users the ability to for example still download product reports. * **flex** (`Optional`\[`int`]) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** (`Optional`\[[`Interaction`](#Interaction "viktor.parametrization.Interaction")]) – Enable view interaction through this button New in v13.2.0 ## ActionButton[​](/sdk/13/api/parametrization/.md#_ActionButton "Direct link to ActionButton") * *class *viktor.parametrization.ActionButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[¶](#ActionButton "Permalink to this definition") Bases: `_ActionButton` Action button which can be pressed to perform a (heavy) calculation without returning a result. Example usage: ``` # in parametrization: calculation_btn = ActionButton("Analysis", "calculation", longpoll=True) # in controller: def calculation(self, params, **kwargs): # perform calculation, no return necessary ``` * Parameters * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – Set this to True if the action button has to remain available for users that do not have permission to make any changes in the editor. This gives such users the ability to for example still download product reports. * **flex** (`Optional`\[`int`]) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** (`Optional`\[[`Interaction`](#Interaction "viktor.parametrization.Interaction")]) – Enable view interaction through this button New in v13.2.0 ## AnalyseButton[​](/sdk/13/api/parametrization/.md#_AnalyseButton "Direct link to AnalyseButton") * viktor.parametrization.AnalyseButton[¶](#AnalyseButton "Permalink to this definition") alias of [`ActionButton`](#ActionButton "viktor.parametrization.ActionButton") ## OptimizationButton[​](/sdk/13/api/parametrization/.md#_OptimizationButton "Direct link to OptimizationButton") * *class *viktor.parametrization.OptimizationButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[¶](#OptimizationButton "Permalink to this definition") Bases: `_ActionButton` Action button which can be pressed to perform an optimization routine. Example usage: ``` # in parametrization: optimize_btn = OptimizationButton("Optimization", "get_optimal_result", longpoll=True) # in controller: def get_optimal_result(self, params, **kwargs): # specific optimization routine ... return OptimizationResult(results) ``` * Parameters * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – Set this to True if the action button has to remain available for users that do not have permission to make any changes in the editor. This gives such users the ability to for example still download product reports. * **flex** (`Optional`\[`int`]) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** (`Optional`\[[`Interaction`](#Interaction "viktor.parametrization.Interaction")]) – Enable view interaction through this button New in v13.2.0 ## OptimiseButton[​](/sdk/13/api/parametrization/.md#_OptimiseButton "Direct link to OptimiseButton") * viktor.parametrization.OptimiseButton[¶](#OptimiseButton "Permalink to this definition") alias of [`OptimizationButton`](#OptimizationButton "viktor.parametrization.OptimizationButton") ## SetParamsButton[​](/sdk/13/api/parametrization/.md#_SetParamsButton "Direct link to SetParamsButton") * *class *viktor.parametrization.SetParamsButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[¶](#SetParamsButton "Permalink to this definition") Bases: `_ActionButton` Action button which can be pressed to perform an analysis and override current input fields. Example usage: ``` # in parametrization: set_params_btn = SetParamsButton("Set params", "set_param_a", longpoll=True) # in controller: def set_param_a(self, params, **kwargs): # get updated input parameters ... return SetParamsResult(updated_parameter_set) ``` * Parameters * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – Set this to True if the action button has to remain available for users that do not have permission to make any changes in the editor. This gives such users the ability to for example still download product reports. * **flex** (`Optional`\[`int`]) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** (`Optional`\[[`Interaction`](#Interaction "viktor.parametrization.Interaction")]) – Enable view interaction through this button New in v13.2.0 ## Lookup[​](/sdk/13/api/parametrization/.md#_Lookup "Direct link to Lookup") * *class *viktor.parametrization.Lookup(*target*)[¶](#Lookup "Permalink to this definition") Can be used to lookup the value of an input field. This can be used to set visibility of a field and to set a minimum and / or maximum boundary on a number field. Example usage on visibility: ``` field_1 = BooleanField('Field 1') field_2 = NumberField('Field 2', visible=Lookup('field_1')) ``` Example usage on min / max: ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', min=Lookup('field_1')) ``` * Parameters **target** (`str`) – Name of input field. ## FunctionLookup[​](/sdk/13/api/parametrization/.md#_FunctionLookup "Direct link to FunctionLookup") * *class *viktor.parametrization.FunctionLookup(*func*, *\*func\_args*, *\*\*kwargs*)[¶](#FunctionLookup "Permalink to this definition") Defines a lookup constraint where the output value is any function of several input fields. Example usages: ``` def multiply(a, b=10): return a * b field_1 = NumberField('Field 1') field_2 = NumberField('Field 2') ``` Standard usage with two field arguments: ``` field_3 = NumberField('Field 3', min=FunctionLookup(multiply, Lookup('field_1'), Lookup('field_2'))) ``` Using the default value of argument b: ``` field_4 = NumberField('Field 4', min=FunctionLookup(multiply, Lookup('field_1'))) ``` Using a constant instead of a field for argument a: ``` field_5 = NumberField('Field 5', min=FunctionLookup(multiply, 8, Lookup('field_2'))) ``` * Parameters * **func** (`Callable`) – Python function or lambda expression. The function can have arguments with default values. * **func\_args** (`Any`) – Arguments that are provided to the function. Arguments of type Lookup / BoolOperator are evaluated first (e.g. to refer to the value of a Field in the editor, a Lookup can be used). ## RowLookup[​](/sdk/13/api/parametrization/.md#_RowLookup "Direct link to RowLookup") * *class *viktor.parametrization.RowLookup(*target*)[¶](#RowLookup "Permalink to this definition") Can be used to lookup the value of an input field within the same row of the dynamic array. This can be used to set the visibility of a field and a minimum and / or maximum boundary on a number field. Example usage: ``` array = DynamicArray('Array') array.field_1 = NumberField('Field 1') array.field_2 = NumberField('Field 2', min=RowLookup('field_1')) ``` For more complex constructions, it is advised to use a callback function. * Parameters **target** (`str`) – Name of input field within the dynamic array. ## BoolOperator[​](/sdk/13/api/parametrization/.md#_BoolOperator "Direct link to BoolOperator") * *class *viktor.parametrization.BoolOperator[¶](#BoolOperator "Permalink to this definition") Bases: `ABC` Warning Do not use this class directly in an application. Base class for operators that can be used for field visibility and min/max. See the documentation of the subclasses for example implementations. ## And[​](/sdk/13/api/parametrization/.md#_And "Direct link to And") * *class *viktor.parametrization.And(*\*operands*)[¶](#And "Permalink to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate multiple operands to be True. ``` field_1 = NumberField('Field 1') field_2 = BooleanField('Field 2') field_3 = NumberField('Field 3', visible=And(IsEqual(Lookup('field_1'), 5), Lookup('field_2'))) ``` * Parameters **operands** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operands to be evaluated. ## Or[​](/sdk/13/api/parametrization/.md#_Or "Direct link to Or") * *class *viktor.parametrization.Or(*\*operands*)[¶](#Or "Permalink to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate if at least one operand is True. ``` field_1 = NumberField('Field 1') field_2 = BooleanField('Field 2') field_3 = NumberField('Field 3', visible=Or(IsEqual(Lookup('field_1'), 5), Lookup('field_2'))) ``` * Parameters **operands** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operands to be evaluated. ## Not[​](/sdk/13/api/parametrization/.md#_Not "Direct link to Not") * *class *viktor.parametrization.Not(*operand*)[¶](#Not "Permalink to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate an operand to be False. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=Not(IsEqual(Lookup('field_1'), 5))) ``` Note, above construction is the same as: ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotEqual(Lookup('field_1'), 5)) ``` * Parameters **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operand to be evaluated. ## IsEqual[​](/sdk/13/api/parametrization/.md#_IsEqual "Direct link to IsEqual") * *class *viktor.parametrization.IsEqual(*operand1*, *operand2*)[¶](#IsEqual "Permalink to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate two operands to be equal. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsEqual(Lookup('field_1'), 5)) ``` * Parameters * **operand1** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – First operand to be evaluated. * **operand2** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Second operand to be evaluated. ## IsNotEqual[​](/sdk/13/api/parametrization/.md#_IsNotEqual "Direct link to IsNotEqual") * *class *viktor.parametrization.IsNotEqual(*operand1*, *operand2*)[¶](#IsNotEqual "Permalink to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate two operands to be NOT equal. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotEqual(Lookup('field_1'), 5)) ``` * Parameters * **operand1** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – First operand to be evaluated. * **operand2** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Second operand to be evaluated. ## IsTrue[​](/sdk/13/api/parametrization/.md#_IsTrue "Direct link to IsTrue") * *class *viktor.parametrization.IsTrue(*operand*)[¶](#IsTrue "Permalink to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate an operand to be True. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsTrue(Lookup('field_1'))) ``` * Parameters **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## IsFalse[​](/sdk/13/api/parametrization/.md#_IsFalse "Direct link to IsFalse") * *class *viktor.parametrization.IsFalse(*operand*)[¶](#IsFalse "Permalink to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate an operand to be False. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsFalse(Lookup('field_1'))) ``` * Parameters **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## IsNotNone[​](/sdk/13/api/parametrization/.md#_IsNotNone "Direct link to IsNotNone") * *class *viktor.parametrization.IsNotNone(*operand*)[¶](#IsNotNone "Permalink to this definition") Bases: [`IsNotEqual`](#IsNotEqual "viktor.parametrization.IsNotEqual") Can be used to evaluate an operand to be NOT None. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotNone(Lookup('field_1'))) ``` * Parameters **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## DynamicArrayConstraint[​](/sdk/13/api/parametrization/.md#_DynamicArrayConstraint "Direct link to DynamicArrayConstraint") * *class *viktor.parametrization.DynamicArrayConstraint(*dynamic\_array\_name*, *operand*)[¶](#DynamicArrayConstraint "Permalink to this definition") This constraint facilitates usage of other constraints within a dynamic array row. Warning The DynamicArrayConstraint can currently only be used for the **visibility** of DynamicArray components. Example usage: ``` _show_y = DynamicArrayConstraint('array_name', IsTrue(Lookup('$row.param_x'))) array = DynamicArray('My array') array.param_x = BooleanField('X') array.param_y = NumberField('Y', visible=_show_y) ``` * Parameters * **dynamic\_array\_name** (`str`) – name of the dynamic array on which the constraint should be applied. * **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup")]) – The inputs of the operand have to be altered to access the correct row within the dynamic array. The input for a target field becomes ‘$row.{field\_name}’. ## DynamicArray[​](/sdk/13/api/parametrization/.md#_DynamicArray "Direct link to DynamicArray") * *class *viktor.parametrization.DynamicArray(*ui\_name*, *min=None*, *max=None*, *copylast=None*, *visible=True*, *default=None*, *\**, *description=None*, *row\_label=None*)[¶](#DynamicArray "Permalink to this definition") Bases: `_AttrGroup` Fields can be added under a dynamic array. Currently, it is not possible to add: > * [`ActionButton`](#ActionButton "viktor.parametrization.ActionButton") > > * [`DownloadButton`](#DownloadButton "viktor.parametrization.DownloadButton") > > * [`OptimizationButton`](#OptimizationButton "viktor.parametrization.OptimizationButton") > > * [`SetParamsButton`](#SetParamsButton "viktor.parametrization.SetParamsButton") > > * [`OutputField`](#OutputField "viktor.parametrization.OutputField") > > * [`HiddenField`](#HiddenField "viktor.parametrization.HiddenField") > > * [`Text`](#Text "viktor.parametrization.Text") Example usage: ``` layers = DynamicArray("layers") layers.depth = NumberField("depth") layers.material = OptionField("material", options=my_options) ``` * Parameters * **ui\_name** (`str`) – This string is visible in the VIKTOR user interface. * **min** (`Union`\[`int`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`, `None`]) – Minimum number of rows in the array. * **max** (`Union`\[`int`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`, `None`]) – Maximum number of rows in the array. * **copylast** (`Optional`\[`bool`]) – Copy the last row when clicking the + button. Takes precedence over field defaults. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. * **default** (`Optional`\[`List`\[`dict`]]) – Default values of complete array. Filled before user interaction. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **row\_label** (`Optional`\[`str`]) – Label to be shown at each row. The row number is appended to the label (max. 30 characters). The default values of the DynamicArray are filled when the editor is entered for the first time (just like the other fields). The fields underneath the dynamic array can also have default values. These are filled when the user adds a new row. If copylast is True, the last values are copied, and the Field defaults are ignored. ``` array = DynamicArray('Dyn Array', default=[{'a': 1, 'b': 'hello'}, {'a': 2, 'b': 'there'}]) array.a = NumberField('A', default=99) array.b = TextField('B', default='foo') ``` When first entering the editor: | A | B | | - | ----- | | 1 | hello | | 2 | there | When adding a new row: | A | B | | -- | ----- | | 1 | hello | | 2 | there | | 99 | foo | When using copylast: ``` array = DynamicArray('Dyn Array', copylast=True, default=[{'a': 1, 'b': 'hello'}]) array.a = NumberField('A', default=99) array.b = TextField('B', default='foo') ``` When first entering the editor: | A | B | | - | ----- | | 1 | hello | When adding a new row: | A | B | | - | ----- | | 1 | hello | | 1 | hello | Data: * list of dictionaries: e.g. \[{‘a’: 1, ‘b’: ‘1’}, {‘a’: 2, ‘b’: ‘2’}] * empty list if there are no ‘rows’ * when fields are empty, the corresponding empty values are used (see documentation of specific field) ## Field[​](/sdk/13/api/parametrization/.md#_Field "Direct link to Field") * *class *viktor.parametrization.Field(*\**, *ui\_name*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *flex=None*, *visible=True*, *description=None*)[¶](#Field "Permalink to this definition") Bases: `ABC` * Parameters * **ui\_name** (`str`) – This string is visible in the VIKTOR user interface. * **name** (`Optional`\[`str`]) – The position of the parameter in the database can be specified in this argument. * **prefix** (`Optional`\[`str`]) – A prefix will be put in front of the ui\_name to provide info such as a dollar sign. Note that this function does not yet work for input fields. * **suffix** (`Optional`\[`str`]) – A suffix will be put behind the ui\_name to provide additional information such as units. * **default** (`Optional`\[`Any`]) – The value or string that is specified here is filled in as a default input. * **flex** (`Optional`\[`int`]) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). ## DateField[​](/sdk/13/api/parametrization/.md#_DateField "Direct link to DateField") * *class *viktor.parametrization.DateField(*ui\_name*, *name=None*, *\**, *default=None*, *flex=None*, *visible=True*, *description=None*)[¶](#DateField "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional params: - Data: * datetime.date object * None, when empty ## NumberField[​](/sdk/13/api/parametrization/.md#_NumberField "Direct link to NumberField") * *class *viktor.parametrization.NumberField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *step=None*, *min=None*, *max=None*, *min\_message=None*, *max\_message=None*, *num\_decimals=None*, *visible=True*, *flex=None*, *variant='standard'*, *description=None*)[¶](#NumberField "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters * **step** (`Optional`\[`float`]) – Stepping interval when clicking up and down spinner buttons * **min** (`Union`\[`float`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`, `None`]) – Specifies a minimum value constraint. * **max** (`Union`\[`float`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`, `None`]) – Specifies a maximum value constraint. * **num\_decimals** (`Optional`\[`int`]) – Specifies the number of decimals. * **variant** (`str`) – Visually alter the input field. Possible options: * ’standard’: default [![/\_images/variant\_NumberField\_standard.png](/_images/variant_NumberField_standard.png)](/_images/variant_NumberField_standard.png) * ’slider’: slider (ignored in Table) [![/\_images/variant\_NumberField\_slider.png](/_images/variant_NumberField_slider.png)](/_images/variant_NumberField_slider.png) Data: * integer or float * None, when empty ## IntegerField[​](/sdk/13/api/parametrization/.md#_IntegerField "Direct link to IntegerField") * *class *viktor.parametrization.IntegerField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *step=None*, *min=None*, *max=None*, *min\_message=None*, *max\_message=None*, *visible=True*, *flex=None*, *description=None*)[¶](#IntegerField "Permalink to this definition") Bases: [`NumberField`](#NumberField "viktor.parametrization.NumberField") See [`NumberField`](#NumberField "viktor.parametrization.NumberField") for parameters Additional parameters: - Data: * integer, when filled * None, when empty ## TextField[​](/sdk/13/api/parametrization/.md#_TextField "Direct link to TextField") * *class *viktor.parametrization.TextField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *description=None*)[¶](#TextField "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: - Data: * string * empty string, when empty ## OutputField[​](/sdk/13/api/parametrization/.md#_OutputField "Direct link to OutputField") * *class *viktor.parametrization.OutputField(*ui\_name*, *\**, *value=None*, *prefix=None*, *suffix=None*, *visible=True*, *flex=None*, *description=None*)[¶](#OutputField "Permalink to this definition") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **value** (`Union`\[`float`, `str`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`, `None`]) – Value to be presented in the interface (can be hard-coded or calculated). Example: Point to another parameter ``` field_1 = NumberField() field_2 = OutputField(ui_name, value=Lookup("field_1")) ``` Example: Compute output value using callback function ``` def get_value(params, entity_id, **kwargs): # app specific logic value = ... return value field = OutputField(ui_name, value=get_value) ``` Data: * OutputFields are not present in the params ## LineBreak[​](/sdk/13/api/parametrization/.md#_LineBreak "Direct link to LineBreak") * *class *viktor.parametrization.LineBreak[¶](#LineBreak "Permalink to this definition") Linebreaks can be used to force input fields to be placed in the next row to obtain a cleaner looking editor. Example usage: ``` field_1 = NumberField() new_line = LineBreak() field_2 = NumberField() ``` ## BooleanField[​](/sdk/13/api/parametrization/.md#_BooleanField "Direct link to BooleanField") * *class *viktor.parametrization.BooleanField(*ui\_name*, *name=None*, *\**, *default=None*, *visible=True*, *flex=None*, *always\_available=False*, *description=None*)[¶](#BooleanField "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters Additional parameters: * Parameters **always\_available** (`bool`) – Set this to True if the toggle has to remain available for users that do not have permission to make any changes in the editor. This gives such users the ability to for example still switch on / off labels in a visualization. Data: * False or True ## ToggleButton[​](/sdk/13/api/parametrization/.md#_ToggleButton "Direct link to ToggleButton") * viktor.parametrization.ToggleButton[¶](#ToggleButton "Permalink to this definition") alias of [`BooleanField`](#BooleanField "viktor.parametrization.BooleanField") ## OptionField[​](/sdk/13/api/parametrization/.md#_OptionField "Direct link to OptionField") * *class *viktor.parametrization.OptionField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*, *variant='standard'*, *autoselect\_single\_option=False*)[¶](#OptionField "Permalink to this definition") Bases: `_SelectField` Present dropdown list with options for user. If there is only one option, this option is automatically selected. If you want to enable multiple options to be select, use a MultiSelectField. Example usage: ``` field = OptionField('Available options', options=['Option 1', 'Option 2'], default='Option 1') ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = OptionField('Available options', options=_options, default='option_1') ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters * **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. * **variant** (`str`) – Visually alter the input field. Possible options: * ’standard’: default ![/\_images/variant\_OptionField\_standard.png](/_images/variant_OptionField_standard.png) * ’radio’: radio buttons, vertically positioned (ignored in Table) ![/\_images/variant\_OptionField\_radio.png](/_images/variant_OptionField_radio.png) * ’radio-inline’: radio buttons, horizontally positioned (ignored in Table) ![/\_images/variant\_OptionField\_radio-inline.png](/_images/variant_OptionField_radio-inline.png) * **autoselect\_single\_option** (`bool`) – True to always automatically select when a single option is provided. This holds for static options as well as dynamic options (see examples below). When autoselect\_single\_option=False (default), expect the following behavior: | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚪ A | | options dynamically change to multiple options | ⚪ A, ⚪ B, ⚪ C | | user selects option B | ⚪ A, ⚫ B, ⚪ C | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | When autoselect\_single\_option=True, expect the following behavior: Warning Keep in mind that in case of dynamic options and the possibility of having a single option, the (automatically) selected option might be changed without the user being aware of this! | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚫ A | | options dynamically change to multiple options | ⚫ A, ⚪ B, ⚪ C | | options dynamically change to single option B (user might not be aware!) | ⚫ B | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | Data: * type of selected option: integer, float or string * None when nothing is selected ## MultiSelectField[​](/sdk/13/api/parametrization/.md#_MultiSelectField "Direct link to MultiSelectField") * *class *viktor.parametrization.MultiSelectField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*)[¶](#MultiSelectField "Permalink to this definition") Bases: `_SelectField` Present dropdown list with options for user, in which multiple options can be selected. If there is only one option, this option will not be automatically selected. Example usage: ``` field = MultiSelectField('Available options', options=['Option 1', 'Option 2'], default=['Option 1', 'Option 2']) ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = MultiSelectField('Available options', options=_options, default=['option_1', 'option_2']) ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. Data: * empty list if no options are selected * list with values of [`OptionListElements`](#OptionListElement "viktor.parametrization.OptionListElement"): integer, float or string ## MultipleSelectField[​](/sdk/13/api/parametrization/.md#_MultipleSelectField "Direct link to MultipleSelectField") * viktor.parametrization.MultipleSelectField[¶](#MultipleSelectField "Permalink to this definition") alias of [`MultiSelectField`](#MultiSelectField "viktor.parametrization.MultiSelectField") ## AutocompleteField[​](/sdk/13/api/parametrization/.md#_AutocompleteField "Direct link to AutocompleteField") * *class *viktor.parametrization.AutocompleteField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*)[¶](#AutocompleteField "Permalink to this definition") Bases: `_SelectField` Similar to OptionField, except for two differences: * user can type to search for option * single option is not pre-selected Example usage: ``` field = AutocompleteField('Available options', options=['Option 1', 'Option 2'], default='Option 1') ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = AutocompleteField('Available options', options=_options, default='option_1') ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. Data: * type of selected option: integer, float or string * None when nothing is selected ## EntityOptionField[​](/sdk/13/api/parametrization/.md#_EntityOptionField "Direct link to EntityOptionField") * *class *viktor.parametrization.EntityOptionField(*ui\_name*, *entity\_type\_names*, *\**, *name=None*, *visible=True*, *flex=None*, *description=None*)[¶](#EntityOptionField "Permalink to this definition") Bases: `_EntitySelectField` Field to select any entity of given type(s). Single option is not automatically pre-selected. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of type(s) within this list. Data: > * [`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity") > > * None when nothing is selected ## ChildEntityOptionField[​](/sdk/13/api/parametrization/.md#_ChildEntityOptionField "Direct link to ChildEntityOptionField") * *class *viktor.parametrization.ChildEntityOptionField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[¶](#ChildEntityOptionField "Permalink to this definition") Bases: `_EntityOptionField` Field to select a child entity of given type(s). Single option is not automatically pre-selected. Data: * [`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity") * None when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – User will only be able to select entities of types within this list. None = all entities. ## SiblingEntityOptionField[​](/sdk/13/api/parametrization/.md#_SiblingEntityOptionField "Direct link to SiblingEntityOptionField") * *class *viktor.parametrization.SiblingEntityOptionField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[¶](#SiblingEntityOptionField "Permalink to this definition") Bases: `_EntityOptionField` Field to select a sibling entity of given type(s). Single option is not automatically pre-selected. Data: * [`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity") * None when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – User will only be able to select entities of types within this list. None = all entities. ## EntityMultiSelectField[​](/sdk/13/api/parametrization/.md#_EntityMultiSelectField "Direct link to EntityMultiSelectField") * *class *viktor.parametrization.EntityMultiSelectField(*ui\_name*, *entity\_type\_names*, *\**, *name=None*, *visible=True*, *flex=None*, *description=None*)[¶](#EntityMultiSelectField "Permalink to this definition") Bases: `_EntityMultiField` Field to select zero or more entities of given type(s). See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. Data: > * List\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")] > > * Empty list when nothing is selected ## ChildEntityMultiSelectField[​](/sdk/13/api/parametrization/.md#_ChildEntityMultiSelectField "Direct link to ChildEntityMultiSelectField") * *class *viktor.parametrization.ChildEntityMultiSelectField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[¶](#ChildEntityMultiSelectField "Permalink to this definition") Bases: `_EntityMultiSelectField` Field to select zero or more child entities of given type(s). Up to 5000 entities may be visualized in the dropdown in the interface. Data: * List\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")] * Empty list when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – User will only be able to select entities of types within this list. None = all entities. ## SiblingEntityMultiSelectField[​](/sdk/13/api/parametrization/.md#_SiblingEntityMultiSelectField "Direct link to SiblingEntityMultiSelectField") * *class *viktor.parametrization.SiblingEntityMultiSelectField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[¶](#SiblingEntityMultiSelectField "Permalink to this definition") Bases: `_EntityMultiSelectField` Field to select zero or more sibling entities of given type(s). Up to 5000 entities may be visualized in the dropdown in the interface. Data: * List\[[`Entity`](/sdk/13/api/api-v1/.md#Entity "viktor.api_v1.Entity")] * Empty list when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **entity\_type\_names** (`Optional`\[`List`\[`str`]]) – User will only be able to select entities of types within this list. None = all entities. ## FileField[​](/sdk/13/api/parametrization/.md#_FileField "Direct link to FileField") * *class *viktor.parametrization.FileField(*ui\_name*, *file\_types=None*, *\**, *max\_size=None*, *name=None*, *visible=True*, *flex=None*, *description=None*)[¶](#FileField "Permalink to this definition") Bases: `_FileField` FileField can be used to let the user upload a file. Data: * [`FileResource`](/sdk/13/api/api-v1/.md#FileResource "viktor.api_v1.FileResource") * None when nothing is uploaded See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters * **file\_types** (`Optional`\[`Sequence`\[`str`]]) – Optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]) (case-insensitive). * **max\_size** (`Optional`\[`int`]) – Optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). ## MultiFileField[​](/sdk/13/api/parametrization/.md#_MultiFileField "Direct link to MultiFileField") * *class *viktor.parametrization.MultiFileField(*ui\_name*, *file\_types=None*, *\**, *max\_size=None*, *name=None*, *visible=True*, *flex=None*, *description=None*)[¶](#MultiFileField "Permalink to this definition") Bases: `_FileField` MultiFileField can be used to let the user upload multiple files. Data: * List\[[`FileResource`](/sdk/13/api/api-v1/.md#FileResource "viktor.api_v1.FileResource")] * Empty list when nothing is uploaded See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters * **file\_types** (`Optional`\[`Sequence`\[`str`]]) – Optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]) (case-insensitive). * **max\_size** (`Optional`\[`int`]) – Optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). ## Table[​](/sdk/13/api/parametrization/.md#_Table "Direct link to Table") * *class *viktor.parametrization.Table(*ui\_name*, *name=None*, *\**, *default=None*, *visible=True*, *description=None*)[¶](#Table "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field"), `_AttrGroup` Example usage: ``` table = Table('Input table') table.name = TextField('Planet') table.period = NumberField('Orbital period', suffix='years') table.eccentricity = NumberField('Orbital eccentricity', num_decimals=3) ``` A table can also be created with default content. Assume the columns as defined above: ``` _default_content = [ {'name': 'Earth', 'period': 1, 'eccentricity': 0.017}, {'name': 'Mars', 'period': 1.88, 'eccentricity': 0.093}, {'name': 'Saturn', 'period': 29.42, 'eccentricity': 0.054}, ] table = Table('Input table', default=_default_content) ... ``` Supported fields are: > * [`TextField`](#TextField "viktor.parametrization.TextField") > > * [`NumberField`](#NumberField "viktor.parametrization.NumberField") > > * [`IntegerField`](#IntegerField "viktor.parametrization.IntegerField") > > * [`BooleanField`](#BooleanField "viktor.parametrization.BooleanField") > > * [`OptionField`](#OptionField "viktor.parametrization.OptionField") > > * [`AutocompleteField`](#AutocompleteField "viktor.parametrization.AutocompleteField") Note, specifying a default and / or constraints on a field within a table is not supported. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: * list of dictionaries * empty list if there are no rows * when fields are empty, the corresponding empty values are used (see documentation of specific field) ## TableInput[​](/sdk/13/api/parametrization/.md#_TableInput "Direct link to TableInput") * viktor.parametrization.TableInput[¶](#TableInput "Permalink to this definition") alias of [`Table`](#Table "viktor.parametrization.Table") ## GeoPointField[​](/sdk/13/api/parametrization/.md#_GeoPointField "Direct link to GeoPointField") * *class *viktor.parametrization.GeoPointField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[¶](#GeoPointField "Permalink to this definition") Bases: `_GeoField` GeoPointField can be used for the selection of a geographical location on a MapView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPoint`](/sdk/13/api/geometry/.md#GeoPoint "viktor.geometry.GeoPoint") ## GeoPolylineField[​](/sdk/13/api/parametrization/.md#_GeoPolylineField "Direct link to GeoPolylineField") * *class *viktor.parametrization.GeoPolylineField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[¶](#GeoPolylineField "Permalink to this definition") Bases: `_GeoField` GeoPolylineField can be used for the selection of a geographical (poly)line on a MapView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPolyline`](/sdk/13/api/geometry/.md#GeoPolyline "viktor.geometry.GeoPolyline") ## GeoPolygonField[​](/sdk/13/api/parametrization/.md#_GeoPolygonField "Direct link to GeoPolygonField") * *class *viktor.parametrization.GeoPolygonField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[¶](#GeoPolygonField "Permalink to this definition") Bases: `_GeoField` GeoPolygonField can be used for the selection of a geographical polygon on a MapView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPolygon`](/sdk/13/api/geometry/.md#GeoPolygon "viktor.geometry.GeoPolygon") ## TextAreaField[​](/sdk/13/api/parametrization/.md#_TextAreaField "Direct link to TextAreaField") * *class *viktor.parametrization.TextAreaField(*ui\_name*, *name=None*, *default=None*, *visible=True*, *flex=100*, *\**, *description=None*)[¶](#TextAreaField "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") Multiple lines textual input. For one line use TextField. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: * string * empty string, when empty ## TextAreaInput[​](/sdk/13/api/parametrization/.md#_TextAreaInput "Direct link to TextAreaInput") * viktor.parametrization.TextAreaInput[¶](#TextAreaInput "Permalink to this definition") alias of [`TextAreaField`](#TextAreaField "viktor.parametrization.TextAreaField") ## Text[​](/sdk/13/api/parametrization/.md#_Text "Direct link to Text") * *class *viktor.parametrization.Text(*value*, *\**, *visible=True*, *flex=100*)[¶](#Text "Permalink to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") Field that can be used to display a static text (max. 1800 characters). It is not included in the params. Changed in v13.3.0: character limit has been increased from 500 to 1800. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters **value** (`str`) – Text to be shown ## HiddenField[​](/sdk/13/api/parametrization/.md#_HiddenField "Direct link to HiddenField") * *class *viktor.parametrization.HiddenField(*ui\_name*, *name=None*)[¶](#HiddenField "Permalink to this definition") The purpose of a HiddenField is to store data in the parametrization, without the necessity to show this information in the editor. Warning Do NOT store tremendous amounts of data when it is not necessary, as this will make your application slow and perhaps unstable! * Parameters * **ui\_name** (`str`) – User-defined name of the field. * **name** (`Optional`\[`str`]) – The position of the parameter in the database can be specified in this argument. ## OptionListElement[​](/sdk/13/api/parametrization/.md#_OptionListElement "Direct link to OptionListElement") * *class *viktor.parametrization.OptionListElement(*value*, *label=None*, *visible=True*)[¶](#OptionListElement "Permalink to this definition") Create an option which can be used inside an OptionField. Example: value only with type str ``` >>> option = OptionListElement('apple') >>> option.value 'apple' >>> option.label 'apple' ``` Example: value only with type int ``` >>> option = OptionListElement(33) >>> option.value 33 >>> option.label '33' ``` Example: value and label ``` >>> option = OptionListElement('apple', 'Delicious apple') >>> option.value 'apple' >>> option.label 'Delicious apple' ``` * Parameters * **value** (`Union`\[`float`, `str`]) – The identifier which is used to store and retrieve chosen option. * **label** (`Optional`\[`str`]) – The identifier which is shown to the user. If no label is specified, the value identifier is used, cast to a string. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup")]) – Determines whether option is visible. Will mostly be used with Constraint. - *property *label*: str*[¶](#OptionListElement.label "Permalink to this definition") * Return type `str` * *property *value*: Union\[float, str]*[¶](#OptionListElement.value "Permalink to this definition") * Return type `Union`\[`float`, `str`] ## Parametrization[​](/sdk/13/api/parametrization/.md#_Parametrization "Direct link to Parametrization") * *class *viktor.parametrization.Parametrization(*\**, *width=None*)[¶](#Parametrization "Permalink to this definition") The Parametrization class functions as the basis of the parameter set of an entity. A simple parametrization looks as follows: ``` from viktor.parametrization import Parametrization, TextField, NumberField class ExampleParametrization(Parametrization): input_1 = TextField('This is a text field') input_2 = NumberField('This is a number field') ``` In the VIKTOR user interface, this will be visualized as: [![/\_images/editor-single-layered.png](/_images/editor-single-layered.png)](/_images/editor-single-layered.png) In some cases, the parametrization becomes quite big which requires a more structured layout. This can be achieved by making use of a [`Tab`](#Tab "viktor.parametrization.Tab") and [`Section`](#Section "viktor.parametrization.Section") object, which represent a tab and collapsible section in the interface respectively. A 2-layered structure using Tab objects looks like this: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Tab class ExampleParametrization(Parametrization): tab_1 = Tab('Tab 1') tab_1.input_1 = TextField('This is a text field') tab_1.input_2 = NumberField('This is a number field') tab_2 = Tab('Tab 2') tab_2.input_1 = TextField('Text field in Tab 2') tab_2.input_2 = NumberField('Number field in Tab 2') ``` [![/\_images/editor-two-layered-tabs.png](/_images/editor-two-layered-tabs.png)](/_images/editor-two-layered-tabs.png) Using Section objects results in the following: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Section class ExampleParametrization(Parametrization): section_1 = Section('Section 1') section_1.input_1 = TextField('This is a text field') section_1.input_2 = NumberField('This is a number field') section_2 = Section('Section 2') section_2.input_1 = TextField('Text field in Section 2') section_2.input_2 = NumberField('Number field in Section 2') ``` [![/\_images/editor-two-layered-sections.png](/_images/editor-two-layered-sections.png)](/_images/editor-two-layered-sections.png) A parametrization with a maximum depth of 3 layers consists of Tab, Section, and Field objects: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Tab, Section class ExampleParametrization(Parametrization): tab_1 = Tab('Tab 1') tab_1.section_1 = Section('Section 1') tab_1.section_1.input_1 = TextField('This is a text field') tab_1.section_1.input_2 = NumberField('This is a number field') tab_1.section_2 = Section('Section 2') ... tab_2 = Tab('Tab 2') ... ``` [![/\_images/editor-three-layered.png](/_images/editor-three-layered.png)](/_images/editor-three-layered.png) Every class attribute is treated as a tab, section, or field. If you want to use a variable inside a field, you can either define it outside of the class or as class attribute starting with an underscore: ``` OPTIONS = ['Option 1', 'Option 2'] class ExampleParametrization(Parametrization): _options = ['Option 3', 'Option 4'] field_1 = OptionField('Choose option', options=OPTIONS) field_2 = OptionField('Choose option', options=_options) ``` * Parameters **width** (`Optional`\[`int`]) – Sets the width of the parametrization side as percentage of the complete width of the editor (input + output). The value should be an integer between 20 and 80 (default: 40). ## ViktorParametrization[​](/sdk/13/api/parametrization/.md#_ViktorParametrization "Direct link to ViktorParametrization") * viktor.parametrization.ViktorParametrization[¶](#ViktorParametrization "Permalink to this definition") alias of [`Parametrization`](#Parametrization "viktor.parametrization.Parametrization") ## Page[​](/sdk/13/api/parametrization/.md#_Page "Direct link to Page") * *class *viktor.parametrization.Page(*title*, *\**, *views=None*, *description=None*)[¶](#Page "Permalink to this definition") Bases: `_Group` A Page can be used to group certain inputs (e.g. fields) with certain outputs (views). For example: ``` class Parametrization(ViktorParametrization): page_1 = Page('Page 1') # no views page_1.field_1 = NumberField(...) ... page_2 = Page('Page 2', views='view_data') # single view page_2.field_1 = NumberField(...) ... page_3 = Page('Page 3', views=['view_map', 'view_data']) # multiple views page_3.field_1 = NumberField(...) ... class Controller(ViktorController): ... @DataView(...) # visible on "Page 2" and "Page 3" def view_data(self, params, **kwargs): ... @MapView(...) # only visible on "Page 3" def view_map(self, params, **kwargs): ... ``` * Parameters * **title** (`str`) – Title which is shown in the interface. * **views** (`Union`\[`str`, `Sequence`\[`str`], `None`]) – View method(s) that should be visible in this page, e.g. ‘my\_view’ for a single view, or \[‘my\_data\_view’, ‘my\_geometry\_view’, …] for multiple views (default: None). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). ## Step[​](/sdk/13/api/parametrization/.md#_Step "Direct link to Step") * *class *viktor.parametrization.Step(*title*, *\**, *views=None*, *description=None*, *previous\_label=None*, *next\_label=None*, *on\_next=None*)[¶](#Step "Permalink to this definition") Bases: [`Page`](#Page "viktor.parametrization.Page") A Step can be used to group certain inputs (e.g. fields) with certain outputs (views) within a predefined order, browsable through a previous and next button. For example: ``` class Parametrization(ViktorParametrization): step_1 = Step('Step 1') # no views step_1.field_1 = NumberField(...) ... step_2 = Step('Step 2', views='view_data') # single view step_2.field_1 = NumberField(...) ... step_3 = Step('Step 3', views=['view_map', 'view_data']) # multiple views step_3.field_1 = NumberField(...) ... class Controller(ViktorController): ... @DataView(...) # visible on "Step 2" and "Step 3" def view_data(self, params, **kwargs): ... @MapView(...) # only visible on "Step 3" def view_map(self, params, **kwargs): ... ``` When implementing the on\_next argument, the corresponding function is called when a user clicks the ‘next’ button to move to the next step. This can be used to, for example, validate the input of the current active step (new in v13.7.0): ``` def validate_step_1(params, **kwargs): if params.step_1.field_z <= params.step_1.field_x + params.step_1.field_y: raise UserError(...) class Parametrization(ViktorParametrization): step_1 = Step('Step 1', on_next=validate_step_1) ... ``` * Parameters * **title** (`str`) – Title which is shown in the interface. * **views** (`Union`\[`str`, `Sequence`\[`str`], `None`]) – View method(s) that should be visible in this step, e.g. ‘my\_view’ for a single view, or \[‘my\_data\_view’, ‘my\_geometry\_view’, …] for multiple views (default: None). * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **previous\_label** (`Optional`\[`str`]) – Text to be shown on the previous button (ignored for first step in Parametrization, max. 30 characters). * **next\_label** (`Optional`\[`str`]) – Text to be shown on the next button (ignored for last step in Parametrization, max. 30 characters). * **on\_next** (`Optional`\[`Callable`]) – Callback function which is triggered when the user moves to the next step New in v13.7.0 . ## Tab[​](/sdk/13/api/parametrization/.md#_Tab "Direct link to Tab") * *class *viktor.parametrization.Tab(*title*, *\**, *description=None*)[¶](#Tab "Permalink to this definition") Bases: `_Group` * Parameters * **title** (`str`) – Title which is shown in the interface. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). ## Section[​](/sdk/13/api/parametrization/.md#_Section "Direct link to Section") * *class *viktor.parametrization.Section(*title*, *\**, *description=None*)[¶](#Section "Permalink to this definition") Bases: `_Group` * Parameters * **title** (`str`) – Title which is shown in the interface. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). --- # viktor.result ## SetParamsResult[​](/sdk/13/api/result/.md#_SetParamsResult "Direct link to SetParamsResult") * *class *viktor.result.SetParamsResult(*params*)[¶](#SetParamsResult "Permalink to this definition") Bases: `_SerializableObject` Container for the output of a [`SetParamsButton`](/sdk/13/api/parametrization/.md#SetParamsButton "viktor.parametrization.SetParamsButton"). In order to set the content of the field Tab 1 > Section 1 > NumberField 1 to 1234 use the format: ``` SetParamsResult({ "tab_1": { "section_1": { "numberfield_1": 1234 } } }) ``` To clear one or more fields one has to explicitly set the params to the empty state. Note that the empty value is different for each field and can be found in their docs: ``` SetParamsResult({ "tab_1": { "section_1": { "numberfield_1": None, } } }) ``` * Parameters **params** (`Union`\[`dict`, `Munch`]) – the params you want to set. If a param is not specified, the value will be kept as is. - get(*key*)[¶](#SetParamsResult.get "Permalink to this definition") * Return type `Any` ## SetParametersResult[​](/sdk/13/api/result/.md#_SetParametersResult "Direct link to SetParametersResult") * viktor.result.SetParametersResult[¶](#SetParametersResult "Permalink to this definition") alias of [`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult") ## DownloadResult[​](/sdk/13/api/result/.md#_DownloadResult "Direct link to DownloadResult") * *class *viktor.result.DownloadResult(*file\_content=None*, *file\_name=None*, *encoding='utf-8'*, *\**, *zipped\_files=None*)[¶](#DownloadResult "Permalink to this definition") Bases: `_SerializableObject` Container for the output of a [`DownloadButton`](/sdk/13/api/parametrization/.md#DownloadButton "viktor.parametrization.DownloadButton"). Download of single file: ``` DownloadResult(file_content=my_file, file_name="my_file.txt") ``` Download of multiple files bundled in a zip-file: ``` DownloadResult(zipped_files={'my_file_1.txt': my_file_1, 'my_file_2.txt': my_file_2}, file_name="my_file.zip") ``` * Parameters * **file\_content** (`Union`\[`str`, `bytes`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `BytesIO`, `None`]) – if type str and encoding is not utf-8, specify in additional argument. Mutual exclusive with ‘zipped\_files’. * **file\_name** (`Optional`\[`str`]) – name (including extension) to be used for download. In case of ‘zipped\_files’, this is the name of the zip-file. May only consist of alphanumeric characters, underscores and dots (any other characters are converted to an underscore). * **encoding** (`str`) – optional argument to specify file encoding when file\_content is provided with type str * **zipped\_files** (`Optional`\[`Dict`\[`str`, `Union`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `BytesIO`]]]) – a dict of {file name: content} to be bundled in a zip-file with file-name ‘file\_name’. Mutual exclusive with ‘file\_content’. ## OptimizationResultElement[​](/sdk/13/api/result/.md#_OptimizationResultElement "Direct link to OptimizationResultElement") * *class *viktor.result.OptimizationResultElement(*params*, *analysis\_result=None*)[¶](#OptimizationResultElement "Permalink to this definition") * Parameters * **params** (`Union`\[`dict`, `Munch`]) – a complete parameter set * **analysis\_result** (`Optional`\[`dict`]) – the accompanying results. For an example, see [`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult") ## OptimisationResultElement[​](/sdk/13/api/result/.md#_OptimisationResultElement "Direct link to OptimisationResultElement") * viktor.result.OptimisationResultElement[¶](#OptimisationResultElement "Permalink to this definition") alias of [`OptimizationResultElement`](#OptimizationResultElement "viktor.result.OptimizationResultElement") ## OptimizationResult[​](/sdk/13/api/result/.md#_OptimizationResult "Direct link to OptimizationResult") * *class *viktor.result.OptimizationResult(*results*, *result\_column\_names\_input=None*, *output\_headers=None*, *image=None*)[¶](#OptimizationResult "Permalink to this definition") Bases: `_SerializableObject` Container for the output of an [`OptimizationButton`](/sdk/13/api/parametrization/.md#OptimizationButton "viktor.parametrization.OptimizationButton"). * Parameters * **results** (`List`\[[`OptimizationResultElement`](#OptimizationResultElement "viktor.result.OptimizationResultElement")]) – list of results, order is kept in user interface. * **result\_column\_names\_input** (`Optional`\[`List`\[`str`]]) – specifies which input parameters should be shown the table. The parametrization class defined the label which is shown * **output\_headers** (`Optional`\[`dict`]) – specifies which results should be shown in the results table. Key should match the key of the analysis\_result inside each result. Value is the corresponding label which the end user sees. * **image** (`Union`\[[`ImageResult`](/sdk/13/api/views/.md#ImageResult "viktor.views.ImageResult"), [`PNGResult`](/sdk/13/api/views/.md#PNGResult "viktor.views.PNGResult"), [`JPGResult`](/sdk/13/api/views/.md#JPGResult "viktor.views.JPGResult"), [`SVGResult`](/sdk/13/api/views/.md#SVGResult "viktor.views.SVGResult"), `None`]) – image which is shown next to the results. Could be JPG, PNG or SVG. Example: ``` params1 = {'tab': {'section': {'field1': 'a', 'field2': 5}}} params2 = {'tab': {'section': {'field1': 'b', 'field2': 8}}} analysis1 = {'result1': 10, 'result2': 20} analysis2 = {'result1': 100, 'result2': 150} results = [ OptimizationResultElement(params1, analysis1), OptimizationResultElement(params2, analysis2), ] OptimizationResult( results, result_column_names_input=['tab.section.field1'], output_headers={'result1': 'Result 1'} ) ``` This renders as the following table for the end-user: | # | Field 1 | Result 1 | | - | ------- | -------- | | 1 | a | 10 | | 2 | b | 100 | ## OptimisationResult[​](/sdk/13/api/result/.md#_OptimisationResult "Direct link to OptimisationResult") * viktor.result.OptimisationResult[¶](#OptimisationResult "Permalink to this definition") alias of [`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult") ## ViktorResult[​](/sdk/13/api/result/.md#_ViktorResult "Direct link to ViktorResult") * *class *viktor.result.ViktorResult(*optimisation\_result=None*, *set\_parameters\_result=None*, *download\_result=None*, *\**, *optimization\_result=None*, *set\_params\_result=None*)[¶](#ViktorResult "Permalink to this definition") Bases: `_SerializableObject` Standard output object of a ViktorController method, which serialises and combines several individual results into the standard automation output. All inputs are optional to facilitate many combinations of results where needed in the future. Currently, the serialisation only accounts for the following (backward compatible) combinations: * a single optimization result * a single set\_params result * a single download result - Parameters * **optimisation\_result** (`Optional`\[[`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult")]) – alias for optimization\_result * **set\_parameters\_result** (`Optional`\[[`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult")]) – alias for set\_params\_result * **download\_result** (`Optional`\[[`DownloadResult`](#DownloadResult "viktor.result.DownloadResult")]) – DownloadResult object * **optimization\_result** (`Optional`\[[`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult")]) – OptimizationResult object * **set\_params\_result** (`Optional`\[[`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult")]) – SetParamsResult object --- # viktor.testing ## mock\_ParamsFromFile[​](/sdk/13/api/testing/.md#_mock_ParamsFromFile "Direct link to mock_ParamsFromFile") * viktor.testing.mock\_ParamsFromFile(*controller*)[¶](#mock_ParamsFromFile "Permalink to this definition") Decorator that can be used for testing methods decorated with [`viktor.core.ParamsFromFile`](/sdk/13/api/core/.md#ParamsFromFile "viktor.core.ParamsFromFile"). Example: ``` import unittest from viktor.testing import mock_ParamsFromFile from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_ParamsFromFile(MyEntityController) def test_process_file(self): file = File.from_data("abc") returned_dict = MyEntityController().process_file(file) self.assertDictEqual(returned_dict, {...}) ``` * Parameters **controller** (`Type`\[[`ViktorController`](/sdk/13/api/core/.md#ViktorController "viktor.core.ViktorController")]) – Controller class on which the ParamsFromFile should be mocked * Return type `Callable` ## mock\_Storage[​](/sdk/13/api/testing/.md#_mock_Storage "Direct link to mock_Storage") * viktor.testing.mock\_Storage(*\**, *get=None*, *list=None*)[¶](#mock_Storage "Permalink to this definition") Decorator that can be used for testing methods which invoke the [`viktor.core.Storage`](/sdk/13/api/core/.md#Storage "viktor.core.Storage"). Use the get and list arguments to instruct which file(s) the respective Storage().get(…) and Storage().list(…) methods should return. Example: ``` import unittest from viktor.testing import mock_Storage from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_Storage( get=[File.from_data("abc"), File.from_data("def")], list=[{'data_key_3': File.from_data("ghi")}] ) def test_process_analysis_result(self): # Storage().get(...) invoked twice, Storage().list(...) invoked once result = MyEntityController().process_analysis_result() ... ``` * Parameters * **get** (`Optional`\[`Sequence`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]) – Files to be returned by Storage().get(…). The files are returned in order of the input list. * **list** (`Optional`\[`Sequence`\[`Dict`\[`str`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – File dicts to be returned by Storage().list(…). The dicts are returned in order of the input list. * Return type `Callable` ## MockedEntityType[​](/sdk/13/api/testing/.md#_MockedEntityType "Direct link to MockedEntityType") * *class *viktor.testing.MockedEntityType(*name='MockedEntityType'*, *entity\_type\_id=1*)[¶](#MockedEntityType "Permalink to this definition") Bases: [`EntityType`](/sdk/13/api/api-v1/.md#EntityType "viktor.api_v1.EntityType") New in v13.3.0 To mock a EntityType. ## MockedEntityRevision[​](/sdk/13/api/testing/.md#_MockedEntityRevision "Direct link to MockedEntityRevision") * *class *viktor.testing.MockedEntityRevision(*params=None*, *created\_date=None*)[¶](#MockedEntityRevision "Permalink to this definition") Bases: [`EntityRevision`](/sdk/13/api/api-v1/.md#EntityRevision "viktor.api_v1.EntityRevision") New in v13.3.0 To mock an EntityRevision. Example: ``` from viktor.testing import MockedEntityRevision, MockedEntity, MockedFileResource params = { 'number': 1, 'entity': MockedEntity(name="MyEntity"), 'file': MockedFileResource(File.from_data("content"), "file.txt") } mocked_entity_revision = MockedEntityRevision(params) ``` params can be passed from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` from viktor import File from viktor.testing import MockedEntityRevision, MockedEntity, MockedFileResource, mock_params from app.my_entity.controller import MyEntityController json_file = File.from_path("path to JSON file") params = mock_params( json_file, MyEntityController.parametrization, entities={1: MockedEntity(name="MyEntity")}, file_resources={1: MockedFileResource(File.from_data("content"), "file")} ) mocked_entity_revision = MockedEntityRevision(params) ``` * Parameters * **params** (`Union`\[`dict`, `Munch`, `None`]) – Return value of EntityRevision.params. Must be the deserialized params (see [`mock_params()`](#mock_params "viktor.testing.mock_params")). None to set default (empty) params. * **created\_date** (`Optional`\[`datetime`]) – Return value of EntityRevision.created\_date. None to set default date (2000, 1, 1). ## MockedUser[​](/sdk/13/api/testing/.md#_MockedUser "Direct link to MockedUser") * *class *viktor.testing.MockedUser(*\**, *first\_name='John'*, *last\_name='Doe'*, *email='john.doe\@email.com'*, *job\_title='Employee'*)[¶](#MockedUser "Permalink to this definition") Bases: [`User`](/sdk/13/api/api-v1/.md#User "viktor.api_v1.User") New in v13.3.0 To mock a User. ## MockedFileResource[​](/sdk/13/api/testing/.md#_MockedFileResource "Direct link to MockedFileResource") * *class *viktor.testing.MockedFileResource(*file=None*, *filename='mocked\_file.txt'*)[¶](#MockedFileResource "Permalink to this definition") New in v13.3.0 To mock a FileResource. * Parameters * **file** (`Optional`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – Return value of FileResource.file. None to set default file with content = “mocked content”. * **filename** (`str`) – Return value of FileResource.filename. ## MockedEntity[​](/sdk/13/api/testing/.md#_MockedEntity "Direct link to MockedEntity") * *class *viktor.testing.MockedEntity(*\**, *entity\_id=1*, *name='Mocked Entity'*, *entity\_type=None*, *last\_saved\_params=None*, *last\_saved\_summary=None*, *get\_file=None*, *parent=None*, *children=None*, *siblings=None*, *revisions=None*, *invalid=False*)[¶](#MockedEntity "Permalink to this definition") New in v13.3.0 To mock an Entity. All arguments are optional: instantiating MockedEntity without parameters returns a default MockedEntity. Example: ``` from viktor.testing import MockedEntity, MockedEntityRevision mocked_entity = MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ``` last\_saved\_params can be passed from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` from viktor import File from viktor.testing import MockedEntity, MockedEntityRevision, MockedFileResource, mock_params from app.my_entity.controller import MyEntityController json_file = File.from_path("path to JSON file") params = mock_params( json_file, MyEntityController.parametrization, entities={1: MockedEntity(name="MyEntity")}, file_resources={1: MockedFileResource(File.from_data("content"), "file")} ) mocked_entity = MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ``` * Parameters * **entity\_id** (`int`) – Return value of Entity.id. * **name** (`str`) – Return value of Entity.name. * **entity\_type** (`Optional`\[[`MockedEntityType`](#MockedEntityType "viktor.testing.MockedEntityType")]) – Return value of Entity.entity\_type. None for default MockedEntityType. * **last\_saved\_params** (`Union`\[`dict`, `Munch`, `None`]) – Return value of Entity.last\_saved\_params(). Must be the deserialized params (see [`mock_params()`](#mock_params "viktor.testing.mock_params")). None to simulate an entity without params. * **last\_saved\_summary** (`Optional`\[`dict`]) – Return value of Entity.last\_saved\_summary(). None to simulate an entity without summary. * **get\_file** (`Optional`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – Return value of Entity.get\_file. None to simulate an entity without file. * **parent** (`Optional`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of Entity.parent. None to simulate an entity without parent. * **children** (`Optional`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of Entity.children. None to simulate an entity without children. * **siblings** (`Optional`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of Entity.siblings. None to simulate an entity without siblings. * **revisions** (`Optional`\[`Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")]]) – Return value of Entity.revisions. None to simulate an entity without revisions. * **invalid** (`bool`) – Set to True to simulate failing API calls on this Entity. - *property *id*: int*[¶](#MockedEntity.id "Permalink to this definition") * Return type `int` * *property *name*: str*[¶](#MockedEntity.name "Permalink to this definition") * Return type `str` - *property *entity\_type*: [MockedEntityType](#MockedEntityType "viktor.testing.MockedEntityType")*[¶](#MockedEntity.entity_type "Permalink to this definition") * Return type [`MockedEntityType`](#MockedEntityType "viktor.testing.MockedEntityType") * *property *last\_saved\_params*: munch.Munch*[¶](#MockedEntity.last_saved_params "Permalink to this definition") * Return type `Munch` - *property *last\_saved\_summary*: munch.Munch*[¶](#MockedEntity.last_saved_summary "Permalink to this definition") * Return type `Munch` * get\_file(*\*args*, *\*\*kwargs*)[¶](#MockedEntity.get_file "Permalink to this definition") * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") - parent(*\*args*, *\*\*kwargs*)[¶](#MockedEntity.parent "Permalink to this definition") * Return type [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") * children(*\*args*, *entity\_type\_names=None*, *\*\*kwargs*)[¶](#MockedEntity.children "Permalink to this definition") * Return type [`MockedEntityList`](#MockedEntityList "viktor.testing.MockedEntityList") - siblings(*\*args*, *entity\_type\_names=None*, *\*\*kwargs*)[¶](#MockedEntity.siblings "Permalink to this definition") * Return type [`MockedEntityList`](#MockedEntityList "viktor.testing.MockedEntityList") * create\_child(*entity\_type\_name*, *name*, *\*args*, *params=None*, *\*\*kwargs*)[¶](#MockedEntity.create_child "Permalink to this definition") * Return type [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") - delete(*\*args*, *\*\*kwargs*)[¶](#MockedEntity.delete "Permalink to this definition") * Return type `None` * rename(*name*, *\*args*, *\*\*kwargs*)[¶](#MockedEntity.rename "Permalink to this definition") * Return type [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") - revisions(*\*args*, *\*\*kwargs*)[¶](#MockedEntity.revisions "Permalink to this definition") * Return type `List`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")] * set\_params(*params*, *\*args*, *\*\*kwargs*)[¶](#MockedEntity.set_params "Permalink to this definition") * Return type [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") ## MockedEntityList[​](/sdk/13/api/testing/.md#_MockedEntityList "Direct link to MockedEntityList") * *class *viktor.testing.MockedEntityList(*entities*, *\**, *error=None*)[¶](#MockedEntityList "Permalink to this definition") ## mock\_API[​](/sdk/13/api/testing/.md#_mock_API "Direct link to mock_API") * viktor.testing.mock\_API(*\**, *get\_entity=None*, *create\_child\_entity=None*, *generate\_upload\_url=None*, *get\_current\_user=None*, *get\_entities\_by\_type=None*, *get\_entity\_children=None*, *get\_entity\_siblings=None*, *get\_root\_entities=None*, *get\_entity\_parent=None*, *get\_entity\_revisions=None*, *get\_entity\_file=None*, *rename\_entity=None*, *set\_entity\_params=None*)[¶](#mock_API "Permalink to this definition") New in v13.3.0 Decorator that can be used to mock API() method calls, to facilitate easier testing. Example: ``` import unittest from viktor import File from viktor.testing import mock_API, MockedEntity from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_API( get_entity=[MockedEntity(entity_id=98), MockedEntity(entity_id=99)], get_entity_file=File.from_data("fake content") ) def test_api_calls(self): MyEntityController().api_calls() ``` Note that last\_saved\_params can be passed to MockedEntity from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` import unittest from viktor import File from viktor.testing import mock_API, MockedEntity, mock_params, MockedFileResource from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): json_file = File.from_path("path to JSON file") params = mock_params( json_file, MyEntityController.parametrization, entities={1: MockedEntity(name="MyEntity")}, file_resources={1: MockedFileResource(File.from_data("content"), "file")} ) @mock_API( get_entity=MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ) def test_api_calls(self): MyEntityController().api_calls() ``` * For all parameters the following holds: * If a Sequence type is provided, the next entry is returned for each corresponding API method call. When an API method is called on a depleted iterable, an Exception is raised. * If a single object is provided, the object is returned each time the corresponding API method is called (endlessly). * If None is provided (default), a default object is returned each time the corresponding API method is called (endlessly). - Parameters * **get\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity"), `None`]) – Return value of API.get\_entity. * **create\_child\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity"), `None`]) – Return value of API.create\_child\_entity. * **generate\_upload\_url** (`Union`\[`Sequence`\[`dict`], `dict`, `None`]) – Return value of API.generate\_upload\_url. * **get\_current\_user** (`Union`\[`Sequence`\[[`MockedUser`](#MockedUser "viktor.testing.MockedUser")], [`MockedUser`](#MockedUser "viktor.testing.MockedUser"), `None`]) – Return value of API.get\_current\_user. * **get\_entities\_by\_type** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], `None`]) – Return value of API.get\_entities\_by\_type. * **get\_entity\_children** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], `None`]) – Return value of API.get\_entity\_children. * **get\_entity\_siblings** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], `None`]) – Return value of API.get\_entity\_siblings. * **get\_root\_entities** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], `None`]) – Return value of API.get\_root\_entities. * **get\_entity\_parent** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity"), `None`]) – Return value of API.get\_entity\_parent. * **get\_entity\_revisions** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")]], `Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")], `None`]) – Return value of API.get\_entity\_revisions. * **get\_entity\_file** (`Union`\[`Sequence`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of API.get\_entity\_file. * **rename\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity"), `None`]) – Return value of API.rename\_entity. * **set\_entity\_params** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity"), `None`]) – Return value of API.set\_entity\_params. - Return type `Callable` ## mock\_params[​](/sdk/13/api/testing/.md#_mock_params "Direct link to mock_params") * viktor.testing.mock\_params(*params*, *parametrization*, *file\_resources=None*, *entities=None*)[¶](#mock_params "Permalink to this definition") Convert a plain dict to the (deserialized) params, replacing FileResource and Entity objects with their mocked counterpart (MockedFileResource, MockedEntity). Can be used to test methods with params in their signature that are called by the VIKTOR platform (e.g. view methods, button methods). Example: ``` import unittest from viktor import File from viktor.testing import mock_params, MockedEntity, MockedFileResource from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): def test_button_method(self): // provide the params manually... params_dict = {'number': 1, 'entity': 2, 'file': 3} // or from a JSON file... params_dict = File.from_path("path to my JSON file") mocked_params = mock_params( params, MyEntityController.parametrization entities={2: MockedEntity(entity_id=2, name="My Entity")} file_resources={3: MockedFileResource(File.from_data("content"), "file.txt")}, ) MyEntityController().button_method(mocked_params) ``` Deserialization only affects the raw values associated with the following fields: > * DateField > > * EntityOptionField > > * ChildEntityOptionField > > * SiblingEntityOptionField > > * EntityMultiSelectField > > * ChildEntityMultiSelectField > > * SiblingEntityMultiSelectField > > * GeoPointField > > * GeoPolylineField > > * GeoPolygonField > > * FileField > > * MultiFileField * Parameters * **params** (`Union`\[`dict`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – Plain dict or JSON file (with serialized params) to be converted to the (deserialized) params. * **parametrization** ([`Parametrization`](/sdk/13/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization")) – Parametrization corresponding to the params. * **file\_resources** (`Optional`\[`Dict`\[`int`, [`MockedFileResource`](#MockedFileResource "viktor.testing.MockedFileResource")]]) – Maps FileResource source id in params to mocked file resource. If source id is not in file\_resources, a default MockedFileResource (with default filename and File) is returned. * **entities** (`Optional`\[`Dict`\[`int`, [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Maps entity id in params to mocked entity. If entity id is not in entities, a default MockedEntity is returned. * Return type `Munch` ## mock\_View[​](/sdk/13/api/testing/.md#_mock_View "Direct link to mock_View") * viktor.testing.mock\_View(*controller*)[¶](#mock_View "Permalink to this definition") New in v13.3.0 Decorator that can be used to mock @View decorators (any subclass of [`viktor.views.View`](/sdk/13/api/views/.md#View "viktor.views.View")), to facilitate easier testing of view methods. Example: ``` import unittest from viktor.testing import mock_View from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_View(MyEntityController) def test_geometry_view(self): params = ... geometry_result = MyEntityController().geometry_view(params=params) self.assertIsInstance(geometry_result.geometry, TransformableObject) self.assertEqual(geometry_result.labels, ...) ``` * Parameters **controller** (`Type`\[[`ViktorController`](/sdk/13/api/core/.md#ViktorController "viktor.core.ViktorController")]) – Controller class on which the @View decorator should be mocked * Return type `Callable` ## mock\_SciaAnalysis[​](/sdk/13/api/testing/.md#_mock_SciaAnalysis "Direct link to mock_SciaAnalysis") * viktor.testing.mock\_SciaAnalysis(*get\_engineering\_report=None*, *get\_updated\_esa\_model=None*, *get\_xml\_output\_file=None*)[¶](#mock_SciaAnalysis "Permalink to this definition") New in v13.3.0 Decorator that can be used to mock `viktor.external.scia.SciaAnalysis`, to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_SciaAnalysis from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_SciaAnalysis( get_engineering_report=File.from_path(Path(__file__).parent / 'test_file.pdf'), get_updated_esa_model=File.from_path(Path(__file__).parent / 'test_file.esa'), get_xml_output_file=File.from_path(Path(__file__).parent / 'test_output.xml') ) def test_scia_analysis(self): MyEntityController().scia_analysis() ``` * For all 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). - Parameters * **get\_engineering\_report** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of SciaAnalysis.get\_engineering\_report. * **get\_updated\_esa\_model** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of SciaAnalysis.get\_updated\_esa\_model. * **get\_xml\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of SciaAnalysis.get\_xml\_output\_file. - Return type `Callable` ## mock\_DSettlementAnalysis[​](/sdk/13/api/testing/.md#_mock_DSettlementAnalysis "Direct link to mock_DSettlementAnalysis") * viktor.testing.mock\_DSettlementAnalysis(*get\_output\_file=None*, *get\_sld\_file=None*)[¶](#mock_DSettlementAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dsettlement.DSettlementAnalysis`](/sdk/13/api/external/dsettlement/.md#DSettlementAnalysis "viktor.external.dsettlement.DSettlementAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_DSettlementAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSettlementAnalysis(get_output_file={ '.sld': File.from_path(Path(__file__).parent / 'test_output.sld'), '.slo': File.from_path(Path(__file__).parent / 'test_output.slo') }) def test_dsettlement_analysis(self): MyEntityTypeController().dsettlement_analysis() ``` * For all 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 or StringIO/BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters * **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of DSettlementAnalysis.get\_output\_file. * **get\_sld\_file** (`Union`\[`Sequence`\[`Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of DSettlementAnalysis.get\_sld\_file. - Return type `Callable` ## mock\_DSheetPilingAnalysis[​](/sdk/13/api/testing/.md#_mock_DSheetPilingAnalysis "Direct link to mock_DSheetPilingAnalysis") * viktor.testing.mock\_DSheetPilingAnalysis(*get\_output\_file=None*)[¶](#mock_DSheetPilingAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dsheetpiling.DSheetPilingAnalysis`](/sdk/13/api/external/dsheetpiling/.md#DSheetPilingAnalysis "viktor.external.dsheetpiling.DSheetPilingAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_DSheetPilingAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSheetPilingAnalysis(get_output_file={ '.shd': File.from_path(Path(__file__).parent / 'test_output.shd'), '.shl': File.from_path(Path(__file__).parent / 'test_output.shl'), '.shs': File.from_path(Path(__file__).parent / 'test_output.shs'), '.sho': File.from_path(Path(__file__).parent / 'test_output.sho') }) def test_dsheetpiling_analysis(self): MyEntityTypeController().dsheetpiling_analysis() ``` * For all 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). - Parameters **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of DSheetPilingAnalysis.get\_output\_file. - Return type `Callable` ## mock\_DStabilityAnalysis[​](/sdk/13/api/testing/.md#_mock_DStabilityAnalysis "Direct link to mock_DStabilityAnalysis") * viktor.testing.mock\_DStabilityAnalysis(*get\_output\_file=None*)[¶](#mock_DStabilityAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dstability.DStabilityAnalysis`](/sdk/13/api/external/dstability/.md#DStabilityAnalysis "viktor.external.dstability.DStabilityAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_DStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DStabilityAnalysis(get_output_file={ '.stix': File.from_path(Path(__file__).parent / 'test_output.stix') }) def test_dstability_analysis(self): MyEntityTypeController().dstability_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of DStabilityAnalysis.get\_output\_file. - Return type `Callable` ## mock\_DGeoStabilityAnalysis[​](/sdk/13/api/testing/.md#_mock_DGeoStabilityAnalysis "Direct link to mock_DGeoStabilityAnalysis") * viktor.testing.mock\_DGeoStabilityAnalysis(*get\_output\_file=None*)[¶](#mock_DGeoStabilityAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dgeostability.DGeoStabilityAnalysis`](/sdk/13/api/external/dgeostability/.md#DGeoStabilityAnalysis "viktor.external.dgeostability.DGeoStabilityAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_DGeoStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DGeoStabilityAnalysis(get_output_file={ '.sto': File.from_path(Path(__file__).parent / 'test_output.sto') }) def test_dgeostability_analysis(self): MyEntityTypeController().dgeostability_analysis() ``` * For all 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). - Parameters **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of DGeoStabilityAnalysis.get\_output\_file. - Return type `Callable` ## mock\_DFoundationsAnalysis[​](/sdk/13/api/testing/.md#_mock_DFoundationsAnalysis "Direct link to mock_DFoundationsAnalysis") * viktor.testing.mock\_DFoundationsAnalysis(*get\_output\_file=None*)[¶](#mock_DFoundationsAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dfoundations.DFoundationsAnalysis`](/sdk/13/api/external/dfoundations/.md#DFoundationsAnalysis "viktor.external.dfoundations.DFoundationsAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_DFoundationsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DFoundationsAnalysis(get_output_file={ '.fod': File.from_path(Path(__file__).parent / 'test_output.fod'), '.fos': File.from_path(Path(__file__).parent / 'test_output.fos') }) def test_dfoundations_analysis(self): MyEntityTypeController().dfoundations_analysis() ``` * For all 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). - Parameters **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of DFoundationsAnalysis.get\_output\_file. - Return type `Callable` ## mock\_GRLWeapAnalysis[​](/sdk/13/api/testing/.md#_mock_GRLWeapAnalysis "Direct link to mock_GRLWeapAnalysis") * viktor.testing.mock\_GRLWeapAnalysis(*get\_output\_file=None*)[¶](#mock_GRLWeapAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.grlweap.GRLWeapAnalysis`](/sdk/13/api/external/grlweap/.md#GRLWeapAnalysis "viktor.external.grlweap.GRLWeapAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_GRLWeapAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GRLWeapAnalysis( get_output_file=File.from_path(Path(__file__).parent / 'test_output.GWO') ) def test_grlweap_analysis(self): MyEntityTypeController().grlweap_analysis() ``` * For all 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). - Parameters **get\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of GRLWeapAnalysis.get\_output\_file. - Return type `Callable` ## mock\_IdeaRcsAnalysis[​](/sdk/13/api/testing/.md#_mock_IdeaRcsAnalysis "Direct link to mock_IdeaRcsAnalysis") * viktor.testing.mock\_IdeaRcsAnalysis(*get\_output\_file=None*, *get\_idea\_rcs\_file=None*)[¶](#mock_IdeaRcsAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock `viktor.external.idea_rcs.IdeaRcsAnalysis`, to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_IdeaRcsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_IdeaRcsAnalysis( get_output_file=File.from_path(Path(__file__).parent / 'test_output.xml'), get_idea_rcs_file=File.from_path(Path(__file__).parent / 'test_rcs.ideaRcs') ) def test_idea_rcs_analysis(self): MyEntityTypeController().idea_rcs_analysis() ``` * For all 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). - Parameters * **get\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of IdeaRcsAnalysis.get\_output\_file. * **get\_idea\_rcs\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of IdeaRcsAnalysis.get\_idea\_rcs\_file. - Return type `Callable` ## mock\_RobotAnalysis[​](/sdk/13/api/testing/.md#_mock_RobotAnalysis "Direct link to mock_RobotAnalysis") * viktor.testing.mock\_RobotAnalysis(*get\_model\_file=None*, *get\_results=None*)[¶](#mock_RobotAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.robot.RobotAnalysis`](/sdk/13/api/external/robot/.md#RobotAnalysis "viktor.external.robot.RobotAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_RobotAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RobotAnalysis( get_model_file=File.from_path(Path(__file__).parent / 'test_model.rtd'), get_results={'bar_forces': {...}, ...} ) def test_robot_analysis(self): MyEntityTypeController().robot_analysis() ``` * For all 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/dict object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters * **get\_model\_file** (`Union`\[`Sequence`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of RobotAnalysis.get\_model\_file. * **get\_results** (`Union`\[`Sequence`\[`dict`], `dict`, `None`]) – Return value of RobotAnalysis.get\_results. - Return type `Callable` ## mock\_AxisVMAnalysis[​](/sdk/13/api/testing/.md#_mock_AxisVMAnalysis "Direct link to mock_AxisVMAnalysis") * viktor.testing.mock\_AxisVMAnalysis(*get\_model\_file=None*, *get\_result\_file=None*, *get\_results=None*)[¶](#mock_AxisVMAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.axisvm.AxisVMAnalysis`](/sdk/13/api/external/axisvm/.md#AxisVMAnalysis "viktor.external.axisvm.AxisVMAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_AxisVMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_AxisVMAnalysis( get_model_file=File.from_path(Path(__file__).parent / 'test_model.axs'), get_result_file=File.from_path(Path(__file__).parent / 'test_model.axe'), get_results={'Forces': ...} ) def test_axisvm_analysis(self): MyEntityTypeController().axisvm_analysis() ``` * For all 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/dict object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters * **get\_model\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of AxisVMAnalysis.get\_model\_file. * **get\_result\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of AxisVMAnalysis.get\_result\_file. * **get\_results** (`Union`\[`Sequence`\[`dict`], `dict`, `None`]) – Return value of AxisVMAnalysis.get\_results. - Return type `Callable` ## mock\_GenericAnalysis[​](/sdk/13/api/testing/.md#_mock_GenericAnalysis "Direct link to mock_GenericAnalysis") * viktor.testing.mock\_GenericAnalysis(*get\_output\_file=None*)[¶](#mock_GenericAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.generic.GenericAnalysis`](/sdk/13/api/external/generic/.md#GenericAnalysis "viktor.external.generic.GenericAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_GenericAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GenericAnalysis(get_output_file={ 'data.out': File.from_path(Path(__file__).parent / 'data.out'), 'info.log': File.from_path(Path(__file__).parent / 'info.log') }) def test_generic_analysis(self): MyEntityTypeController().generic_analysis() ``` * For all 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 or BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters **get\_output\_file** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]]]) – Return value of GenericAnalysis.get\_output\_file. - Return type `Callable` ## mock\_Excel[​](/sdk/13/api/testing/.md#_mock_Excel "Direct link to mock_Excel") * viktor.testing.mock\_Excel(*get\_named\_cell\_result=None*, *get\_direct\_cell\_result=None*, *get\_filled\_template=None*)[¶](#mock_Excel "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.excel.Excel`](/sdk/13/api/external/excel/.md#Excel "viktor.external.excel.Excel"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_Excel from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_Excel( get_filled_template=File.from_path(Path(__file__).parent / 'test_model.xlsx'), get_named_cell_result={"cell name": 5.5}, get_direct_cell_result={ ("Sheet1", "A", 5): "cell value", ("Sheet2", "B", 1): 1.4, } ) def test_excel_analysis(self): MyEntityTypeController().excel_analysis() ``` * For all 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 object (with empty content) is returned for the template, whereas None is returned for the cell values, each time the corresponding method is called (endlessly). - Parameters * **get\_named\_cell\_result** (`Optional`\[`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`str`, `int`, `float`, `bool`]], `str`, `int`, `float`, `bool`]]]) – Return value of Excel.get\_named\_cell\_result. * **get\_direct\_cell\_result** (`Optional`\[`Dict`\[`Tuple`\[`str`, `str`, `int`], `Union`\[`Sequence`\[`Union`\[`str`, `int`, `float`, `bool`]], `str`, `int`, `float`, `bool`]]]) – Return value of Excel.get\_direct\_cell\_result. * **get\_filled\_template** (`Union`\[`Sequence`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of Excel.get\_filled\_template. - Return type `Callable` ## mock\_RFEMAnalysis[​](/sdk/13/api/testing/.md#_mock_RFEMAnalysis "Direct link to mock_RFEMAnalysis") * viktor.testing.mock\_RFEMAnalysis(*get\_model=None*, *get\_result=None*)[¶](#mock_RFEMAnalysis "Permalink to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.rfem.RFEMAnalysis`](/sdk/13/api/external/rfem/.md#RFEMAnalysis "viktor.external.rfem.RFEMAnalysis"), to facilitate easier testing. Example: ``` import unittest from viktor.testing import mock_RFEMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RFEMAnalysis( get_model=File.from_path(Path(__file__).parent / 'test_model.rfx') get_result={ 3: File.from_path(Path(__file__).parent / 'load_case_3.json'), 5: File.from_path(Path(__file__).parent / 'load_case_5.json') } ) def test_rfem_analysis(self): MyEntityTypeController().rfem_analysis() }) def test_rfem_analysis(self): MyEntityTypeController().rfem_analysis() ``` * For all parameters the following can be provided: * 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 BytesIO/File object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters * **get\_model** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `None`]) – Return value of RFEMAnalysis.get\_model. * **get\_result** (`Optional`\[`Dict`\[`int`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]], [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `BytesIO`]]]) – Return value of RFEMAnalysis.get\_result. - Return type `Callable` --- # viktor.utils ## memoize[​](/sdk/13/api/utils/.md#_memoize "Direct link to memoize") * viktor.utils.memoize(*fun*)[¶](#memoize "Permalink to this definition") Decorator that applies memoization to a function. This can increase performance when the function is called multiple times with identical input. When using multiple decorators, this should be the last decorator. Warning memoized keys will differ depending on parameters being passed as args or kwargs, which can cause a (unexpected) cache miss! For example, f(1, y=2) and f(x=1, y=2) will be treated as two different entries. Prefer to use functions with kwargs only to prevent this. Example: ``` # In this example, a DataView performs a long-running calculation when # calling `func`. When the user changes input in the editor and updates # the view again, `func` will only be evaluated again if either one of # `param_a`, `param_b`, or `param_c` is changed in-between jobs. @memoize def func(*, param_a, param_b, param_c): # perform lengthy calculation return result class Controller(ViktorController): ... @DataView("Results", duration_guess=30) def get_data_view(self, params, **kwargs): ... result = func(param_a=..., param_b=..., param_c=...) ... return DataResult(...) ``` CAUTION: Only use this function when you are 100% sure of the following: > * The function is a pure function (e.g. @staticmethod) meaning: > > > * It always returns the same result for a given input. [1](#id5) > > > > * It does not depend on other data and does not have side effects such as API calls or calls to others objects that persist state. [2](#id6) > > * If part of the returning data contains a modified input, it must not be a problem that the memory reference is lost and a new object is returned. > > * The input of the function is serializable. [3](#id7) > > * The output of the function is serializable. [3](#id7) > > * During memoization, tuples in the input are casted to lists before determining uniqueness. > > * During memoization, tuples in the output are casted to lists before returning. > > * In the design of your application you should take into account that the application should not fail in timeouts/unresponsiveness if the memoization does not work. It should be a bonus if it works. > > * The function name is unique within the Python file. * [1](#id1) Variables/objects/functions defined outside of the memoized function are not used in the memoized function. * [2](#id2) The function should only return results. Any other actions defined in the function are not performed if the function call is memoized. * 3([1](#id3),[2](#id4)) ‘Serializable’ in this context means the data is any of the following types: boolean, dictionary, float, int, list, none, string, tuple. Types as returned in the ‘params’ are also allowed (e.g. GeoPoint, FileResource, datetime.date, etc.) with the exception of Entity. When data is nested, the nesting can only contain any of the aforementioned types. Practical uses of this are, but not limited to, function calls with input and output that is relatively small compared to the amount of time required for the evaluation. Note When using the memoization decorator on your development environment the cache is stored locally. The local storage is limited to 10 function calls. If the limit is exceeded, cached results are cleared based on a first in, first out approach. In production the storage is not limited to 10 function calls. * Parameters **fun** (`Callable`) – original function * Return type `Callable` ## render\_jinja\_template[​](/sdk/13/api/utils/.md#_render_jinja_template "Direct link to render_jinja_template") * viktor.utils.render\_jinja\_template(*template*, *variables*)[¶](#render_jinja_template "Permalink to this definition") Render a template using Jinja. Example usage: ``` with open("path/to/template.jinja", 'rb') as template: result = render_jinja_template(template, {'name': 'John Doe'}) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters * **template** (`BinaryIO`) – Jinja template file. * **variables** (`dict`) – set of variables to fill the template with. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing the rendered template ## merge\_pdf\_files[​](/sdk/13/api/utils/.md#_merge_pdf_files "Direct link to merge_pdf_files") * viktor.utils.merge\_pdf\_files(*\*files*)[¶](#merge_pdf_files "Permalink to this definition") This method can be used to merge several PDFs into one document. BinaryIO objects can be directly used as arguments in the method. The merged document is returned as a File object. The order of the input files is preserved in the resulting document. Example usages: ``` from viktor.core import File # using File object file1 = File.from_path(Path(__file__).parent / "pdf1.pdf") file2 = File.from_path(Path(__file__).parent / "pdf2.pdf") with file1.open_binary() as f1, file2.open_binary() as f2: merged_pdf = merge_pdf_files(f1, f2) # using built-in `open()` with open(Path(__file__).parent / "pdf1.pdf", "rb") as f1, open(Path(__file__).parent / "pdf2.pdf", "rb") as f2: merged_pdf = merge_pdf_files(f1, f2) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing merged document. ## convert\_word\_to\_pdf[​](/sdk/13/api/utils/.md#_convert_word_to_pdf "Direct link to convert_word_to_pdf") * viktor.utils.convert\_word\_to\_pdf(*file*)[¶](#convert_word_to_pdf "Permalink to this definition") Convert a Word document to PDF. Example usages: ``` from viktor.core import File # using File object file1 = File.from_path(Path(__file__).parent / "mydocument.docx") with file1.open_binary() as f1: pdf = convert_word_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.docx", "rb") as f1: pdf = convert_word_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **file** (`BinaryIO`) – Document to be converted. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing converted document. ## convert\_excel\_to\_pdf[​](/sdk/13/api/utils/.md#_convert_excel_to_pdf "Direct link to convert_excel_to_pdf") * viktor.utils.convert\_excel\_to\_pdf(*file*)[¶](#convert_excel_to_pdf "Permalink to this definition") Convert an Excel document to PDF. Example usages: ``` from viktor.core import File # using File object file1 = File.from_path(Path(__file__).parent / "mydocument.xlsx") with file1.open_binary() as f1: pdf = convert_excel_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.xlsx", "rb") as f1: pdf = convert_excel_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **file** (`BinaryIO`) – Document to be converted. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing converted document. ## convert\_svg\_to\_pdf[​](/sdk/13/api/utils/.md#_convert_svg_to_pdf "Direct link to convert_svg_to_pdf") * viktor.utils.convert\_svg\_to\_pdf(*file*)[¶](#convert_svg_to_pdf "Permalink to this definition") Convert a SVG document to PDF. Example usages: ``` from viktor.core import File # using File object file1 = File.from_path(Path(__file__).parent / "mydocument.svg") with file1.open_binary() as f1: pdf = convert_svg_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.svg", "rb") as f1: pdf = convert_svg_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters **file** (`BinaryIO`) – Document to be converted. * Return type [`File`](/sdk/13/api/core/.md#File "viktor.core.File") * Returns File object containing converted document. --- # viktor.views ## DataStatus[​](/sdk/13/api/views/.md#_DataStatus "Direct link to DataStatus") * *class *viktor.views.DataStatus(*value*)[¶](#DataStatus "Permalink to this definition") Bases: `Enum` Enumeration of statuses to annotate a DataItem. * INFO*: [DataStatus](#DataStatus "viktor.views.DataStatus")** = 'info'*[¶](#DataStatus.INFO "Permalink to this definition") - SUCCESS*: [DataStatus](#DataStatus "viktor.views.DataStatus")** = 'success'*[¶](#DataStatus.SUCCESS "Permalink to this definition") * WARNING*: [DataStatus](#DataStatus "viktor.views.DataStatus")** = 'warning'*[¶](#DataStatus.WARNING "Permalink to this definition") - ERROR*: [DataStatus](#DataStatus "viktor.views.DataStatus")** = 'error'*[¶](#DataStatus.ERROR "Permalink to this definition") ## DataItem[​](/sdk/13/api/views/.md#_DataItem "Direct link to DataItem") * *class *viktor.views.DataItem(*label*, *value*, *subgroup=None*, *\**, *prefix=''*, *suffix=''*, *number\_of\_decimals=None*, *status=DataStatus.INFO*, *status\_message=''*, *explanation\_label=''*)[¶](#DataItem "Permalink to this definition") Constructs an entry that can be used as input of a DataGroup, to fill the data view with results. The data view is dynamic, which means that a DataItem itself can consist of another DataGroup as subgroup. Both examples are demonstrated below. Example single entry: ``` result = "I am a great result" item = DataItem('output 1', result) ``` Example subgroup: ``` result = "I am a great result" item = DataItem('output 1', result, subgroup=DataGroup( output11=DataItem('output 1.1', "I can also be a numeric result"), output12=DataItem('output 1.2', 123) )) ``` The prefix / suffix can potentially change with every call. However, when the result is used in the Summary, the prefix / suffix of the DataItem should be equal to the prefix / suffix of the SummaryItem to maintain a consistent database. * Parameters * **label** (`str`) – Description of the value which is shown. e.g: ‘Uc bending’ * **value** (`Union`\[`str`, `float`, `None`]) – Value of the data. e.g: 0.9 * **subgroup** (`Optional`\[[`DataGroup`](#DataGroup "viktor.views.DataGroup")]) – Optional DataItems grouped together in a DataGroup underneath this DataItem. Maximum depth = 3 * **prefix** (`str`) – E.g: €. Should be equal to the prefix of the SummaryItem if linked. * **suffix** (`str`) – E.g: N. Should be equal to the suffix of the SummaryItem if linked. * **number\_of\_decimals** (`Optional`\[`int`]) – Number of decimals with which the value is rounded for display. * **status** ([`DataStatus`](#DataStatus "viktor.views.DataStatus")) – Status of value. This controls the formatting of the status\_message: * status=DataStatus.INFO: black text * status=DataStatus.SUCCESS: green text * status=DataStatus.WARNING: orange text * status=DataStatus.ERROR: red text * **status\_message** (`str`) – Message which will be shown underneath the value. Color can be formatted with status. * **explanation\_label** (`str`) – Optional text which is placed between the label and the value. Could for instance be used for a calculation. * Raises **TypeError** – if number\_of\_decimals is used on a non-numeric value. - *property *subgroup*: [DataGroup](#DataGroup "viktor.views.DataGroup")*[¶](#DataItem.subgroup "Permalink to this definition") * Return type [`DataGroup`](#DataGroup "viktor.views.DataGroup") ## DataGroup[​](/sdk/13/api/views/.md#_DataGroup "Direct link to DataGroup") * *class *viktor.views.DataGroup(*\*args*, *\*\*kwargs*)[¶](#DataGroup "Permalink to this definition") Bases: `OrderedDict` Container for DataItems, maximum number = 100. They can be added with or without a keyword argument, but they should be equal for all DataItems in the same DataGroup. Keywords are necessary when you want to use a DataItem in the summary (for lookup). The following two use cases are valid: ``` d1 = DataGroup( DataItem('item1',0), DataItem('item2',1), ) d2 = DataGroup( a=DataItem('item1',0), b=DataItem('item2',1), ) ``` * Parameters * **args** ([`DataItem`](#DataItem "viktor.views.DataItem")) – DataItem entries. * **kwargs** ([`DataItem`](#DataItem "viktor.views.DataItem")) – Keyworded DataItem entries. * Raises * TypeError when positional- and keyword arguments are used together * AttributeError when more than 100 DataItems are used - *classmethod *from\_data\_groups(*groups*)[¶](#DataGroup.from_data_groups "Permalink to this definition") Constructs a combined DataGroup object from a list of individual DataGroup entries. Note that is not possible to have multiple DataGroups that share a specific key for a DataItem, e.g. the following will result in an error: ``` d1 = DataGroup(output_a=DataItem(...)) d2 = DataGroup(output_a=DataItem(...)) d3 = DataGroup.from_data_groups([d1, d2]) ``` * Return type [`DataGroup`](#DataGroup "viktor.views.DataGroup") ## MapEntityLink[​](/sdk/13/api/views/.md#_MapEntityLink "Direct link to MapEntityLink") * *class *viktor.views.MapEntityLink(*label*, *entity\_id*)[¶](#MapEntityLink "Permalink to this definition") Represents a link between a feature in a MapView and a specific entity. Example usage: ``` gef_link = MapEntityLink('GEF x', gef_entity_id) gef_marker = MapPoint(51.99311570849245, 4.385752379894256, entity_links=[gef_link]) ``` * Parameters * **label** (`str`) – text which is shown to the user. * **entity\_id** (`int`) – id of the linked entity. ## MapFeature[​](/sdk/13/api/views/.md#_MapFeature "Direct link to MapFeature") * *class *viktor.views.MapFeature(*\**, *title=None*, *description=None*, *color=Color(39, 45, 51)*, *entity\_links=None*, *identifier=None*)[¶](#MapFeature "Permalink to this definition") Bases: `ABC` Base class for features that can be shown in a MapView. See the documentation of the subclasses for example implementations. * Parameters * **title** (`Optional`\[`str`]) – Title of a clickable map feature. * **description** (`Optional`\[`str`]) – Description of a clickable map feature. * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – Specifies the color of the map feature. * **entity\_links** (`Optional`\[`List`\[[`MapEntityLink`](#MapEntityLink "viktor.views.MapEntityLink")]]) – When clicking on the map feature, links towards multiple entities can be shown. * **identifier** (`Union`\[`int`, `str`, `None`]) – feature identifier New in v13.2.0 ## MapPoint[​](/sdk/13/api/views/.md#_MapPoint "Direct link to MapPoint") * *class *viktor.views.MapPoint(*lat*, *lon*, *alt=0*, *\**, *icon=None*, *\*\*kwargs*)[¶](#MapPoint "Permalink to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a point on the Earth’s surface described by a latitude/longitude coordinate pair. Example usage: ``` marker = MapPoint(51.99311570849245, 4.385752379894256) ``` * Parameters * **lat** (`float`) – Latitude. * **lon** (`float`) – Longitude. * **alt** (`float`) – Altitude. * **icon** (`Optional`\[`str`]) – icon to be shown (default: “pin”). See below for all possible icons. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. List of icons: > * arrow-down: [![arrow-down](/_images/arrow-down.svg)](/_images/arrow-down.svg) > > * arrow-left: [![arrow-left](/_images/arrow-left.svg)](/_images/arrow-left.svg) > > * arrow-right: [![arrow-right](/_images/arrow-right.svg)](/_images/arrow-right.svg) > > * arrow-up: [![arrow-up](/_images/arrow-up.svg)](/_images/arrow-up.svg) > > * chevron-down: [![chevron-down](/_images/chevron-down.svg)](/_images/chevron-down.svg) > > * chevron-left: [![chevron-left](/_images/chevron-left.svg)](/_images/chevron-left.svg) > > * chevron-right: [![chevron-right](/_images/chevron-right.svg)](/_images/chevron-right.svg) > > * chevron-up: [![chevron-up](/_images/chevron-up.svg)](/_images/chevron-up.svg) > > * circle: [![circle](/_images/circle.svg)](/_images/circle.svg) > > * circle-filled: [![circle-filled](/_images/circle-filled.svg)](/_images/circle-filled.svg) > > * cross: [![cross](/_images/cross.svg)](/_images/cross.svg) > > * diamond: [![diamond](/_images/diamond.svg)](/_images/diamond.svg) > > * diamond-horizontal: [![diamond-horizontal](/_images/diamond-horizontal.svg)](/_images/diamond-horizontal.svg) > > * drop: [![drop](/_images/drop.svg)](/_images/drop.svg) > > * exclamation-circle: [![exclamation-circle](/_images/exclamation-circle.svg)](/_images/exclamation-circle.svg) > > * exclamation-circle-filled: [![exclamation-circle-filled](/_images/exclamation-circle-filled.svg)](/_images/exclamation-circle-filled.svg) > > * message: [![message](/_images/message.svg)](/_images/message.svg) > > * minus: [![minus](/_images/minus.svg)](/_images/minus.svg) > > * minus-circle: [![minus-circle](/_images/minus-circle.svg)](/_images/minus-circle.svg) > > * minus-circle-filled: [![minus-circle-filled](/_images/minus-circle-filled.svg)](/_images/minus-circle-filled.svg) > > * pin: [![pin](/_images/pin.svg)](/_images/pin.svg) > > * pin-add: [![pin-add](/_images/pin-add.svg)](/_images/pin-add.svg) > > * pin-edit: [![pin-edit](/_images/pin-edit.svg)](/_images/pin-edit.svg) > > * plus: [![plus](/_images/plus.svg)](/_images/plus.svg) > > * plus-circle: [![plus-circle](/_images/plus-circle.svg)](/_images/plus-circle.svg) > > * plus-circle-filled: [![plus-circle-filled](/_images/plus-circle-filled.svg)](/_images/plus-circle-filled.svg) > > * plus-thick: [![plus-thick](/_images/plus-thick.svg)](/_images/plus-thick.svg) > > * question-circle: [![question-circle](/_images/question-circle.svg)](/_images/question-circle.svg) > > * question-circle-filled: [![question-circle-filled](/_images/question-circle-filled.svg)](/_images/question-circle-filled.svg) > > * square: [![square](/_images/square.svg)](/_images/square.svg) > > * square-filled: [![square-filled](/_images/square-filled.svg)](/_images/square-filled.svg) > > * star: [![star](/_images/star.svg)](/_images/star.svg) > > * triangle: [![triangle](/_images/triangle.svg)](/_images/triangle.svg) > > * triangle-down: [![triangle-down](/_images/triangle-down.svg)](/_images/triangle-down.svg) > > * triangle-down-filled: [![triangle-down-filled](/_images/triangle-down-filled.svg)](/_images/triangle-down-filled.svg) > > * triangle-filled: [![triangle-filled](/_images/triangle-filled.svg)](/_images/triangle-filled.svg) > > * triangle-left: [![triangle-left](/_images/triangle-left.svg)](/_images/triangle-left.svg) > > * triangle-left-filled: [![triangle-left-filled](/_images/triangle-left-filled.svg)](/_images/triangle-left-filled.svg) > > * triangle-right: [![triangle-right](/_images/triangle-right.svg)](/_images/triangle-right.svg) > > * triangle-right-filled: [![triangle-right-filled](/_images/triangle-right-filled.svg)](/_images/triangle-right-filled.svg) > > * viktor: [![viktor](/_images/viktor.svg)](/_images/viktor.svg) > > * warning: [![warning](/_images/warning.svg)](/_images/warning.svg) > > * warning-filled: [![warning-filled](/_images/warning-filled.svg)](/_images/warning-filled.svg) > > * wye: [![wye](/_images/wye.svg)](/_images/wye.svg) * *classmethod *from\_geo\_point(*point*, *\**, *icon=None*, *\*\*kwargs*)[¶](#MapPoint.from_geo_point "Permalink to this definition") Instantiates a MapPoint from the provided GeoPoint. * Parameters * **point** ([`GeoPoint`](/sdk/13/api/geometry/.md#GeoPoint "viktor.geometry.GeoPoint")) – GeoPoint. * **icon** (`Optional`\[`str`]) – icon to be shown (default: “pin”). For a complete list of all available markers, see `__init__()` * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type [`MapPoint`](#MapPoint "viktor.views.MapPoint") - *property *lat*: float*[¶](#MapPoint.lat "Permalink to this definition") * Return type `float` * *property *lon*: float*[¶](#MapPoint.lon "Permalink to this definition") * Return type `float` - *property *alt*: float*[¶](#MapPoint.alt "Permalink to this definition") * Return type `float` ## MapPolyline[​](/sdk/13/api/views/.md#_MapPolyline "Direct link to MapPolyline") * *class *viktor.views.MapPolyline(*\*points*, *\*\*kwargs*)[¶](#MapPolyline "Permalink to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a polyline on the earth’s surface between several latitude/longitude pairs. Example usage: ``` line = MapPolyline( MapPoint(51.99311570849245, 4.385752379894256), MapPoint(52.40912125231122, 5.031738281255681), ... ) ``` * Parameters * **points** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – MapPoints with latitude and longitude pair. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *classmethod *from\_geo\_polyline(*polyline*, *\*\*kwargs*)[¶](#MapPolyline.from_geo_polyline "Permalink to this definition") Instantiates a MapPolyline from the provided GeoPolyline. * Parameters * **polyline** ([`GeoPolyline`](/sdk/13/api/geometry/.md#GeoPolyline "viktor.geometry.GeoPolyline")) – GeoPolyline. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") * *property *points*: List\[[MapPoint](#MapPoint "viktor.views.MapPoint")]*[¶](#MapPolyline.points "Permalink to this definition") * Return type `List`\[[`MapPoint`](#MapPoint "viktor.views.MapPoint")] ## MapLine[​](/sdk/13/api/views/.md#_MapLine "Direct link to MapLine") * *class *viktor.views.MapLine(*start\_point*, *end\_point*, *\*\*kwargs*)[¶](#MapLine "Permalink to this definition") Bases: [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") Represents a line on the earth’s surface between two latitude/longitude pairs. In case multiple line segments are to be created, a [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") may be preferred. Example usage: ``` line = MapLine( MapPoint(51.99311570849245, 4.385752379894256), MapPoint(52.40912125231122, 5.031738281255681) ) ``` * Parameters * **start\_point** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – Map point with latitude and longitude pair. * **end\_point** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – Map point with latitude and longitude pair. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *property *start\_point*: [MapPoint](#MapPoint "viktor.views.MapPoint")*[¶](#MapLine.start_point "Permalink to this definition") * Return type [`MapPoint`](#MapPoint "viktor.views.MapPoint") * *property *end\_point*: [MapPoint](#MapPoint "viktor.views.MapPoint")*[¶](#MapLine.end_point "Permalink to this definition") * Return type [`MapPoint`](#MapPoint "viktor.views.MapPoint") ## MapPolygon[​](/sdk/13/api/views/.md#_MapPolygon "Direct link to MapPolygon") * *class *viktor.views.MapPolygon(*points*, *\**, *holes=None*, *\*\*kwargs*)[¶](#MapPolygon "Permalink to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a polygon on the earth’s surface formed by a set of latitude/longitude pairs. Example usage: ``` polygon = MapPolygon([ MapPoint(52.373922404495474, 5.2459716796875), MapPoint(52.10313118589299, 5.3997802734375), MapPoint(52.373922404495474, 5.57281494140625), ]) ``` * Parameters * **points** (`List`\[[`MapPoint`](#MapPoint "viktor.views.MapPoint")]) – Map points with latitude and longitude pair. The profile is automatically closed, so it is not necessary to add the start point at the end. * **holes** (`Optional`\[`List`\[[`MapPolygon`](#MapPolygon "viktor.views.MapPolygon")]]) – List of interior polygons which form holes in the exterior polygon. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *classmethod *from\_geo\_polygon(*polygon*, *\*\*kwargs*)[¶](#MapPolygon.from_geo_polygon "Permalink to this definition") Instantiates a MapPolygon from the provided GeoPolygon. * Parameters * **polygon** ([`GeoPolygon`](/sdk/13/api/geometry/.md#GeoPolygon "viktor.geometry.GeoPolygon")) – GeoPolygon. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type [`MapPolygon`](#MapPolygon "viktor.views.MapPolygon") * *property *points*: List\[[MapPoint](#MapPoint "viktor.views.MapPoint")]*[¶](#MapPolygon.points "Permalink to this definition") * Return type `List`\[[`MapPoint`](#MapPoint "viktor.views.MapPoint")] - *property *holes*: List\[[MapPolygon](#MapPolygon "viktor.views.MapPolygon")]*[¶](#MapPolygon.holes "Permalink to this definition") * Return type `List`\[[`MapPolygon`](#MapPolygon "viktor.views.MapPolygon")] ## MapLegend[​](/sdk/13/api/views/.md#_MapLegend "Direct link to MapLegend") * *class *viktor.views.MapLegend(*entries*)[¶](#MapLegend "Permalink to this definition") A legend which is placed as an overlay on a map view. Example usage: ``` legend = MapLegend([ (Color.from_hex('#0016FF'), "I'm blue"), (Color.from_hex('#FF0000'), "I'm red"), ... ]) ``` * Parameters **entries** (`List`\[`Tuple`\[[`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color"), `str`]]) – Items in the legend, defined by color and label. ## MapLabel[​](/sdk/13/api/views/.md#_MapLabel "Direct link to MapLabel") * *class *viktor.views.MapLabel(*lat*, *lon*, *text*, *scale*, *\**, *fixed\_size=False*)[¶](#MapLabel "Permalink to this definition") Text which is placed as an overlay on the map. Scale 0-5 is approximately the scale for countries: [![/\_images/map\_label\_scale\_0\_5.png](/_images/map_label_scale_0_5.png)](/_images/map_label_scale_0_5.png) Scale 6-10 is approximately the scale for cities: [![/\_images/map\_label\_scale\_6\_11.png](/_images/map_label_scale_6_11.png)](/_images/map_label_scale_6_11.png) Scale 11-15 is approximately the scale for neighborhoods and streets [![/\_images/map\_label\_scale\_11\_15.png](/_images/map_label_scale_11_15.png)](/_images/map_label_scale_11_15.png) Scale 16-18 is approximately for individual houses. [![/\_images/map\_label\_scale\_14\_19.png](/_images/map_label_scale_14_19.png)](/_images/map_label_scale_14_19.png) * Parameters * **lat** (`float`) – Latitude of text in degrees. * **lon** (`float`) – Longitude of text in degrees. * **text** (`str`) – Text with is displayed on the map. * **scale** (`float`) – Size of the text on an exponential scale. See example in class docstring for estimate. * **fixed\_size** (`bool`) – When True, the size of the text is fixed regardless of zoom level (default: False). ## Label[​](/sdk/13/api/views/.md#_Label "Direct link to Label") * *class *viktor.views.Label(*point*, *\*text*, *size\_factor=1*, *color=Color(0, 0, 0)*)[¶](#Label "Permalink to this definition") Text label * Parameters * **point** ([`Point`](/sdk/13/api/geometry/.md#Point "viktor.geometry.Point")) – Position of the label. * **text** (`str`) – Text to show; multiple text arguments will each be shown on a new line. * **size\_factor** (`float`) – Factor to be applied to the font size (0 < size\_factor <= 10). * **color** ([`Color`](/sdk/13/api/core/.md#Color "viktor.core.Color")) – Color of the text. - *property *point*: [Point](/sdk/13/api/geometry/.md#Point "viktor.geometry.Point")*[¶](#Label.point "Permalink to this definition") * Return type [`Point`](/sdk/13/api/geometry/.md#Point "viktor.geometry.Point") * *property *text*: Union\[str, Tuple\[str, ...]]*[¶](#Label.text "Permalink to this definition") * Return type `Union`\[`str`, `Tuple`\[`str`, `...`]] - serialize()[¶](#Label.serialize "Permalink to this definition") * Return type `dict` ## GeometryResult[​](/sdk/13/api/views/.md#_GeometryResult "Direct link to GeometryResult") * *class *viktor.views.GeometryResult(*geometry*, *labels=None*)[¶](#GeometryResult "Permalink to this definition") Bases: `_ViewResult` Container with the results that should be visualized in a GeometryView. This consists of three-dimensional geometry object(s) and optional text labels. Example viktor.geometry TransformableObject(s): ``` geometry = Sphere(Point(0, 0), 10) GeometryResult(geometry) # or [obj1, obj2, ...] in case of multiple objects ``` Example glTF/GLB file: ``` geometry = File.from_path(Path(__file__).parent / "my_model.gltf") # or .glb GeometryResult(geometry) ``` Example glTF/GLB file from the internet: ``` geometry = File.from_url("https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb") GeometryResult(geometry) ``` Example trimesh package: ``` sphere = trimesh.creation.uv_sphere(10) scene = trimesh.Scene(geometry={'sphere': sphere}) geometry = File() with geometry.open_binary() as w: w.write(trimesh.exchange.gltf.export_glb(scene)) GeometryResult(geometry) ``` * Parameters * **geometry** (`Union`\[[`TransformableObject`](/sdk/13/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject"), `Sequence`\[[`TransformableObject`](/sdk/13/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – TransformableObject(s) that contain the geometric objects, or a glTF/GLB (v2.0) file (). * **labels** (`Optional`\[`List`\[[`Label`](#Label "viktor.views.Label")]]) – Text labels that can be used to provide additional information. ## GeometryAndDataResult[​](/sdk/13/api/views/.md#_GeometryAndDataResult "Direct link to GeometryAndDataResult") * *class *viktor.views.GeometryAndDataResult(*geometry*, *data*, *labels=None*)[¶](#GeometryAndDataResult "Permalink to this definition") Bases: `_ViewResult` Container with the results that should be visualized in a GeometryAndDataView. This consists of three-dimensional geometry object(s) with optional text labels and data. Please have a look at GeometryResult for examples. * Parameters * **geometry** (`Union`\[[`TransformableObject`](/sdk/13/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject"), `Sequence`\[[`TransformableObject`](/sdk/13/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject")], [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – TransformableObject(s) that contain the geometric objects, or a glTF/GLB (v2.0) file (). * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`Optional`\[`List`\[[`Label`](#Label "viktor.views.Label")]]) – Text labels that can be used to provide additional information. ## DataResult[​](/sdk/13/api/views/.md#_DataResult "Direct link to DataResult") * *class *viktor.views.DataResult(*data*)[¶](#DataResult "Permalink to this definition") Bases: `_ViewResult` Container with the data that should be shown in a DataView. This data can be nested up to three levels deep. * Parameters **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## ImageResult[​](/sdk/13/api/views/.md#_ImageResult "Direct link to ImageResult") * *class *viktor.views.ImageResult(*image*)[¶](#ImageResult "Permalink to this definition") Bases: `_ViewResult` New in v13.7.0 Image to be visualized in an ImageView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. * Parameters **image** (`Union`\[`StringIO`, `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – image file. - *classmethod *from\_path(*file\_path*)[¶](#ImageResult.from_path "Permalink to this definition") Use file path to construct the image result. * Parameters **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Path to the image. * Return type [`ImageResult`](#ImageResult "viktor.views.ImageResult") ## ImageAndDataResult[​](/sdk/13/api/views/.md#_ImageAndDataResult "Direct link to ImageAndDataResult") * *class *viktor.views.ImageAndDataResult(*image*, *data*)[¶](#ImageAndDataResult "Permalink to this definition") Bases: `_ViewResult` New in v13.7.0 Container with the image and result data that should be visualized in a ImageAndDataView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. * Parameters * **image** (`Union`\[`StringIO`, `BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – image file. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## PNGResult[​](/sdk/13/api/views/.md#_PNGResult "Direct link to PNGResult") * *class *viktor.views.PNGResult(*image*)[¶](#PNGResult "Permalink to this definition") Bases: `_ImageResult` Container with the PNG data that should be visualized in a PNGView. * Parameters **image** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – PNG image. - *classmethod *from\_path(*file\_path*)[¶](#PNGResult.from_path "Permalink to this definition") Use file path to construct the image result. * Parameters **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Path to the image. * Return type [`PNGResult`](#PNGResult "viktor.views.PNGResult") * *property *image*: Union\[BytesIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#PNGResult.image "Permalink to this definition") * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## PNGAndDataResult[​](/sdk/13/api/views/.md#_PNGAndDataResult "Direct link to PNGAndDataResult") * *class *viktor.views.PNGAndDataResult(*image*, *data*)[¶](#PNGAndDataResult "Permalink to this definition") Bases: `_ImageAndDataResult` Container with the PNG data that should be visualized in a PNGAndDataView, along with the result data. * Parameters * **image** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – PNG image. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. - *property *image*: Union\[BytesIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#PNGAndDataResult.image "Permalink to this definition") * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## JPGResult[​](/sdk/13/api/views/.md#_JPGResult "Direct link to JPGResult") * *class *viktor.views.JPGResult(*image*)[¶](#JPGResult "Permalink to this definition") Bases: `_ImageResult` Container with the JPG data that should be visualized in a JPGView. * Parameters **image** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – JPG image. - *classmethod *from\_path(*file\_path*)[¶](#JPGResult.from_path "Permalink to this definition") Use file path to construct the image result. * Parameters **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Path to the image. * Return type [`JPGResult`](#JPGResult "viktor.views.JPGResult") * *property *image*: Union\[BytesIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#JPGResult.image "Permalink to this definition") * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## JPGAndDataResult[​](/sdk/13/api/views/.md#_JPGAndDataResult "Direct link to JPGAndDataResult") * *class *viktor.views.JPGAndDataResult(*image*, *data*)[¶](#JPGAndDataResult "Permalink to this definition") Bases: `_ImageAndDataResult` Container with the JPG data that should be visualized in a JPGAndDataView, along with the result data. * Parameters * **image** (`Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – JPG image. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. - *property *image*: Union\[BytesIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#JPGAndDataResult.image "Permalink to this definition") * Return type `Union`\[`BytesIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## SVGResult[​](/sdk/13/api/views/.md#_SVGResult "Direct link to SVGResult") * *class *viktor.views.SVGResult(*image*)[¶](#SVGResult "Permalink to this definition") Bases: `_ImageResult` Container with the SVG data that should be visualized in a SVGView. * Parameters **image** (`Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – SVG image. - *classmethod *from\_path(*file\_path*)[¶](#SVGResult.from_path "Permalink to this definition") Use file path to construct the image result. * Parameters **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Path to the image. * Return type [`SVGResult`](#SVGResult "viktor.views.SVGResult") * *property *image*: Union\[StringIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#SVGResult.image "Permalink to this definition") * Return type `Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## SVGAndDataResult[​](/sdk/13/api/views/.md#_SVGAndDataResult "Direct link to SVGAndDataResult") * *class *viktor.views.SVGAndDataResult(*image*, *data*)[¶](#SVGAndDataResult "Permalink to this definition") Bases: `_ImageAndDataResult` Container with the SVG data that should be visualized in a SVGAndDataView, along with the result data. * Parameters * **image** (`Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – SVG image. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. - *property *image*: Union\[StringIO, [File](/sdk/13/api/core/.md#File "viktor.core.File")]*[¶](#SVGAndDataResult.image "Permalink to this definition") * Return type `Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File")] ## GeoJSONResult[​](/sdk/13/api/views/.md#_GeoJSONResult "Direct link to GeoJSONResult") * *class *viktor.views.GeoJSONResult(*geojson*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[¶](#GeoJSONResult "Permalink to this definition") Bases: `_ViewResult` Container with the GeoJSON data that should be visualized in a GeoJSONView. Optionally a legend and map labels can be included. The following geojson properties are supported that can be used for styling of the map elements: > * icon (geometry type ‘Point’ only): icon to be shown (default: “pin”). For a complete list of all available markers, see [`MapPoint`](#MapPoint "viktor.views.MapPoint") > > * marker-color: the color of a marker [\*](#id2) > > * description: text to show when this item is clicked > > * stroke: the color of a line as part of a polygon, polyline, or multigeometry \* > > * fill: the color of the interior of a polygon \* * [\*](#id1) color rules: Colors can be in short form “#ace” or long form “#aaccee”, and should contain the # prefix. Colors are interpreted the same as in CSS, in #RRGGBB and #RGB order. To enable interaction, the map feature identifiers can be defined within the geojson dict by adding an “id” attribute to a feature as follows: ``` { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": ..., "geometry": ... "id": "my identifier", ... ``` * Parameters * **geojson** (`dict`) – GeoJSON dictionary. * **labels** (`Optional`\[`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]]) – Labels that should be placed on the map. * **legend** (`Optional`\[[`MapLegend`](#MapLegend "viktor.views.MapLegend")]) – Map legend. * **interaction\_groups** (`Optional`\[`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *geojson*: dict*[¶](#GeoJSONResult.geojson "Permalink to this definition") * Return type `dict` ## GeoJSONAndDataResult[​](/sdk/13/api/views/.md#_GeoJSONAndDataResult "Direct link to GeoJSONAndDataResult") * *class *viktor.views.GeoJSONAndDataResult(*geojson*, *data*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[¶](#GeoJSONAndDataResult "Permalink to this definition") Bases: `_ViewResult` Container with the GeoJSON data and result data that should be visualized in a GeoJSONAndDataView. Optionally a legend and map labels can be included. * Parameters * **geojson** (`dict`) – GeoJSON dictionary. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`Optional`\[`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]]) – Labels that should be placed on the map. * **legend** (`Optional`\[[`MapLegend`](#MapLegend "viktor.views.MapLegend")]) – Map legend. * **interaction\_groups** (`Optional`\[`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *geojson*: dict*[¶](#GeoJSONAndDataResult.geojson "Permalink to this definition") * Return type `dict` ## MapResult[​](/sdk/13/api/views/.md#_MapResult "Direct link to MapResult") * *class *viktor.views.MapResult(*features*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[¶](#MapResult "Permalink to this definition") Bases: [`GeoJSONResult`](#GeoJSONResult "viktor.views.GeoJSONResult") Container with the Map data that should be visualized in a MapView. Optionally a legend and map labels can be included. * Parameters * **features** (`List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")]) – List that contains the map objects. * **labels** (`Optional`\[`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]]) – Labels that should be placed on the map. * **legend** (`Optional`\[[`MapLegend`](#MapLegend "viktor.views.MapLegend")]) – Map legend. * **interaction\_groups** (`Optional`\[`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *features*: List\[[MapFeature](#MapFeature "viktor.views.MapFeature")]*[¶](#MapResult.features "Permalink to this definition") * Return type `List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")] * *property *geojson*: dict*[¶](#MapResult.geojson "Permalink to this definition") * Return type `dict` ## MapAndDataResult[​](/sdk/13/api/views/.md#_MapAndDataResult "Direct link to MapAndDataResult") * *class *viktor.views.MapAndDataResult(*features*, *data*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[¶](#MapAndDataResult "Permalink to this definition") Bases: [`GeoJSONAndDataResult`](#GeoJSONAndDataResult "viktor.views.GeoJSONAndDataResult") Container with the Map data and result data that should be visualized in a MapAndDataView. Optionally a legend and map labels can be included. * Parameters * **features** (`List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")]) – List that contains the map objects. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`Optional`\[`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]]) – Labels that should be placed on the map. * **legend** (`Optional`\[[`MapLegend`](#MapLegend "viktor.views.MapLegend")]) – Map legend. * **interaction\_groups** (`Optional`\[`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *features*: List\[[MapFeature](#MapFeature "viktor.views.MapFeature")]*[¶](#MapAndDataResult.features "Permalink to this definition") * Return type `List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")] * *property *geojson*: dict*[¶](#MapAndDataResult.geojson "Permalink to this definition") * Return type `dict` ## WebResult[​](/sdk/13/api/views/.md#_WebResult "Direct link to WebResult") * *class *viktor.views.WebResult(*\**, *html=None*, *url=None*)[¶](#WebResult "Permalink to this definition") Bases: `_ViewResult` Container with the data that should be visualized in a WebView. There are two options, which should not be used together: * url: to serve a URL (takes precedence if both are defined) * html: for serving a single html page - Parameters * **html** (`Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `str`, `None`]) – HTML formatted content. * **url** (`Optional`\[`str`]) – Direct URL. * *classmethod *from\_path(*file\_path*)[¶](#WebResult.from_path "Permalink to this definition") * Return type [`WebResult`](#WebResult "viktor.views.WebResult") ## WebAndDataResult[​](/sdk/13/api/views/.md#_WebAndDataResult "Direct link to WebAndDataResult") * *class *viktor.views.WebAndDataResult(*\**, *html=None*, *url=None*, *data=None*)[¶](#WebAndDataResult "Permalink to this definition") Bases: `_ViewResult` Container with the web data and result data that should be visualized in a WebAndDataView. The Web part can be constructed in two ways, which should not be used together: * url: to serve a URL (takes precedence if both are defined) * html: for serving a single html page - Parameters * **html** (`Union`\[`StringIO`, [`File`](/sdk/13/api/core/.md#File "viktor.core.File"), `str`, `None`]) – HTML formatted content. * **url** (`Optional`\[`str`]) – Direct URL. * **data** (`Optional`\[[`DataGroup`](#DataGroup "viktor.views.DataGroup")]) – Result data. ## PlotlyResult[​](/sdk/13/api/views/.md#_PlotlyResult "Direct link to PlotlyResult") * *class *viktor.views.PlotlyResult(*figure*)[¶](#PlotlyResult "Permalink to this definition") Bases: `_ViewResult` Plotly figure to be visualized in a PlotlyView. The figure can be provided in json-string or dict format. Example usages: ``` @PlotlyView("Plotly view", duration_guess=1) def get_plotly_view(self, params, **kwargs): fig = go.Figure( data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])], layout=go.Layout(title=go.layout.Title(text="A Figure Specified By A Graph Object")) ) return PlotlyResult(fig.to_json()) ``` ``` @PlotlyView("Plotly view", duration_guess=1) def get_plotly_view(self, params, **kwargs): fig = { "data": [{"type": "bar", "x": [1, 2, 3], "y": [1, 3, 2]}], "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} } return PlotlyResult(fig) ``` * Parameters **figure** (`Union`\[`str`, `dict`]) – Plotly figure in str (json) or dict format ## PlotlyAndDataResult[​](/sdk/13/api/views/.md#_PlotlyAndDataResult "Direct link to PlotlyAndDataResult") * *class *viktor.views.PlotlyAndDataResult(*figure*, *data*)[¶](#PlotlyAndDataResult "Permalink to this definition") Bases: `_ViewResult` Plotly figure to be visualized in a PlotlyAndDataView. The figure can be provided in json-string or dict format. Example usage: ``` @PlotlyAndDataView("Plotly and data view", duration_guess=1) def get_plotly_and_data_view(self, params, **kwargs): data_group = ... fig = go.Figure( data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])], layout=go.Layout(title=go.layout.Title(text="A Figure Specified By A Graph Object")) ) return PlotlyAndDataResult(fig.to_json(), data_group) ``` * Parameters * **figure** (`Union`\[`str`, `dict`]) – Plotly figure in json-str or dict format * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – result data ## PDFResult[​](/sdk/13/api/views/.md#_PDFResult "Direct link to PDFResult") * *class *viktor.views.PDFResult(*\**, *file=None*, *url=None*)[¶](#PDFResult "Permalink to this definition") Bases: `_ViewResult` PDF document to be visualized in a PDFView. Can be defined from a File object or from a URL (direct-sharing). If both file and url are defined, url takes precedence. In case of URL: the hosting website must allow for direct accessing for the document to be shown. If this is forbidden (undefined CORS-headers), the document can alternatively be shown via the file argument with a File.from\_url(…), in which it is downloaded first and viewed subsequently (indirect-sharing). Example usages: From URL (direct-sharing): ``` PDFResult(url="https://www...") ``` From URL (indirect-sharing): ``` f = File.from_url("https://www...") PDFResult(file=f) ``` From path: ``` file_path = Path(__file__).parent / 'sample.pdf' PDFResult.from_path(file_path) # or ... PDFResult(File.from_path(file_path)) ``` * Parameters * **file** (`Optional`\[[`File`](/sdk/13/api/core/.md#File "viktor.core.File")]) – PDF document to view * **url** (`Optional`\[`str`]) – URL of PDF document to view. If accessing the PDF directly from the URL is not allowed by the host website (undefined CORS-headers), this will result in the document not showing up in the view (as an alternative one can use File.from\_url). - *classmethod *from\_path(*file\_path*)[¶](#PDFResult.from_path "Permalink to this definition") Create the PDFResult from a path to the PDF file. * Parameters **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – file path to a PDF file * Return type [`PDFResult`](#PDFResult "viktor.views.PDFResult") ## SummaryItem[​](/sdk/13/api/views/.md#_SummaryItem "Direct link to SummaryItem") * *class *viktor.views.SummaryItem(*label*, *item\_type*, *source*, *value\_path*, *\**, *suffix=''*, *prefix=''*)[¶](#SummaryItem "Permalink to this definition") A summary consists of SummaryItem objects, that define which input / result values should be displayed. Suppose we have a data view with a controller method ‘data\_view’, which returns a DataItem with key ‘output\_item\_1’. The following summary item can be constructed to refer to this result: ``` item_1 = SummaryItem('Label', float, 'data_view', 'output_item_1', suffix='N') ``` Suppose we have a parametrization with a certain parameter defined as geometry.input.length, this can be converted to a summary item by doing: ``` item_2 = SummaryItem('Length', float, 'parametrization', 'geometry.input.length', suffix='m') ``` * Parameters * **label** (`str`) – Text label of the item. * **item\_type** (`Type`\[`Union`\[`str`, `float`]]) – Type of value, options are ‘str’ | ‘float’. * **source** (`str`) – Source from which the input / output should be extracted. * **value\_path** (`str`) – Dotted path of value in parametrization / data structure of view. e.g: level1.level2.value * **suffix** (`str`) – A prefix will be put behind the value to provide additional information such as units. * **prefix** (`str`) – A prefix will be put in front of the value to provide info such as a dollar sign. ## Summary[​](/sdk/13/api/views/.md#_Summary "Direct link to Summary") * *class *viktor.views.Summary(*\*\*items*)[¶](#Summary "Permalink to this definition") Bases: `OrderedDict` Summary of resulting data items, which can be used in the summary view of an entity. Example usage: ``` class Controller: ... summary = Summary( item_1=SummaryItem(...), item_2=SummaryItem(...), item_3=SummaryItem(...) ) ``` * Parameters **items** ([`SummaryItem`](#SummaryItem "viktor.views.SummaryItem")) – Items that are shown in the summary, with a maximum of 6 items per summary. ## View[​](/sdk/13/api/views/.md#_View "Direct link to View") * *class *viktor.views.View(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#View "Permalink to this definition") Bases: `ABC` Warning Do not use this class directly in an application. Base-class of a function decorator that can be used to specify the desired view to be returned. See the subclasses for specific examples of each type of view. * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## GeometryView[​](/sdk/13/api/views/.md#_GeometryView "Direct link to GeometryView") * *class *viktor.views.GeometryView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *view\_mode='3D'*, *default\_shadow=False*, *up\_axis='Z'*)[¶](#GeometryView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a geometry view (2D / 3D). Example usage: ``` @GeometryView("3D model", duration_guess=2) def get_geometry_view(self, params, **kwargs): ... return GeometryResult(...) @GeometryView("2D model", duration_guess=2, view_mode='2D') def get_geometry_view_2d(self, params, **kwargs): ... return GeometryResult(...) ``` * Parameters * **label** (`str`) – See [`View`](#View "viktor.views.View"). * **duration\_guess** (`int`) – See [`View`](#View "viktor.views.View"). * **description** (`Optional`\[`str`]) – See [`View`](#View "viktor.views.View"). * **update\_label** (`Optional`\[`str`]) – See [`View`](#View "viktor.views.View"). * **view\_mode** (`str`) – Sets the view mode: * ’3D’: Camera is free to move and user can choose between orthographic and perspective view. * ’2D’: Camera is fixed on the xy-plane and view is orthographic. * **default\_shadow** (`bool`) – Show shadow when editor is opened. User can still switch it off. * **up\_axis** (`str`) – Upwards pointing axis. Possible options: ‘Y’, ‘Z’ (default: ‘Z’) ## DataView[​](/sdk/13/api/views/.md#_DataView "Direct link to DataView") * *class *viktor.views.DataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#DataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a data view that contains calculation result. Example usage: ``` @DataView("Cost breakdown", duration_guess=2) def get_data_view(self, params, **kwargs): # calculate data ... return DataResult(data_group) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## GeometryAndDataView[​](/sdk/13/api/views/.md#_GeometryAndDataView "Direct link to GeometryAndDataView") * *class *viktor.views.GeometryAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *view\_mode='3D'*, *default\_shadow=False*, *up\_axis='Z'*)[¶](#GeometryAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of geometries and data. Example usage: ``` @GeometryAndDataView("Model / Cost", duration_guess=2) def get_geometry_data_view(self, params, **kwargs): ... return GeometryAndDataResult(...) ``` * Parameters * **label** (`str`) – See [`View`](#View "viktor.views.View"). * **duration\_guess** (`int`) – See [`View`](#View "viktor.views.View"). * **description** (`Optional`\[`str`]) – See [`View`](#View "viktor.views.View"). * **update\_label** (`Optional`\[`str`]) – See [`View`](#View "viktor.views.View"). * **view\_mode** (`str`) – Sets the view mode: * ’3D’: Camera is free to move and user can choose between orthographic and perspective view. * ’2D’: Camera is fixed on the xy-plane and view is orthographic. * **default\_shadow** (`bool`) – Show shadow when editor is opened. User can still switch it off. * **up\_axis** (`str`) – Upwards pointing axis. Possible options: ‘Y’, ‘Z’ (default: ‘Z’) ## SVGView[​](/sdk/13/api/views/.md#_SVGView "Direct link to SVGView") * *class *viktor.views.SVGView(*\*args*, *\*\*kwargs*)[¶](#SVGView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return an SVG view. Example usage: ``` @SVGView("SVG plot", duration_guess=2) def get_svg_view(self, params, **kwargs): # create svg image ... return SVGResult(svg_image) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## SVGAndDataView[​](/sdk/13/api/views/.md#_SVGAndDataView "Direct link to SVGAndDataView") * *class *viktor.views.SVGAndDataView(*\*args*, *\*\*kwargs*)[¶](#SVGAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of an SVG and data. Example usage: ``` @SVGAndDataView("Plot / Cost", duration_guess=2) def get_svg_data_view(self, params, **kwargs): # create svg image ... # calculate data ... return SVGAndDataResult(svg_image, data_group) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## GeoJSONView[​](/sdk/13/api/views/.md#_GeoJSONView "Direct link to GeoJSONView") * *class *viktor.views.GeoJSONView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#GeoJSONView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a GeoJSON (geographic data) view. Example usage: ``` @GeoJSONView("Map", duration_guess=2) def get_geojson_view(self, params, **kwargs): ... return GeoJSONResult(...) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## GeoJSONAndDataView[​](/sdk/13/api/views/.md#_GeoJSONAndDataView "Direct link to GeoJSONAndDataView") * *class *viktor.views.GeoJSONAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#GeoJSONAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a GeoJSON and data. Example usage: ``` @SVGAndDataView("Map / Data", duration_guess=2) def get_geojson_data_view(self, params, **kwargs): ... return GeoJSONAndDataResult(...) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## MapView[​](/sdk/13/api/views/.md#_MapView "Direct link to MapView") * *class *viktor.views.MapView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#MapView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a Map (geographic data) view. Example usage: ``` @MapView("Map", duration_guess=2) def get_map_view(self, params, **kwargs): ... return MapResult(...) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## MapAndDataView[​](/sdk/13/api/views/.md#_MapAndDataView "Direct link to MapAndDataView") * *class *viktor.views.MapAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#MapAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a Map and data. Example usage: ``` @MapAndDataView("Map / Data", duration_guess=2) def get_map_data_view(self, params, **kwargs): ... return MapAndDataResult(...) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## ImageView[​](/sdk/13/api/views/.md#_ImageView "Direct link to ImageView") * *class *viktor.views.ImageView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#ImageView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") New in v13.7.0 Function decorator to instruct the controller method to return an ImageView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. Example usage: ``` @ImageView("Image View", duration_guess=1) def get_image_view(self, params, **kwargs): file_path = Path(__file__).parent / 'sample.png' return ImageResult(File.from_path(file_path)) # or `ImageResult.from_path(file_path)` ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## ImageAndDataView[​](/sdk/13/api/views/.md#_ImageAndDataView "Direct link to ImageAndDataView") * *class *viktor.views.ImageAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#ImageAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") New in v13.7.0 Function decorator to instruct the controller method to return a combined view consisting of an image and data. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. Example usage: ``` @ImageAndDataView("Image View", duration_guess=1) def get_image_data_view(self, params, **kwargs): ... return ImageAndDataResult(image, data_group) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## PNGView[​](/sdk/13/api/views/.md#_PNGView "Direct link to PNGView") * *class *viktor.views.PNGView(*\*args*, *\*\*kwargs*)[¶](#PNGView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a PNG view. Example usage: ``` @PNGView("PNG image", duration_guess=1) def get_png_view(self, params, **kwargs): # get png image ... return PNGResult(image) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## PNGAndDataView[​](/sdk/13/api/views/.md#_PNGAndDataView "Direct link to PNGAndDataView") * *class *viktor.views.PNGAndDataView(*\*args*, *\*\*kwargs*)[¶](#PNGAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a PNG and data. Example usage: ``` @PNGAndDataView("PNG / Data", duration_guess=1) def get_png_data_view(self, params, **kwargs): # get png image ... # calculate data ... return PNGAndDataResult(image, data_group) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## JPGView[​](/sdk/13/api/views/.md#_JPGView "Direct link to JPGView") * *class *viktor.views.JPGView(*\*args*, *\*\*kwargs*)[¶](#JPGView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a JPG view. Example usage: ``` @JPGView("JPG image", duration_guess=1) def get_jpg_view(self, params, **kwargs): # get jpg image ... return JPGResult(image) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## JPGAndDataView[​](/sdk/13/api/views/.md#_JPGAndDataView "Direct link to JPGAndDataView") * *class *viktor.views.JPGAndDataView(*\*args*, *\*\*kwargs*)[¶](#JPGAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a JPG and data. Example usage: ``` @JPGAndDataView("JPG / Data", duration_guess=1) def get_jpg_data_view(self, params, **kwargs): # get jpg image ... # calculate data ... return JPGAndDataResult(image, data_group) ``` * Parameters * **label** – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** – Name which is shown on the update button in case of a slow view (max. 30 characters). ## WebView[​](/sdk/13/api/views/.md#_WebView "Direct link to WebView") * *class *viktor.views.WebView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#WebView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a web-content view. Example usage: ``` @WebView("Hello world", duration_guess=1) def get_web_view(self, params, **kwargs): return WebResult(html="Hello world") ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## WebAndDataView[​](/sdk/13/api/views/.md#_WebAndDataView "Direct link to WebAndDataView") * *class *viktor.views.WebAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#WebAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of web-content and data. Example usage: ``` @WebAndDataView("Web / Data", duration_guess=1) def get_web_data_view(self, params, **kwargs): # calculate data ... return WebAndDataResult(html="Hello world", data=data_group) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## PlotlyView[​](/sdk/13/api/views/.md#_PlotlyView "Direct link to PlotlyView") * *class *viktor.views.PlotlyView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#PlotlyView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a PlotlyView. Example usage: ``` @PlotlyView("Plotly view", duration_guess=1) def get_plotly_view(self, params, **kwargs): ... return PlotlyResult(figure) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## PlotlyAndDataView[​](/sdk/13/api/views/.md#_PlotlyAndDataView "Direct link to PlotlyAndDataView") * *class *viktor.views.PlotlyAndDataView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#PlotlyAndDataView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a PlotlyView and a DataView. Example usage: ``` @PlotlyAndDataView("Plotly and data view", duration_guess=1) def get_plotly_and_data_view(self, params, **kwargs): ... return PlotlyAndDataResult(figure, data_group) ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## PDFView[​](/sdk/13/api/views/.md#_PDFView "Direct link to PDFView") * *class *viktor.views.PDFView(*label*, *duration\_guess*, *\**, *description=None*, *update\_label=None*, *\*\*kwargs*)[¶](#PDFView "Permalink to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a PDFView. Example usage: ``` @PDFView("PDF View", duration_guess=1) def get_pdf_view(self, params, **kwargs): file_path = Path(__file__).parent / 'sample.pdf' return PDFResult(File.from_path(file_path)) # or `PDFResult.from_path(file_path)` ``` * Parameters * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time. * **description** (`Optional`\[`str`]) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`Optional`\[`str`]) – Name which is shown on the update button in case of a slow view (max. 30 characters). ## InteractionEvent[​](/sdk/13/api/views/.md#_InteractionEvent "Direct link to InteractionEvent") * *class *viktor.views.InteractionEvent(*event\_type*, *value*)[¶](#InteractionEvent "Permalink to this definition") Event triggered by the user as a consequence of an [`viktor.parametrization.Interaction`](/sdk/13/api/parametrization/.md#Interaction "viktor.parametrization.Interaction"). Warning Do not instantiate this class directly, it is returned as ‘event’ in the method of the button with the corresponding interaction. * Parameters * **event\_type** (`str`) – type of the event (‘map\_select’) * **value** (`Any`) – value of the user performed interaction. Type depends on event\_type: * map\_select: List\[Union\[str, int]] = identifier of selected features --- # Changelog All notable changes to the viktor SDK will be documented in this file, categorized by version number. The changes can be categorized further in the following headers: * **Action Required**: when a backwards incompatible change is made, which requires actions in the application code. You will find a reference to the upgrade instructions in this change. This header will only be present in major releases or on Beta Features. * **Added**: when a functionality is added, without breaking compatibility with older versions. * **Deprecated**: when an existing functionality will be removed in upcoming releases. You will find a reference to the upgrade instructions in this change. * **Docs**: when the change involves SDK documentation, docstring, and/or type hinting. * **Fixed**: when the change fixes a bug/error. * **Security**: when a vulnerability is fixed. Each change consists of a tag to annotate which VIKTOR module is involved. If the change encompasses multiple modules, the `viktor` tag is used. ## v13[​](/sdk/13/changelog/.md#v13 "Direct link to v13") ### Beta Features[​](/sdk/13/changelog/.md#beta-features "Direct link to Beta Features") Changes denoted with **\[BETA]** are experimental (beta) features. This means that the API might change without major version increment. Features currently in **\[BETA]** are: None ### v13.8.0 - 16/02/2023[​](/sdk/13/changelog/.md#v1380---16022023 "Direct link to v13.8.0 - 16/02/2023") #### Added[​](/sdk/13/changelog/.md#added "Direct link to Added") * `viktor` Support for Python 3.11 ### v13.7.2 - 08/02/2023[​](/sdk/13/changelog/.md#v1372---08022023 "Direct link to v13.7.2 - 08/02/2023") #### Docs[​](/sdk/13/changelog/.md#docs "Direct link to Docs") * `views` Added info about "id" attribute for interaction to docstring of GeoJSONResult * `result` Fixed example in `OptimizationResult` docstring #### Fixed[​](/sdk/13/changelog/.md#fixed "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` now correctly implements transparency * `geometry` Fixed rotation bug in Cone geometry when oriented in (0, -1, 0) direction ### v13.7.1 - 16/01/2023[​](/sdk/13/changelog/.md#v1371---16012023 "Direct link to v13.7.1 - 16/01/2023") #### Fixed[​](/sdk/13/changelog/.md#fixed-1 "Direct link to Fixed") * `errors` Fixed `UserError` to accept multiple messages of any type, in line with `UserException` ### v13.7.0 - 16/12/2022[​](/sdk/13/changelog/.md#v1370---16122022 "Direct link to v13.7.0 - 16/12/2022") #### Added[​](/sdk/13/changelog/.md#added-1 "Direct link to Added") * `result` Support 'Munch' type in a `SetParamsResult` * `views` New `ImageView` and `ImageAndDataView` that accept 'svg', 'jpeg', 'png', 'gif' files * `parametrization` Validation of a `Step` using the `on_next` callback function * `errors` `UserError` to show an error to the user and mark fields invalid in the interface * `core` Show/hide top-level entities on the dashboard with `InitialEntity` `show_on_dashboard` argument #### Deprecated[​](/sdk/13/changelog/.md#deprecated "Direct link to Deprecated") * `views` `SVGView`, `JPGView`, `PNGView` are replaced by `ImageView` [(U82)](/sdk/13/upgrades/.md#U82) * `views` `SVGResult`, `JPGResult`, `PNGResult` are replaced by `ImageResult` [(U82)](/sdk/13/upgrades/.md#U82) * `views` `SVGAndDataView`, `JPGAndDataView`, `PNGAndDataView` are replaced by `ImageAndDataView` [(U82)](/sdk/13/upgrades/.md#U82) * `views` `SVGAndDataResult`, `JPGAndDataResult`, `PNGAndDataResult` are replaced by `ImageAndDataResult` [(U82)](/sdk/13/upgrades/.md#U82) * `parametrization` Violated field constraints will block actions [(U83)](/sdk/13/upgrades/.md#U83) * `viktor` `UserException` will be replaced by `UserError` [(U84)](/sdk/13/upgrades/.md#U84) ### v13.6.2 - 05/12/2022[​](/sdk/13/changelog/.md#v1362---05122022 "Direct link to v13.6.2 - 05/12/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-2 "Direct link to Fixed") * `geometry` Regression in `CircularExtrusion` causing incorrect positioning ### v13.6.1 - 17/11/2022[​](/sdk/13/changelog/.md#v1361---17112022 "Direct link to v13.6.1 - 17/11/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-3 "Direct link to Fixed") * `views` Regression in SVGAndDataResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) ### v13.6.0 - 7/11/2022[​](/sdk/13/changelog/.md#v1360---7112022 "Direct link to v13.6.0 - 7/11/2022") #### Added[​](/sdk/13/changelog/.md#added-2 "Direct link to Added") * `viktor` Show progress messages in terminal * `geometry` Specify `shell_thickness` on a `CircularExtrusion` to create a hollow extrusion #### Deprecated[​](/sdk/13/changelog/.md#deprecated-1 "Direct link to Deprecated") * `geometry` Remove `open_ends` from `CircularExtrusion` [(U81)](/sdk/13/upgrades/.md#U81) #### Fixed[​](/sdk/13/changelog/.md#fixed-4 "Direct link to Fixed") * `codemod` Fixed codemods failing on f-string with unparenthesized tuples * `viktor` Ignore errors in sending progress messages * `views` Regression in SVGResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) ### v13.5.1 - 18/10/2022[​](/sdk/13/changelog/.md#v1351---18102022 "Direct link to v13.5.1 - 18/10/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-5 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` fix colors ### v13.5.0 - 11/10/2022[​](/sdk/13/changelog/.md#v1350---11102022 "Direct link to v13.5.0 - 11/10/2022") #### Added[​](/sdk/13/changelog/.md#added-3 "Direct link to Added") * `external` Added repr function to spreadsheet input classes * `external` Various analysis classes and functions now accept a `File` object, or return a `File` object if as\_file=True * `views` All image results (`PNGResult`, etc...) allow for image of type `File` * `geo` `gef_visualization` returns `File` object if as\_file=True * `views` `WebResult` allows for `html` of type `File` and `str` * `geometry` Support visualization of `Arc`, `Line`, and `Polyline` in a `GeometryView` * `testing` Various `mock_*Analysis` classes to facilitate easier testing of analysis classes #### Deprecated[​](/sdk/13/changelog/.md#deprecated-2 "Direct link to Deprecated") * `geometry` Remove `hex_to_rgb` and `rgb_to_hex` from geometry module [(U79)](/sdk/13/upgrades/.md#U79) * `parametrization` Remove `min_message` and `max_message` from `NumberField`/`IntegerField` [(U80)](/sdk/13/upgrades/.md#U80) ### v13.4.0 - 12/09/2022[​](/sdk/13/changelog/.md#v1340---12092022 "Direct link to v13.4.0 - 12/09/2022") #### Added[​](/sdk/13/changelog/.md#added-4 "Direct link to Added") * `external` Upload inputs of `render_word_file` and `WordFileTemplate.render` to s3 to prevent payload errors * `external` Added torsion and interaction results to `RcsOutputFileParser` #### Fixed[​](/sdk/13/changelog/.md#fixed-6 "Direct link to Fixed") * `codemod` U77 incorrectly includes yaml-comments in welcome\_text * `external` Dynamo `convert_geometry_to_glb` now generates double-sided faces * `codemod` U78 unintentionally removes comments from viktor.config.toml ### v13.3.1 - 24/08/2022[​](/sdk/13/changelog/.md#v1331---24082022 "Direct link to v13.3.1 - 24/08/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-7 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions * `external` Fix type-error in fill-spreadsheet helper * `geometry` `get_lowest_or_highest_profile_x` sometimes returns the incorrect profile * `parametrization` Raise a warning when using an `OptionField` with an `int` value in a `Table` ### v13.3.0 - 10/08/2022[​](/sdk/13/changelog/.md#v1330---10082022 "Direct link to v13.3.0 - 10/08/2022") #### Added[​](/sdk/13/changelog/.md#added-5 "Direct link to Added") * `parametrization` Increased character limit on `Text` element from 500 to 1800 * `testing` `mock_API` decorator to mock the `API` class in tests * `testing` `mock_params` function to convert a JSON/dict to the (deserialized) params * `testing` `mock_View` decorator to mock `View` decorators in tests * `testing` `mock_SciaAnalysis` to mock `SciaAnalysis.execute` and analysis returns in tests * `api_v1` Compare `EntityType`s or `User`s with "==" * `geometry` Compare `GeoPoint`s, `GeoPolyline`s, or `GeoPolygon`s with "==" #### Deprecated[​](/sdk/13/changelog/.md#deprecated-3 "Direct link to Deprecated") * `viktor` `app_type` entry should be defined in viktor.config.toml [(U78)](/sdk/13/upgrades/.md#U78) ### v13.2.1 - 27/06/2022[​](/sdk/13/changelog/.md#v1321---27062022 "Direct link to v13.2.1 - 27/06/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-8 "Direct link to Fixed") * `codemod` U77 incorrectly fixing the `welcome_text` path ### v13.2.0 - 15/06/2022[​](/sdk/13/changelog/.md#v1320---15062022 "Direct link to v13.2.0 - 15/06/2022") #### Added[​](/sdk/13/changelog/.md#added-6 "Direct link to Added") * `geometry` Construct an extruded polygon using `Polygon.extrude()` * `geometry` Compare `Point`s and `Line`s with "==" (e.g. `Point(1, 1) == Point(1, 1)` -> True) * `geometry` Allow for indexing/iterating of `Vector`, `Point` and `Line` objects * `geometry` `Line` methods `project_point` and `distance_to_point` * `codemod` Apply all fixes of current major when using the `viktor-cli fix` command without --upgrade flag * `parametrization` Select interaction on Map/GeoJSONView #### Deprecated[​](/sdk/13/changelog/.md#deprecated-4 "Direct link to Deprecated") * `viktor` Removal of manifest [(U77)](/sdk/13/upgrades/.md#U77) #### Fixed[​](/sdk/13/changelog/.md#fixed-9 "Direct link to Fixed") * `geometry` bug in `points_are_coplanar` * `geometry` `point_is_on_bounded_line` now correctly calculates for 3D ### v13.1.0 - 06/05/2022[​](/sdk/13/changelog/.md#v1310---06052022 "Direct link to v13.1.0 - 06/05/2022") #### Added[​](/sdk/13/changelog/.md#added-7 "Direct link to Added") * `external` SCIA binding: `description` on (nonlinear) load combination * `external` SCIA binding: (general) solver settings * `external` SCIA binding: library cross-sections * `external` SCIA binding: basic project data * `external` SCIA binding: cross-links #### Fixed[​](/sdk/13/changelog/.md#fixed-10 "Direct link to Fixed") * `viktor` Set timeouts on addons requests to 60 seconds to prevent timeout errors * `external` SCIA binding: applying a line load on a circular plane edge no longer raises an error ### v13.0.0 - 13/04/2022[​](/sdk/13/changelog/.md#v1300---13042022 "Direct link to v13.0.0 - 13/04/2022") #### Action Required[​](/sdk/13/changelog/.md#action-required "Direct link to Action Required") * `viktor` Upgrade instructions U61 - U75 have been applied #### Added[​](/sdk/13/changelog/.md#added-8 "Direct link to Added") * `core` `Storage` class to permanently store files which can be retrieved at any time * `parametrization` `FileField` and `MultiFileField` which allow users to upload one or multiple files * `parametrization` `EntityOptionField` and `EntityMultiSelectField` for generic selection of entities * `parametrization` `ViktorParametrization` as alias of `Parametrization` #### Deprecated[​](/sdk/13/changelog/.md#deprecated-5 "Direct link to Deprecated") * `codemod` Cleanup previously set flags which were necessary to migrate to v13 [(U76)](/sdk/13/upgrades/.md#U76) ## v12[​](/sdk/13/changelog/.md#v12 "Direct link to v12") ### v12.12.2 - 23/08/2022[​](/sdk/13/changelog/.md#v12122---23082022 "Direct link to v12.12.2 - 23/08/2022") #### Fixed[​](/sdk/13/changelog/.md#fixed-11 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions ### v12.12.1 - 11/04/2022[​](/sdk/13/changelog/.md#v12121---11042022 "Direct link to v12.12.1 - 11/04/2022") #### Docs[​](/sdk/13/changelog/.md#docs-1 "Direct link to Docs") * `external` Fixed example in Dynamo docstring #### Fixed[​](/sdk/13/changelog/.md#fixed-12 "Direct link to Fixed") * `parametrization` Fixed U74 warning not being logged in case of dynamic options ### v12.12.0 - 06/04/2022[​](/sdk/13/changelog/.md#v12120---06042022 "Direct link to v12.12.0 - 06/04/2022") #### Added[​](/sdk/13/changelog/.md#added-9 "Direct link to Added") * `views` `up_axis` setting to GeometryView and GeometryAndDataView * `views` `GeometryResult` accepts a GLB `File` * `views` Fix the font size of a `MapLabel` regardless of zoom level by setting the `fixed_size` flag * `external` Helper functions for updating Dynamo input files and processing output files (results + geometry) * `external` `GenericAnalysis.get_output_file` returns File object if as\_file=True * `parametrization` Support setting a `value` and a `label` of an `OptionField` option within a table * `parametrization` Added `entity_name` in signature of controller methods and callback functions #### Deprecated[​](/sdk/13/changelog/.md#deprecated-6 "Direct link to Deprecated") * `views` `GeometryResult` argument `visualization_group` renamed to `geometry` [(U73)](/sdk/13/upgrades/.md#U73) * `parametrization` Setting both a `value` and a `label` of an `OptionField` option within a table will no longer be ignored [(U74)](/sdk/13/upgrades/.md#U74) * `viktor` Removed `name` and `filename` from the params [(U75)](/sdk/13/upgrades/.md#U75) #### Fixed[​](/sdk/13/changelog/.md#fixed-13 "Direct link to Fixed") * `codemod` U68 fixed for the case of having multiple 'import as' aliases * `geometry` `Torus` and `ArcRevolve` showing wrong face normals and ignoring rotation angle ### v12.11.0 - 09/03/2022[​](/sdk/13/changelog/.md#v12110---09032022 "Direct link to v12.11.0 - 09/03/2022") #### Added[​](/sdk/13/changelog/.md#added-10 "Direct link to Added") * `viktor` Create a views-only entity type by omitting the `parametrization` attribute on the corresponding `Controller` class * `views` Select a custom map marker using the `icon` attribute on `MapPoint` #### Deprecated[​](/sdk/13/changelog/.md#deprecated-7 "Direct link to Deprecated") * `viktor` The `background_image` of a workspace is customizable through the admin panel instead of the manifest [(U71)](/sdk/13/upgrades/.md#U71) * `api` The complete `viktor.api` module and all of its classes and functions [(U72)](/sdk/13/upgrades/.md#U72) #### Docs[​](/sdk/13/changelog/.md#docs-2 "Direct link to Docs") * `views` Fixed example in PlotlyView docstring ### v12.10.0 - 08/02/2022[​](/sdk/13/changelog/.md#v12100---08022022 "Direct link to v12.10.0 - 08/02/2022") #### Added[​](/sdk/13/changelog/.md#added-11 "Direct link to Added") * `views` PlotlyView and PlotlyAndDataView * `api_v1` Various missing functionalities (e.g. to create, delete and modify entities) * `views` `GeometryResult` accepts a (sequence of) `TransformableObject`(s) * `testing` `mock_ParamsFromFile` to mock the `ParamsFromFile` class in tests #### Deprecated[​](/sdk/13/changelog/.md#deprecated-8 "Direct link to Deprecated") * `parametrization` Automatic selection of a single option in an `OptionField` will no longer be the standard behavior [(U69)](/sdk/13/upgrades/.md#U69) * `geometry` Removed method `Polyline.from_dict` [(U70)](/sdk/13/upgrades/.md#U70) #### Fixed[​](/sdk/13/changelog/.md#fixed-14 "Direct link to Fixed") * `external` D-Foundations parser: `IsKsi3Used` incorrectly returns `True` ### v12.9.0 - 11/01/2022[​](/sdk/13/changelog/.md#v1290---11012022 "Direct link to v12.9.0 - 11/01/2022") #### Added[​](/sdk/13/changelog/.md#added-12 "Direct link to Added") * `parametrization` `Step` which can be used to have pages within a predefined order, browsable through a previous and next button * `parametrization` `row_label` attribute on `DynamicArray` which can be used to prefix the row index #### Deprecated[​](/sdk/13/changelog/.md#deprecated-9 "Direct link to Deprecated") * `viktor` GEOLIB is now publicly available; hosting by VIKTOR will be terminated [(U67)](/sdk/13/upgrades/.md#U67) * `parametrization` Input argument `require_all_fields` will be removed from buttons [(U68)](/sdk/13/upgrades/.md#U68) ### v12.8.0 - 1/12/2021[​](/sdk/13/changelog/.md#v1280---1122021 "Direct link to v12.8.0 - 1/12/2021") #### Added[​](/sdk/13/changelog/.md#added-13 "Direct link to Added") * `external` Removed **\[BETA]** status from the Robot integration * `parametrization` Radio variant of `OptionField` (vertical + horizontal) #### Deprecated[​](/sdk/13/changelog/.md#deprecated-10 "Direct link to Deprecated") * `parametrization` Entity selection fields return an `Entity` object in the params instead of an integer [(U65)](/sdk/13/upgrades/.md#U65) * `parametrization` NumberField variant attribute of type `str` ('slider') replaces type `Enum` (`NumberField.Variant.SLIDER`) [(U66)](/sdk/13/upgrades/.md#U66) #### Fixed[​](/sdk/13/changelog/.md#fixed-15 "Direct link to Fixed") * `external` D-Foundations and D-Settlement input file generation timeout increased to 30 seconds ### v12.7.0 - 3/11/2021[​](/sdk/13/changelog/.md#v1270---3112021 "Direct link to v12.7.0 - 3/11/2021") #### Added[​](/sdk/13/changelog/.md#added-14 "Direct link to Added") * `views` An `update_label` can be used to change the label of the update button of a View * `parametrization` A `description` can now be added on action buttons, to provide more information to the user through a tooltip * `external` IDEA-RCS RcsOutputFileParser: decision method added to fatigue results * `external` IDEA-RCS RcsOutputFileParser: obtain combined results per extreme using `section.extremes()` * `external` IDEA binding: `Member.create_bar_layer()` and `ReinforcedCrossSection.create_bar_layer()` to create multiple bars positioned on a line * `external` IDEA binding: `theta`, `theta_min`, `theta_max`, and `n_cycles_fatigue` can be set in the `CodeSettings` * `external` IDEA binding: `relative_humidity` can be set in the design member data * `external` IDEA binding: a general cross-section can be added to a model, defined by a set of coordinates * `parametrization` `Text` field that can be used to display a static text #### Docs[​](/sdk/13/changelog/.md#docs-3 "Direct link to Docs") * `parametrization` Parameter NumberField.step added to docstring * `parametrization` Fixed example in ParamsFromFile docstring #### Fixed[​](/sdk/13/changelog/.md#fixed-16 "Direct link to Fixed") * `external` Scia input file generation timeout increased to 30 seconds ### v12.6.0 - 29/09/2021[​](/sdk/13/changelog/.md#v1260---29092021 "Direct link to v12.6.0 - 29/09/2021") #### Action Required[​](/sdk/13/changelog/.md#action-required-1 "Direct link to Action Required") * `external` **\[BETA]** Robot binding: `requested_results` format has changed; specify per category which components are to be returned #### Added[​](/sdk/13/changelog/.md#added-15 "Direct link to Added") * `external` SCIA binding: Model.create\_numerical\_cross\_section * `external` SCIA binding: Model.create\_point\_load\_node * `external` SCIA binding: added `angle` argument to Model.create\_point\_load * `core` Controller attribute `summary` is no longer required to be defined * `core` Controller attributes (`label`, `summary`, `parametrization`, etc.) visible in stubs and docs #### Deprecated[​](/sdk/13/changelog/.md#deprecated-11 "Direct link to Deprecated") * `api_v1` `PrivilegedAPI` has been replaced by explicit `privileged` flag on the individual API calls [(U64)](/sdk/13/upgrades/.md#U64) #### Docs[​](/sdk/13/changelog/.md#docs-4 "Direct link to Docs") * `geometry` Fixed code-block in `RDWGSConverter.from_wgs_to_rd()` * `viktor` Link to upgrade instruction webpage in deprecation warnings #### Fixed[​](/sdk/13/changelog/.md#fixed-17 "Direct link to Fixed") * `external` Word file rendering timeout increased to 60 seconds * `parametrization` Naming a table column 'name' does no longer cause a warning in the IDE about not being able to set the 'name' property ### v12.5.0 - 24/08/2021[​](/sdk/13/changelog/.md#v1250---24082021 "Direct link to v12.5.0 - 24/08/2021") #### Added[​](/sdk/13/changelog/.md#added-16 "Direct link to Added") * `parametrization` Page which can be used to construct a combination of inputs (e.g. tabs / sections) and outputs (views) * `core` Improved upload performance when no data is returned during post processing * `api_v1` Multiple API requests within the same job are now faster due to session sharing * `core` Improved error messages when a Summary is wrongly defined (e.g. non-existing SummaryItem 'source') * `geo` SoilLayout.filter\_layers\_on\_thickness merges adjacent layers with equal property values of type 'str', and raises a more explicit error otherwise * `external` IDEA-RCS `RcsOutputFileParser` which is an improved version of `OutputFileParser` (allowing large files) * `geometry` Improved performance of TriangleAssembly and Polygon visualization. Additionally a `skip_duplicate_vertices_check` flag can be set to boost performance further. * `parametrization` The width-ratio between input and output of an editor can be adjusted through a `width` argument on Parametrization * `parametrization` A `description` can now be added on a Field / Tab / Section / Page, to provide more information to the user through a tooltip * `views` A `description` can now be added on a View, to provide more information to the user through a tooltip #### Deprecated[​](/sdk/13/changelog/.md#deprecated-12 "Direct link to Deprecated") * `geo` Renamed `SoilLayout2D.threejs_visualisation()` to `SoilLayout2D.visualize_geometry()` and `SoilLayer2D.threejs_visualisation()` to `SoilLayer2D.visualize_geometry()` [(U62)](/sdk/13/upgrades/.md#U62) * `parametrization` Input arguments `prefix` and `suffix` on a DateField will be removed [(U63)](/sdk/13/upgrades/.md#U63) #### Docs[​](/sdk/13/changelog/.md#docs-5 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/sdk/13/changelog/.md#fixed-18 "Direct link to Fixed") * `geometry` Small triangles return NaN when calling the area ### v12.4.0 - 14/07/2021[​](/sdk/13/changelog/.md#v1240---14072021 "Direct link to v12.4.0 - 14/07/2021") #### Added[​](/sdk/13/changelog/.md#added-17 "Direct link to Added") * `external` SCIA binding: NonLinearLoadCombination can be used in `Model.create_result_class()` #### Docs[​](/sdk/13/changelog/.md#docs-6 "Direct link to Docs") * `viktor` Added description of publish commands to cli guide #### Fixed[​](/sdk/13/changelog/.md#fixed-19 "Direct link to Fixed") * `external` Timeout issue when using large files in `render_spreadsheet()` and `SpreadsheetCalculation.evaluate()` ### v12.3.1 - 25/06/2021[​](/sdk/13/changelog/.md#v1231---25062021 "Direct link to v12.3.1 - 25/06/2021") #### Fixed[​](/sdk/13/changelog/.md#fixed-20 "Direct link to Fixed") * `parametrization` Issue where clicking "Add new row" on a Table does not work ### v12.3.0 - 25/06/2021[​](/sdk/13/changelog/.md#v1230---25062021 "Direct link to v12.3.0 - 25/06/2021") #### Added[​](/sdk/13/changelog/.md#added-18 "Direct link to Added") * `external` IDEA-RCS binding: fatigue loading can be applied on an extreme * `external` IDEA-RCS OutputFileParser: fatigue results can be parsed * `views` 'points' and 'holes' properties added on MapPolygon * `external` Log when external analysis job has been completed successfully * `parametrization` Simple options can be used in OptionField, AutocompleteField, MultiSelectField (e.g. `options=['A', 'B', 'C']`) #### Deprecated[​](/sdk/13/changelog/.md#deprecated-13 "Direct link to Deprecated") * `core` Entity-type information (`label`, `children`, and `show_children_as`) is moved from the manifest to the Controller [(U61)](/sdk/13/upgrades/.md#U61) #### Fixed[​](/sdk/13/changelog/.md#fixed-21 "Direct link to Fixed") * `utils` Memoized functions called on app-load breaks in production ### v12.2.0 - 26/05/2021[​](/sdk/13/changelog/.md#v1220---26052021 "Direct link to v12.2.0 - 26/05/2021") #### Added[​](/sdk/13/changelog/.md#added-19 "Direct link to Added") * `parametrization` GeoPointField, GeoPolylineField, and GeoPolygonField can now be used in a DynamicArray * `external` **\[BETA]** RobotAnalysis #### Docs[​](/sdk/13/changelog/.md#docs-7 "Direct link to Docs") * `viktor` Regular docs maintenance ### v12.1.0 - 18/05/2021[​](/sdk/13/changelog/.md#v1210---18052021 "Direct link to v12.1.0 - 18/05/2021") #### Added[​](/sdk/13/changelog/.md#added-20 "Direct link to Added") * `parametrization` Parametrization can consist of 1 layer (Field) or 2 layers (Tab + Field, Section + Field) * `external` Improved error handling in execution of RFEMAnalysis * `geometry` Cone object * `api_v1` Allow negative indexing on EntityList * `parametrization` More consistent naming for many fields (old names will be deprecated in future) * `result` Allow for multiple files to be downloaded (as zip-file) in DownloadResult #### Docs[​](/sdk/13/changelog/.md#docs-8 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/sdk/13/changelog/.md#fixed-22 "Direct link to Fixed") * `parametrization` Setting field `name` argument using dot-notation within TableInput/DynamicArray was mistakenly allowed ### v12.0.0 - 20/04/2021[​](/sdk/13/changelog/.md#v1200---20042021 "Direct link to v12.0.0 - 20/04/2021") --- # Upgrades This document lists all current deprecations, with upgrade steps and planned removal. When the deprecation is removed with a major update, it will be moved under its corresponding header. ## This version[​](/sdk/13/upgrades/.md#this-version "Direct link to This version") ### U86 - Remove support for Python 3.7[​](/sdk/13/upgrades/.md#U86 "Direct link to U86 - Remove support for Python 3.7") * deprecated since: CLI v0.29.2 * planned removal: SDK v14.0.0 * automated code fix available: no #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change "Direct link to Current behaviour + reason for change") VIKTOR currently supports Python 3.7 - 3.11, however version 3.7 will soon reach its [end-of-life](https://devguide.python.org/versions/). This means that the VIKTOR SDK will no longer be built for Python 3.7 in the future. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour "Direct link to New behaviour") The VIKTOR SDK will no longer be available in combination with Python 3.7. #### Conversion[​](/sdk/13/upgrades/.md#conversion "Direct link to Conversion") Update the `python_version` in the `viktor.config.toml` file: ``` python_version = '3.11' # '3.8' | '3.9' | '3.10' | '3.11' ``` caution Please make sure to update your code in case you are using Python features that will no longer be available in Python 3.8 or higher. ### U85 - Remove leading hashtag for `viktor` dependency[​](/sdk/13/upgrades/.md#U85 "Direct link to U85") * deprecated since: CLI v0.29.0 * planned removal: SDK v14.0.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-1 "Direct link to Current behaviour + reason for change") Specifying `viktor` as dependency in the requirements.txt file requires a leading hashtag, which differs from other external dependencies. Since the `viktor` package is now publicly available on PyPI, the leading hashtag is no longer necessary. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-1 "Direct link to New behaviour") Specifying `# viktor` in the requirements.txt file will no longer be supported. #### Conversion[​](/sdk/13/upgrades/.md#conversion-1 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by submitting "yes" when the CLI asks to apply the diff: ``` - # viktor==X.X.X + viktor==X.X.X ``` ### U84 - UserException replaced by UserError[​](/sdk/13/upgrades/.md#U84 "Direct link to U84 - UserException replaced by UserError") * deprecated since: v13.7.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-2 "Direct link to Current behaviour + reason for change") A `UserException` can be raised by the app to inform the user of an error. Since the term `UserException` does not adhere to the naming [conventions](https://peps.python.org/pep-0008/#exception-names), we decided to replace it by `UserError`. In addition, `UserError` allows for marking of fields invalid in the interface, to improve user experience. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-2 "Direct link to New behaviour") `UserException` will no longer be available in the future, and will be replaced by `UserError`. #### Conversion[​](/sdk/13/upgrades/.md#conversion-2 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 84`: ``` - from viktor import UserException + from viktor import UserError - raise UserException("message") + raise UserError("message") ``` ### U83 - Violated field constraints block actions[​](/sdk/13/upgrades/.md#U83 "Direct link to U83 - Violated field constraints block actions") * deprecated since: v13.7.0 * planned removal: v14 * automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-3 "Direct link to Current behaviour + reason for change") When a field constraint is violated by the user, he / she is still able to perform actions which potentially make use of the invalid value. This can lead to erroneous calculation results, which is undesired. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-3 "Direct link to New behaviour") In order to protect and guide the user in a better way, violation of field constraints will block actions in the future. The constraints that are automatically assessed by the platform are: * Numeric min/max boundary (`IntegerField` / `NumberField` / `DynamicArray`) * Non-existing option (`OptionField` / `MultiSelectField` / `AutocompleteField`) * Non-existing coordinate (`GeoPointField` / `GeoPolylineField` / `GeoPolygonField`) * Invalid date format (`DateField`) By defining `viktor_enforce_field_constraints = True` on the controller class, this behavior can be simulated: ``` class Controller(ViktorController): viktor_enforce_field_constraints = True ``` #### Conversion[​](/sdk/13/upgrades/.md#conversion-3 "Direct link to Conversion") Add a `viktor_enforce_field_constraints` class attribute on the `Controller` and set it to True. This can be done automatically by using the CLI command `viktor-cli fix -u 83`: ``` class Controller(ViktorController): + viktor_enforce_field_constraints = True ``` caution Unfortunately we cannot automatically fix your app logic because we do not know the intentions of your code. If, for example, exceeding of the `max` value of a `NumberField` is perfectly fine, you could log a warning to the user, instead of using the `max` constraint on the `NumberField` itself: ``` def my_view(self, params, **kwargs): if params.height > 5: progress_message('WARNING: height should be smaller than 5!') # optionally add a sleep to show the message for longer period of time ... ``` ### U82 - Specific image views replaced by `ImageView`[​](/sdk/13/upgrades/.md#U82 "Direct link to U82") * deprecated since: v13.7.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-4 "Direct link to Current behaviour + reason for change") We currently offer a specific view per image type ('png' / 'jpg' / 'svg'). This inseparable relation between view and image type makes implementation of these views limited and inflexible. For example, in case the type of a result image can be either 'png' or 'jpg', you are forced to implement 2 views instead of 1. The individual views will therefore be replaced by the generic `ImageView` (and `ImageAndDataView`). The corresponding results will be replaced by the generic `ImageResult` (and `ImageAndDataResult`). #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-4 "Direct link to New behaviour") * `PNGView`, `JPGView`, and `SVGView` will be replaced by `ImageView` in the future. * `PNGAndDataView`, `JPGAndDataView`, and `SVGAndDataView` will be replaced by `ImageAndDataView` in the future. * `PNGResult`, `JPGResult`, and `SVGResult` will be replaced by `ImageResult` in the future. * `PNGAndDataResult`, `JPGAndDataResult`, and `SVGAndDataResult` will be replaced by `ImageAndDataResult` in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-4 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 82`: ``` - from viktor.views import PNGView, PNGResult + from viktor.views import ImageView, ImageResult - @PNGView(...) + @ImageView(...) def my_view(self, params, **kwargs): ... - return PNGResult(...) + return ImageResult(...) ``` A similar conversion is required for all other views that are listed above. ### U81 - Remove `open_ends` from `CircularExtrusion`[​](/sdk/13/upgrades/.md#U81 "Direct link to U81") * deprecated since: v13.6.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-5 "Direct link to Current behaviour + reason for change") A `CircularExtrusion` can have open or closed ends depending on the `open_ends` argument: * `open_ends=False` (default): the extrusion is a solid * `open_ends=True`: the extrusion is a shell with zero thickness It is not possible to create a shell **with** a certain thickness. The additional `shell_thickness` can be used to achieve this, which makes the `open_ends` argument redundant. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-5 "Direct link to New behaviour") The `open_ends` argument will be removed in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-5 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 81`: ``` - CircularExtrusion(..., open_ends=True) + CircularExtrusion(..., shell_thickness=0) - CircularExtrusion(..., open_ends=False) + CircularExtrusion(..., shell_thickness=None) ``` ### U80 - Remove `min_message` and `max_message` from `NumberField`/`IntegerField`[​](/sdk/13/upgrades/.md#U80 "Direct link to U80") * deprecated since: v13.5.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-6 "Direct link to Current behaviour + reason for change") The `min_message` and `max_message` arguments on `NumberField`/`IntegerField` currently do not work as expected (they are ignored). We decided to not fix the problem, but remove the feature, since specific information can already be provided by means of the `description` argument. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-6 "Direct link to New behaviour") `min_message` and `max_message` will be removed from `NumberField`/`IntegerField` in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-6 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 80`: ``` - number = NumberField(..., min_message="...", max_message="...") + number = NumberField(...) - integer = IntegerField(..., min_message="...", max_message="...") + integer = IntegerField(...) ``` ### U79 - Remove `hex_to_rgb` and `rgb_to_hex` from geometry module[​](/sdk/13/upgrades/.md#U79 "Direct link to U79") * deprecated since: v13.5.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-7 "Direct link to Current behaviour + reason for change") `hex_to_rgb` and `rgb_to_hex` that are present in the geometry module can be used for color conversion. These are legacy functions and can be replaced by `Color.hex_to_rgb` and `Color.rgb_to_hex` respectively. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-7 "Direct link to New behaviour") `hex_to_rgb` and `rgb_to_hex` will be removed in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-7 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 79`: ``` - from viktor.geometry import hex_to_rgb, rgb_to_hex + from viktor.core import Color - rgb = hex_to_rgb("FFFFFF") + rgb = Color.hex_to_rgb("FFFFFF") - hex = rgb_to_hex(255, 255, 255) + hex = Color.rgb_to_hex(255, 255, 255) ``` ### U78 - viktor.config.toml requires `app_type` entry[​](/sdk/13/upgrades/.md#U78 "Direct link to U78") * deprecated since: v13.3.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-8 "Direct link to Current behaviour + reason for change") Currently, it is relatively complex to create a simple app with only 1 entity type, as there should always exist a second, top-level folder-like entity type. With the introduction of the `app_type` entry in the `viktor.config.toml` file, it becomes possible to define a 'simple' app-type, which allows for 1 (and only 1) entity type, instead of the current behaviour (from now on called 'tree'). This app-type entry also allows to introduce other types at a later stage. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-8 "Direct link to New behaviour") The `app_type` entry in `viktor.config.toml` is obligatory and defines the type of app you want to create. App layout, requirements and corresponding feedback errors might differ depending on the chosen app type. #### Conversion[​](/sdk/13/upgrades/.md#conversion-8 "Direct link to Conversion") Add the 'app\_type' key to `viktor.config.toml` ('tree' represents the current behaviour). This can be done automatically by using the CLI command `viktor-cli fix -u 78`: ``` + app_type = "tree" ``` ### U77 - Removal of manifest[​](/sdk/13/upgrades/.md#U77 "Direct link to U77 - Removal of manifest") * deprecated since: v13.2.0 * planned removal: v14 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-9 "Direct link to Current behaviour + reason for change") The entity type information is currently partly described in the corresponding Controller, but some data is defined in the `manifest.yml`. This manifest is a concept which is often hard to grasp for a starting developer. In order to improve the onboarding of new developers, as well as consistency of where to define entity type information, we would like to get rid of the manifest completely. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-9 "Direct link to New behaviour") The manifest can be removed completely. This means that the following properties need to be removed / moved: ##### entity\_types[​](/sdk/13/upgrades/.md#entity_types "Direct link to entity_types") * `show_properties`: Legacy key which can be removed. * `has_designer`: Redundant in most cases. In specific cases it could happen that the entity type has a parametrization, but that `has_designer` has been set to False explicitly. For these cases, you may set `hide_editor` to True on the corresponding `Controller`. * naming of the entity type controller will no longer be in format `{entity_type}Controller`, but simply `{entity_type}` (e.g. `from .my_entity_type.controller import MyEntityTypeController` becomes `from .my_entity_type.controller import MyEntityTypeController as MyEntityType`, or rename the class and import with `from .my_entity_type.controller import MyEntityType`) ##### entities[​](/sdk/13/upgrades/.md#entities "Direct link to entities") Initial entities are created by setting the `initial_entities` variable in the `app.__init__.py` file, passing 1 or more `InitialEntity` objects. ``` from .my_entity_type.controller import MyEntityType from viktor import InitialEntity initial_entities = [ InitialEntity('MyEntityType', name='My Entity', params=...), ... ] ``` ##### metadata[​](/sdk/13/upgrades/.md#metadata "Direct link to metadata") * `welcome_text`: Moved to the `viktor.config.toml` file. * `uses_privileged_api`: Moved to the `viktor.config.toml` file. #### Conversion[​](/sdk/13/upgrades/.md#conversion-9 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 77`: ##### entity\_types[​](/sdk/13/upgrades/.md#entity_types-1 "Direct link to entity_types") `manifest.yaml` ``` - entity_types: - EntityTypeA: - show_properties: false - has_designer: true ``` Import the controller in the `app.__init__.py` with the updated format: ``` - from .entity_type_a.controller import EntityTypeAController + from .entity_type_a.controller import EntityTypeAController as EntityTypeA ``` In case of explicit hiding the editor, set the `hide_editor` flag: ``` class EntityTypeController(ViktorController): + hide_editor = True ... ``` ##### entities[​](/sdk/13/upgrades/.md#entities-1 "Direct link to entities") `manifest.yaml` ``` - entities: - - entity_type: SettingsDatabase - properties: settings_database.json - - entity_type: ProjectFolder - properties: - name: Projects - children: - - entity_type: Project - properties: project_x.json ``` `app.__init__.py` ``` - from .settings_database.controller import SettingsDatabaseController - from .project_folder.controller import ProjectFolderController - from .project.controller import ProjectController + from .settings_database.controller import SettingsDatabaseController as SettingsDatabase + from .project_folder.controller import ProjectFolderController as ProjectFolder + from .project.controller import ProjectController as Project + + from viktor import InitialEntity + + initial_entities = [ + InitialEntity('SettingsDatabase', name='Settings', params='settings_database.json'), + InitialEntity('ProjectFolder', name='Projects', children=[ + InitialEntity('Project', name='Project X', params='project_x.json') + ]) + ] ``` ##### metadata[​](/sdk/13/upgrades/.md#metadata-1 "Direct link to metadata") `manifest.yaml` ``` - metadata: - welcome_text: file_path.md - uses_privileged_api: true ``` `viktor.config.toml` ``` + welcome_text = "manifest/file_path.md" + enable_privileged_api = true # true | false ``` Note that the `welcome_text` file is defined in the manifest with respect to the manifest folder (e.g. `my-app/manifest/`), while in the viktor.config.toml file it should be defined with respect to the root folder (e.g. `my-app/`). You are also free to move the `welcome_text` to any other location, for example directly in the root folder. This way, you could remove the manifest folder completely. ### U76 - v13 cleanup[​](/sdk/13/upgrades/.md#U76 "Direct link to U76 - v13 cleanup") * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-10 "Direct link to Current behaviour + reason for change") Previous upgrades that were necessary to migrate to v13 instructed to add several flags on, for example, the `Controller` of the relevant entity type. Since v13 these flags became redundant. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-10 "Direct link to New behaviour") Previously set flags can be removed. #### Conversion[​](/sdk/13/upgrades/.md#conversion-10 "Direct link to Conversion") See the specific sections below for the required conversion. This can be done automatically by using the CLI command `viktor-cli fix -u 76`: ##### Cleanup U65[​](/sdk/13/upgrades/.md#cleanup-u65 "Direct link to Cleanup U65") ``` class Controller(ViktorController): - viktor_convert_entity_field = True ``` ##### Cleanup U69[​](/sdk/13/upgrades/.md#cleanup-u69 "Direct link to Cleanup U69") When `autoselect_single_option` is set to `False`, it can be removed (`autoselect_single_option=True` is still valid): ``` class Parametrization(ViktorParametrization): - options = OptionField("Options", options=dynamic_options, autoselect_single_option=False) + options = OptionField("Options", options=dynamic_options) ``` ##### Cleanup U74[​](/sdk/13/upgrades/.md#cleanup-u74 "Direct link to Cleanup U74") ``` class Controller(ViktorController): - viktor_store_table_option_field_value = True ``` ##### Cleanup U75[​](/sdk/13/upgrades/.md#cleanup-u75 "Direct link to Cleanup U75") ``` class Controller(ViktorController): - viktor_name_filename_in_params = False ``` ## Removed in v13[​](/sdk/13/upgrades/.md#removed-in-v13 "Direct link to Removed in v13") ### U75 - Remove `name` and `filename` from params[​](/sdk/13/upgrades/.md#U75 "Direct link to U75") * deprecated since: v12.12.0 * automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-11 "Direct link to Current behaviour + reason for change") Up to now you might have noticed a `name` property that was always present in the params of an entity, even though you had not specified a field referring to that position in the database. The entity name has been added to the signature of each controller method or can be obtained by using the API (e.g. `Entity.name`), which makes the `name` property redundant and will be removed. In case of file-upload entities, a `filename` property can be observed which will also be removed. Furthermore, the `name` and `filename` keys will become reserved for internal use and can no longer be used as `name` argument in parametrization fields. In order to simulate the removal of these params, you can use the `viktor_name_filename_in_params` controller flag: ``` class Controller(ViktorController): viktor_name_filename_in_params = False ``` This upgrade affects the following parts: * Parametrization + params * Entity mutations * `Entity.create_child()` / `API.create_child_entity()` * `Entity.set_params()` / `API.set_entity_params()` #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-11 "Direct link to New behaviour") Both `name` and `filename` will no longer be present in the params, and cannot be used as `name` argument of parametrization fields. #### Conversion[​](/sdk/13/upgrades/.md#conversion-11 "Direct link to Conversion") Add a `viktor_name_filename_in_params` class attribute on the `Controller` and set it to False. This can be done automatically by using the CLI command `viktor-cli fix -u 75`: ``` class Controller(ViktorController): + viktor_name_filename_in_params = False ``` caution Unfortunately we cannot automatically fix your app logic. The following sections will guide you through the manual conversion of the affected code. ##### Parametrization + params[​](/sdk/13/upgrades/.md#parametrization--params "Direct link to Parametrization + params") There are two ways for a field to be positioned on the `name` (or `filename`) key in the database: 1. using `name` as toplevel field name ``` - name = NumberField(...) ``` 2. using `name="name"` as field input argument ``` - tab.field = NumberField(..., name='name') ``` Also make sure to update all parts of the code where `name` (or `filename`) is obtained from the params. Instead, the entity name can be obtained from the signature: ``` - def func(params, **kwargs): + def func(params, entity_name, **kwargs): - entity_name = params.name ... ``` This also holds in case the property is taken from the `last_saved_params` of a different entity: ``` - entity_name = entity.last_saved_params['name'] + entity_name = entity.name ``` ##### Entity mutations[​](/sdk/13/upgrades/.md#entity-mutations "Direct link to Entity mutations") In functions that involve entity mutation, the `name` of the entity could have been stored in the params. This should be added as explicit `name` argument: ``` entity_name = "my_entity" - params = {"name": entity_name, ...} + params = {...} entity.create_child(..., name=entity_name, params=params) ``` ### U74 - Store table OptionField value in params[​](/sdk/13/upgrades/.md#U74 "Direct link to U74 - Store table OptionField value in params") * deprecated since: v12.12.0 * automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-12 "Direct link to Current behaviour + reason for change") When an `OptionField` is used within a table, it is not possible to show the `label` of the options in the dropdown menu, while using the `value` of the selected option in the params. This functionality will become available in the future, creating consistency between regular option fields and option fields used within tables. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-12 "Direct link to New behaviour") By setting the controller flag `viktor_store_table_option_field_value` to True, the `label` of options will be shown in the interface, and the `value` of the selected option will be returned in the params. This flag will be True by default in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-12 "Direct link to Conversion") Add a `viktor_store_table_option_field_value` class attribute on the Controller. This can be done automatically by using the CLI command `viktor-cli fix -u 74`: ``` class MyController(ViktorController): + viktor_store_table_option_field_value = True ``` caution Unfortunately we cannot automatically fix your app logic in case your app already defines both a `value` and `label` in options within a table dropdown (i.e. you ignored the warning). In that case you should update your code manually: ``` class MyParametrization(Parametrization): ... table.option = OptionField(..., options=[OptionListElement('a', 'Option A'), OptionListElement('b', 'Option B')]) class MyController(ViktorController): ... + viktor_store_table_option_field_value = True def func(params): - if params.table.option == 'Option A': + if params.table.option == 'a': ... ``` ### U73 - GeometryResult `visualization_group` parameter renamed to `geometry`[​](/sdk/13/upgrades/.md#U73 "Direct link to U73") * deprecated since: v12.12.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-13 "Direct link to Current behaviour + reason for change") `GeometryResult` and `GeometryAndDataResult` accept the geometry to be visualized through a `visualization_group` parameter. Since not only a `Group` but all sorts of geometry (any (list of) `TransformableObject`(s) or GLB file) can be passed, the naming of this parameter is outdated. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-13 "Direct link to New behaviour") GeometryResult `visualization_group` parameter has been renamed to `geometry`. #### Conversion[​](/sdk/13/upgrades/.md#conversion-13 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 73`: ``` - GeometryResult(visualization_group=...) - GeometryAndDataResult(visualization_group=...) + GeometryResult(geometry=...) + GeometryAndDataResult(geometry=...) ``` ### U72 - Remove viktor.api module[​](/sdk/13/upgrades/.md#U72 "Direct link to U72 - Remove viktor.api module") * deprecated since: v12.11.0 * automated code fix available: no #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-14 "Direct link to Current behaviour + reason for change") The `viktor.api` module consists of (outdated) functions and classes that are superseded by the entity option fields and functions from the `viktor.api_v1` module, or provide insignificant value such that it's better to replace them with simple app code. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-14 "Direct link to New behaviour") All (useful) functionalities from the `viktor.api` module can be mimicked by using the entity option fields and/or functions from the `viktor.api_v1` module. The `viktor.api` module will be removed completely in the future. #### Conversion[​](/sdk/13/upgrades/.md#conversion-14 "Direct link to Conversion") ##### `get_database_value_from_entity_id` / `get_entity_id_from_database_value` / `get_entity_option_list_for_designer`[​](/sdk/13/upgrades/.md#get_database_value_from_entity_id--get_entity_id_from_database_value--get_entity_option_list_for_designer "Direct link to get_database_value_from_entity_id--get_entity_id_from_database_value--get_entity_option_list_for_designer") If the entities are all children/siblings, the `OptionField` can be replaced with a `Child/SiblingEntityOptionField` (or similar for its multi-select counterpart): ``` - options = get_entity_option_list_for_designer(entities) - field = OptionField("...", options=options) + field = ChildEntityOptionField("...") # or similar field ... - entity_id = get_entity_id_from_database_value(params['field']) + entity = params['field'] # obtain its id with entity.id if desired ``` #### `API`, `Entity` & `EntityType`[​](/sdk/13/upgrades/.md#api-entity--entitytype "Direct link to api-entity--entitytype") The classes `API`, `Entity` and `EntityType` and all of its (useful) functionalities from the `viktor.api` module have a counterpart with equal or similar functionalities in the `viktor.api_v1` module. Below are the main differences: ``` - from viktor.api import API + from viktor.api_v1 import API ... api = API() ... - API.verify_status_code(response, allowed=200) # check the response.status_code yourself + if response.status_code != 200: + ... # handle not allowed status code(s) ``` ``` - entity = API().entity(entity_id) # from viktor.api + entity = API().get_entity(entity_id) # from viktor.api_v1 ... - entity_dict = entity.get() + entity_params = entity.last_saved_params # or any other attribute ... - root_entities = entity.root_entities() # or entity.list() + root_entities = API().get_root_entities() ... - parent_entity_dict = entity.parents()[0] - parent_id = entity_parent_ids()[0] + parent_entity = entity.parent() ... - entity.create_child(entity_dict) + entity.create_child(entity_type_name, name, params=params) ... - entity.post_properties(new_params) + entity.set_params(new_params) ... - entity.update_properties(new_params_subset) + params = entity.last_saved_params + params.update(new_params_subset) + entity.set_params(params) ... - file_content = entity.download() + file = entity.get_file() # file.getvalue_binary() to obtain the binary content ``` ``` - entity_type = API().entity_type(entity_type_id) - entity_type.entities() + API().get_entities_by_type(entity_type_name) ``` Apps already using (unsupported!) code to create a file-type child entity using the `viktor.api` module can make use of the function `generate_upload_url` to fully switch to the `viktor.api_v1` module. This method should not be introduced in an app other than for above-mentioned reason: ``` - result = requests.post(f".../entity_types/{entity_type_id}/upload/", headers=...).json() + result = API().generate_upload_url(entity_type_name) - entity_properties = {"name": entity_name, "filename": result['fields']['key']} - entity.create_child({"properties": entity_properties, "entity_type": entity_type_id}) + entity.create_child(entity_type_name, name=entity_name, filename=result['fields']['key'], params={}) requests.post(result['url'], data=result['fields'], files={'file': ...}) ``` caution An unused import of the `viktor.api` module does not trigger any deprecation warning, but will crash the app when the module is deleted in v13. Be sure to remove all such imports. ### U71 - Remove manifest key `background_image`[​](/sdk/13/upgrades/.md#U71 "Direct link to U71") * deprecated since: v12.11.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-15 "Direct link to Current behaviour + reason for change") The background image of a single app was customizable using the manifest metadata key `background_image`. This custom background image is frozen since the migration of workspaces to a single organization environment, and can now be changed through the administrator panel per workspace. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-15 "Direct link to New behaviour") The background image can be customized per workspace through the administrator panel. This makes the `background_image` manifest key redundant. #### Conversion[​](/sdk/13/upgrades/.md#conversion-15 "Direct link to Conversion") Remove the `background_image` metadata key from the manifest, which can be done automatically by using the CLI command `viktor-cli fix -u 71`: ``` metadata: welcome_text: file_path.txt - background_image: file_path.jpg ``` ``` - metadata: - background_image: file_path.jpg ``` ### U70 - Removed `Polyline.from_dict()`[​](/sdk/13/upgrades/.md#U70 "Direct link to U70") * deprecated since: v12.10.0 * automated code fix available: no #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-16 "Direct link to Current behaviour + reason for change") A `Polyline` can be instantiated using the class method `from_dict`, however this should not be part of the public api. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-16 "Direct link to New behaviour") The class method will be removed. #### Conversion[​](/sdk/13/upgrades/.md#conversion-16 "Direct link to Conversion") ``` polyline_points = [...] # list of dictionaries - polyline = Polyline.from_dict(polyline_points) + polyline = Polyline([Point(p['x'], p['y']) for p in polyline_points]) ``` ### U69 - Autoselect single option in OptionField[​](/sdk/13/upgrades/.md#U69 "Direct link to U69 - Autoselect single option in OptionField") * deprecated since: v12.10.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-17 "Direct link to Current behaviour + reason for change") The list of available options in an OptionField may consist of a single entry. This can either be achieved by providing a static list of options, or when the options are created dynamically. In the latter case, a single option will automatically be selected in the interface (without user interaction). However, this could lead to unintended behavior. In the following example, the selected option is automatically changed without the user being aware of it: | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚫ A | | options dynamically change to multiple options | ⚫ A, ⚪ B, ⚪ C | | options dynamically change to single option B (user might not be aware!) | ⚫ B | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-17 "Direct link to New behaviour") In the future, the new default will be to not automatically select a single option within an `OptionField`. The `autoselect_single_option` flag has been added to explicitly set the behaviour of selecting a single option to `True` or `False`. ``` options = OptionField("Options", options=dynamic_options, autoselect_single_option=False) ``` In case you want to keep the current behavior, this flag can be set to True. #### Conversion[​](/sdk/13/upgrades/.md#conversion-17 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 69`: ``` - options = OptionField("Options", options=dynamic_options) + options = OptionField("Options", options=dynamic_options, autoselect_single_option=True) ``` ### U68 - Remove `require_all_fields` on buttons[​](/sdk/13/upgrades/.md#U68 "Direct link to U68") * deprecated since: v12.9.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-18 "Direct link to Current behaviour + reason for change") The argument `require_all_fields` can be specified on an action button, however it is not implemented in the platform. This argument could cause confusion and makes the SDK reference less readable. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-18 "Direct link to New behaviour") The `require_all_fields` argument will be removed. The following fields are affected: * `DownloadButton` * `SetParamsButton` * `ActionButton` (`AnalyseButton`) * `OptimizationButton` (`OptimiseButton`) #### Conversion[​](/sdk/13/upgrades/.md#conversion-18 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 68`: ``` - download_button = DownloadButton("Download X", method="download_x", require_all_fields=True) + download_button = DownloadButton("Download X", method="download_x") ``` ### U67 - GEOLIB hosting by VIKTOR will be terminated[​](/sdk/13/upgrades/.md#U67 "Direct link to U67 - GEOLIB hosting by VIKTOR will be terminated") * deprecated since: v12.9.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-19 "Direct link to Current behaviour + reason for change") Deltares' GEOLIB is currently hosted by VIKTOR to make it available for its clients. The GEOLIB (>= 0.1.6) has now become publicly available on pypi, removing the need to host it ourselves. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-19 "Direct link to New behaviour") The GEOLIB can be installed directly from pypi by pointing to the correct package in the app's requirements.txt. #### Conversion[​](/sdk/13/upgrades/.md#conversion-19 "Direct link to Conversion") In case you are not using the GEOLIB in your app, no action is required. Otherwise, update `requirements.txt` which can be done automatically by using the CLI command `viktor-cli fix -u 67`: ``` # viktor==X.X.X - geolib==0.1.6 + d-geolib==0.1.6 ... ``` caution GEOLIB is available on pypi from version >= 0.1.6. With the termination of the hosting by VIKTOR, older versions will become unavailable. If your app uses a version older than 0.1.6, please update your code accordingly. ### U66 - NumberField.Variant replaced with str-type[​](/sdk/13/upgrades/.md#U66 "Direct link to U66 - NumberField.Variant replaced with str-type") * deprecated since: v12.8.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-20 "Direct link to Current behaviour + reason for change") The variant of a `NumberField` is currently set with `NumberField.Variant`, which is of type `Enum`. To make the product easier to understand and use, also for starting programmers, this is updated to a simple `str`-type. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-20 "Direct link to New behaviour") The variant of a `NumberField` can be set with a simple `str`-type ('slider', 'standard'). #### Conversion[​](/sdk/13/upgrades/.md#conversion-20 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 66`: ``` - NumberField("MyField", min=10, max=20, variant=NumberField.Variant.SLIDER) + NumberField("MyField", min=10, max=20, variant='slider') - NumberField("MyField", variant=NumberField.Variant.STANDARD) + NumberField("MyField", variant='standard') # or just NumberField("MyField") ``` ### U65 - Entity selection fields return `Entity` object[​](/sdk/13/upgrades/.md#U65 "Direct link to U65") * deprecated since: v12.8.0 * automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-21 "Direct link to Current behaviour + reason for change") The value of the entity selection fields as returned in the params is of type integer. Returning objects in the params will become the standard behavior. This allows for already existing fields, such as the entity selection fields, to return more logical types. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-21 "Direct link to New behaviour") Returned values in the params will be strictly of type `Entity` in the future. By defining `viktor_convert_entity_field = True` on a controller, this behavior can be simulated. The following fields are affected: * `ChildEntityOptionField` * `SiblingEntityOptionField` * `ChildEntityMultiSelectField` * `SiblingEntityMultiSelectField` Note that if `viktor_convert_entity_field` is defined, not only the params of the **current** controller are converted, but also the params obtained from API calls. In the example below, the params of an entity of EntityTypeA are converted when retrieved in an entity of EntityTypeB. ``` class ControllerA(ViktorController) # EntityTypeA viktor_convert_entity_field = False ... def func(self, params, **kwargs): entity = params['child_entity_option_field'] # of type int! class ControllerB(ViktorController) # EntityTypeB viktor_convert_entity_field = True ... def func(self, params, **kwargs): params_entity_a = ... # API call to retrieve params of EntityTypeA entity = params_entity_a['child_entity_option_field'] # of type Entity! ``` #### Conversion[​](/sdk/13/upgrades/.md#conversion-21 "Direct link to Conversion") Add a `viktor_convert_entity_field` class attribute on the `Controller`. This can be done automatically by using the CLI command `viktor-cli fix -u 65`: ``` class MyController(ViktorController): + viktor_convert_entity_field = True ``` caution Unfortunately we cannot automatically fix your app logic. Please update the affected code manually, for example: ``` entity = params.tab.section.child_entity - entity = API().get_entity(entity) ``` An `Entity` is not serializable meaning that it cannot be used as input of a `memoized` function. In case you are passing the complete `params` as input, a conversion is required: ``` - memoized_func(params=params) + params_ = copy.deepcopy(params) + del params_['tab']['section']['child_entity'] + memoized_func(params=params_) ``` ### U64 - Replace PrivilegedAPI by explicit `privileged` flag[​](/sdk/13/upgrades/.md#U64 "Direct link to U64") * deprecated since: v12.6.0 * automated code fix available: no #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-22 "Direct link to Current behaviour + reason for change") Privileged API calls are done by using the `PrivilegedAPI` class. A danger of this approach is that the object may be instantiated well in advance of the actual API call, such that it is no longer transparent whether that call is privileged or not. Furthermore, `PrivilegedAPI` and the default `API` could be mixed within a method which can also result in unwanted privileged calls. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-22 "Direct link to New behaviour") The `PrivilegedAPI` class will be removed and privileged API calls should be done by adding an explicit `privileged` flag in the corresponding method (e.g. `entity.children(privileged=True)`). The following methods are affected: * `API.get_entity()` * `API.get_entity_file()` * `API.get_root_entities()` * `Entity.parent()` * `Entity.children()` * `Entity.siblings()` caution If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using the `privileged` flag: * Make sure the app's admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. #### Conversion[​](/sdk/13/upgrades/.md#conversion-22 "Direct link to Conversion") ``` - api = PrivilegedAPI() - privileged_root_entities = api.get_root_entities() + api = API() + privileged_root_entities = api.get_root_entities(privileged=True) ``` ### U63 - Remove `prefix` and `suffix` on DateField[​](/sdk/13/upgrades/.md#U63 "Direct link to U63") * deprecated since: v12.5.0 * automated code fix available: no #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-23 "Direct link to Current behaviour + reason for change") A `prefix` and / or `suffix` can be defined on a DateField, which is not relevant for this type of field. The attributes will therefore be removed. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-23 "Direct link to New behaviour") It will not be possible to use `prefix` and `suffix` on a DateField. #### Conversion[​](/sdk/13/upgrades/.md#conversion-23 "Direct link to Conversion") ``` - DateField('Some date', suffix='XYZ') + DateField('Some date (XYZ)') ``` ### U62 - Renamed `threejs_visualisation()` to `visualize_geometry()`[​](/sdk/13/upgrades/.md#U62 "Direct link to U62") * deprecated since: v12.5.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-24 "Direct link to Current behaviour + reason for change") A `SoilLayout2D` or `SoilLayer2D` can be visualized by calling `threejs_visualisation()` on the corresponding object. The "threejs" part in this name is no longer relevant and might be unclear to the developer. #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-24 "Direct link to New behaviour") Both methods return the geometric representation of the object, which can be used in a GeometryView. Therefore the methods are renamed to `visualize_geometry()`: * `SoilLayout2D.threejs_visualisation()` -> `SoilLayout2D.visualize_geometry()` * `SoilLayer2D.threejs_visualisation()` -> `SoilLayer2D.visualize_geometry()` #### Conversion[​](/sdk/13/upgrades/.md#conversion-24 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 62`: ``` layout = SoilLayout2D(...) - geometry, labels = layout.threejs_visualisation(...) + geometry, labels = layout.visualize_geometry(...) ``` ### U61 - Move entity-type information from manifest to Controller[​](/sdk/13/upgrades/.md#U61 "Direct link to U61 - Move entity-type information from manifest to Controller") * deprecated since: v12.3.0 * automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/13/upgrades/.md#current-behaviour--reason-for-change-25 "Direct link to Current behaviour + reason for change") The entity-type information is currently partly described in the corresponding Controller (parametrization / views / summary), but some data is defined in the `manifest.yml` (label, children, show\_children\_as). This manifest is a concept which is often hard to grasp for a starting developer. In order to improve the onboarding of new developers, as well as consistency of where to define entity-type information, we would like to get rid of the manifest completely. The first step is to move the definition of the following keys to the corresponding controller: * `label` (required) * `children` (if present) * `show_children_as` (if present) #### New behaviour[​](/sdk/13/upgrades/.md#new-behaviour-25 "Direct link to New behaviour") The keys will become simple class attributes, similar as `parametrization` and `summary`: ``` class EntityTypeController(ViktorController): label = 'Label of the entity-type' children = ['SomeType', 'AnotherType'] show_children_as = 'Cards' # or 'Table' ``` If they are still present in the manifest, you may expect the following warning: ``` Entity.label is present in manifest.yml but is overwritten by the app logic. Remove entry from manifest. ``` Note, when you are defining `label` on the Controller, the SDK will also try to get `children` + `show_children_as` or use the default of "no children" if not found. Therefore you **cannot** define `label` on the Controller, while keeping `children` and `show_children_as` in the manifest! #### Conversion[​](/sdk/13/upgrades/.md#conversion-25 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 61`: ``` # manifest.yml version: '1' entity_types: EntityTypeA: - label: This is A - show_children_as: Cards - children: - - EntityTypeB ... EntityTypeB: - label: This is B ... ``` ``` # entity_type_a/controller.py class EntityTypeAController(ViktorController): + label = 'This is A' + children = ['EntityTypeB'] + show_children_as = 'Cards' ... # entity_type_b/controller.py class EntityTypeBController(ViktorController): + label = 'This is B' ... ``` --- # Migrate (v13 to v14) This guide has been written for developers with existing VIKTOR application(s) on v13 who want to upgrade to v14. It provides a general overview of the necessary actions and links to relevant documents for more information. ## Breaking changes[​](/sdk/13/v13-to-v14/.md#breaking-changes "Direct link to Breaking changes") VIKTOR uses semantic versioning, which means that a major version upgrade (such as v13 -> v14) contains backwards incompatible (breaking) changes: you might need to make changes in your app code to ensure that it functions as expected after the upgrade. Under [Removed in v14](/sdk/13/upgrades/.md#removed-in-v14) we have listed all the changes: * a description of the change * reason for the change * necessary steps to update your code For some upgrades we provide an [automated code fix](/docs/create-apps/references/cli/.md#fix) which helps you in applying the necessary steps, e.g.: ``` viktor-cli fix -u ID ``` or apply all available upgrades by using: ``` viktor-cli fix ``` ## Upgrade steps[​](/sdk/13/v13-to-v14/.md#upgrade-steps "Direct link to Upgrade steps") Steps to upgrade: 1. Upgrade to the [latest v13 version](/sdk/13/changelog/.md#v13). This is backwards compatible, so you can change the version number and run your app without any changes needed. 2. Check the upgrade list below and update your app code accordingly. 3. As a check: run your code + run your tests. It should not emit any deprecation warnings introduced by the SDK. 4. Change the version to 14.0.0. This is backwards incompatible, but you have already implemented the necessary changes, so you're ready to go. caution The absence of deprecation warnings when running your app does not mean that all updates have been applied correctly, so make sure to check the list. You might not cover all your code when testing (warning is not triggered) and sometimes we cannot raise the warning at all On average, we expect this upgrade to take less than 1 hour per app. It depends on the size of the app and how many open updates need to be applied. In case you are experiencing difficulties upgrading, either manually or using the provided `fix` command, please contact VIKTOR. The table below shows an overview of the upgrades introduced in v13 and the estimated duration to fix: | ID | Deprecation | Upgrade duration | deprecated since | codemod available | | -- | -------------------------------------------------------------------------- | ---------------- | ---------------- | ----------------- | | 86 | Remove support for Python 3.7 | ? | CLI v0.29.2 | no | | 85 | Remove leading hashtag for viktor dependency | 5 minutes | CLI v0.29.0 | yes | | 84 | UserException replaced by UserError | 5 minutes | SDK v13.7.0 | yes | | 83 | Violated field constraints block actions | 15 minutes | SDK v13.7.0 | partly | | 82 | Specific image views replaced by `ImageView` | 5 minutes | SDK v13.7.0 | yes | | 81 | Removed `open_ends` from `CircularExtrusion` | 5 minutes | SDK v13.6.0 | yes | | 80 | Removed `min_messages` and `max_message` from `NumberField`/`IntegerField` | 5 minutes | SDK v13.5.0 | yes | | 79 | Remove `hex_to_rgb` and `rgb_to_hex` from geometry module | 5 minutes | SDK v13.5.0 | yes | | 78 | viktor.config.toml requires `app_type` entry | 5 minutes | SDK v13.3.0 | yes | | 77 | Removal of the manifest | 5 minutes | SDK v13.2.0 | yes | --- # SDK Reference Welcome to the SDK reference page. Here you will find the detailed API reference of the VIKTOR SDK which you can use to build your applications. * A list of all notable changes per SDK version can be found in the [Changelog](/sdk/changelog/.md). * All deprecations & upgrades can be found in [Upgrades](/sdk/upgrades/.md). To upgrade the version used in your app, please look at [this guide](/docs/publish-apps/upgrade-viktor-version/.md). --- # viktor.api\_v1 ## API[​](/sdk/api/api-v1/.md#_API "Direct link to API") * *class *viktor.api\_v1.API(*environment=None*, *token=None*)[](#API "Link to this definition") Bases: `_API` Starting point of making an API call to, for example, retrieve properties of an entity. Can be initialized: > 1. within a VIKTOR app, without init-arguments, to perform API calls to any data within the corresponding workspace. > > 2. **(new in v14.9.0)** within a VIKTOR app, with token argument, to perform API calls to any data within the environment (cross-workspace). > > 3. **(new in v14.9.0)** outside a VIKTOR app, with token and environment arguments, to perform API calls to any data within the specified environment. Note that the permissions of a user (group) are reflected on the permissions of this API call, e.g. if a user only has read-navigate or read-basic permission, calling the params (read-all) of the object using this API will NOT work for this specific user. Example for case 1 (inside app, within context of current workspace): ``` api = API() current_entity = api.get_entity(entity_id) parent = current_entity.parent() parent_params = parent.last_saved_params ``` Example for case 2 (inside app, outside context of current workspace): ``` api = API(token=os.environ["TOKEN"]) for workspace in api.get_workspaces(): for entity in workspace.get_root_entities(): entity_params = entity.last_saved_params ``` Example for case 3 (external to VIKTOR platform): ``` from viktor.api_v1 import API if __name__ == "__main__": api = API(token=os.environ["TOKEN"], environment="cloud.us1.viktor.ai") for workspace in api.get_workspaces(): for entity in workspace.get_root_entities(): entity_params = entity.last_saved_params ``` * get\_workspace(*id\_*)[](#API.get_workspace "Link to this definition") New in v14.9.0 Get the workspace with given id. (Requires a token to be set on the API class) * Parameters: **id** – workspace\_id * Return type: [`Workspace`](#Workspace "viktor.api_v1.Workspace") - get\_workspaces(*\**, *app\_name=None*, *include\_archived=False*)[](#API.get_workspaces "Link to this definition") New in v14.9.0 Get the workspaces in the environment. (Requires a token to be set on the API class) * Parameters: * **app\_name** (`Optional`\[`str`]) – Filter the workspaces by app name. * **include\_archived** (`bool`) – True to include the archived workspaces. (Only permitted for Organization Admins) * Return type: [`WorkspaceList`](#WorkspaceList "viktor.api_v1.WorkspaceList") Can be used to iterate over the workspaces: > ``` > api = API(token=os.environ["TOKEN"]) > for workspace in api.get_workspaces(): > for entity in workspace.get_root_entities(): > ... > ``` * get\_entity\_type(*id\_*, *\**, *workspace\_id=None*)[](#API.get_entity_type "Link to this definition") New in v14.9.0 Get the entity type with given id. * Parameters: * **id** – entity\_type\_id * **workspace\_id** (`int`) – (optional) Provide workspace id if you want to access entity types outside the context of the app. * Return type: [`EntityType`](#EntityType "viktor.api_v1.EntityType") - get\_entity\_types(*\**, *workspace\_id=None*)[](#API.get_entity_types "Link to this definition") New in v14.9.0 Get the entity types. * Parameters: **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * Return type: [`EntityTypeList`](#EntityTypeList "viktor.api_v1.EntityTypeList") * get\_entity(*id\_*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.get_entity "Link to this definition") Get the entity with given id. * Parameters: * **id** – entity\_id * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") - get\_entities\_by\_type(*entity\_type\_name*, *\**, *include\_params=True*, *privileged=False*, *workspace\_id=None*)[](#API.get_entities_by_type "Link to this definition") Get all entities of the given type. * Parameters: * **entity\_type\_name** (`str`) – entity type to get all entities for. * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") * get\_root\_entities(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*, *workspace\_id=None*)[](#API.get_root_entities "Link to this definition") Get the root entities. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the root entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") - get\_entity\_parent(*entity\_id*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.get_entity_parent "Link to this definition") Get the parent entity of the entity with given id. * Parameters: * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") * get\_entity\_children(*entity\_id*, *\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*, *workspace\_id=None*)[](#API.get_entity_children "Link to this definition") Get the child entities of the entity with given id. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the child entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") - get\_entity\_siblings(*entity\_id*, *\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*, *workspace\_id=None*)[](#API.get_entity_siblings "Link to this definition") Get the sibling entities of the entity with given id. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the sibling entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") * get\_entity\_revisions(*entity\_id*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.get_entity_revisions "Link to this definition") Get all revisions of the entity with given id. * Parameters: * **entity\_id** (`int`) – id of the entity to get the revisions from. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityRevisionList`](#EntityRevisionList "viktor.api_v1.EntityRevisionList") - get\_entity\_file(*entity\_id*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.get_entity_file "Link to this definition") Get the file of the entity with given id. * Parameters: * **entity\_id** (`int`) – id of the entity to get the file from. * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object (SourceType.URL) * Raises: **ValueError** – if file does not have a file associated with it. * get\_current\_user()[](#API.get_current_user "Link to this definition") Get the current user in the environment. * Return type: [`User`](#User "viktor.api_v1.User") - create\_child\_entity(*parent\_entity\_id*, *entity\_type\_name*, *name*, *\**, *params=None*, *privileged=False*, *workspace\_id=None*, *\*\*kwargs*)[](#API.create_child_entity "Link to this definition") Create a child entity with given name and type from parent entity with given id. Warning It is currently not possible to create a file-type entity Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. API.get\_entity\_children) within the same job because of memoization. * Parameters: * **parent\_entity\_id** (`int`) – id of the parent entity to create the child from. * **entity\_type\_name** (`str`) – type of the entity to be created (type must be a child-type of the parent entity). * **name** (`str`) – name of the entity to be created. * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity. * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") * delete\_entity(*entity\_id*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.delete_entity "Link to this definition") Delete the entity with given id. * Parameters: * **entity\_id** (`int`) – id of the entity to be deleted. * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: `None` - rename\_entity(*entity\_id*, *name*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.rename_entity "Link to this definition") Rename the entity with given id (creates a revision). Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.name) within the same job because of memoization. * Parameters: * **entity\_id** (`int`) – id of the entity to rename. * **name** (`str`) – name of the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") * set\_entity\_params(*entity\_id*, *params*, *\**, *privileged=False*, *workspace\_id=None*)[](#API.set_entity_params "Link to this definition") Create a new revision of the entity with given id, storing given params. Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.last\_saved\_params) within the same job because of memoization. * Parameters: * **entity\_id** (`int`) – id of the entity to create a revision for. * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity revision. * **workspace\_id** (`int`) – (optional) Provide id if you want to access resource from outside the context of the app * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") ## App[​](/sdk/api/api-v1/.md#_App "Direct link to App") * *class *viktor.api\_v1.App(*api*, *id\_*, *name*, *\*\*\_kwargs*)[](#App "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **api** (`_API`) – API instance * **id** – ID of the App * **name** (`str`) – Name of the App ## AppVersion[​](/sdk/api/api-v1/.md#_AppVersion "Direct link to AppVersion") * *class *viktor.api\_v1.AppVersion(*api*, *id\_*, *tag*, *status*, *app\_type*, *sdk\_version*, *python\_version*, *created\_at*, *\*\*\_kwargs*)[](#AppVersion "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **api** (`_API`) – API instance * **id** – ID of the AppVersion * **tag** (`str`) – Tag of the AppVersion * **status** (`str`) – Status of the AppVersion publish * **app\_type** (`str`) – Type of App as defined in the App definition * **sdk\_version** (`str`) – Version of the SDK * **python\_version** (`str`) – Version of the python * **created\_at** (`str`) – Timestamp of when AppVersion was created. ## ChatConversation[​](/sdk/api/api-v1/.md#_ChatConversation "Direct link to ChatConversation") * *class *viktor.api\_v1.ChatConversation(*\**, *api*, *workspace\_id*, *entity\_id*, *latest\_exchange\_id*)[](#ChatConversation "Link to this definition") New in v14.21.0 Warning Do not instantiate this class directly, it is created by the API. * get\_messages()[](#ChatConversation.get_messages "Link to this definition") Get the full history of the conversation as a list of messages. Each message in the list has the following format: ``` { 'role': str, # user | assistant 'content': str, # the actual message } ``` * Return type: `list`\[`dict`\[`str`, `str`]] ## Entity[​](/sdk/api/api-v1/.md#_Entity "Direct link to Entity") * *class *viktor.api\_v1.Entity(*api*, *workspace\_id*, *origin\_id*, *operations*, *resolved=None*)[](#Entity "Link to this definition") Warning Do not instantiate this class directly, it is created by the API. * children(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[](#Entity.children "Link to this definition") Get the child entities. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the child entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") - compute(*method\_name*, *\**, *params*, *timeout=None*)[](#Entity.compute "Link to this definition") New in v14.12.0 Run a callable entity controller method (view-method, button-method, step-method or preprocess-method) and return the result. * Parameters: * **method\_name** (`str`) – Name of the controller method to call * **params** (`Union`\[`dict`, `Munch`]) – Params to call the method with * **timeout** (`int`) – Maximum job duration after which it will time out * Return type: `dict` * Returns: Return value of the controller method * create\_child(*entity\_type\_name*, *name*, *\**, *params=None*, *privileged=False*, *\*\*kwargs*)[](#Entity.create_child "Link to this definition") Create a child entity with given name and type. Warning It is currently not possible to create a file-type entity Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. API.get\_entity\_children) within the same job because of internal caching. * Parameters: * **entity\_type\_name** (`str`) – type of the entity to be created (type must be a child-type of the parent entity). * **name** (`str`) – name of the entity to be created. * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") - delete(*\**, *privileged=False*)[](#Entity.delete "Link to this definition") Delete the entity. * Parameters: **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: `None` * *property *entity\_type*: [EntityType](#EntityType "viktor.api_v1.EntityType")*[](#Entity.entity_type "Link to this definition") EntityType of the entity. - get\_file()[](#Entity.get_file "Link to this definition") Get the file of the entity. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object (SourceType.URL) * Raises: **ValueError** – if file does not have a file associated with it. * *property *id*: int*[](#Entity.id "Link to this definition") id of the entity. - *property *last\_saved\_params*: munch.Munch*[](#Entity.last_saved_params "Link to this definition") Get the params of the last saved entity revision. * *property *last\_saved\_summary*: munch.Munch*[](#Entity.last_saved_summary "Link to this definition") Get the summary of the last saved entity revision. - *property *name*: str*[](#Entity.name "Link to this definition") Name of the entity. * parent(*\**, *privileged=False*)[](#Entity.parent "Link to this definition") Get the parent of the entity. * Parameters: **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") - rename(*name*, *\**, *privileged=False*)[](#Entity.rename "Link to this definition") Rename the entity (creates a revision). Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.name) within the same job because of memoization. * Parameters: * **name** (`str`) – name of the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") * revisions()[](#Entity.revisions "Link to this definition") Get all revisions of the entity. * Return type: [`EntityRevisionList`](#EntityRevisionList "viktor.api_v1.EntityRevisionList") - set\_params(*params*, *\**, *privileged=False*)[](#Entity.set_params "Link to this definition") Create a new revision of the entity, storing given params. Warning Be aware that changes made using this method might not be reflected in subsequent API calls (e.g. Entity.last\_saved\_params) within the same job because of memoization. * Parameters: * **params** (`Union`\[`dict`, `Munch`]) – params to be stored on the newly created entity revision. * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") * siblings(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[](#Entity.siblings "Link to this definition") Get the sibling entities. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the sibling entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") ## EntityList[​](/sdk/api/api-v1/.md#_EntityList "Direct link to EntityList") * *class *viktor.api\_v1.EntityList(*api*, *workspace\_id*, *relation*, *origin*, *entity\_type\_names*, *include\_params*, *\**, *privileged=False*)[](#EntityList "Link to this definition") Warning Do not instantiate this class directly, it is created by the API. Object which resembles a list of Entity objects. Most commonly used list operations are supported: ``` # indexing children = entity.children() children[0] # first child entity children[-1] # last child entity # length number_of_children = len(children) # for loop for child in children: # perform operation on child ``` ## EntityRevision[​](/sdk/api/api-v1/.md#_EntityRevision "Direct link to EntityRevision") * *class *viktor.api\_v1.EntityRevision(*api*, *id\_*, *params*, *created\_date*)[](#EntityRevision "Link to this definition") Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **params** (`Munch`) – Stored params in the entity’s revision. * **created\_date** (`datetime`) – Date(time) of creation of the entity’s revision. ## EntityRevisionList[​](/sdk/api/api-v1/.md#_EntityRevisionList "Direct link to EntityRevisionList") * *class *viktor.api\_v1.EntityRevisionList(*api*, *entity*, *\**, *privileged=False*)[](#EntityRevisionList "Link to this definition") Warning Do not instantiate this class directly, it is created by the API. Object which resembles a list of EntityRevision objects. Most commonly used list operations are supported: ``` # indexing revisions = entity.revisions() revisions[0] # first revision revisions[-1] # last revision # length number_of_revisions = len(revisions) # for loop for revision in revisions: # perform operation on revision ``` ## EntityType[​](/sdk/api/api-v1/.md#_EntityType "Direct link to EntityType") * *class *viktor.api\_v1.EntityType(*api*, *id\_*, *class\_name*, *\*\*\_kwargs*)[](#EntityType "Link to this definition") Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **id** – Unique ID of the entity type. * **name** – Entity type name (not label). ## EntityTypeList[​](/sdk/api/api-v1/.md#_EntityTypeList "Direct link to EntityTypeList") * *class *viktor.api\_v1.EntityTypeList(*api*, *workspace\_id*)[](#EntityTypeList "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. Object which resembles a list of EntityType objects. Most commonly used list operations are supported: ``` # indexing entity_types = api.get_entity_types() entity_types[0] # first entity_type entity_types[-1] # last entity_type # length number_of_entity_types = len(entity_types) # for loop for entity_type in entity_types: # perform operation on entity_type ``` ## FileResource[​](/sdk/api/api-v1/.md#_FileResource "Direct link to FileResource") * *class *viktor.api\_v1.FileResource(*workspace\_id*, *source\_id*, *api=None*)[](#FileResource "Link to this definition") File resource stored in the file manager. Warning Do not instantiate this class directly, it will be returned in the parameter set when using a [`FileField`](/sdk/api/parametrization/.md#FileField "viktor.parametrization.FileField") or [`MultiFileField`](/sdk/api/parametrization/.md#MultiFileField "viktor.parametrization.MultiFileField"). * *property *file*: [File](/sdk/api/core/.md#File "viktor.core.File")*[](#FileResource.file "Link to this definition") Returns the File object (URL-file) attached to the resource. - *property *filename*: str*[](#FileResource.filename "Link to this definition") Returns the filename of the resource (API call required!). ## Job[​](/sdk/api/api-v1/.md#_Job "Direct link to Job") * *class *viktor.api\_v1.Job(*api*, *workspace\_id*, *id\_*)[](#Job "Link to this definition") New in v14.12.0 Warning Do not instantiate this class directly, it is created by the API. * get\_result(*\**, *timeout=15*)[](#Job.get_result "Link to this definition") Obtain the job result * Return type: `dict` * Returns: Job result * Raises: **TimeoutError** – If timeout is exceeded ## Label[​](/sdk/api/api-v1/.md#_Label "Direct link to Label") * *class *viktor.api\_v1.Label(*api*, *id\_*, *name*, *description*, *color*, *\*\*\_kwargs*)[](#Label "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **api** (`_API`) – API instance * **id** – ID of the Label * **name** (`str`) – Name of the Label * **description** (`str`) – Description of the Label * **color** (`str`) – Color of the Label ## User[​](/sdk/api/api-v1/.md#_User "Direct link to User") * *class *viktor.api\_v1.User(*api*, *\**, *id\_*, *first\_name*, *last\_name*, *email*, *job\_title*, *\*\*\_kwargs*)[](#User "Link to this definition") User information. Warning Do not instantiate this class directly, it is created by the API. * Parameters: * **id** – user’s id * **first\_name** (`str`) – user’s first name * **last\_name** (`str`) – user’s last name * **email** (`str`) – user’s email address * **job\_title** (`str`) – user’s job title - *property *full\_name*: str*[](#User.full_name "Link to this definition") User’s full name (first name + last name). ## Workspace[​](/sdk/api/api-v1/.md#_Workspace "Direct link to Workspace") * *class *viktor.api\_v1.Workspace(*api*, *id\_*, *name*, *description*, *visibility*, *created\_at*, *updated\_at*, *is\_archived*, *app*, *app\_version*, *labels*, *\*\*kwargs*)[](#Workspace "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. Can be used to fetch additional data within the given workspace. ``` # Get workspace object workspace: Workspace = api.get_workspace(workspace_id) # Iterate over underlying data for entity in workspace.get_root_entities(): ... for entity_type in workspace.get_entity_types(): ... ``` * Parameters: * **id** – Unique ID of the workspace. * **name** (`str`) – Name of the workspace. * **description** (`str`) – Descriptive text of the workspace content. * **visibility** (`str`) – Visibility of the workspace. (Can be INTERNAL, PRIVATE, PUBLIC, or DEVELOPMENT) * **created\_at** (`str`) – Timestamp of when workspace was created. * **updated\_at** (`str`) – Timestamp of when workspace was last updated. * **is\_archived** (`bool`) – Whether the workspace is archived. * **app** (`Optional`\[`dict`]) – App assigned to the workspace. (Can be None for Development workspace) * **app\_version** (`Optional`\[`dict`]) – Published AppVersion assigned to the workspace. (Can be None for Development workspace) * **labels** (`List`\[`dict`]) – Labels assigned to the workspace. - entity\_compute(*\**, *entity\_id*, *method\_name*, *params*, *timeout=None*)[](#Workspace.entity_compute "Link to this definition") New in v14.12.0 Run a callable entity controller method (view-method, button-method, step-method or preprocess-method) and return the result. * Parameters: * **entity\_id** (`int`) – ID of the entity to call the method from * **method\_name** (`str`) – Name of the controller method to call * **params** (`Union`\[`dict`, `Munch`]) – Params to call the method with * **timeout** (`int`) – Maximum job duration after which it will time out * Return type: `dict` * Returns: Return value of the controller method * get\_entity(*id\_*, *privileged=False*)[](#Workspace.get_entity "Link to this definition") Get the entity with given id. * Parameters: * **id** – entity\_id * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`Entity`](#Entity "viktor.api_v1.Entity") - get\_entity\_type(*id\_*)[](#Workspace.get_entity_type "Link to this definition") Get the entity type with given id in the workspace. * Return type: [`EntityType`](#EntityType "viktor.api_v1.EntityType") * get\_entity\_types()[](#Workspace.get_entity_types "Link to this definition") Get the entity types in the workspace. * Return type: [`EntityTypeList`](#EntityTypeList "viktor.api_v1.EntityTypeList") - get\_root\_entities(*\**, *include\_params=True*, *entity\_type\_names=None*, *privileged=False*)[](#Workspace.get_root_entities "Link to this definition") Get the root entities. * Parameters: * **include\_params** (`bool`) – True to include the parameters of the root entities. * **entity\_type\_names** (`List`\[`str`]) – Only filters the entities of the defined type(s) (default = None, returns all). * **privileged** (`bool`) – bypass the user access restrictions managed by the admin of an application. Warning If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using this flag: * Make sure the app’s admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. API calls can only bypass the restrictions if the key enable\_privileged\_api is set to true in viktor.config.toml. This is to provide an additional layer of security / awareness. Restrictions can only be bypassed when using the API module within a VIKTOR app and within the context of the current workspace. * Return type: [`EntityList`](#EntityList "viktor.api_v1.EntityList") ## WorkspaceList[​](/sdk/api/api-v1/.md#_WorkspaceList "Direct link to WorkspaceList") * *class *viktor.api\_v1.WorkspaceList(*api*, *app\_name=None*, *include\_archived=False*)[](#WorkspaceList "Link to this definition") New in v14.9.0 Warning Do not instantiate this class directly, it is created by the API. Object which resembles a list of Workspace objects. Most commonly used list operations are supported: ``` # indexing workspaces = api.get_workspaces() workspaces[0] # first workspace workspaces[-1] # last workspace # length number_of_workspaces = len(workspaces) # for loop for workspace in workspaces: # perform operation on workspace ``` --- # viktor.core ## Color[​](/sdk/api/core/.md#_Color "Direct link to Color") * *class *viktor.core.Color(*r: int*, *g: int*, *b: int*)[](#Color "Link to this definition") Bases: [`Color`](#Color "viktor.core.Color") Create an immutable instance of Color * Parameters: * **r** – red-value (0-255) * **g** – green-value (0-255) * **b** – blue-value (0-255) - *static *black()[](#Color.black "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") * *static *blue()[](#Color.blue "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") - *property *deltares*: int*[](#Color.deltares "Link to this definition") * *static *deltares\_to\_rgb(*value*)[](#Color.deltares_to_rgb "Link to this definition") Conversion from red-green-blue to Deltares-type color value. * Parameters: **value** (`int`) – Integer representation of the color as used in the Deltares software series. * Return type: `Tuple`\[`int`, `int`, `int`] - *classmethod *from\_deltares(*value*)[](#Color.from_deltares "Link to this definition") Color defined by Deltares-type integer. * Parameters: **value** (`int`) – Integer representation of the color as used in the Deltares software series. * Return type: [`Color`](#Color "viktor.core.Color") * *classmethod *from\_hex(*hex\_value*)[](#Color.from_hex "Link to this definition") Color defined by hexadecimal code. * Return type: [`Color`](#Color "viktor.core.Color") - *static *green()[](#Color.green "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") * *property *hex*: str*[](#Color.hex "Link to this definition") Hexadecimal representation of the color. - *static *hex\_to\_rgb(*hex\_value*)[](#Color.hex_to_rgb "Link to this definition") Conversion from hexadecimal to red-green-blue value * Return type: `Tuple`\[`int`, `int`, `int`] * *static *lime()[](#Color.lime "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") - *static *random()[](#Color.random "Link to this definition") Generate a random color. * Return type: [`Color`](#Color "viktor.core.Color") * *static *red()[](#Color.red "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") - *property *rgb*: Tuple\[int, int, int]*[](#Color.rgb "Link to this definition") * *static *rgb\_to\_deltares(*r*, *g*, *b*)[](#Color.rgb_to_deltares "Link to this definition") Conversion from Deltares-type color value to red-green-blue value. :return Integer representation of the color as used in the Deltares software series. * Return type: `int` - *static *rgb\_to\_hex(*r*, *g*, *b*, *include\_hashtag=True*)[](#Color.rgb_to_hex "Link to this definition") Conversion from red-green-blue to hexadecimal value * Return type: `str` * *static *viktor\_black()[](#Color.viktor_black "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") - *static *viktor\_blue()[](#Color.viktor_blue "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") * *static *viktor\_yellow()[](#Color.viktor_yellow "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") - *static *white()[](#Color.white "Link to this definition") * Return type: [`Color`](#Color "viktor.core.Color") ## Controller[​](/sdk/api/core/.md#_Controller "Direct link to Controller") * *class *viktor.core.Controller(*\*\*kwargs*)[](#Controller "Link to this definition") The main function of the ViktorController is to “control” the information flow between the frontend (what is inputted by a user) and the application code (what is returned as a result of the user input). **(new in v14.15.0)** The ‘label’ attribute is now optional. * allow\_saving*: `Optional`\[`bool`]** = None*[](#Controller.allow_saving "Link to this definition") **(new in v14.24.0)** Specify whether user is allowed to save entities of this entity-type. May only be set for root entity types in tree-type app. - children*: `Optional`\[`List`\[`str`]]** = None*[](#Controller.children "Link to this definition") Optional list of child entity-types. * label*: `Optional`\[`str`]** = None*[](#Controller.label "Link to this definition") Entity-type label. - parametrization*: `Optional`\[[`Parametrization`](/sdk/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization")]** = None*[](#Controller.parametrization "Link to this definition") [`viktor.parametrization.Parametrization`](/sdk/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization") that describes the entity-type. * show\_children\_as*: `Optional`\[`str`]** = None*[](#Controller.show_children_as "Link to this definition") When children are defined, specify how they are shown in the interface (‘Table’ | ‘Cards’). - summary*: `Optional`\[[`Summary`](/sdk/api/views/.md#Summary "viktor.views.Summary")]** = None*[](#Controller.summary "Link to this definition") [`viktor.views.Summary`](/sdk/api/views/.md#Summary "viktor.views.Summary") of the entity-type. ## File[​](/sdk/api/core/.md#_File "Direct link to File") * *class *viktor.core.File(*\**, *data=None*, *path=None*, *url=None*, *\*\*kwargs*)[](#File "Link to this definition") Creates a File object. Only 1 of data, path or url should be set, or File() for writable file. Or use the corresponding class-methods. A File object can have one of the following 4 types: > * SourceType.DATA: File object with in-memory data as its source > > > * Created with File.from\_data(…) > > > > * writable: False > > * SourceType.PATH: File object with an existing file (path) as its source > > > * Created with File.from\_path(…) > > > > * writable: False > > * SourceType.URL: File object with a URL as its source > > > * Created with File.from\_url(…) > > > > * writable: False > > * SourceType.WRITABLE: File object with a (temporary) writable file on disk as its source > > > * Created with File() > > > > * writable: True (writing always takes place at end of file) Note: Reading from a File with SourceType.URL downloads (part of the) URL content to a (temporary) file on disk, so that re-reading (previously read) content within the same open-context does not require downloading twice. Opening the File object a second time DOES involve downloading the content anew. If such a File needs to be opened multiple times, consider copying the File locally ([`copy()`](#File.copy "viktor.core.File.copy")), so that downloading takes place only once. Example usage: > ``` > data_file = File.from_data("my content") > path_file = File.from_path(Path(__file__).parent / "my_file.txt") > url_file = File.from_url("https://...") > writable_file = File() > > data_content = data_file.getvalue_binary() # bytes (b"my content") > path_content = path_file.getvalue() # str > > with url_file.open() as r: # open in text-mode, so read -> str > first_character = r.read(1) # downloads only partially > all_other_characters = r.read() # downloads the rest > > with writable_file.open_binary() as w: # open as binary-mode, so read/write -> bytes > w.write(b"my content") > > writable_content = writable_file.getvalue() # "my content" > ``` * Parameters: * **data** (`Union`\[`str`, `bytes`, `None`]) – in-memory data source (also [`from_data()`](#File.from_data "viktor.core.File.from_data")) * **path** (`Union`\[`str`, `bytes`, `PathLike`, `None`]) – existing file path source (also [`from_path()`](#File.from_path "viktor.core.File.from_path")) * **url** (`Optional`\[`str`]) – URL source (also [`from_url()`](#File.from_url "viktor.core.File.from_url")) - *class *SourceType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#File.SourceType "Link to this definition") Bases: `Enum` * DATA*: [`SourceType`](#File.SourceType "viktor.core.File.SourceType")** = 1*[](#File.SourceType.DATA "Link to this definition") - PATH*: [`SourceType`](#File.SourceType "viktor.core.File.SourceType")** = 2*[](#File.SourceType.PATH "Link to this definition") * URL*: [`SourceType`](#File.SourceType "viktor.core.File.SourceType")** = 3*[](#File.SourceType.URL "Link to this definition") - WRITABLE*: [`SourceType`](#File.SourceType "viktor.core.File.SourceType")** = 4*[](#File.SourceType.WRITABLE "Link to this definition") * copy(*writable=False*)[](#File.copy "Link to this definition") Make a local copy of the file to disk. Example usages: URL-file that needs to be opened multiple times: ``` # copying to path-file prevents re-downloading if opening more than once. path_file = url_file.copy() # download the complete content locally with path_file.open() as r: # no downloading ... with path_file.open() as r: # no downloading ... ``` Make writable file from read-only file: ``` writable_file = read_only_file.copy(writable=True) with writable_file.open() as w: w.write("my content") ``` * Parameters: **writable** (`bool`) – True to return writable file, False for read-only (default: False). * Return type: [`File`](#File "viktor.core.File") * Returns: File object (SourceType.WRITABLE if writable = True, else SourceType.PATH). - *classmethod *from\_data(*data*)[](#File.from_data "Link to this definition") Create a File object with in-memory data as its source. * Return type: [`File`](#File "viktor.core.File") * *classmethod *from\_path(*path*)[](#File.from_path "Link to this definition") Create a File object with an existing file (path) as its source. * Return type: [`File`](#File "viktor.core.File") - *classmethod *from\_url(*url*, *\**, *headers=None*)[](#File.from_url "Link to this definition") Create a File object with a URL as its source. * Return type: [`File`](#File "viktor.core.File") * getvalue(*encoding=None*)[](#File.getvalue "Link to this definition") Read the content (text) of the file in memory. For large files, open the file and read in chunks, to prevent the app from running out of memory. * Return type: `str` - getvalue\_binary()[](#File.getvalue_binary "Link to this definition") Read the content (binary) of the file in memory. For large files, open the file and read in chunks, to prevent the app from running out of memory. * Return type: `bytes` * open(*encoding=None*)[](#File.open "Link to this definition") Open the file in text-mode. * Parameters: **encoding** (`str`) – encoding used for reading the bytes -> str (default: default local encoding) * Return type: `TextIO` * Returns: opened text file - open\_binary()[](#File.open_binary "Link to this definition") Open the file in binary-mode. * Return type: `BinaryIO` * Returns: opened binary file * *property *source*: str | None*[](#File.source "Link to this definition") Source of the File object: * SourceType.DATA -> None * SourceType.PATH -> path of (readable) file on disk * SourceType.URL -> url * SourceType.WRITABLE -> path of (writable) file on disk - *property *source\_type*: [SourceType](#File.SourceType "viktor.core.File.SourceType")*[](#File.source_type "Link to this definition") Source type of the file. * *property *writable*: bool*[](#File.writable "Link to this definition") Whether the File is writable or not (only True for SourceType.WRITABLE). ## InitialEntity[​](/sdk/api/core/.md#_InitialEntity "Direct link to InitialEntity") * *class *viktor.core.InitialEntity(*entity\_type\_name*, *name*, *\**, *params=None*, *children=None*, *show\_on\_dashboard=None*, *use\_as\_start\_page=None*)[](#InitialEntity "Link to this definition") Construct an initial entity in the app.\_\_init\_\_py file. ``` from .settings_database.controller import Controller as SettingsDatabaseController from .project_folder.controller import Controller as ProjectFolderController from .project.controller import Controller as ProjectController from viktor import InitialEntity initial_entities = [ InitialEntity('SettingsDatabase', name='Settings', params=...), InitialEntity('ProjectFolder', name='Projects', children=[ InitialEntity('Project', 'Project X), InitialEntity('Project', 'Project Y), ]), ] ``` * Parameters: * **entity\_type\_name** (`str`) – Type of the initial entity. * **name** (`str`) – Name of the initial entity. * **params** (`Union`\[`dict`, `str`]) – Optional params in dictionary format or path to a .json, relative to the app.\_\_init\_\_.py. Note that path traversal (beyond the root directory) is not permitted (e.g. “../../entity.json”). * **children** (`List`\[[`InitialEntity`](#InitialEntity "viktor.core.InitialEntity")]) – Optional child entities. * **show\_on\_dashboard** (`bool`) – Show/hide the entity on the dashboard. Only top-level entities can be shown (default: True) New in v13.7.0 * **use\_as\_start\_page** (`bool`) – Appoint the entity as the start page (instead of the dashboard). Only top-level entities can be appointed (default: False) New in v14.19.0 ## ParamsFromFile[​](/sdk/api/core/.md#_ParamsFromFile "Direct link to ParamsFromFile") * *class *viktor.core.ParamsFromFile(*\**, *max\_size=None*, *file\_types=None*)[](#ParamsFromFile "Link to this definition") Decorator that can be used on a pre-process method during a file upload, to produce the parameter set that is stored in the database. Warning Prevent storing the complete file content on the properties if the file is large, as this may cause speed and/or stability issues. The file content can be retrieved at all times using the API whenever necessary. Example with nothing to store: ``` class Controller(ViktorController): ... @ParamsFromFile(...) def process_file(self, file: File, **kwargs): # viktor.core.File return {} ``` Example with parameters to store: ``` class Controller(ViktorController): ... @ParamsFromFile(...) def process_file(self, file: File, **kwargs): # viktor.core.File # app specific parsing logic file_content = file.getvalue() # or use reading in chunks, for large files number_of_entries = ... project_name = ... # linking the parsed output to the parametrization fields (names in database) return { 'tab': { 'section': { 'number_of_entries': number_of_entries, 'project_name': project_name } } } ``` Warning Loading the content of a large file in memory (file.getvalue()) may cause the app to crash (out-of-memory). Read the file content in chunks to avoid such memory issues (see [`File`](#File "viktor.core.File")). Note [`viktor.testing.mock_ParamsFromFile()`](/sdk/api/testing/.md#mock_ParamsFromFile "viktor.testing.mock_ParamsFromFile") can be used to test methods decorated with ParamsFromFile. * Parameters: * **max\_size** (`int`) – optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). * **file\_types** (`Sequence`\[`str`]) – optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]). Note that the extensions are filtered regardless of capitalization. ## Storage[​](/sdk/api/core/.md#_Storage "Direct link to Storage") * *class *viktor.core.Storage[](#Storage "Link to this definition") Starting point to communicate with the storage to, for example, set or retrieve analysis results. The following actions are supported: ``` storage = Storage() # Setting data on a key storage.set('data_key_1', data=File.from_data('abc'), scope='entity') storage.set('data_key_2', data=File.from_data('def'), scope='entity') # Retrieve the data by key storage.get('data_key_1', scope='entity') # List available data keys (by prefix) storage.list(scope='entity') # lists all files in current entity scope storage.list(prefix='data_key_', scope='entity') # lists 'data_key_1', 'data_key_2', ... etc. # Delete data by key storage.delete('data_key_1', scope='entity') ``` For each of these methods, a scope can be defined to point to a specific section in the storage. These scopes ensure efficient arrangement and handling of data. The following scopes can be used: > * entity : when data needs to be accessed within a specific entity > > * workspace : when data needs to be accessed workspace-wide * delete(*key*, *\**, *scope*, *entity=None*)[](#Storage.delete "Link to this definition") Delete a key-value pair for the specified scope. * Parameters: * **key** (`str`) – Unique key from which the key-value pair should be deleted. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** ([`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Raises: **FileNotFoundError** – When trying to delete a file that does not exist in the defined storage scope. * Return type: `None` - get(*key*, *\**, *scope*, *entity=None*)[](#Storage.get "Link to this definition") Retrieve data from a key for the specified scope. * Parameters: * **key** (`str`) – Unique key from which the data should be retrieved. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** ([`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Raises: **FileNotFoundError** – When trying to retrieve a file that does not exist in the defined storage scope. * Return type: [`File`](#File "viktor.core.File") * list(*\**, *prefix=None*, *scope*, *entity=None*)[](#Storage.list "Link to this definition") List all available key-value pairs for the specified scope. * Parameters: * **prefix** (`str`) – List all data of which the keys start with the provided prefix. Using a prefix potentially results in much higher performance due to a more efficient lookup in case of many stored files. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** ([`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Return type: `Dict`\[`str`, [`File`](#File "viktor.core.File")] - set(*key*, *data*, *\**, *scope*, *entity=None*)[](#Storage.set "Link to this definition") Set data on a key for the specified scope. * Parameters: * **key** (`str`) – Unique key on which the data is set (max. 64 characters). * **data** ([`File`](#File "viktor.core.File")) – Data to be stored. * **scope** (`str`) – Applicable scope, ‘entity’ | ‘workspace’. * **entity** ([`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")) – Applicable entity, used in combination with scope==’entity’ (default: current entity). * Return type: `None` ## UserMessage[​](/sdk/api/core/.md#_UserMessage "Direct link to UserMessage") * *class *viktor.core.UserMessage[](#UserMessage "Link to this definition") New in v14.0.0 A non-breaking message that is shown to the user in the web-interface. Example usage: ``` UserMessage.warning("Show this warning") UserMessage.info("Show this info") UserMessage.success("Analysis successfully finished!") ``` * *classmethod *info(*message*)[](#UserMessage.info "Link to this definition") Show an info message to the user. * Return type: `None` - *classmethod *success(*message*)[](#UserMessage.success "Link to this definition") Show a success message to the user. * Return type: `None` * *classmethod *warning(*message*)[](#UserMessage.warning "Link to this definition") Show a warning message to the user. * Return type: `None` ## ViktorController[​](/sdk/api/core/.md#_ViktorController "Direct link to ViktorController") * viktor.core.ViktorController[](#ViktorController "Link to this definition") alias of [`Controller`](#Controller "viktor.core.Controller") ## make\_data\_json\_serializable[​](/sdk/api/core/.md#_make_data_json_serializable "Direct link to make_data_json_serializable") * viktor.core.make\_data\_json\_serializable(*input\_data*)[](#make_data_json_serializable "Link to this definition") The python built-in json dump does not support all the desired types. This function converts those, thereby enabling broader json conversion. :rtype: `Any` * numpy number types -> equivalent python builtin * datetime.datetime and datetime.date -> isoformat str * tuple -> list (otherwise sub elements cannot be converted due to tuple immutability) ## progress\_message[​](/sdk/api/core/.md#_progress_message "Direct link to progress_message") * viktor.core.progress\_message(*message*, *percentage=None*)[](#progress_message "Link to this definition") Send a user facing progress message informing the progress of an evaluation. Messages are truncated to 500 characters * Parameters: * **message** (`str`) – Message shown to the user * **percentage** (`float`) – Value between 0 and 100 quantifying the progress * Return type: `None` --- # viktor.errors ## BadRequestError[​](/sdk/api/errors/.md#_BadRequestError "Direct link to BadRequestError") * *exception *viktor.errors.BadRequestError[](#BadRequestError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if BE API returns 400. ## ComputeError[​](/sdk/api/errors/.md#_ComputeError "Direct link to ComputeError") * *exception *viktor.errors.ComputeError[](#ComputeError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if the job computation didn’t finish successfully. ## EntityCreateError[​](/sdk/api/errors/.md#_EntityCreateError "Direct link to EntityCreateError") * *exception *viktor.errors.EntityCreateError[](#EntityCreateError "Link to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if creation of an entity failed. ## EntityDeleteError[​](/sdk/api/errors/.md#_EntityDeleteError "Direct link to EntityDeleteError") * *exception *viktor.errors.EntityDeleteError[](#EntityDeleteError "Link to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if deletion of an entity failed. ## EntityError[​](/sdk/api/errors/.md#_EntityError "Direct link to EntityError") * *exception *viktor.errors.EntityError[](#EntityError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Base class exception for all entity errors raised in the API. ## EntityNotFoundError[​](/sdk/api/errors/.md#_EntityNotFoundError "Direct link to EntityNotFoundError") * *exception *viktor.errors.EntityNotFoundError[](#EntityNotFoundError "Link to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if an entity is requested using the api module but does not exist. ## EntityReviseError[​](/sdk/api/errors/.md#_EntityReviseError "Direct link to EntityReviseError") * *exception *viktor.errors.EntityReviseError[](#EntityReviseError "Link to this definition") Bases: [`EntityError`](#EntityError "viktor.errors.EntityError") Exception raised if creating a revision (e.g. set params, rename) of an entity failed. ## Error[​](/sdk/api/errors/.md#_Error "Direct link to Error") * *exception *viktor.errors.Error[](#Error "Link to this definition") Bases: `Exception` ## ExecutionError[​](/sdk/api/errors/.md#_ExecutionError "Direct link to ExecutionError") * *exception *viktor.errors.ExecutionError[](#ExecutionError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs during the execution of an external analysis. ## GEFClassificationError[​](/sdk/api/errors/.md#_GEFClassificationError "Direct link to GEFClassificationError") * *exception *viktor.errors.GEFClassificationError[](#GEFClassificationError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during classification of [`viktor.geo.GEFData`](/sdk/api/geo/.md#GEFData "viktor.geo.GEFData"). ## GEFParsingError[​](/sdk/api/errors/.md#_GEFParsingError "Direct link to GEFParsingError") * *exception *viktor.errors.GEFParsingError[](#GEFParsingError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during parsing of a [`viktor.geo.GEFFile`](/sdk/api/geo/.md#GEFFile "viktor.geo.GEFFile"). ## InputViolation[​](/sdk/api/errors/.md#_InputViolation "Direct link to InputViolation") * *class *viktor.errors.InputViolation(*message*, *fields*)[](#InputViolation "Link to this definition") New in v13.7.0 Annotate fields that should be marked as invalid in the interface, along with a message. Example: ``` InputViolation("Width cannot be larger than height", fields=['width', 'height']) ``` * Parameters: * **message** (`str`) – Message that is shown to the user. * **fields** (`Sequence`\[`str`]) – Fields that are marked invalid in the interface. Note that these refer to the parametrization class attributes (e.g. ‘step\_1.field\_x’), and not the database location in case name is set. ## InternalError[​](/sdk/api/errors/.md#_InternalError "Direct link to InternalError") * *exception *viktor.errors.InternalError[](#InternalError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception applicable for incorrect internal VIKTOR logic. Please contact VIKTOR. ## LicenseError[​](/sdk/api/errors/.md#_LicenseError "Direct link to LicenseError") * *exception *viktor.errors.LicenseError[](#LicenseError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an external analysis cannot be executed due to license issues. ## ModelError[​](/sdk/api/errors/.md#_ModelError "Direct link to ModelError") * *exception *viktor.errors.ModelError[](#ModelError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs within the model of one of the bindings (e.g. SCIA, D-Settlement, …). ## ParsingError[​](/sdk/api/errors/.md#_ParsingError "Direct link to ParsingError") * *exception *viktor.errors.ParsingError[](#ParsingError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if an error occurs during parsing. ## PermissionDeniedError[​](/sdk/api/errors/.md#_PermissionDeniedError "Direct link to PermissionDeniedError") * *exception *viktor.errors.PermissionDeniedError[](#PermissionDeniedError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if a resource is requested using the api module but access is not permitted (403) ## PreconditionFailedError[​](/sdk/api/errors/.md#_PreconditionFailedError "Direct link to PreconditionFailedError") * *exception *viktor.errors.PreconditionFailedError[](#PreconditionFailedError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if some precondition failed (412) ## ResourceNotFoundError[​](/sdk/api/errors/.md#_ResourceNotFoundError "Direct link to ResourceNotFoundError") * *exception *viktor.errors.ResourceNotFoundError[](#ResourceNotFoundError "Link to this definition") Bases: [`Error`](#Error "viktor.errors.Error") Exception raised if a resource is requested using the api module but does not exist (404) ## SciaParsingError[​](/sdk/api/errors/.md#_SciaParsingError "Direct link to SciaParsingError") * *exception *viktor.errors.SciaParsingError[](#SciaParsingError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during parsing of SCIA output results. ## SpreadsheetError[​](/sdk/api/errors/.md#_SpreadsheetError "Direct link to SpreadsheetError") * *exception *viktor.errors.SpreadsheetError[](#SpreadsheetError "Link to this definition") Bases: `Exception` Exception raised if an error occurs in the Excel or Spreadsheet service. ## SummaryError[​](/sdk/api/errors/.md#_SummaryError "Direct link to SummaryError") * *exception *viktor.errors.SummaryError[](#SummaryError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during the generation of the summary. ## UserError[​](/sdk/api/errors/.md#_UserError "Direct link to UserError") * *exception *viktor.errors.UserError(*\*messages*, *input\_violations=None*)[](#UserError "Link to this definition") Bases: `Exception` New in v13.7.0 Exception that is shown to the user in the web-interface. Example: ``` raise UserError("The design is not feasible") ``` By providing input\_violations you can mark specific fields as invalid: ``` violations = [ InputViolation("Width cannot be larger than height", fields=['width', 'height']), InputViolation(...), ] raise UserError("The design is not feasible", input_violations=violations) ``` * Parameters: * **messages** (`Any`) – Messages to be shown to the user. * **input\_violations** (`Sequence`\[[`InputViolation`](#InputViolation "viktor.errors.InputViolation")]) – Mark fields invalid in the interface, along with a message. ## ViewError[​](/sdk/api/errors/.md#_ViewError "Direct link to ViewError") * *exception *viktor.errors.ViewError[](#ViewError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during the generation of a view. ## WordFileError[​](/sdk/api/errors/.md#_WordFileError "Direct link to WordFileError") * *exception *viktor.errors.WordFileError[](#WordFileError "Link to this definition") Bases: `Exception` Exception raised if an error occurs during rendering of a Word file. --- # viktor.external.axisvm ## AxisVMAnalysis[​](/sdk/api/external/axisvm/.md#_AxisVMAnalysis "Direct link to AxisVMAnalysis") * *class *viktor.external.axisvm.AxisVMAnalysis(*model*, *\**, *return\_results=True*, *return\_model=False*, *report\_template=None*)[](#AxisVMAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Perform an analysis using AxisVM on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_results()`](#AxisVMAnalysis.get_results "viktor.external.axisvm.AxisVMAnalysis.get_results"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). The model file can be retrieved by calling [`get_model_file()`](#AxisVMAnalysis.get_model_file "viktor.external.axisvm.AxisVMAnalysis.get_model_file") and the result by calling [`get_result_file()`](#AxisVMAnalysis.get_result_file "viktor.external.axisvm.AxisVMAnalysis.get_result_file"). Usage: ``` axisvm_analysis = AxisVMAnalysis(model, return_results=True, return_model=True) axisvm_analysis.execute(timeout=10) results = axisvm_analysis.get_results() model_file = axisvm_analysis.get_model_file() result_file = axisvm_analysis.get_result_file() ``` Exceptions which can be raised during calculation: > * [`ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **model** ([`Model`](#Model "viktor.external.axisvm.Model")) – AxisVM model ([`Model`](#Model "viktor.external.axisvm.Model")) * **return\_results** (`bool`) – If True, an analysis will be run and the result file is returned. * **return\_model** (`bool`) – If True, the model file is returned. * **report\_template** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – (optional) report template that is added to AxisVM file - get\_model\_file(*\**, *as\_file=False*)[](#AxisVMAnalysis.get_model_file "Link to this definition") Retrieve the model file (only if return\_model = True). [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Parameters: **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * get\_result\_file(*\**, *as\_file=False*)[](#AxisVMAnalysis.get_result_file "Link to this definition") Retrieve the result file (only if return\_results = True). [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Parameters: **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] - get\_results()[](#AxisVMAnalysis.get_results "Link to this definition") Retrieve the results (only if return\_results = True). `execute()` must be called first. The format of the returned dictionary is: ``` { 'Forces': , 'Displacements': , 'Sections': } ``` * Return type: `dict` ## CircleArc[​](/sdk/api/external/axisvm/.md#_CircleArc "Direct link to CircleArc") * *class *viktor.external.axisvm.CircleArc(*center*, *normal\_vector*, *alpha*)[](#CircleArc "Link to this definition") Circular arc defined by its center, normal vector and angle. Used in various methods, in conjunction with a start and end point. * Parameters: * **center** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the arc’s center point. * **normal\_vector** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) component \[m] of the arc plane’s normal vector. * **alpha** (`float`) – signed angle \[rad]. Positive angle is counterclockwise, from the start point. ## CrossSection[​](/sdk/api/external/axisvm/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.axisvm.CrossSection(*id\_*, *name*)[](#CrossSection "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *Process(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CrossSection.Process "Link to this definition") Bases: `Enum` Manufacturing process. * COLD\_FORMED*: [`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 3*[](#CrossSection.Process.COLD_FORMED "Link to this definition") - OTHER*: [`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 0*[](#CrossSection.Process.OTHER "Link to this definition") * ROLLED*: [`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 1*[](#CrossSection.Process.ROLLED "Link to this definition") - WELDED*: [`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")** = 2*[](#CrossSection.Process.WELDED "Link to this definition") - *property *name*: str*[](#CrossSection.name "Link to this definition") Name of the cross-section. ## CrossSectionInterface[​](/sdk/api/external/axisvm/.md#_CrossSectionInterface "Direct link to CrossSectionInterface") * *class *viktor.external.axisvm.CrossSectionInterface[](#CrossSectionInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.cross_sections`](#Model.cross_sections "viktor.external.axisvm.Model.cross_sections") * create\_circular(*diameter*, *\**, *name=None*)[](#CrossSectionInterface.create_circular "Link to this definition") Create a circular cross-section with given diameter. * Parameters: * **diameter** (`float`) – diameter \[m] of the cross-section. * **name** (`str`) – name of the cross-section (must be unique) (default: auto). * Return type: [`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection") - create\_rectangular(*width*, *height*, *\**, *process=Process.OTHER*, *name=None*)[](#CrossSectionInterface.create_rectangular "Link to this definition") Create a rectangular cross-section with given width and height. * Parameters: * **width** (`float`) – width \[m] of the cross-section. * **height** (`float`) – height \[m] of the cross-section. * **process** ([`Process`](#CrossSection.Process "viktor.external.axisvm.CrossSection.Process")) – process (default: other). * **name** (`str`) – name of the cross-section (must be unique) (default: auto). * Return type: [`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection") ## Domain[​](/sdk/api/external/axisvm/.md#_Domain "Direct link to Domain") * *class *viktor.external.axisvm.Domain(*id\_*, *interface*)[](#Domain "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *EccentricityType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Domain.EccentricityType "Link to this definition") Bases: `Enum` Type of eccentricity. * BOTTOM\_ALIGNED*: [`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 5*[](#Domain.EccentricityType.BOTTOM_ALIGNED "Link to this definition") - CONSTANT*: [`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 1*[](#Domain.EccentricityType.CONSTANT "Link to this definition") * ONE\_WAY*: [`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 2*[](#Domain.EccentricityType.ONE_WAY "Link to this definition") - TOP\_ALIGNED*: [`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 4*[](#Domain.EccentricityType.TOP_ALIGNED "Link to this definition") * TWO\_WAY*: [`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")** = 3*[](#Domain.EccentricityType.TWO_WAY "Link to this definition") - *class *MeshGeometry(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Domain.MeshGeometry "Link to this definition") Bases: `Enum` Mesh geometry type. * MIXED*: [`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 2*[](#Domain.MeshGeometry.MIXED "Link to this definition") - QUAD*: [`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 1*[](#Domain.MeshGeometry.QUAD "Link to this definition") * TRIANGLE*: [`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")** = 0*[](#Domain.MeshGeometry.TRIANGLE "Link to this definition") * *class *MeshType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Domain.MeshType "Link to this definition") Bases: `Enum` Contour division method. * ADAPTIVE*: [`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")** = 0*[](#Domain.MeshType.ADAPTIVE "Link to this definition") - UNIFORM*: [`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")** = 1*[](#Domain.MeshType.UNIFORM "Link to this definition") - *class *SurfaceType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Domain.SurfaceType "Link to this definition") Bases: `Enum` Finite element type. * HOLE*: [`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 0*[](#Domain.SurfaceType.HOLE "Link to this definition") - MEMBRANE\_STRAIN*: [`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 2*[](#Domain.SurfaceType.MEMBRANE_STRAIN "Link to this definition") * MEMBRANE\_STRESS*: [`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 1*[](#Domain.SurfaceType.MEMBRANE_STRESS "Link to this definition") - PLATE*: [`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 3*[](#Domain.SurfaceType.PLATE "Link to this definition") * SHELL*: [`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")** = 4*[](#Domain.SurfaceType.SHELL "Link to this definition") * generate\_mesh(*mesh\_geometry*, *mesh\_size*, *\**, *mesh\_type=MeshType.UNIFORM*, *fit\_to\_point\_loads=None*, *fit\_to\_line\_loads=None*, *fit\_to\_surface\_loads=None*, *quad\_mesh\_quality=2*)[](#Domain.generate_mesh "Link to this definition") Generate a mesh on the domain. * Parameters: * **mesh\_geometry** ([`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")) – mesh geometry type. * **mesh\_size** (`float`) – average mesh size \[m]. * **mesh\_type** ([`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")) – contour division method (default: uniform). * **fit\_to\_point\_loads** (`float`) – fit mesh to point loads (default: false). * **fit\_to\_line\_loads** (`float`) – fit mesh to line loads (default: false). * **fit\_to\_surface\_loads** (`float`) – fit mesh to surface loads (default: false) * **quad\_mesh\_quality** (`int`) – smoothing quality (1-6) (default: 2) * Return type: `None` - set\_eccentricity(*eccentricity\_type*, *\**, *ecc\_1=None*, *p1=None*, *ecc\_2=None*, *p2=None*, *ecc\_3=None*, *p3=None*)[](#Domain.set_eccentricity "Link to this definition") Set eccentricity for the domain. * Parameters: * **eccentricity\_type** ([`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")) – type of eccentricity. * **ecc\_1** (`float`) – eccentricity \[m] at reference point 1. * **p1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 1. * **ecc\_2** (`float`) – eccentricity \[m] at reference point 2. * **p2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 2. * **ecc\_3** (`float`) – eccentricity \[m] at reference point 3. * **p3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 3. * Return type: `None` ## DomainInterface[​](/sdk/api/external/axisvm/.md#_DomainInterface "Direct link to DomainInterface") * *class *viktor.external.axisvm.DomainInterface[](#DomainInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.domains`](#Model.domains "viktor.external.axisvm.Model.domains") * create(*lines*, *\**, *surface\_type*, *thickness*, *material*)[](#DomainInterface.create "Link to this definition") Create a domain from given lines. * Parameters: * **lines** (`List`\[[`Line`](#Line "viktor.external.axisvm.Line")]) – lines to create a domain from (lines must form a closed loop!). * **surface\_type** ([`SurfaceType`](#Domain.SurfaceType "viktor.external.axisvm.Domain.SurfaceType")) – finite element surface type. * **thickness** (`float`) – thickness \[m] of the surface. * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the surface. * Return type: [`Domain`](#Domain "viktor.external.axisvm.Domain") - generate\_mesh\_on\_domains(*domains*, *mesh\_geometry*, *mesh\_size*, *\**, *mesh\_type=MeshType.UNIFORM*, *fit\_to\_point\_loads=None*, *fit\_to\_line\_loads=None*, *fit\_to\_surface\_loads=None*, *quad\_mesh\_quality=2*)[](#DomainInterface.generate_mesh_on_domains "Link to this definition") Generate a mesh on one or more domains. * Parameters: * **domains** (`List`\[[`Domain`](#Domain "viktor.external.axisvm.Domain")]) – domain(s) to generate the mesh on. * **mesh\_geometry** ([`MeshGeometry`](#Domain.MeshGeometry "viktor.external.axisvm.Domain.MeshGeometry")) – mesh geometry type. * **mesh\_size** (`float`) – average mesh size \[m]. * **mesh\_type** ([`MeshType`](#Domain.MeshType "viktor.external.axisvm.Domain.MeshType")) – contour division method (default: uniform). * **fit\_to\_point\_loads** (`float`) – fit mesh to point loads (default: false). * **fit\_to\_line\_loads** (`float`) – fit mesh to line loads (default: false). * **fit\_to\_surface\_loads** (`float`) – fit mesh to surface loads (default: false) * **quad\_mesh\_quality** (`int`) – smoothing quality (1-6) (default: 2) * Return type: `None` * set\_eccentricity(*domain*, *eccentricity\_type*, *\**, *ecc\_1=None*, *p1=None*, *ecc\_2=None*, *p2=None*, *ecc\_3=None*, *p3=None*)[](#DomainInterface.set_eccentricity "Link to this definition") Set eccentricity for a domain. * Parameters: * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to set eccentricity. * **eccentricity\_type** ([`EccentricityType`](#Domain.EccentricityType "viktor.external.axisvm.Domain.EccentricityType")) – type of eccentricity. * **ecc\_1** (`float`) – eccentricity \[m] at reference point 1. * **p1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 1. * **ecc\_2** (`float`) – eccentricity \[m] at reference point 2. * **p2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 2. * **ecc\_3** (`float`) – eccentricity \[m] at reference point 3. * **p3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 3. * Return type: `None` ## Line[​](/sdk/api/external/axisvm/.md#_Line "Direct link to Line") * *class *viktor.external.axisvm.Line(*id\_*, *interface*, *node1*, *node2*)[](#Line "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * define\_as\_beam(*material*, *css\_start*, *css\_end=None*, *\**, *local\_z\_reference=None*)[](#Line.define_as_beam "Link to this definition") Define the line as beam with given material and cross-section. * Parameters: * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the beam. * **css\_start** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam. * **css\_end** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam (default: same as css\_start). * **local\_z\_reference** ([`Reference`](#Reference "viktor.external.axisvm.Reference")) – local z-reference (must be of type vector) (default: auto). * Return type: [`Member`](#Member "viktor.external.axisvm.Member") - *property *end\_node*: [Node](#Node "viktor.external.axisvm.Node")*[](#Line.end_node "Link to this definition") End node of the line. * split\_by\_number(*n*)[](#Line.split_by_number "Link to this definition") Split the line in ‘n’ equal parts. * Parameters: **n** (`int`) – number of parts after the split. * Return type: `None` - *property *start\_node*: [Node](#Node "viktor.external.axisvm.Node")*[](#Line.start_node "Link to this definition") Start node of the line. ## LineInterface[​](/sdk/api/external/axisvm/.md#_LineInterface "Direct link to LineInterface") * *class *viktor.external.axisvm.LineInterface[](#LineInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.lines`](#Model.lines "viktor.external.axisvm.Model.lines") * create(*start\_node*, *end\_node*, *circle\_arc=None*)[](#LineInterface.create "Link to this definition") Create a line between start and end node. * Parameters: * **start\_node** ([`Node`](#Node "viktor.external.axisvm.Node")) – start node. * **end\_node** ([`Node`](#Node "viktor.external.axisvm.Node")) – end node. * **circle\_arc** ([`CircleArc`](#CircleArc "viktor.external.axisvm.CircleArc")) – circular arc between the nodes (default: straight line). * Return type: [`Line`](#Line "viktor.external.axisvm.Line") - define\_as\_beam(*line*, *material*, *css\_start*, *css\_end=None*, *\**, *local\_z\_reference=None*)[](#LineInterface.define_as_beam "Link to this definition") Define a line as beam with given material and cross-section. * Parameters: * **line** ([`Line`](#Line "viktor.external.axisvm.Line")) – line to define as beam. * **material** ([`Material`](#Material "viktor.external.axisvm.Material")) – material of the beam. * **css\_start** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam. * **css\_end** ([`CrossSection`](#CrossSection "viktor.external.axisvm.CrossSection")) – cross-section at the start node of the beam (default: same as css\_start). * **local\_z\_reference** ([`Reference`](#Reference "viktor.external.axisvm.Reference")) – local z-reference (must be of type vector) (default: auto). * Return type: [`Member`](#Member "viktor.external.axisvm.Member") * split\_by\_number(*line*, *n*)[](#LineInterface.split_by_number "Link to this definition") Split a line in ‘n’ equal parts. * Parameters: * **line** ([`Line`](#Line "viktor.external.axisvm.Line")) – line to split. * **n** (`int`) – number of parts after the split. * Return type: `None` ## LineSupport[​](/sdk/api/external/axisvm/.md#_LineSupport "Direct link to LineSupport") * *class *viktor.external.axisvm.LineSupport(*id\_*)[](#LineSupport "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *NonLinearity(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.NonLinearity "Link to this definition") Bases: `Enum` Type of non-linear behavior. * COMPRESSION\_ONLY*: [`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 2*[](#LineSupport.NonLinearity.COMPRESSION_ONLY "Link to this definition") - LINEAR*: [`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 0*[](#LineSupport.NonLinearity.LINEAR "Link to this definition") * TENSION\_ONLY*: [`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")** = 1*[](#LineSupport.NonLinearity.TENSION_ONLY "Link to this definition") ## LineSupportInterface[​](/sdk/api/external/axisvm/.md#_LineSupportInterface "Direct link to LineSupportInterface") * *class *viktor.external.axisvm.LineSupportInterface[](#LineSupportInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.line_supports`](#Model.line_supports "viktor.external.axisvm.Model.line_supports") * create\_on\_member(*member*, *k\_x*, *k\_y*, *k\_z*, *\**, *non\_linearity\_x=NonLinearity.LINEAR*, *non\_linearity\_y=NonLinearity.LINEAR*, *non\_linearity\_z=NonLinearity.LINEAR*, *resistance\_fx=0.0*, *resistance\_fy=0.0*, *resistance\_fz=0.0*)[](#LineSupportInterface.create_on_member "Link to this definition") Create a line support on a member (beam), in the member’s coordinate system. * Parameters: * **member** ([`Member`](#Member "viktor.external.axisvm.Member")) – member (beam) to create the line support on. * **k\_x** (`float`) – stiffness \[kN/m/m] in the local x-direction. * **k\_y** (`float`) – stiffness \[kN/m/m] in the local y-direction. * **k\_z** (`float`) – stiffness \[kN/m/m] in the local z-direction. * **non\_linearity\_x** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local x-direction (default: linear). * **non\_linearity\_y** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local y-direction (default: linear). * **non\_linearity\_z** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – non-linear behaviour in the local z-direction (default: linear). * **resistance\_fx** (`float`) – resistance \[kN/m] in the local x-direction (default: 0.0). * **resistance\_fy** (`float`) – resistance \[kN/m] in the local y-direction (default: 0.0). * **resistance\_fz** (`float`) – resistance \[kN/m] in the local z-direction (default: 0.0). * Return type: [`LineSupport`](#LineSupport "viktor.external.axisvm.LineSupport") ## Load[​](/sdk/api/external/axisvm/.md#_Load "Direct link to Load") * *class *viktor.external.axisvm.Load(*id\_*)[](#Load "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *Axis(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Load.Axis "Link to this definition") Bases: `Enum` * X*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 0*[](#Load.Axis.X "Link to this definition") - XX*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 3*[](#Load.Axis.XX "Link to this definition") * Y*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 1*[](#Load.Axis.Y "Link to this definition") - YY*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 4*[](#Load.Axis.YY "Link to this definition") * Z*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 2*[](#Load.Axis.Z "Link to this definition") - ZZ*: [`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")** = 5*[](#Load.Axis.ZZ "Link to this definition") - *class *DistributionType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Load.DistributionType "Link to this definition") Bases: `Enum` * GLOBAL*: [`DistributionType`](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 0*[](#Load.DistributionType.GLOBAL "Link to this definition") - LOCAL*: [`DistributionType`](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 1*[](#Load.DistributionType.LOCAL "Link to this definition") * PROJECTED*: [`DistributionType`](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")** = 2*[](#Load.DistributionType.PROJECTED "Link to this definition") * *class *SurfaceDistributionType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Load.SurfaceDistributionType "Link to this definition") Bases: `Enum` * PROJECTED*: [`SurfaceDistributionType`](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")** = 1*[](#Load.SurfaceDistributionType.PROJECTED "Link to this definition") - SURFACE*: [`SurfaceDistributionType`](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")** = 0*[](#Load.SurfaceDistributionType.SURFACE "Link to this definition") - *class *System(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Load.System "Link to this definition") Bases: `Enum` * GLOBAL*: [`System`](#Load.System "viktor.external.axisvm.Load.System")** = 0*[](#Load.System.GLOBAL "Link to this definition") - LOCAL*: [`System`](#Load.System "viktor.external.axisvm.Load.System")** = 1*[](#Load.System.LOCAL "Link to this definition") * REFERENCE*: [`System`](#Load.System "viktor.external.axisvm.Load.System")** = 2*[](#Load.System.REFERENCE "Link to this definition") ## LoadCase[​](/sdk/api/external/axisvm/.md#_LoadCase "Direct link to LoadCase") * *class *viktor.external.axisvm.LoadCase(*id\_*, *name*)[](#LoadCase "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *name*: str*[](#LoadCase.name "Link to this definition") Name of the load case. ## LoadCaseInterface[​](/sdk/api/external/axisvm/.md#_LoadCaseInterface "Direct link to LoadCaseInterface") * *class *viktor.external.axisvm.LoadCaseInterface[](#LoadCaseInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.load_cases`](#Model.load_cases "viktor.external.axisvm.Model.load_cases") * create(*name=None*)[](#LoadCaseInterface.create "Link to this definition") Create a load case. * Parameters: **name** (`str`) – name of the load case (default: auto). * Return type: [`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase") ## LoadCombination[​](/sdk/api/external/axisvm/.md#_LoadCombination "Direct link to LoadCombination") * *class *viktor.external.axisvm.LoadCombination(*id\_*, *name*)[](#LoadCombination "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCombination.Type "Link to this definition") Bases: `Enum` * OTHER*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 0*[](#LoadCombination.Type.OTHER "Link to this definition") - SLS\_1*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 1*[](#LoadCombination.Type.SLS_1 "Link to this definition") * SLS\_2*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 2*[](#LoadCombination.Type.SLS_2 "Link to this definition") - SLS\_3*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 3*[](#LoadCombination.Type.SLS_3 "Link to this definition") * SLS\_CHAR*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 1*[](#LoadCombination.Type.SLS_CHAR "Link to this definition") - SLS\_FREQ*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 2*[](#LoadCombination.Type.SLS_FREQ "Link to this definition") * SLS\_QUASI*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 3*[](#LoadCombination.Type.SLS_QUASI "Link to this definition") - ULS*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 4*[](#LoadCombination.Type.ULS "Link to this definition") * ULS\_1*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 4*[](#LoadCombination.Type.ULS_1 "Link to this definition") - ULS\_2*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 5*[](#LoadCombination.Type.ULS_2 "Link to this definition") * ULS\_3*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 6*[](#LoadCombination.Type.ULS_3 "Link to this definition") - ULS\_A*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 9*[](#LoadCombination.Type.ULS_A "Link to this definition") * ULS\_A1*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 12*[](#LoadCombination.Type.ULS_A1 "Link to this definition") - ULS\_A2*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 13*[](#LoadCombination.Type.ULS_A2 "Link to this definition") * ULS\_A3*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 14*[](#LoadCombination.Type.ULS_A3 "Link to this definition") - ULS\_A4*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 15*[](#LoadCombination.Type.ULS_A4 "Link to this definition") * ULS\_A5*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 16*[](#LoadCombination.Type.ULS_A5 "Link to this definition") - ULS\_A6*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 17*[](#LoadCombination.Type.ULS_A6 "Link to this definition") * ULS\_A7*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 18*[](#LoadCombination.Type.ULS_A7 "Link to this definition") - ULS\_A8*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 19*[](#LoadCombination.Type.ULS_A8 "Link to this definition") * ULS\_AB*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 8*[](#LoadCombination.Type.ULS_AB "Link to this definition") - ULS\_ALL*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 7*[](#LoadCombination.Type.ULS_ALL "Link to this definition") * ULS\_ALL\_AB*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 11*[](#LoadCombination.Type.ULS_ALL_AB "Link to this definition") - ULS\_B*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 10*[](#LoadCombination.Type.ULS_B "Link to this definition") * ULS\_EXCEPTIONAL*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 6*[](#LoadCombination.Type.ULS_EXCEPTIONAL "Link to this definition") - ULS\_SEISMIC*: [`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")** = 5*[](#LoadCombination.Type.ULS_SEISMIC "Link to this definition") - *property *name*: str*[](#LoadCombination.name "Link to this definition") Name of the load case. ## LoadCombinationInterface[​](/sdk/api/external/axisvm/.md#_LoadCombinationInterface "Direct link to LoadCombinationInterface") * *class *viktor.external.axisvm.LoadCombinationInterface[](#LoadCombinationInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.load_combinations`](#Model.load_combinations "viktor.external.axisvm.Model.load_combinations") * create(*combination\_type*, *load\_case\_factors*, *\**, *name=None*)[](#LoadCombinationInterface.create "Link to this definition") Create a load combination from given load cases and factors. * Parameters: * **combination\_type** ([`Type`](#LoadCombination.Type "viktor.external.axisvm.LoadCombination.Type")) – load combination type. * **load\_case\_factors** (`Dict`\[[`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase"), `float`]) – factorized load cases {load\_case: factor}. * **name** (`str`) – name of the load combination (default: auto). * Return type: [`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination") ## LoadInterface[​](/sdk/api/external/axisvm/.md#_LoadInterface "Direct link to LoadInterface") * *class *viktor.external.axisvm.LoadInterface[](#LoadInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.loads`](#Model.loads "viktor.external.axisvm.Model.loads") * create\_beam\_self\_weight(*load\_case*, *member*)[](#LoadInterface.create_beam_self_weight "Link to this definition") Create a self-weight load on a member (beam). * Parameters: * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **member** ([`Member`](#Member "viktor.external.axisvm.Member")) – member to create the load on. * Return type: [`Load`](#Load "viktor.external.axisvm.Load") - create\_domain\_constant(*load\_case*, *domain*, *load*, *\**, *distribution\_type=SurfaceDistributionType.SURFACE*, *system=System.GLOBAL*)[](#LoadInterface.create_domain_constant "Link to this definition") Create a constant distributed load on a domain. * Parameters: * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * **load** (`Tuple`\[`float`, `float`, `float`]) – magnitude of the load (x, y, z) \[kN]. * **distribution\_type** ([`SurfaceDistributionType`](#Load.SurfaceDistributionType "viktor.external.axisvm.Load.SurfaceDistributionType")) – distribution type (default: SURFACE). * **system** ([`System`](#Load.System "viktor.external.axisvm.Load.System")) – coordinate system (default: GLOBAL). * Return type: [`Load`](#Load "viktor.external.axisvm.Load") * create\_domain\_linear(*load\_case*, *domain*, *load*, *\**, *component*, *point\_1*, *point\_2*, *point\_3*, *distribution\_type=DistributionType.GLOBAL*, *load\_on\_hole=False*)[](#LoadInterface.create_domain_linear "Link to this definition") Create a linear distributed load on a domain. * Parameters: * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * **load** (`Tuple`\[`float`, `float`, `float`]) – magnitude of the load at (point\_1, point\_2, point\_3) \[kN]. * **component** ([`Axis`](#Load.Axis "viktor.external.axisvm.Load.Axis")) – direction of the load (X, Y, Z only). * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 1. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 2. * **point\_3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of reference point 3. * **distribution\_type** ([`DistributionType`](#Load.DistributionType "viktor.external.axisvm.Load.DistributionType")) – distribution type (default: GLOBAL). * **load\_on\_hole** (`bool`) – apply load on hole (default: False -> loads disappear on holes). * Return type: [`Load`](#Load "viktor.external.axisvm.Load") - create\_domain\_self\_weight(*load\_case*, *domain*)[](#LoadInterface.create_domain_self_weight "Link to this definition") Create a self-weight load on a domain. * Parameters: * **load\_case** ([`LoadCase`](#LoadCase "viktor.external.axisvm.LoadCase")) – load case to add the load to. * **domain** ([`Domain`](#Domain "viktor.external.axisvm.Domain")) – domain to create the load on. * Return type: [`Load`](#Load "viktor.external.axisvm.Load") ## Material[​](/sdk/api/external/axisvm/.md#_Material "Direct link to Material") * *class *viktor.external.axisvm.Material(*id\_*, *name*)[](#Material "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *class *DesignCode(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Material.DesignCode "Link to this definition") Bases: `Enum` National design code. * CA\_BRIDGE*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 24*[](#Material.DesignCode.CA_BRIDGE "Link to this definition") - CA\_NBCC*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 22*[](#Material.DesignCode.CA_NBCC "Link to this definition") * CA\_ONTARIO*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 23*[](#Material.DesignCode.CA_ONTARIO "Link to this definition") - DUTCH\_NEN*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 5*[](#Material.DesignCode.DUTCH_NEN "Link to this definition") * EURO\_CODE*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 2*[](#Material.DesignCode.EURO_CODE "Link to this definition") - EURO\_CODE\_AUSTRIAN*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 10*[](#Material.DesignCode.EURO_CODE_AUSTRIAN "Link to this definition") * EURO\_CODE\_B*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 17*[](#Material.DesignCode.EURO_CODE_B "Link to this definition") - EURO\_CODE\_CZ*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 16*[](#Material.DesignCode.EURO_CODE_CZ "Link to this definition") * EURO\_CODE\_DK*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 19*[](#Material.DesignCode.EURO_CODE_DK "Link to this definition") - EURO\_CODE\_FIN*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 13*[](#Material.DesignCode.EURO_CODE_FIN "Link to this definition") * EURO\_CODE\_GER*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 8*[](#Material.DesignCode.EURO_CODE_GER "Link to this definition") - EURO\_CODE\_HU*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 15*[](#Material.DesignCode.EURO_CODE_HU "Link to this definition") * EURO\_CODE\_NL*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 12*[](#Material.DesignCode.EURO_CODE_NL "Link to this definition") - EURO\_CODE\_PL*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 18*[](#Material.DesignCode.EURO_CODE_PL "Link to this definition") * EURO\_CODE\_RO*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 14*[](#Material.DesignCode.EURO_CODE_RO "Link to this definition") - EURO\_CODE\_S*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 20*[](#Material.DesignCode.EURO_CODE_S "Link to this definition") * EURO\_CODE\_SK*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 25*[](#Material.DesignCode.EURO_CODE_SK "Link to this definition") - EURO\_CODE\_UK*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 11*[](#Material.DesignCode.EURO_CODE_UK "Link to this definition") * GERMAN\_DIN1045\_1*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 6*[](#Material.DesignCode.GERMAN_DIN1045_1 "Link to this definition") - HUNGARIAN\_MSZ*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 1*[](#Material.DesignCode.HUNGARIAN_MSZ "Link to this definition") * ITALIAN*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 9*[](#Material.DesignCode.ITALIAN "Link to this definition") - OTHER*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 0*[](#Material.DesignCode.OTHER "Link to this definition") * ROMANIAN\_STAS*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 4*[](#Material.DesignCode.ROMANIAN_STAS "Link to this definition") - SWISS\_SIA26X*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 7*[](#Material.DesignCode.SWISS_SIA26X "Link to this definition") * US*: [`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")** = 21*[](#Material.DesignCode.US "Link to this definition") - *property *name*: str*[](#Material.name "Link to this definition") Name of the material. ## MaterialInterface[​](/sdk/api/external/axisvm/.md#_MaterialInterface "Direct link to MaterialInterface") * *class *viktor.external.axisvm.MaterialInterface[](#MaterialInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.materials`](#Model.materials "viktor.external.axisvm.Model.materials") * add\_from\_catalog(*name*, *national\_design\_code*)[](#MaterialInterface.add_from_catalog "Link to this definition") Adds a material from the catalog. * Parameters: * **name** (`str`) – name of the material to be added (must exist in the corresponding national design code). * **national\_design\_code** ([`DesignCode`](#Material.DesignCode "viktor.external.axisvm.Material.DesignCode")) – national design code in which the material with given name resides. * Return type: [`Material`](#Material "viktor.external.axisvm.Material") - create\_concrete\_eurocode(*\**, *e\_x*, *e\_y=None*, *e\_z=None*, *nu\_x*, *nu\_y=None*, *nu\_z=None*, *alpha\_x=0.0*, *alpha\_y=None*, *alpha\_z=None*, *rho*, *f\_ck*, *gamma\_c*, *alpha\_cc*, *phi\_t=0.0*, *material\_code=None*, *name=None*)[](#MaterialInterface.create_concrete_eurocode "Link to this definition") Create a concrete material according to the Eurocode. * Parameters: * **e\_x** (`float`) – Young’s modulus of elasticity \[kN/m2] in local x-direction. * **e\_y** (`float`) – Young’s modulus of elasticity \[kN/m2] in local y-direction (default = e\_x). * **e\_z** (`float`) – Young’s modulus of elasticity \[kN/m2] in local z-direction (default = e\_x). * **nu\_x** (`float`) – Poisson’s ratio \[-] in local x-direction (0 <= nu <= 0.5). * **nu\_y** (`float`) – Poisson’s ratio \[-] in local y-direction (0 <= nu <= 0.5) (default = nu\_x). * **nu\_z** (`float`) – Poisson’s ratio \[-] in local z-direction (0 <= nu <= 0.5) (default = nu\_x). * **alpha\_x** (`float`) – thermal expansion coefficient \[1/C] in local x-direction (default = 0.0). * **alpha\_y** (`float`) – thermal expansion coefficient \[1/C] in local y-direction (default = alpha\_x). * **alpha\_z** (`float`) – thermal expansion coefficient \[1/C] in local z-direction (default = alpha\_x). * **rho** (`float`) – density \[kg/m3]. * **f\_ck** (`float`) – characteristic compressive cylinder strength \[kN/m2] at 28 days. * **gamma\_c** (`float`) – safety factor \[-]. * **alpha\_cc** (`float`) – concrete strength-reduction factor for sustained loading \[-]. * **phi\_t** (`float`) – creeping factor \[-] (default = 0.0). * **material\_code** (`str`) – material code name, as shown in the interface (default: auto). * **name** (`str`) – material name, as shown in the interface (default: auto). * Return type: [`Material`](#Material "viktor.external.axisvm.Material") ## Member[​](/sdk/api/external/axisvm/.md#_Member "Direct link to Member") * *class *viktor.external.axisvm.Member(*line*, *type\_*)[](#Member "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## Model[​](/sdk/api/external/axisvm/.md#_Model "Direct link to Model") * *class *viktor.external.axisvm.Model[](#Model "Link to this definition") Can be used to construct an AxisVM model, which can be used as input of [`AxisVMAnalysis`](#AxisVMAnalysis "viktor.external.axisvm.AxisVMAnalysis"). Objects are created/modified through the methods on their respective interface (see the properties below for all available interfaces). The following basic actions can be performed on all interfaces (example: node interface): * cast to list, indexing and slicing: > ``` > nodes = list(model.nodes) # List[Node] > node2 = model.nodes[1] # Node > nodes_2_3 = model.nodes[1:3] # List[Node] > ``` * iteration: > ``` > for node in model.nodes: > print(node.id) > ``` * length: > ``` > number_of_nodes = len(model.nodes) > ``` * containment check: > ``` > node_in_model = node in model.nodes # bool > ``` Example usage: ``` model = Model() material = model.materials.add_from_catalog('C12/15', AxisVMMaterial.DesignCode.EURO_CODE) cross_section = model.cross_sections.create_rectangular(0.01, 0.01) n1 = model.nodes.create(0, 0, 0) n2 = model.nodes.create(1, 0, 0) beam = model.lines.create(n1, n2).define_as_beam(material, cross_section) model.node_supports.create_relative_to_member(n1, stiffness_x=1e10, stiffness_y=1e10, stiffness_z=1e10, stiffness_xx=1e10, stiffness_yy=1e10, stiffness_zz=1e10) load_case = model.load_cases.create() model.loads.create_beam_self_weight(load_case, beam) model.results.nodal_displacements([n2]) ``` * *property *cross\_sections*: [CrossSectionInterface](#CrossSectionInterface "viktor.external.axisvm.CrossSectionInterface")*[](#Model.cross_sections "Link to this definition") Interface for creating cross-sections. - *property *domains*: [DomainInterface](#DomainInterface "viktor.external.axisvm.DomainInterface")*[](#Model.domains "Link to this definition") Interface for creating domains. * *property *line\_supports*: [LineSupportInterface](#LineSupportInterface "viktor.external.axisvm.LineSupportInterface")*[](#Model.line_supports "Link to this definition") Interface for creating line supports. - *property *lines*: [LineInterface](#LineInterface "viktor.external.axisvm.LineInterface")*[](#Model.lines "Link to this definition") Interface for creating lines, beams, etc. * *property *load\_cases*: [LoadCaseInterface](#LoadCaseInterface "viktor.external.axisvm.LoadCaseInterface")*[](#Model.load_cases "Link to this definition") Interface for creating load cases. - *property *load\_combinations*: [LoadCombinationInterface](#LoadCombinationInterface "viktor.external.axisvm.LoadCombinationInterface")*[](#Model.load_combinations "Link to this definition") Interface for creating load combinations. * *property *loads*: [LoadInterface](#LoadInterface "viktor.external.axisvm.LoadInterface")*[](#Model.loads "Link to this definition") Interface for creating loads. - *property *materials*: [MaterialInterface](#MaterialInterface "viktor.external.axisvm.MaterialInterface")*[](#Model.materials "Link to this definition") Interface for creating materials. * *property *node\_supports*: [NodeSupportInterface](#NodeSupportInterface "viktor.external.axisvm.NodeSupportInterface")*[](#Model.node_supports "Link to this definition") Interface for creating node supports. - *property *nodes*: [NodeInterface](#NodeInterface "viktor.external.axisvm.NodeInterface")*[](#Model.nodes "Link to this definition") Interface for creating nodes. * *property *references*: [ReferenceInterface](#ReferenceInterface "viktor.external.axisvm.ReferenceInterface")*[](#Model.references "Link to this definition") Interface for creating reference points, vectors, axes, planes and angles. - *property *results*: [ResultInterface](#ResultInterface "viktor.external.axisvm.ResultInterface")*[](#Model.results "Link to this definition") Interface for requesting results from the worker (only requested results will be returned). * *property *sections*: [SectionInterface](#SectionInterface "viktor.external.axisvm.SectionInterface")*[](#Model.sections "Link to this definition") Interface for creating sections, on which results can be obtained. ## Node[​](/sdk/api/external/axisvm/.md#_Node "Direct link to Node") * *class *viktor.external.axisvm.Node(*id\_*, *x*, *y*, *z*)[](#Node "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *x*: float*[](#Node.x "Link to this definition") X-coordinate. - *property *y*: float*[](#Node.y "Link to this definition") Y-coordinate. * *property *z*: float*[](#Node.z "Link to this definition") Z-coordinate. ## NodeInterface[​](/sdk/api/external/axisvm/.md#_NodeInterface "Direct link to NodeInterface") * *class *viktor.external.axisvm.NodeInterface[](#NodeInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.nodes`](#Model.nodes "viktor.external.axisvm.Model.nodes") * create(*x*, *y*, *z*)[](#NodeInterface.create "Link to this definition") Create a node at the given position and with given degree-of-freedom. * Parameters: * **x** (`float`) – x-position \[m]. * **y** (`float`) – y-position \[m]. * **z** (`float`) – z-position \[m]. * Return type: [`Node`](#Node "viktor.external.axisvm.Node") ## NodeSupport[​](/sdk/api/external/axisvm/.md#_NodeSupport "Direct link to NodeSupport") * *class *viktor.external.axisvm.NodeSupport(*id\_*)[](#NodeSupport "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## NodeSupportInterface[​](/sdk/api/external/axisvm/.md#_NodeSupportInterface "Direct link to NodeSupportInterface") * *class *viktor.external.axisvm.NodeSupportInterface(*lines*)[](#NodeSupportInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.node_supports`](#Model.node_supports "viktor.external.axisvm.Model.node_supports") * create\_relative\_to\_member(*node*, *\**, *stiffness\_x=0.0*, *stiffness\_y=0.0*, *stiffness\_z=0.0*, *stiffness\_xx=0.0*, *stiffness\_yy=0.0*, *stiffness\_zz=0.0*, *resistance\_x=0.0*, *resistance\_y=0.0*, *resistance\_z=0.0*, *resistance\_xx=0.0*, *resistance\_yy=0.0*, *resistance\_zz=0.0*, *non\_linearity\_x=NonLinearity.LINEAR*, *non\_linearity\_y=NonLinearity.LINEAR*, *non\_linearity\_z=NonLinearity.LINEAR*, *non\_linearity\_xx=NonLinearity.LINEAR*, *non\_linearity\_yy=NonLinearity.LINEAR*, *non\_linearity\_zz=NonLinearity.LINEAR*)[](#NodeSupportInterface.create_relative_to_member "Link to this definition") Create a nodal support, relative to the member’s local coordinate system. * Parameters: * **node** ([`Node`](#Node "viktor.external.axisvm.Node")) – node to create the support on. Must be an end-point of a member of type beam or rib. * **stiffness\_x** (`float`) – translational stiffness \[kN/m] in local x-direction (default = 0.0). * **stiffness\_y** (`float`) – translational stiffness \[kN/m] in local y-direction (default = 0.0). * **stiffness\_z** (`float`) – translational stiffness \[kN/m] in local z-direction (default = 0.0). * **stiffness\_xx** (`float`) – rotational stiffness \[kNm/rad] around the local x-axis (default = 0.0). * **stiffness\_yy** (`float`) – rotational stiffness \[kNm/rad] around the local y-axis (default = 0.0). * **stiffness\_zz** (`float`) – rotational stiffness \[kNm/rad] around the local z-axis (default = 0.0). * **resistance\_x** (`float`) – translational resistance \[kN/m] in local x-direction (default = 0.0). * **resistance\_y** (`float`) – translational resistance \[kN/m] in local y-direction (default = 0.0). * **resistance\_z** (`float`) – translational resistance \[kN/m] in local z-direction (default = 0.0). * **resistance\_xx** (`float`) – rotational resistance \[kNm/m] around the local x-axis (default = 0.0). * **resistance\_yy** (`float`) – rotational resistance \[kNm/m] around the local y-axis (default = 0.0). * **resistance\_zz** (`float`) – rotational resistance \[kNm/m] around the local z-axis (default = 0.0). * **non\_linearity\_x** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local x-direction (default: linear). * **non\_linearity\_y** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local y-direction (default: linear). * **non\_linearity\_z** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – translational non-linear behaviour in local z-direction (default: linear). * **non\_linearity\_xx** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local x-axis (default: linear). * **non\_linearity\_yy** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local y-axis (default: linear). * **non\_linearity\_zz** ([`NonLinearity`](#LineSupport.NonLinearity "viktor.external.axisvm.LineSupport.NonLinearity")) – rotational non-linear behaviour around the local z-axis (default: linear). * Return type: [`NodeSupport`](#NodeSupport "viktor.external.axisvm.NodeSupport") ## Object[​](/sdk/api/external/axisvm/.md#_Object "Direct link to Object") * *class *viktor.external.axisvm.Object(*id\_*)[](#Object "Link to this definition") Bases: `ABC` Abstract base class of all AxisVM objects. Do not use this \_\_init\_\_ directly. * *property *id*: int*[](#Object.id "Link to this definition") Object id. ## Reference[​](/sdk/api/external/axisvm/.md#_Reference "Direct link to Reference") * *class *viktor.external.axisvm.Reference(*id\_*)[](#Reference "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object"), `ABC` Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") ## ReferenceInterface[​](/sdk/api/external/axisvm/.md#_ReferenceInterface "Direct link to ReferenceInterface") * *class *viktor.external.axisvm.ReferenceInterface[](#ReferenceInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.references`](#Model.references "viktor.external.axisvm.Model.references") * create\_angle(*angle*)[](#ReferenceInterface.create_angle "Link to this definition") Create a reference angle. * Parameters: **angle** (`float`) – angle \[rad]. * Return type: [`Reference`](#Reference "viktor.external.axisvm.Reference") - create\_axis(*point\_1*, *point\_2*)[](#ReferenceInterface.create_axis "Link to this definition") Create a reference axis. * Parameters: * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the start point. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the end point. * Return type: [`Reference`](#Reference "viktor.external.axisvm.Reference") * create\_plane(*point\_1*, *point\_2*, *point\_3*)[](#ReferenceInterface.create_plane "Link to this definition") Create a reference plane. * Parameters: * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 1. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 2. * **point\_3** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of point 3. * Return type: [`Reference`](#Reference "viktor.external.axisvm.Reference") - create\_point(*x*, *y*, *z*)[](#ReferenceInterface.create_point "Link to this definition") Create a reference point. * Parameters: * **x** (`float`) – x-position \[m]. * **y** (`float`) – y-position \[m]. * **z** (`float`) – z-position \[m]. * Return type: [`Reference`](#Reference "viktor.external.axisvm.Reference") * create\_vector(*point\_1*, *point\_2*)[](#ReferenceInterface.create_vector "Link to this definition") Create a reference vector. * Parameters: * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the start point. * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the end point. * Return type: [`Reference`](#Reference "viktor.external.axisvm.Reference") ## ResultInterface[​](/sdk/api/external/axisvm/.md#_ResultInterface "Direct link to ResultInterface") * *class *viktor.external.axisvm.ResultInterface(*nodes*, *node\_supports*, *lines*, *sections*)[](#ResultInterface "Link to this definition") * line\_forces(*members=None*, *\**, *by\_load\_case=True*)[](#ResultInterface.line_forces "Link to this definition") Request line forces for all load cases or combinations. * Parameters: * **members** (`List`\[[`Member`](#Member "viktor.external.axisvm.Member")]) – members to request the results for, or None for all members (default: all members). * **by\_load\_case** (`bool`) – True to get the result on all load cases; False to get results on all load combinations. * Return type: `None` - nodal\_displacements(*nodes=None*, *\**, *by\_load\_case=True*)[](#ResultInterface.nodal_displacements "Link to this definition") Request nodal displacements for all load cases or combinations. * Parameters: * **nodes** (`List`\[[`Node`](#Node "viktor.external.axisvm.Node")]) – nodes to request the results for, or None for all nodes (default: all nodes). * **by\_load\_case** (`bool`) – True to get result on all load cases; False to get results on all load combinations. * Return type: `None` * nodal\_support\_forces(*node\_supports=None*, *\**, *by\_load\_case=True*)[](#ResultInterface.nodal_support_forces "Link to this definition") Request nodal support forces for all load cases or combinations. * Parameters: * **node\_supports** (`List`\[[`NodeSupport`](#NodeSupport "viktor.external.axisvm.NodeSupport")]) – node supports to request the results for, or None for all node supports (default: all node supports). * **by\_load\_case** (`bool`) – True to get result on all load cases; False to get results on all load combinations. * Return type: `None` - section\_surface\_forces(*sections*, *cases*, *chain\_index=1*)[](#ResultInterface.section_surface_forces "Link to this definition") Request section chain’s surface forces for given load combinations. * Parameters: * **sections** (`List`\[[`Section`](#Section "viktor.external.axisvm.Section")]) – sections to request the results for, or None for all sections (default: all sections). * **cases** (`List`\[[`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination")]) – list of load combinations to request the results for. * **chain\_index** (`int`) – index of the segment chain to request the results for (default: 1). * Return type: `None` * section\_surface\_stresses(*sections*, *cases*, *chain\_index=1*)[](#ResultInterface.section_surface_stresses "Link to this definition") Request section chain’s surface stresses for given load combinations. * Parameters: * **sections** (`List`\[[`Section`](#Section "viktor.external.axisvm.Section")]) – sections to request the results for, or None for all sections (default: all sections). * **cases** (`List`\[[`LoadCombination`](#LoadCombination "viktor.external.axisvm.LoadCombination")]) – list of load combinations to request the results for. * **chain\_index** (`int`) – index of the segment chain to request the results for (default: 1). * Return type: `None` ## Section[​](/sdk/api/external/axisvm/.md#_Section "Direct link to Section") * *class *viktor.external.axisvm.Section(*id\_*, *interface*, *name*)[](#Section "Link to this definition") Bases: [`Object`](#Object "viktor.external.axisvm.Object") Do not use this \_\_init\_\_ directly, but create the object from [`Model`](#Model "viktor.external.axisvm.Model") * *property *name*: str*[](#Section.name "Link to this definition") Name of the section. ## SectionInterface[​](/sdk/api/external/axisvm/.md#_SectionInterface "Direct link to SectionInterface") * *class *viktor.external.axisvm.SectionInterface[](#SectionInterface "Link to this definition") Bases: `_Interface` Do not use this \_\_init\_\_ directly, but use [`Model.sections`](#Model.sections "viktor.external.axisvm.Model.sections") * create(*start\_point*, *end\_point*, *normal\_vector*, *\**, *name=None*)[](#SectionInterface.create "Link to this definition") Create a section (segment) from coordinates, to obtain results from. * Parameters: * **start\_point** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the section’s start point. * **end\_point** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) position \[m] of the section’s end point. * **normal\_vector** (`Tuple`\[`float`, `float`, `float`]) – (x, y, z) components \[m] of the section plane’s normal vector. * **name** (`str`) – name of the section (default: auto). * Return type: [`Section`](#Section "viktor.external.axisvm.Section") --- # viktor.external.dfoundations ## BearingPilesCalculationOptions[​](/sdk/api/external/dfoundations/.md#_BearingPilesCalculationOptions "Direct link to BearingPilesCalculationOptions") * *class *viktor.external.dfoundations.BearingPilesCalculationOptions(*calculation\_type*, *rigid*, *max\_allowed\_settlement\_str\_geo=150*, *max\_allowed\_settlement\_sls=150*, *max\_allowed\_relative\_rotation\_str\_geo=100*, *max\_allowed\_relative\_rotation\_sls=300*, *\**, *xi3=None*, *xi4=None*, *gamma\_b=None*, *gamma\_s=None*, *gamma\_fnk=None*, *area=None*, *e\_ea\_gem=None*, *write\_intermediate\_results=False*, *use\_pile\_group=True*, *overrule\_excavation=False*, *suppress\_qciii\_reduction=False*, *use\_almere\_rules=False*, *use\_extra\_almere\_rules=False*, *trajectory\_begin\_end\_interval=None*, *net\_bearing\_capacity=None*, *cpt\_test\_level=None*)[](#BearingPilesCalculationOptions "Link to this definition") Bases: `_CalculationOptions` * Parameters: * **calculation\_type** ([`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")) * **rigid** (`bool`) – True for rigid, False for non-rigid * **max\_allowed\_settlement\_str\_geo** (`int`) – \[mm] * **max\_allowed\_relative\_rotation\_str\_geo** (`int`) – 1 : \[-] * **max\_allowed\_settlement\_sls** (`int`) – \[mm] * **max\_allowed\_relative\_rotation\_sls** (`int`) – 1 : \[-] * **xi3** (`float`) – ξ\_3 \[-] * **xi4** (`float`) – ξ\_4 \[-] * **gamma\_b** (`float`) – γ\_b \[-] * **gamma\_s** (`float`) – γ\_s \[-] * **gamma\_fnk** (`float`) – γ\_f;nk \[-] * **area** (`float`) – \[m²] * **e\_ea\_gem** (`float`) – E\_ea;gem \[kN/m2] * **write\_intermediate\_results** (`bool`) * **use\_pile\_group** (`bool`) * **overrule\_excavation** (`bool`) * **suppress\_qciii\_reduction** (`bool`) * **use\_almere\_rules** (`bool`) * **use\_extra\_almere\_rules** (`bool`) * **trajectory\_begin\_end\_interval** (`Tuple`\[`float`, `float`, `float`]) – tuple(\[m], \[m], \[m]) * **net\_bearing\_capacity** (`int`) – \[kN] * **cpt\_test\_level** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘calculation\_type’ is DESIGN\_CALCULATION or INDICATION\_BEARING\_CAPACITY or PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and trajectory\_begin\_end\_interval’ is not set. * if the number of iterations > 151, based on the provided ‘trajectory\_begin\_end\_interval’. * if ‘calculation\_type’ is PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘net\_bearing\_capacity’ is not set. * if ‘calculation\_type’ is DESIGN\_CALCULATION or COMPLETE\_CALCULATION and ‘cpt\_test\_level’ is not set. ## BearingPilesModel[​](/sdk/api/external/dfoundations/.md#_BearingPilesModel "Direct link to BearingPilesModel") * *class *viktor.external.dfoundations.BearingPilesModel(*construction\_sequence*, *calculation\_options*, *excavation\_level*, *reduction\_cone\_resistance=None*, *\**, *create\_default\_materials=True*)[](#BearingPilesModel "Link to this definition") Bases: `_Model` Create a Bearing Piles (EC7-NL) model. * Parameters: * **construction\_sequence** ([`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")) * **calculation\_options** ([`BearingPilesCalculationOptions`](#BearingPilesCalculationOptions "viktor.external.dfoundations.BearingPilesCalculationOptions")) * **excavation\_level** (`float`) – \[m] * **reduction\_cone\_resistance** (`float`) – Distance edge pile to excavation boundary \[m] to implement ‘Begemann’. ‘None’ to implement ‘Safe (NEN)’. * **create\_default\_materials** (`bool`) – whether to start with the default D-Foundations materials. The default materials are: > * BClay, clean, moderate > > * BClay, clean, modstiff > > * BClay, clean, stiff > > * BClay, clean, weak > > * BClay, sl san, moderate > > * BClay, sl san, modstiff > > * BClay, sl san, stiff > > * BClay, sl san, weak > > * BGravel, clean, moderate > > * BGravel, clean, stiff > > * BGravel, ve sil, moderate > > * BGravel, ve sil, stiff > > * BLoam, clean, moderate > > * BLoam, clean, modstiff > > * BLoam, clean, stiff > > * BLoam, clean, weak > > * BLoam, sl san, moderate > > * BLoam, sl san, modstiff > > * BLoam, sl san, stiff > > * BLoam, sl san, weak > > * BPeat, sl san, moderate > > * BPeat, sl san, stiff > > * BPeat, sl san, weak > > * BSand, clean, loose > > * BSand, clean, moderate > > * BSand, clean, stiff > > * BSand, ve sil, loose > > * BSand, ve sil, moderate > > * BSand, ve sil, stiff > > * Clay, clean, moderate > > * Clay, clean, stiff > > * Clay, clean, weak > > * Clay, organ, moderate > > * Clay, organ, weak > > * Clay, sl san, moderate > > * Clay, sl san, stiff > > * Clay, sl san, weak > > * Clay, ve san, stiff > > * Gravel, sl sil, loose > > * Gravel, sl sil, moderate > > * Gravel, sl sil, stiff > > * Gravel, ve sil, loose > > * Gravel, ve sil, moderate > > * Gravel, ve sil, stiff > > * Loam, sl san, moderate > > * Loam, sl san, stiff > > * Loam, sl san, weak > > * Loam, ve san, stiff > > * Peat, mod pl, moderate > > * Peat, not pl, weak > > * Sand, clean, loose > > * Sand, clean, moderate > > * Sand, clean, stiff > > * Sand, sl sil, moderate > > * Sand, ve sil, loose * materials[](#BearingPilesModel.materials "Link to this definition") Lists all materials currently in de model. - profiles[](#BearingPilesModel.profiles "Link to this definition") Lists all profiles currently in de model. * pile\_types[](#BearingPilesModel.pile_types "Link to this definition") Lists all pile types currently in de model. - piles[](#BearingPilesModel.piles "Link to this definition") Lists all piles currently in de model. * generate\_input\_file(*metadata=None*, *\**, *as\_file=False*)[](#BearingPilesModel.generate_input_file "Link to this definition") Generate a D-Foundations input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **metadata** ([`Metadata`](#Metadata "viktor.external.dfoundations.Metadata")) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **as\_file** (`bool`) – return as BytesIO (default) or File * Return type: `Union`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), `BytesIO`] - create\_material(*name*, *soil\_type*, *gamma\_unsat*, *gamma\_sat*, *friction\_angle*, *diameter\_d50=0.2*, *color=None*)[](#BearingPilesModel.create_material "Link to this definition") Create a material with the given name and properties. * Parameters: * **name** (`str`) – name of the material to create (max. 25 characters) * **soil\_type** ([`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")) – \[-] * **gamma\_unsat** (`float`) – gamma-unsaturated, dry \[kN/m³] * **gamma\_sat** (`float`) – gamma-saturated, wet \[kN/m³] * **friction\_angle** (`float`) – phi \[degree] * **diameter\_d50** (`float`) – median \[mm] * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – color for visualization in deltares software (None for default color ‘white’) * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type: `None` * create\_pile(*name*, *x*, *y*, *pile\_head\_level*, *surcharge*, *limit\_state\_str\_geo*, *serviceability\_limit\_state*)[](#BearingPilesModel.create_pile "Link to this definition") Create a pile with given properties. * Parameters: * **name** (`str`) – name of the pile. Must be unique. Max. 10 characters. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **pile\_head\_level** (`float`) – \[m R.L.] * **surcharge** (`float`) – \[kN/m2] * **limit\_state\_str\_geo** (`float`) – Limit state STR/GEO \[kN] * **serviceability\_limit\_state** (`float`) – \[kN] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if pile with given name already exists. * if name exceeds the max. number of characters (10). * Return type: `None` - create\_pile\_type(*name*, *shape*, *pile\_type*, *slip\_layer*, *type\_sand\_gravel=None*, *type\_clay\_loam\_peat=None*, *type\_p=None*, *load\_settlement\_curve=None*, *material=None*, *factor\_sand\_gravel=None*, *factor\_clay\_loam\_peat=None*, *factor\_pile\_class=None*, *e\_modulus=None*, *slip\_layer\_adhesion=None*, *\**, *use\_pre\_2016=False*, *as\_prefab=False*, *qciii\_reduction=None*, *overrule\_tip\_section\_factor=None*, *overrule\_tip\_shape\_factor=None*)[](#BearingPilesModel.create_pile_type "Link to this definition") Create a pile type with the given properties. * Parameters: * **name** (`str`) – name of the pile type. Must be unique. Max. 10 characters. * **shape** (`_PileShape`) – pile type shape class instance. See below for possible shapes. * **pile\_type** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – predefined/user-defined pile type. Only certain types are valid in combination with the provided ‘shape’. For more information on valid combinations, please refer to the D-Foundations software. * **slip\_layer** ([`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")) * **type\_sand\_gravel** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – pile type for α\_s sand/gravel * **type\_clay\_loam\_peat** ([`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")) – pile type for α\_s clay/loam/peat * **type\_p** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – pile type for α\_p * **load\_settlement\_curve** ([`PileLoadSettlementCurve`](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")) * **material** ([`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")) * **factor\_sand\_gravel** (`float`) – α\_s \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **factor\_clay\_loam\_peat** (`float`) – α\_s \[-]. Only required if ‘type\_clay\_loam\_peat’ is of type user-defined. * **factor\_pile\_class** (`float`) – α\_p \[-]. Only required if ‘type\_p’ is of type user-defined. * **e\_modulus** (`float`) – Young’s modulus \[kN/m2]. Only required if ‘material’ is of type user-defined. * **slip\_layer\_adhesion** (`float`) – Representative cohesion \[kN/m2]. Only required if ‘slip\_layer’ is of type user-defined. * **use\_pre\_2016** (`bool`) * **as\_prefab** (`bool`) * **qciii\_reduction** (`float`) – \[%] * **overrule\_tip\_section\_factor** (`float`) – Pile top cross section factor (s) \[-] * **overrule\_tip\_shape\_factor** (`float`) – Pile tip shape factor (β) \[-] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘pile\_type’ is of type user-defined and ‘type\_sand\_gravel’ is not set. * if ‘pile\_type’ is of type user-defined and ‘type\_clay\_loam\_peat’ is not set. * if ‘pile\_type’ is of type user-defined and ‘material’ is not set. * if ‘pile\_type’ is of type user-defined and ‘type\_p’ is not set. * if ‘pile\_type’ is of type user-defined and ‘load\_settlement\_curve’ is not set. * if ‘type\_sand\_gravel’ is of type user-defined and ‘factor\_sand\_gravel’ is not set. * if ‘type\_clay\_loam\_peat’ is of type user-defined and ‘factor\_clay\_loam\_peat’ is not set. * if ‘material’ is of type user-defined and ‘e\_modulus’ is not set. * if ‘type\_p’ is of type user-defined and ‘factor\_pile\_class’ is not set. * if ‘slip\_layer’ is of type user-defined and ‘slip\_layer\_adhesion’ is not set. * if an invalid ‘shape’ is provided. * if a ‘pile\_type’ is provided that is invalid in combination with the given ‘shape’. * if one of the types PileType.USER\_DEFINED\_VIBRATING or PileType.USER\_DEFINED\_LOW\_VIBRATING is selected for ‘type\_sand\_gravel’ or ‘type\_p’ (no valid options). * if a pile type with the give name already exists. * if ‘factor\_sand\_gravel’, ‘factor\_clay\_loam\_peat’ or ‘factor\_pile\_class’ is outside valid range 0-9. * if ‘overrule\_tip\_section\_factor’ or ‘overrule\_tip\_shape\_factor’ is outside valid range 0-10. * Return type: `None` Possible shapes are: > * RectPile > > * RectEnlPile > > * SectionPile > > * RoundPile > > * TaperPile > > * HollowPile > > * HollowOpenPile > > * RoundEnlPile > > * LostTipPile > > * DrivenBasePile > > * HShapedPile * create\_profile(*name*, *layers*, *x*, *y*, *measurements*, *phreatic\_level*, *pile\_tip\_level*, *overconsolidation\_ratio*, *top\_positive\_skin\_friction*, *bottom\_negative\_skin\_friction*, *expected\_ground\_level\_settlement*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[](#BearingPilesModel.create_profile "Link to this definition") Create a profile manually. * Parameters: * **name** (`str`) – name of the profile (must be unique). * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **measurements** (`List`\[`Tuple`\[`float`, `float`]]) – list of measurement data (level \[m], qc-value \[MPa]). * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **overconsolidation\_ratio** (`float`) – overconsolidation ratio of bearing zone \[-] * **top\_positive\_skin\_friction** (`float`) – top of positive skin friction \[m] * **bottom\_negative\_skin\_friction** (`float`) – bottom of negative skin friction \[m] * **expected\_ground\_level\_settlement** (`float`) – \[m] * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) * **min\_layer\_thickness** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * Return type: `None` - import\_profile(*cpt*, *layers*, *x*, *y*, *phreatic\_level*, *pile\_tip\_level*, *overconsolidation\_ratio*, *top\_positive\_skin\_friction*, *bottom\_negative\_skin\_friction*, *expected\_ground\_level\_settlement*, *name=None*, *manual\_ground\_level=None*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[](#BearingPilesModel.import_profile "Link to this definition") Create a profile by importing a CPT-file. * Parameters: * **cpt** ([`GEFData`](/sdk/api/geo/.md#GEFData "viktor.geo.GEFData")) – CPT file to import. * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **overconsolidation\_ratio** (`float`) – overconsolidation ratio of bearing zone \[-] * **top\_positive\_skin\_friction** (`float`) – top of positive skin friction \[m] * **bottom\_negative\_skin\_friction** (`float`) – bottom of negative skin friction \[m] * **expected\_ground\_level\_settlement** (`float`) – \[m] * **name** (`str`) – name of the profile (must be unique). None for default (name of the cpt). * **manual\_ground\_level** (`float`) – set to override the ground level \[m] from the cpt. * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) * **min\_layer\_thickness** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * if ground level could not be read from cpt file. * Return type: `None` ## CPTRule[​](/sdk/api/external/dfoundations/.md#_CPTRule "Direct link to CPTRule") * *class *viktor.external.dfoundations.CPTRule(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CPTRule "Link to this definition") Bases: `Enum` * CUR*: [`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")** = 1*[](#CPTRule.CUR "Link to this definition") - NEN*: [`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")** = 0*[](#CPTRule.NEN "Link to this definition") * NEN\_STRESS*: [`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")** = 0*[](#CPTRule.NEN_STRESS "Link to this definition") - QC\_ONLY*: [`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")** = 3*[](#CPTRule.QC_ONLY "Link to this definition") * TYPE\_3*: [`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")** = 2*[](#CPTRule.TYPE_3 "Link to this definition") ## CalculationType[​](/sdk/api/external/dfoundations/.md#_CalculationType "Direct link to CalculationType") * *class *viktor.external.dfoundations.CalculationType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CalculationType "Link to this definition") Bases: `Enum` * BEARING\_CAPACITY\_AT\_FIXED\_PILE\_TIP\_LEVEL*: [`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")** = 3*[](#CalculationType.BEARING_CAPACITY_AT_FIXED_PILE_TIP_LEVEL "Link to this definition") - COMPLETE\_CALCULATION*: [`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")** = 1*[](#CalculationType.COMPLETE_CALCULATION "Link to this definition") * DESIGN\_CALCULATION*: [`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")** = 0*[](#CalculationType.DESIGN_CALCULATION "Link to this definition") - INDICATION\_BEARING\_CAPACITY*: [`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")** = 2*[](#CalculationType.INDICATION_BEARING_CAPACITY "Link to this definition") * PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY*: [`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")** = 4*[](#CalculationType.PILE_TIP_LEVEL_AND_NET_BEARING_CAPACITY "Link to this definition") ## ConstructionSequence[​](/sdk/api/external/dfoundations/.md#_ConstructionSequence "Direct link to ConstructionSequence") * *class *viktor.external.dfoundations.ConstructionSequence(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConstructionSequence "Link to this definition") Bases: `Enum` * CPT\_EXCAVATION\_INSTALL*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 1*[](#ConstructionSequence.CPT_EXCAVATION_INSTALL "Link to this definition") - CPT\_INSTALL\_EXCAVATION*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 6*[](#ConstructionSequence.CPT_INSTALL_EXCAVATION "Link to this definition") * EXCAVATION\_CPT\_BOTH\_BEFORE\_AND\_AFTER\_INSTALL*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 7*[](#ConstructionSequence.EXCAVATION_CPT_BOTH_BEFORE_AND_AFTER_INSTALL "Link to this definition") - EXCAVATION\_CPT\_INSTALL*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 3*[](#ConstructionSequence.EXCAVATION_CPT_INSTALL "Link to this definition") * EXCAVATION\_INSTALL\_CPT*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 4*[](#ConstructionSequence.EXCAVATION_INSTALL_CPT "Link to this definition") - INSTALL\_CPT\_EXCAVATION*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 2*[](#ConstructionSequence.INSTALL_CPT_EXCAVATION "Link to this definition") * INSTALL\_EXCAVATION\_CPT*: [`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")** = 5*[](#ConstructionSequence.INSTALL_EXCAVATION_CPT "Link to this definition") ## DFoundationsAnalysis[​](/sdk/api/external/dfoundations/.md#_DFoundationsAnalysis "Direct link to DFoundationsAnalysis") * *class *viktor.external.dfoundations.DFoundationsAnalysis(*input\_file*)[](#DFoundationsAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DFoundationsAnalysis can be used to perform an analysis using D-Foundations on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DFoundationsAnalysis.get_output_file "viktor.external.dfoundations.DFoundationsAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Note: the input for the BytesIO object should be of type bytes. You can convert a string to bytes by calling the method `encode()`. Default encoding is ‘utf-8’. Usage: ``` input_file = BytesIO("dfoundations input file body".encode('utf-8')) dfoundations_analysis = DFoundationsAnalysis(input_file=input_file) dfoundations_analysis.execute(timeout=10) output_file = dfoundations_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – .foi input file. - get\_output\_file(*extension='.fod'*, *\**, *as\_file=False*)[](#DFoundationsAnalysis.get_output_file "Link to this definition") * Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DFoundationsAnalysis.get_output_file "viktor.external.dfoundations.DFoundationsAnalysis.get_output_file") afterwards. - Parameters: * **extension** (`str`) – extension of the file you want to return; one of: ‘.fos’, ‘.fod’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – return as BytesIO (default) or File - Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] - Returns: * File, if as\_file = True * BytesIO, if as\_file = False (default) ## DrivenBasePile[​](/sdk/api/external/dfoundations/.md#_DrivenBasePile "Direct link to DrivenBasePile") * *class *viktor.external.dfoundations.DrivenBasePile(*base\_diameter*, *pile\_diameter*, *base\_height*)[](#DrivenBasePile "Link to this definition") Bases: [`RoundEnlPile`](#RoundEnlPile "viktor.external.dfoundations.RoundEnlPile") Round pile with in situ formed base. Round pile with enlarged base. * Parameters: * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * **base\_height** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## HShapedPile[​](/sdk/api/external/dfoundations/.md#_HShapedPile "Direct link to HShapedPile") * *class *viktor.external.dfoundations.HShapedPile(*height*, *width*, *thickness\_web*, *thickness\_flange*)[](#HShapedPile "Link to this definition") Bases: `_PileShape` H-shaped profile. * Parameters: * **height** (`float`) – \[m] * **width** (`float`) – \[m] * **thickness\_web** (`float`) – \[mm]. Must be smaller than ‘width’. * **thickness\_flange** (`float`) – \[mm]. Must be smaller than half of ‘height’. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘thickness\_web’ is not smaller than ‘width’. * if ‘thickness\_flange’ is not smaller than half of ‘height’. ## HollowOpenPile[​](/sdk/api/external/dfoundations/.md#_HollowOpenPile "Direct link to HollowOpenPile") * *class *viktor.external.dfoundations.HollowOpenPile(*external\_diameter*, *wall\_thickness*)[](#HollowOpenPile "Link to this definition") Bases: `_PileShape` Round open-ended hollow pile. * Parameters: * **external\_diameter** (`float`) – \[m] * **wall\_thickness** (`float`) – \[mm]. Must be smaller than half of ‘external\_diameter’. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘wall\_thickness’ is not smaller than half of ‘external\_diameter’. - *property *internal\_diameter*: float*[](#HollowOpenPile.internal_diameter "Link to this definition") ## HollowPile[​](/sdk/api/external/dfoundations/.md#_HollowPile "Direct link to HollowPile") * *class *viktor.external.dfoundations.HollowPile(*external\_diameter*, *wall\_thickness*)[](#HollowPile "Link to this definition") Bases: `_PileShape` Round hollow pile with closed base. * Parameters: * **external\_diameter** (`float`) – \[m] * **wall\_thickness** (`float`) – \[mm]. Must be smaller than half of ‘external\_diameter’. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘wall\_thickness’ is not smaller than half of ‘external\_diameter’. - *property *internal\_diameter*: float*[](#HollowPile.internal_diameter "Link to this definition") ## LostTipPile[​](/sdk/api/external/dfoundations/.md#_LostTipPile "Direct link to LostTipPile") * *class *viktor.external.dfoundations.LostTipPile(*base\_diameter*, *pile\_diameter*)[](#LostTipPile "Link to this definition") Bases: `_PileShape` Round pile with lost tip. * Parameters: * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## MaxConeResistType[​](/sdk/api/external/dfoundations/.md#_MaxConeResistType "Direct link to MaxConeResistType") * *class *viktor.external.dfoundations.MaxConeResistType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#MaxConeResistType "Link to this definition") Bases: `Enum` * MANUAL*: [`MaxConeResistType`](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")** = 1*[](#MaxConeResistType.MANUAL "Link to this definition") - STANDARD*: [`MaxConeResistType`](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")** = 0*[](#MaxConeResistType.STANDARD "Link to this definition") ## Metadata[​](/sdk/api/external/dfoundations/.md#_Metadata "Direct link to Metadata") * *class *viktor.external.dfoundations.Metadata(*file\_name='-'*, *company='-'*, *title\_1='-'*, *title\_2='-'*, *geotechnical\_consultant=''*, *design\_engineer=''*, *principal=''*, *project\_id=''*, *location=''*, *current\_date=False*, *current\_time=False*)[](#Metadata "Link to this definition") Data container for metadata to be added to the D-Foundations input file. * Parameters: * **file\_name** (`str`) – file name, as shown in the input file header * **company** (`str`) – company name, as shown in the input file header * **title\_1** (`str`) * **title\_2** (`str`) * **geotechnical\_consultant** (`str`) * **design\_engineer** (`str`) * **principal** (`str`) * **project\_id** (`str`) * **location** (`str`) * **current\_date** (`bool`) – date, as shown in the input file header * **current\_time** (`bool`) – time, as shown in the input file header ## OutputFileParser[​](/sdk/api/external/dfoundations/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.dfoundations.OutputFileParser(*fod\_file*)[](#OutputFileParser "Link to this definition") Helper class to extract results from a D-Foundations output file (.fod). Currently the following versions are (partly) supported: * * v17: * Tension Piles model * Bearing Piles model - Preliminary Design (calculation options only) * * v19: * Tension Piles model * Bearing Piles model - Verification Example usage: ``` parser = OutputFileParser(fod_file) calculation_parameters = parser.calculation_parameters results = parser.results(False) ``` * Parameters: **fod\_file** (`StringIO`) – D-Foundations output file (.fod) - *abstract property *calculation\_parameters*: Dict\[str, float | bool]*[](#OutputFileParser.calculation_parameters "Link to this definition") Calculation parameters. * *property *raw\_results*: str*[](#OutputFileParser.raw_results "Link to this definition") - *abstract *results(*as\_pandas=True*)[](#OutputFileParser.results "Link to this definition") All result data. * Parameters: **as\_pandas** (`bool`) – True to return the results as a dictionary of pandas DataFrame objects. False for dicts. * Return type: `Dict`\[`str`, `Union`\[`DataFrame`, `Dict`\[`str`, `Any`]]] ## PileLoadSettlementCurve[​](/sdk/api/external/dfoundations/.md#_PileLoadSettlementCurve "Direct link to PileLoadSettlementCurve") * *class *viktor.external.dfoundations.PileLoadSettlementCurve(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PileLoadSettlementCurve "Link to this definition") Bases: `Enum` * ONE*: [`PileLoadSettlementCurve`](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 0*[](#PileLoadSettlementCurve.ONE "Link to this definition") - THREE*: [`PileLoadSettlementCurve`](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 2*[](#PileLoadSettlementCurve.THREE "Link to this definition") * TWO*: [`PileLoadSettlementCurve`](#PileLoadSettlementCurve "viktor.external.dfoundations.PileLoadSettlementCurve")** = 1*[](#PileLoadSettlementCurve.TWO "Link to this definition") ## PileMaterial[​](/sdk/api/external/dfoundations/.md#_PileMaterial "Direct link to PileMaterial") * *class *viktor.external.dfoundations.PileMaterial(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PileMaterial "Link to this definition") Bases: `Enum` * CONCRETE*: [`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 0*[](#PileMaterial.CONCRETE "Link to this definition") - STEEL*: [`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 1*[](#PileMaterial.STEEL "Link to this definition") * TIMBER*: [`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 2*[](#PileMaterial.TIMBER "Link to this definition") - USER\_DEFINED*: [`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 3*[](#PileMaterial.USER_DEFINED "Link to this definition") * WOOD*: [`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")** = 2*[](#PileMaterial.WOOD "Link to this definition") ## PileSlipLayer[​](/sdk/api/external/dfoundations/.md#_PileSlipLayer "Direct link to PileSlipLayer") * *class *viktor.external.dfoundations.PileSlipLayer(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PileSlipLayer "Link to this definition") Bases: `Enum` * BENTONITE*: [`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 2*[](#PileSlipLayer.BENTONITE "Link to this definition") - BITUMEN*: [`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 3*[](#PileSlipLayer.BITUMEN "Link to this definition") * NONE*: [`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 0*[](#PileSlipLayer.NONE "Link to this definition") - SYNTHETIC*: [`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 1*[](#PileSlipLayer.SYNTHETIC "Link to this definition") * USER\_DEFINED*: [`PileSlipLayer`](#PileSlipLayer "viktor.external.dfoundations.PileSlipLayer")** = 4*[](#PileSlipLayer.USER_DEFINED "Link to this definition") ## PileType[​](/sdk/api/external/dfoundations/.md#_PileType "Direct link to PileType") * *class *viktor.external.dfoundations.PileType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PileType "Link to this definition") Bases: `Enum` * BORED\_DRILLING*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 12*[](#PileType.BORED_DRILLING "Link to this definition") - BORED\_SHELLING*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 13*[](#PileType.BORED_SHELLING "Link to this definition") * CLOSED\_STEEL*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 1*[](#PileType.CLOSED_STEEL "Link to this definition") - CONTINUOUS\_FLIGHT\_AUGER*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 11*[](#PileType.CONTINUOUS_FLIGHT_AUGER "Link to this definition") * DRIVEN\_TUBE\_BACK\_DRIVING*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 2*[](#PileType.DRIVEN_TUBE_BACK_DRIVING "Link to this definition") - DRIVEN\_TUBE\_BACK\_VIBRATION*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 3*[](#PileType.DRIVEN_TUBE_BACK_VIBRATION "Link to this definition") * GROUTED\_STEEL\_PIPE*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 24*[](#PileType.GROUTED_STEEL_PIPE "Link to this definition") - GROUTED\_STEEL\_PROFILE*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 23*[](#PileType.GROUTED_STEEL_PROFILE "Link to this definition") * MICRO\_ANCHOR\_BORED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 20*[](#PileType.MICRO_ANCHOR_BORED "Link to this definition") - MICRO\_ANCHOR\_SCREWED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 21*[](#PileType.MICRO_ANCHOR_SCREWED "Link to this definition") * MICRO\_DOUBLE\_EXTORTED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 16*[](#PileType.MICRO_DOUBLE_EXTORTED "Link to this definition") - MICRO\_DOUBLE\_NOT\_EXTORTED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 17*[](#PileType.MICRO_DOUBLE_NOT_EXTORTED "Link to this definition") * MICRO\_SINGLE\_EXTORTED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 18*[](#PileType.MICRO_SINGLE_EXTORTED "Link to this definition") - MICRO\_SINGLE\_NOT\_EXTORTED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 19*[](#PileType.MICRO_SINGLE_NOT_EXTORTED "Link to this definition") * MICRO\_VIBRATED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 22*[](#PileType.MICRO_VIBRATED "Link to this definition") - MV*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 15*[](#PileType.MV "Link to this definition") * OPEN\_STEEL*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 14*[](#PileType.OPEN_STEEL "Link to this definition") - PREFAB\_CONCRETE*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 0*[](#PileType.PREFAB_CONCRETE "Link to this definition") * PREFAB\_WITHOUT\_GROUT*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 9*[](#PileType.PREFAB_WITHOUT_GROUT "Link to this definition") - PREFAB\_WITH\_GROUT*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 8*[](#PileType.PREFAB_WITH_GROUT "Link to this definition") * SCREW\_LOST\_TIP*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 6*[](#PileType.SCREW_LOST_TIP "Link to this definition") - SCREW\_WITH\_GROUT*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 7*[](#PileType.SCREW_WITH_GROUT "Link to this definition") * STEEL*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 10*[](#PileType.STEEL "Link to this definition") - STRAIGHT\_TIMBER*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 5*[](#PileType.STRAIGHT_TIMBER "Link to this definition") * TAPERED\_TIMBER*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 4*[](#PileType.TAPERED_TIMBER "Link to this definition") - USER\_DEFINED*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 27*[](#PileType.USER_DEFINED "Link to this definition") * USER\_DEFINED\_LOW\_VIBRATING*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 26*[](#PileType.USER_DEFINED_LOW_VIBRATING "Link to this definition") - USER\_DEFINED\_VIBRATING*: [`PileType`](#PileType "viktor.external.dfoundations.PileType")** = 25*[](#PileType.USER_DEFINED_VIBRATING "Link to this definition") ## PileTypeClayLoamPeat[​](/sdk/api/external/dfoundations/.md#_PileTypeClayLoamPeat "Direct link to PileTypeClayLoamPeat") * *class *viktor.external.dfoundations.PileTypeClayLoamPeat(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PileTypeClayLoamPeat "Link to this definition") Bases: `Enum` * ACCORDING\_TO\_STANDARD*: [`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")** = 0*[](#PileTypeClayLoamPeat.ACCORDING_TO_STANDARD "Link to this definition") - USER\_DEFINED*: [`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")** = 1*[](#PileTypeClayLoamPeat.USER_DEFINED "Link to this definition") ## ProfileLayer[​](/sdk/api/external/dfoundations/.md#_ProfileLayer "Direct link to ProfileLayer") * *class *viktor.external.dfoundations.ProfileLayer(*top\_level*, *material*, *ad\_pore\_pressure\_at\_top=0.0*, *ad\_pore\_pressure\_at\_bottom=0.0*, *ocr=1.0*)[](#ProfileLayer "Link to this definition") Data container for a single layer within a profile. * Parameters: * **top\_level** (`float`) – \[m] * **material** (`str`) – name of the material. * **ad\_pore\_pressure\_at\_top** (`float`) – \[kN/m2]. Tensions Piles (EC7-NL) model only. Ignored for other model types. * **ad\_pore\_pressure\_at\_bottom** (`float`) – \[kN/m2]. Tensions Piles (EC7-NL) model only. Ignored for other model types. * **ocr** (`float`) – \[-]. Tensions Piles (EC7-NL) model only. Ignored for other model types. - *property *material*: str*[](#ProfileLayer.material "Link to this definition") ## RectEnlPile[​](/sdk/api/external/dfoundations/.md#_RectEnlPile "Direct link to RectEnlPile") * *class *viktor.external.dfoundations.RectEnlPile(*base\_width*, *base\_length*, *base\_height*, *shaft\_width*, *shaft\_length*)[](#RectEnlPile "Link to this definition") Bases: `_PileShape` Round pile with enlarged base. * Parameters: * **base\_width** (`float`) – \[m] * **base\_length** (`float`) – \[m] * **base\_height** (`float`) – \[m] * **shaft\_width** (`float`) – \[m]. Must be smaller than ‘base\_width’. * **shaft\_length** (`float`) – \[m]. Must be smaller than ‘base\_length’. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘shaft\_width’ is not smaller than ‘base\_width’. * if ‘shaft\_length’ is not smaller than ‘base\_length’. ## RectPile[​](/sdk/api/external/dfoundations/.md#_RectPile "Direct link to RectPile") * *class *viktor.external.dfoundations.RectPile(*width*, *length*)[](#RectPile "Link to this definition") Bases: `_PileShape` Rectangular pile. * Parameters: * **width** (`float`) – \[m] * **length** (`float`) – \[m] ## RoundEnlPile[​](/sdk/api/external/dfoundations/.md#_RoundEnlPile "Direct link to RoundEnlPile") * *class *viktor.external.dfoundations.RoundEnlPile(*base\_diameter*, *pile\_diameter*, *base\_height*)[](#RoundEnlPile "Link to this definition") Bases: [`LostTipPile`](#LostTipPile "viktor.external.dfoundations.LostTipPile") Round pile with enlarged base. * Parameters: * **base\_diameter** (`float`) – \[m] * **pile\_diameter** (`float`) – \[m]. Must be smaller than ‘base\_diameter’. * **base\_height** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if ‘pile\_diameter’ is not smaller than ‘base\_diameter’. ## RoundPile[​](/sdk/api/external/dfoundations/.md#_RoundPile "Direct link to RoundPile") * *class *viktor.external.dfoundations.RoundPile(*diameter*)[](#RoundPile "Link to this definition") Bases: `_PileShape` Round pile. * Parameters: **diameter** (`float`) – \[m] ## SectionPile[​](/sdk/api/external/dfoundations/.md#_SectionPile "Direct link to SectionPile") * *class *viktor.external.dfoundations.SectionPile(*width*, *length*)[](#SectionPile "Link to this definition") Bases: [`RectPile`](#RectPile "viktor.external.dfoundations.RectPile") Section pile. Rectangular pile. * Parameters: * **width** (`float`) – \[m] * **length** (`float`) – \[m] ## SoilType[​](/sdk/api/external/dfoundations/.md#_SoilType "Direct link to SoilType") * *class *viktor.external.dfoundations.SoilType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SoilType "Link to this definition") Bases: `Enum` * CLAY*: [`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")** = 3*[](#SoilType.CLAY "Link to this definition") - GRAVEL*: [`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")** = 0*[](#SoilType.GRAVEL "Link to this definition") * LOAM*: [`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")** = 2*[](#SoilType.LOAM "Link to this definition") - PEAT*: [`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")** = 4*[](#SoilType.PEAT "Link to this definition") * SAND*: [`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")** = 1*[](#SoilType.SAND "Link to this definition") ## TaperPile[​](/sdk/api/external/dfoundations/.md#_TaperPile "Direct link to TaperPile") * *class *viktor.external.dfoundations.TaperPile(*diameter\_tip*, *increase*)[](#TaperPile "Link to this definition") Bases: `_PileShape` Round tapered pile. * Parameters: * **diameter\_tip** (`float`) – \[m] * **increase** (`float`) – \[m/m’] ## TensionPilesCalculationOptions[​](/sdk/api/external/dfoundations/.md#_TensionPilesCalculationOptions "Direct link to TensionPilesCalculationOptions") * *class *viktor.external.dfoundations.TensionPilesCalculationOptions(*calculation\_type*, *rigid*, *unit\_weight\_water=9.81*, *surcharge=0.0*, *\**, *xi3=None*, *xi4=None*, *gamma\_m\_var\_qc=None*, *gamma\_st=None*, *gamma\_gamma=None*, *use\_compaction=False*, *overrule\_excavation=False*, *overrule\_excess\_pore\_pressure=True*, *trajectory\_begin\_end\_interval=None*, *net\_bearing\_capacity=None*)[](#TensionPilesCalculationOptions "Link to this definition") Bases: `_CalculationOptions` Data container for the calculation options for a Tension Piles (EC7-NL) model. * Parameters: * **calculation\_type** ([`CalculationType`](#CalculationType "viktor.external.dfoundations.CalculationType")) – valid types: * CalculationType.INDICATION\_BEARING\_CAPACITY * CalculationType.BEARING\_CAPACITY\_AT\_FIXED\_PILE\_TIP\_LEVEL * CalculationType.PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY * **rigid** (`bool`) – True for rigid, False for non-rigid * **unit\_weight\_water** (`float`) – \[kN/m3] * **surcharge** (`float`) – \[kN/m2] * **xi3** (`float`) – ξ\_3 \[-] * **xi4** (`float`) – ξ\_4 \[-] * **gamma\_m\_var\_qc** (`float`) – γ\_m;var;qc \[-] * **gamma\_st** (`float`) – γ\_st \[-] * **gamma\_gamma** (`float`) – γ\_γ \[-] * **overrule\_excavation** (`bool`) * **use\_compaction** (`bool`) * **overrule\_excess\_pore\_pressure** (`bool`) * **trajectory\_begin\_end\_interval** (`Tuple`\[`float`, `float`, `float`]) – tuple(\[m], \[m], \[m]) * **net\_bearing\_capacity** (`int`) – \[kN] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘calculation\_type’ is not one of the valid types. * if ‘calculation\_type’ is INDICATION\_BEARING\_CAPACITY or PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘trajectory\_begin\_end\_interval’ is not set. * if the number of iterations > 151, based on the provided ‘trajectory\_begin\_end\_interval’. * if ‘calculation\_type’ is PILE\_TIP\_LEVEL\_AND\_NET\_BEARING\_CAPACITY and ‘net\_bearing\_capacity’ is not set. ## TensionPilesModel[​](/sdk/api/external/dfoundations/.md#_TensionPilesModel "Direct link to TensionPilesModel") * *class *viktor.external.dfoundations.TensionPilesModel(*construction\_sequence*, *calculation\_options*, *excavation\_level*, *reduction\_cone\_resistance=None*, *\**, *create\_default\_materials=True*)[](#TensionPilesModel "Link to this definition") Bases: `_Model` Create a Tension Piles (EC7-NL) model. * Parameters: * **construction\_sequence** ([`ConstructionSequence`](#ConstructionSequence "viktor.external.dfoundations.ConstructionSequence")) * **calculation\_options** ([`TensionPilesCalculationOptions`](#TensionPilesCalculationOptions "viktor.external.dfoundations.TensionPilesCalculationOptions")) * **excavation\_level** (`float`) – \[m] * **reduction\_cone\_resistance** (`float`) – Distance edge pile to excavation boundary \[m] to implement ‘Begemann’. ‘None’ to implement ‘Safe (NEN)’. * **create\_default\_materials** (`bool`) – whether to start with the default D-Foundations materials. The default materials are: > * BClay, clean, moderate > > * BClay, clean, modstiff > > * BClay, clean, stiff > > * BClay, clean, weak > > * BClay, sl san, moderate > > * BClay, sl san, modstiff > > * BClay, sl san, stiff > > * BClay, sl san, weak > > * BGravel, clean, moderate > > * BGravel, clean, stiff > > * BGravel, ve sil, moderate > > * BGravel, ve sil, stiff > > * BLoam, clean, moderate > > * BLoam, clean, modstiff > > * BLoam, clean, stiff > > * BLoam, clean, weak > > * BLoam, sl san, moderate > > * BLoam, sl san, modstiff > > * BLoam, sl san, stiff > > * BLoam, sl san, weak > > * BPeat, sl san, moderate > > * BPeat, sl san, stiff > > * BPeat, sl san, weak > > * BSand, clean, loose > > * BSand, clean, moderate > > * BSand, clean, stiff > > * BSand, ve sil, loose > > * BSand, ve sil, moderate > > * BSand, ve sil, stiff > > * Clay, clean, moderate > > * Clay, clean, stiff > > * Clay, clean, weak > > * Clay, organ, moderate > > * Clay, organ, weak > > * Clay, sl san, moderate > > * Clay, sl san, stiff > > * Clay, sl san, weak > > * Clay, ve san, stiff > > * Gravel, sl sil, loose > > * Gravel, sl sil, moderate > > * Gravel, sl sil, stiff > > * Gravel, ve sil, loose > > * Gravel, ve sil, moderate > > * Gravel, ve sil, stiff > > * Loam, sl san, moderate > > * Loam, sl san, stiff > > * Loam, sl san, weak > > * Loam, ve san, stiff > > * Peat, mod pl, moderate > > * Peat, not pl, weak > > * Sand, clean, loose > > * Sand, clean, moderate > > * Sand, clean, stiff > > * Sand, sl sil, moderate > > * Sand, ve sil, loose * materials[](#TensionPilesModel.materials "Link to this definition") Lists all materials currently in de model. - profiles[](#TensionPilesModel.profiles "Link to this definition") Lists all profiles currently in de model. * pile\_types[](#TensionPilesModel.pile_types "Link to this definition") Lists all pile types currently in de model. - piles[](#TensionPilesModel.piles "Link to this definition") Lists all piles currently in de model. * generate\_input\_file(*metadata=None*, *\**, *as\_file=False*)[](#TensionPilesModel.generate_input_file "Link to this definition") Generate a D-Foundations input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **metadata** ([`Metadata`](#Metadata "viktor.external.dfoundations.Metadata")) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **as\_file** (`bool`) – return as BytesIO (default) or File * Return type: `Union`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), `BytesIO`] - create\_material(*name*, *soil\_type*, *gamma\_unsat*, *gamma\_sat*, *friction\_angle*, *diameter\_d50=0.2*, *max\_cone\_resist\_type=MaxConeResistType.STANDARD*, *max\_cone\_resist=0.0*, *apply\_tension=True*, *min\_void\_ratio=0.4*, *max\_void\_ratio=0.8*, *color=None*)[](#TensionPilesModel.create_material "Link to this definition") Create a material with the given name and properties. * Parameters: * **name** (`str`) – name of the material to create (max. 25 characters) * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – color for visualization in deltares software (None for default color ‘white’) * **soil\_type** ([`SoilType`](#SoilType "viktor.external.dfoundations.SoilType")) – \[-] * **gamma\_unsat** (`float`) – gamma-unsaturated, dry \[kN/m³] * **gamma\_sat** (`float`) – gamma-saturated, wet \[kN/m³] * **friction\_angle** (`float`) – phi \[degree] * **diameter\_d50** (`float`) – median \[mm] * **max\_cone\_resist\_type** ([`MaxConeResistType`](#MaxConeResistType "viktor.external.dfoundations.MaxConeResistType")) – \[-] * **max\_cone\_resist** (`float`) – \[MPa] * **apply\_tension** (`bool`) – True (default) / False * **min\_void\_ratio** (`float`) – \[-] * **max\_void\_ratio** (`float`) – \[-] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type: `None` * create\_pile(*name*, *x*, *y*, *pile\_head\_level*, *load\_max\_min=None*)[](#TensionPilesModel.create_pile "Link to this definition") Create a pile with given properties. * Parameters: * **name** (`str`) – name of the pile. Must be unique. Max. 10 characters. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **pile\_head\_level** (`float`) – \[m R.L.] * **load\_max\_min** (`Tuple`\[`float`, `float`]) – (max. load \[kN], min. load \[kN]). None for ‘No’ use of alternating loads. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if pile with given name already exists. * if name exceeds the max. number of characters (10). * Return type: `None` - create\_pile\_type(*name*, *shape*, *type\_sand\_gravel*, *type\_clay\_loam\_peat*, *material*, *factor\_sand\_gravel=None*, *factor\_clay\_loam\_peat=None*, *unit\_weight\_material=None*)[](#TensionPilesModel.create_pile_type "Link to this definition") Create a pile type with the given properties. * Parameters: * **name** (`str`) – name of the pile type. Must be unique. Max. 10 characters. * **shape** (`_PileShape`) – pile type shape class instance. See below for possible shapes. * **type\_sand\_gravel** ([`PileType`](#PileType "viktor.external.dfoundations.PileType")) – pile type for α\_t sand/gravel. predefined/user-defined pile type. Only certain types are valid in combination with the provided ‘shape’. For more information on valid combinations, please refer to the D-Foundations software. * **type\_clay\_loam\_peat** ([`PileTypeClayLoamPeat`](#PileTypeClayLoamPeat "viktor.external.dfoundations.PileTypeClayLoamPeat")) – pile type for α\_t clay/loam/peat. * **material** ([`PileMaterial`](#PileMaterial "viktor.external.dfoundations.PileMaterial")) * **factor\_sand\_gravel** (`float`) – α\_t \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **factor\_clay\_loam\_peat** (`float`) – α\_t \[-]. Only required if ‘type\_sand\_gravel’ is of type user-defined. * **unit\_weight\_material** (`float`) – unit weight pile material \[kN/m3]. Only required if ‘material’ is of type ser-defined. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘type\_sand\_gravel’ is of type user-defined and ‘factor\_sand\_gravel’ is not set. * if ‘type\_clay\_loam\_peat’ is of type user-defined and ‘factor\_clay\_loam\_peat’ is not set. * if ‘material’ is of type user-defined and ‘unit\_weight\_material’ is not set. * if an invalid ‘shape’ is provided. * if a ‘type\_sand\_gravel’ is provided that is invalid in combination with the given ‘shape’. * if a pile type with the give name already exists. * if ‘factor\_sand\_gravel’ or ‘factor\_clay\_loam\_peat’ is outside valid range 0-9. * Return type: `None` Possible shapes are: > * RectPile > > * RectEnlPile > > * UserPile > > * RoundPile > > * TaperPile > > * HollowPile > > * HollowOpenPile > > * RoundEnlPile > > * LostTipPile > > * DrivenBasePile > > * HShapedPile * create\_profile(*name*, *layers*, *x*, *y*, *measurements*, *phreatic\_level*, *pile\_tip\_level*, *top\_tension\_zone*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[](#TensionPilesModel.create_profile "Link to this definition") Create a profile manually. * Parameters: * **name** (`str`) – name of the profile (must be unique). * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **measurements** (`List`\[`Tuple`\[`float`, `float`]]) – list of measurement data (level \[m], qc-value \[MPa]). * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **top\_tension\_zone** (`float`) – Top of tension zone \[m] * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) * **min\_layer\_thickness** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * Return type: `None` - import\_profile(*cpt*, *layers*, *x*, *y*, *phreatic\_level*, *pile\_tip\_level*, *top\_tension\_zone*, *name=None*, *manual\_ground\_level=None*, *\**, *cpt\_rule=CPTRule.NEN*, *min\_layer\_thickness=0.1*)[](#TensionPilesModel.import_profile "Link to this definition") Create a profile by importing a CPT-file. * Parameters: * **cpt** ([`GEFData`](/sdk/api/geo/.md#GEFData "viktor.geo.GEFData")) – CPT file to import. * **layers** (`List`\[[`ProfileLayer`](#ProfileLayer "viktor.external.dfoundations.ProfileLayer")]) – list of layers. * **x** (`float`) – \[m] * **y** (`float`) – \[m] * **phreatic\_level** (`float`) – \[m] * **pile\_tip\_level** (`float`) – \[m] * **top\_tension\_zone** (`float`) – Top of tension zone \[m] * **name** (`str`) – name of the profile (must be unique). None for default (name of the cpt). * **manual\_ground\_level** (`float`) – set to override the ground level \[m] from the cpt. * **cpt\_rule** ([`CPTRule`](#CPTRule "viktor.external.dfoundations.CPTRule")) * **min\_layer\_thickness** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if max. number of profiles (350) was reached. * if profile with the given name already exists. * if a material exists within one of the layers of which the name does not exist in the model. * if measurements exceeds max. number of rows (5000). * if layers exceeds max. number for a single profile (100). * if ground level could not be read from cpt file. * Return type: `None` ## UserPile[​](/sdk/api/external/dfoundations/.md#_UserPile "Direct link to UserPile") * *class *viktor.external.dfoundations.UserPile(*circumference*, *cross\_section*)[](#UserPile "Link to this definition") Bases: `_PileShape` User defined pile. * Parameters: * **circumference** (`float`) – \[m] * **cross\_section** (`float`) – \[m2] --- # viktor.external.dgeostability ## DGeoStabilityAnalysis[​](/sdk/api/external/dgeostability/.md#_DGeoStabilityAnalysis "Direct link to DGeoStabilityAnalysis") * *class *viktor.external.dgeostability.DGeoStabilityAnalysis(*input\_file*)[](#DGeoStabilityAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DGeoStabilityAnalysis can be used to perform an analysis using DGeoStability on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DGeoStabilityAnalysis.get_output_file "viktor.external.dgeostability.DGeoStabilityAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` dgeostability_analysis = DGeoStabilityAnalysis(input_file=input_file) dgeostability_analysis.execute(timeout=10) output_file = dgeostability_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – .sti input file. - get\_output\_file(*extension='.sto'*, *\**, *as\_file=False*)[](#DGeoStabilityAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DGeoStabilityAnalysis.get_output_file "viktor.external.dgeostability.DGeoStabilityAnalysis.get_output_file") afterwards. * Parameters: * **extension** (`str`) – extension of the file you want to return; ‘.sto’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.dsettlement ## CalculationModel[​](/sdk/api/external/dsettlement/.md#_CalculationModel "Direct link to CalculationModel") * *class *viktor.external.dsettlement.CalculationModel(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CalculationModel "Link to this definition") Bases: `Enum` * ISOTACHE*: [`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 2*[](#CalculationModel.ISOTACHE "Link to this definition") - NEN\_BJERRUM*: [`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 1*[](#CalculationModel.NEN_BJERRUM "Link to this definition") * NEN\_KOPPEJAN*: [`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")** = 0*[](#CalculationModel.NEN_KOPPEJAN "Link to this definition") ## ConsolidationModel[​](/sdk/api/external/dsettlement/.md#_ConsolidationModel "Direct link to ConsolidationModel") * *class *viktor.external.dsettlement.ConsolidationModel(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConsolidationModel "Link to this definition") Bases: `Enum` * DARCY*: [`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")** = 0*[](#ConsolidationModel.DARCY "Link to this definition") - TERZAGHI*: [`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")** = 1*[](#ConsolidationModel.TERZAGHI "Link to this definition") ## DSettlementAnalysis[​](/sdk/api/external/dsettlement/.md#_DSettlementAnalysis "Direct link to DSettlementAnalysis") * *class *viktor.external.dsettlement.DSettlementAnalysis(*input\_file*)[](#DSettlementAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DSettlementAnalysis can be used to perform an analysis using DSettlement on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DSettlementAnalysis.get_output_file "viktor.external.dsettlement.DSettlementAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` input_file = File.from_data("dsettlement input file body") dsettlement_analysis = DSettlementAnalysis(input_file=input_file) dsettlement_analysis.execute(timeout=10) output_file = dsettlement_analysis.get_output_file() # obtain output file in BytesIO sld_file = dsettlement_analysis.get_sld_file() # obtain sld file in StringIO (to post-process) ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – .sli input file. - get\_output\_file(*extension='.sld'*, *\**, *as\_file=False*)[](#DSettlementAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DSettlementAnalysis.get_output_file "viktor.external.dsettlement.DSettlementAnalysis.get_output_file") afterwards. * Parameters: * **extension** (`str`) – extension of the file you want to return; one of: ‘.sld’, ‘.slo’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * get\_sld\_file(*\**, *as\_file=False*)[](#DSettlementAnalysis.get_sld_file "Link to this definition") Method to retrieve the sld (result) file. * Parameters: **as\_file** (`bool`) – return as StringIO (default) or File New in v13.5.0 * Raises: **ValueError** – if file can not be obtained. * Return type: `Union`\[`StringIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] ## DrainGrid[​](/sdk/api/external/dsettlement/.md#_DrainGrid "Direct link to DrainGrid") * *class *viktor.external.dsettlement.DrainGrid(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#DrainGrid "Link to this definition") Bases: `Enum` * RECTANGULAR*: [`DrainGrid`](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 1*[](#DrainGrid.RECTANGULAR "Link to this definition") - TRIANGULAR*: [`DrainGrid`](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 0*[](#DrainGrid.TRIANGULAR "Link to this definition") * UNDETERMINED*: [`DrainGrid`](#DrainGrid "viktor.external.dsettlement.DrainGrid")** = 2*[](#DrainGrid.UNDETERMINED "Link to this definition") ## DrainType[​](/sdk/api/external/dsettlement/.md#_DrainType "Direct link to DrainType") * *class *viktor.external.dsettlement.DrainType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#DrainType "Link to this definition") Bases: `Enum` * COLUMN*: [`DrainType`](#DrainType "viktor.external.dsettlement.DrainType")** = 1*[](#DrainType.COLUMN "Link to this definition") - SAND\_WALL*: [`DrainType`](#DrainType "viktor.external.dsettlement.DrainType")** = 2*[](#DrainType.SAND_WALL "Link to this definition") * STRIP*: [`DrainType`](#DrainType "viktor.external.dsettlement.DrainType")** = 0*[](#DrainType.STRIP "Link to this definition") ## DrainageSimpleMode[​](/sdk/api/external/dsettlement/.md#_DrainageSimpleMode "Direct link to DrainageSimpleMode") * *class *viktor.external.dsettlement.DrainageSimpleMode(*begin\_time*, *end\_time*, *underpressure*, *dewatering\_head\_or\_pressure*)[](#DrainageSimpleMode "Link to this definition") Simple drainage schema; to be used in VerticalDrain. * Parameters: * **begin\_time** (`float`) – \[days] * **end\_time** (`float`) – \[days] * **underpressure** (`float`) – \[kPa] * **dewatering\_head\_or\_pressure** (`float`) – water head \[m] or tube pressure (if VerticalDrain.drain\_type = SAND\_WALL) \[kPa] ## Metadata[​](/sdk/api/external/dsettlement/.md#_Metadata "Direct link to Metadata") * *class *viktor.external.dsettlement.Metadata(*file\_name='-'*, *company='-'*, *created\_by='-'*, *title\_1='-'*, *title\_2='-'*, *title\_3='-'*, *write\_date=False*, *write\_time=False*)[](#Metadata "Link to this definition") Data-class for defining metadata. * Parameters: * **file\_name** (`str`) * **company** (`str`) * **created\_by** (`str`) * **title\_1** (`str`) – max. 50 characters * **title\_2** (`str`) – max. 50 characters * **title\_3** (`str`) – max. 50 characters * **write\_date** (`bool`) – True to write the current date to the sli file; False for dummy (‘01/01/1900’) * **write\_time** (`bool`) – True to write the current date to the sli file; False for dummy (‘00:00:00’) * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if title\_1, title\_2 or title\_3 has more than 50 characters ## Model1D[​](/sdk/api/external/dsettlement/.md#_Model1D "Direct link to Model1D") * *class *viktor.external.dsettlement.Model1D(*calculation\_model*, *consolidation\_model*, *create\_default\_materials=True*, *\**, *natural\_strain=False*, *water\_unit\_weight=9.81*, *verticals\_discretization=100*, *verticals\_z\_coordinate=0.0*, *maintain\_profile=False*, *profile\_unit\_weight\_above\_phreatic\_level=10.0*, *profile\_unit\_weight\_below\_phreatic\_level=10.0*, *end\_of\_settlement\_calculation=10000*, *vertical\_drain=None*)[](#Model1D "Link to this definition") Bases: `_Model` Model for a 1D D-Settlement analysis. Example usage: ``` # instantiate 1D model model = Model1D(CalculationModel.NEN_KOPPEJAN, ConsolidationModel.TERZAGHI) # update the geometry model.create_material("my_mat", 21.0, 19.0, color=Color(0, 0, 0)) model.update_geometry(-1.0, [(1.0, "Loam"), (0.0, "my_mat")], phreatic_level=-3.0) # add load(s) model.create_uniform_load("my_load", 0, 0.001, 0.0, 0.0) # generate the input file input_file = model.generate_input_file() ``` * Parameters: * **calculation\_model** ([`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")) * **consolidation\_model** ([`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")) * **create\_default\_materials** (`bool`) – start with default materials or none * **natural\_strain** (`bool`) – if False -> linear strain * **water\_unit\_weight** (`float`) – in \[kN/m³] * **vertical\_drain** ([`VerticalDrain`](#VerticalDrain "viktor.external.dsettlement.VerticalDrain")) – parameters for vertical drains, or None (default) to disable option - materials[](#Model1D.materials "Link to this definition") * create\_material(*name*, *gam\_dry*, *gam\_wet*, *color=None*, *\**, *initial\_void\_ratio=0.0*, *cohesion=0.0*, *phi=0.0*, *precon\_isotache\_type=0*, *precon\_koppejan\_type=0*, *use\_equivalent\_age=0*, *equivalent\_age=0.0*, *pc=0.0*, *ocr=1.0*, *pop=0.0*, *limit\_stress=1.0*, *drained=0*, *ap\_as\_approximation\_by\_cp\_cs=0*, *cv=10.0*, *permeability\_ver=0.05*, *permeability\_hor\_factor=1.0*, *storage\_type=0*, *permeability\_strain\_modulus=1000000000000000.0*, *use\_prob\_defaults=1*, *std\_gam\_dry=0.0*, *std\_gam\_wet=0.0*, *std\_cv=0.0*, *std\_pc=0.0*, *std\_pri\_comp\_index=0.0*, *std\_sec\_comp\_index=0.0*, *std\_sec\_comp\_rate=0.0*, *std\_ocr=0.0*, *std\_permeability\_ver=0.0*, *std\_pop=0.0*, *std\_permeability\_hor\_factor=0.0*, *std\_initial\_void\_ratio=0.0*, *std\_permeability\_strain\_modulus=0.0*, *std\_limit\_stress=0.0*, *std\_cp=0.0*, *std\_cp1=0.0*, *std\_cs=0.0*, *std\_cs1=0.0*, *std\_ap=0.0*, *std\_asec=0.0*, *std\_car=0.0*, *std\_ca=0.0*, *std\_r\_ratio=0.0*, *std\_c\_ratio=0.0*, *std\_s\_ratio=0.0*, *std\_cr\_index=0.0*, *std\_cc\_index=0.0*, *std\_csw\_index=0.0*, *dist\_gam\_dry=2*, *dist\_gam\_wet=2*, *dist\_cv=2*, *dist\_pc=2*, *dist\_pri\_comp\_index=2*, *dist\_sec\_comp\_index=2*, *dist\_sec\_comp\_rate=2*, *dist\_ocr=2*, *dist\_permeability\_ver=2*, *dist\_pop=2*, *dist\_permeability\_hor\_factor=2*, *dist\_initial\_void\_ratio=2*, *dist\_permeability\_strain\_modulus=2*, *dist\_limit\_stress=2*, *dist\_cp=2*, *dist\_cp1=2*, *dist\_cs=2*, *dist\_cs1=2*, *dist\_ap=2*, *dist\_asec=2*, *dist\_car=2*, *dist\_ca=2*, *dist\_r\_ratio=2*, *dist\_c\_ratio=2*, *dist\_s\_ratio=2*, *dist\_cr\_index=2*, *dist\_cc\_index=2*, *dist\_csw\_index=2*, *cor\_cp\_cp1=0.0*, *cor\_cs\_cp1=0.0*, *cor\_cs1\_cp1=0.0*, *cor\_ap\_cp1=0.0*, *cor\_asec\_cp1=0.0*, *cor\_cr\_index\_cc\_index=0.0*, *cor\_r\_ratio\_c\_ratio=0.0*, *cor\_ca\_cc\_index\_or\_c\_ratio=0.0*, *cor\_pri\_comp\_index\_sec\_comp\_index=0.0*, *cor\_sec\_comp\_rate\_sec\_comp\_index=0.0*, *cp=1.0*, *cp1=1.0*, *cs=1.0*, *cs1=1.0*, *ap=1.0*, *asec=1.0*, *car=0.0*, *ca=1.0*, *comp\_ratio=1*, *r\_ratio=1.0*, *c\_ratio=1.0*, *s\_ratio=0.0*, *cr\_index=1.0*, *cc\_index=1.0*, *csw\_index=0.0*, *pri\_comp\_index=0.01*, *sec\_comp\_index=0.1*, *sec\_comp\_rate=0.005*, *horizontal\_behaviour\_type=2*, *elasticity=1000.0*, *default\_elasticity=1*)[](#Model1D.create_material "Link to this definition") Create a material with the given name and properties. * Parameters: * **name** (`str`) – name of the material to create (max. 25 characters) * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – color for visualization in deltares software (None for random color) * **gam\_dry** (`float`) – unit weight above phreatic level in \[kN/m³] * **gam\_wet** (`float`) – unit weight below phreatic level in \[kN/m³] * **...****.** – etc. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type: `None` - create\_uniform\_load(*name*, *time*, *unit\_weight*, *height*, *y\_application*)[](#Model1D.create_uniform_load "Link to this definition") Create a uniform load with the given name and properties. * Parameters: * **name** (`str`) – name of the uniform load to create * **time** (`int`) – in \[days], -1 for initial load * **unit\_weight** (`float`) – in \[kN/m³] * **height** (`float`) – in \[m] * **y\_application** (`float`) – in \[m] * Return type: `None` * set\_calculation\_times(*\*time*)[](#Model1D.set_calculation_times "Link to this definition") (Re)set calculation time(s) * Parameters: **time** (`int`) – one or more calculation times at which results will be obtained # todo: days * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if time < 0 or > end time * if duplicates exist * Return type: `None` - generate\_input\_file(*metadata=None*, *\**, *dissipation\_calculation=None*, *as\_file=False*)[](#Model1D.generate_input_file "Link to this definition") Generate a D-Settlement input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **metadata** ([`Metadata`](#Metadata "viktor.external.dsettlement.Metadata")) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **dissipation\_calculation** (`_Vertical`) – select vertical to add dissipation calculation; ‘None’ to disable. * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * *property *bottom\_level*: float*[](#Model1D.bottom_level "Link to this definition") - *property *layers*: List\[Tuple\[float, str]]*[](#Model1D.layers "Link to this definition") * *property *phreatic\_level*: float | None*[](#Model1D.phreatic_level "Link to this definition") - *property *top\_level*: float*[](#Model1D.top_level "Link to this definition") * update\_geometry(*bottom\_level*, *layers*, *phreatic\_level=None*)[](#Model1D.update_geometry "Link to this definition") Overwrite the current (default if not updated before) geometry with the given data. * Parameters: * **bottom\_level** (`float`) – bottom level of the bottom-most layer \[m] * **layers** (`List`\[`Tuple`\[`float`, `str`]]) – list of layers defined by top level \[m] and material name (must be created beforehand with [`create_material()`](#Model1D.create_material "viktor.external.dsettlement.Model1D.create_material") or one of the default materials). Should be defined from top to bottom. * **phreatic\_level** (`float`) – in \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if layers are not defined from top to bottom * if lowest layer top level is below given bottom level * if material with given name does not exist * Return type: `None` Example usage: ``` model.update_geometry(-1, [(1.0, "Loam"), (0.0, "Sand")], phreatic_level=-3) ``` ## Model2D[​](/sdk/api/external/dsettlement/.md#_Model2D "Direct link to Model2D") * *class *viktor.external.dsettlement.Model2D(*calculation\_model*, *consolidation\_model*, *boundary\_bottom*, *create\_default\_materials=True*, *\**, *natural\_strain=False*, *limits=(0.0, 100.0)*, *water\_unit\_weight=9.81*, *verticals\_discretization=100*, *verticals\_z\_coordinate=0.0*, *maintain\_profile=False*, *profile\_time=0*, *profile\_unit\_weight\_above\_phreatic\_level=10.0*, *profile\_unit\_weight\_below\_phreatic\_level=10.0*, *end\_of\_settlement\_calculation=10000*, *stress\_distribution\_loads=False*, *vertical\_drain=None*)[](#Model2D "Link to this definition") Bases: `_Model` Model for a 2D D-Settlement analysis. Example usage: ``` # Initialize parameters for vertical drainage, to be used in the init of Model2D. vertical_drain = VerticalDrain(DrainType.SAND_WALL, 5.0, 90.0, 0.0, 2.0, 4.0, start_of_drainage=2.0, phreatic_level_in_drain=4.0) # Create the model (NEN - Koppejan / Terzaghi) with a starting bottom boundary, vertical drainage and # miscellaneous default parameters. model = Model2D(CalculationModel.NEN_KOPPEJAN, ConsolidationModel.TERZAGHI, boundary_bottom=[(0.0, 0.0), (100.0, 0.0)], vertical_drain=vertical_drain) # Create points for defining boundaries and pl-lines. points_boundary1 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 2.5)]] points_boundary2 = [model.create_point(x, y) for (x, y) in [(0.0, 5.0), (50.0, 5.0), (100.0, 7.5)]] points_boundary3 = [model.create_point(x, y) for (x, y) in [(0.0, 10.0), (25, 10.0), (75, 10.0), (100.0, 10.0)]] points_plline1 = [model.create_point(x, y) for (x, y) in [(0.0, 4.0), (100.0, 4.0)]] points_plline2 = [model.create_point(x, y) for (x, y) in [(0.0, 6.0), (100.0, 6.0)]] # Create the pl-lines. plline1 = model.create_pl_line(points_plline1, is_phreatic=True) plline2 = model.create_pl_line(points_plline2) # Create the layers. model.create_layer(points_boundary1, 'Sand', pl_line_top=99, pl_line_bottom=plline2) model.create_layer(points_boundary2, 'Soft Clay', pl_line_top=99, pl_line_bottom=99) model.create_layer(points_boundary3, 'Loam', pl_line_top=plline1, pl_line_bottom=99) # Create verticals. model.create_vertical(45.0) model.create_vertical(50.0) model.create_vertical(55.0) # Create loads. model.create_non_uniform_load('load1', [(25, 10.0), (50.0, 12.0), (75, 10.0)]) # Create calculation/residual times. model.set_calculation_times(1, 4, 2, 5) # Generate the input file for the model as if it was generated by D-Settlement. input_file = model.generate_input_file() ``` * Parameters: * **calculation\_model** ([`CalculationModel`](#CalculationModel "viktor.external.dsettlement.CalculationModel")) – Specifies which calculation model is used. * **consolidation\_model** ([`ConsolidationModel`](#ConsolidationModel "viktor.external.dsettlement.ConsolidationModel")) – Specifies which consolidation model is used. * **boundary\_bottom** (`List`\[`Tuple`\[`float`, `float`]]) – The bottom boundary of the geometry. * **create\_default\_materials** (`bool`) – start with default materials or none * **natural\_strain** (`bool`) – Indicates if natural strain is used. If False, linear strain is used. * **water\_unit\_weight** (`float`) – in \[kN/m³] * **stress\_distribution\_loads** (`bool`) – True for ‘Simulate’, False for ‘None’ (default). * **vertical\_drain** ([`VerticalDrain`](#VerticalDrain "viktor.external.dsettlement.VerticalDrain")) – parameters for vertical drains, or None (default) to disable option - materials[](#Model2D.materials "Link to this definition") * create\_material(*name*, *gam\_dry*, *gam\_wet*, *color=None*, *\**, *initial\_void\_ratio=0.0*, *cohesion=0.0*, *phi=0.0*, *precon\_isotache\_type=0*, *precon\_koppejan\_type=0*, *use\_equivalent\_age=0*, *equivalent\_age=0.0*, *pc=0.0*, *ocr=1.0*, *pop=0.0*, *limit\_stress=1.0*, *drained=0*, *ap\_as\_approximation\_by\_cp\_cs=0*, *cv=10.0*, *permeability\_ver=0.05*, *permeability\_hor\_factor=1.0*, *storage\_type=0*, *permeability\_strain\_modulus=1000000000000000.0*, *use\_prob\_defaults=1*, *std\_gam\_dry=0.0*, *std\_gam\_wet=0.0*, *std\_cv=0.0*, *std\_pc=0.0*, *std\_pri\_comp\_index=0.0*, *std\_sec\_comp\_index=0.0*, *std\_sec\_comp\_rate=0.0*, *std\_ocr=0.0*, *std\_permeability\_ver=0.0*, *std\_pop=0.0*, *std\_permeability\_hor\_factor=0.0*, *std\_initial\_void\_ratio=0.0*, *std\_permeability\_strain\_modulus=0.0*, *std\_limit\_stress=0.0*, *std\_cp=0.0*, *std\_cp1=0.0*, *std\_cs=0.0*, *std\_cs1=0.0*, *std\_ap=0.0*, *std\_asec=0.0*, *std\_car=0.0*, *std\_ca=0.0*, *std\_r\_ratio=0.0*, *std\_c\_ratio=0.0*, *std\_s\_ratio=0.0*, *std\_cr\_index=0.0*, *std\_cc\_index=0.0*, *std\_csw\_index=0.0*, *dist\_gam\_dry=2*, *dist\_gam\_wet=2*, *dist\_cv=2*, *dist\_pc=2*, *dist\_pri\_comp\_index=2*, *dist\_sec\_comp\_index=2*, *dist\_sec\_comp\_rate=2*, *dist\_ocr=2*, *dist\_permeability\_ver=2*, *dist\_pop=2*, *dist\_permeability\_hor\_factor=2*, *dist\_initial\_void\_ratio=2*, *dist\_permeability\_strain\_modulus=2*, *dist\_limit\_stress=2*, *dist\_cp=2*, *dist\_cp1=2*, *dist\_cs=2*, *dist\_cs1=2*, *dist\_ap=2*, *dist\_asec=2*, *dist\_car=2*, *dist\_ca=2*, *dist\_r\_ratio=2*, *dist\_c\_ratio=2*, *dist\_s\_ratio=2*, *dist\_cr\_index=2*, *dist\_cc\_index=2*, *dist\_csw\_index=2*, *cor\_cp\_cp1=0.0*, *cor\_cs\_cp1=0.0*, *cor\_cs1\_cp1=0.0*, *cor\_ap\_cp1=0.0*, *cor\_asec\_cp1=0.0*, *cor\_cr\_index\_cc\_index=0.0*, *cor\_r\_ratio\_c\_ratio=0.0*, *cor\_ca\_cc\_index\_or\_c\_ratio=0.0*, *cor\_pri\_comp\_index\_sec\_comp\_index=0.0*, *cor\_sec\_comp\_rate\_sec\_comp\_index=0.0*, *cp=1.0*, *cp1=1.0*, *cs=1.0*, *cs1=1.0*, *ap=1.0*, *asec=1.0*, *car=0.0*, *ca=1.0*, *comp\_ratio=1*, *r\_ratio=1.0*, *c\_ratio=1.0*, *s\_ratio=0.0*, *cr\_index=1.0*, *cc\_index=1.0*, *csw\_index=0.0*, *pri\_comp\_index=0.01*, *sec\_comp\_index=0.1*, *sec\_comp\_rate=0.005*, *horizontal\_behaviour\_type=2*, *elasticity=1000.0*, *default\_elasticity=1*)[](#Model2D.create_material "Link to this definition") Create a material with the given name and properties. * Parameters: * **name** (`str`) – name of the material to create (max. 25 characters) * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – color for visualization in deltares software (None for random color) * **gam\_dry** (`float`) – unit weight above phreatic level in \[kN/m³] * **gam\_wet** (`float`) – unit weight below phreatic level in \[kN/m³] * **...****.** – etc. * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name already exists in the model * if name is longer than 25 characters * Return type: `None` - create\_uniform\_load(*name*, *time*, *unit\_weight*, *height*, *y\_application*)[](#Model2D.create_uniform_load "Link to this definition") Create a uniform load with the given name and properties. * Parameters: * **name** (`str`) – name of the uniform load to create * **time** (`int`) – in \[days], -1 for initial load * **unit\_weight** (`float`) – in \[kN/m³] * **height** (`float`) – in \[m] * **y\_application** (`float`) – in \[m] * Return type: `None` * set\_calculation\_times(*\*time*)[](#Model2D.set_calculation_times "Link to this definition") (Re)set calculation time(s) * Parameters: **time** (`int`) – one or more calculation times at which results will be obtained # todo: days * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if time < 0 or > end time * if duplicates exist * Return type: `None` - generate\_input\_file(*metadata=None*, *\**, *dissipation\_calculation=None*, *as\_file=False*)[](#Model2D.generate_input_file "Link to this definition") Generate a D-Settlement input file. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **metadata** ([`Metadata`](#Metadata "viktor.external.dsettlement.Metadata")) – Metadata which will be written to the input file. If no metadata is provided, default data will be used. * **dissipation\_calculation** (`_Vertical`) – select vertical to add dissipation calculation; ‘None’ to disable. * **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * create\_layer(*boundary\_top*, *material*, *pl\_line\_top*, *pl\_line\_bottom*)[](#Model2D.create_layer "Link to this definition") Define layers from bottom to top. * Parameters: * **boundary\_top** (`List`\[`_Point`]) – boundary at top of layer * **material** (`str`) – name of the material to be used (must be created beforehand) * **pl\_line\_top** (`Union`\[`_PlLine`, `int`]) – pl-line at top, or 0 for no pressure, or 99 for interpolation * **pl\_line\_bottom** (`Union`\[`_PlLine`, `int`]) – pl-line at bottom, or 0 for no pressure, or 99 for interpolation * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if material with given name does not exist * if boundary\_bottom is provided for layer other than first * if pl\_line\_top or pl\_line\_bottom are not valid * if ‘points’ contains duplicates * if start and end ‘points’ are not on the left and right boundary limit respectively * if ‘points’ are not in ascending X-direction * if ‘is\_phreatic’ is True but was already set before * Return type: `_Layer` - create\_non\_uniform\_load(*name*, *points*, *time=0*, *end\_time=0*, *gamma\_dry=10.0*, *gamma\_wet=10.0*, *temporary=False*)[](#Model2D.create_non_uniform_load "Link to this definition") Create a non-uniform load. DSettlement assumes that a non-uniform load is caused by soil self weight. Initial loads only affects the initial stresses and do not cause creep or consolidation. * Parameters: * **name** (`str`) – Name of the load. * **points** (`List`\[`Tuple`\[`float`, `float`]]) – Points, as x-y coordinates, of the load. The first and last points must be located on a layer or another non-uniform load. * **time** (`int`) – The moment the load is laid down \[days]. If time is set to -1 days, the load is considered an initial load. * **end\_time** (`int`) – The moment the load is removed (only in the case of temporary loads) \[days]. * **temporary** (`bool`) – Bool which indicates if the load is a temporary load. * **gamma\_dry** (`float`) – Total unit weight above phreatic level \[kN/m3]. * **gamma\_wet** (`float`) – Total unit weight below phreatic level \[kN/m3]. * Return type: `_NonUniformLoad` * create\_pl\_line(*points*, *is\_phreatic=False*)[](#Model2D.create_pl_line "Link to this definition") Create a piezometric level line (pl-line) from the given points. * Parameters: * **points** (`List`\[`_Point`]) – list of points that define the pl-line * **is\_phreatic** (`bool`) – whether to set the current pl-line as the phreatic line (overwrites previous!) * Return type: `_PlLine` * Returns: pl-line * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – * if ‘points’ contains duplicates * if start and end ‘points’ are not on the left and right boundary limit respectively * if ‘points’ are not in ascending X-direction * if ‘is\_phreatic’ is True but was already set before - create\_point(*x*, *y*)[](#Model2D.create_point "Link to this definition") Create a point with given x and y coordinates. * Parameters: * **x** (`float`) – in \[m] * **y** (`float`) – in \[m] * Return type: `_Point` * Returns: \_Point which can be used to create boundaries for layers or pl-lines. * create\_vertical(*x*)[](#Model2D.create_vertical "Link to this definition") Create vertical based on x-coordinate. * Parameters: **x** (`float`) – \[m] * Raises: [**ModelError**](/sdk/api/errors/.md#ModelError "viktor.errors.ModelError") – if x < left boundary limit or > right boundary limit * Return type: `_Vertical` ## OutputFileParser[​](/sdk/api/external/dsettlement/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.dsettlement.OutputFileParser(*sld\_file*)[](#OutputFileParser "Link to this definition") Helper class to extract results from a D-Settlement output file (.sld). Example usage: ``` parser = OutputFileParser(sld_file) vertical_results = parser.vertical_results residual_times = parser.residual_times ``` * *property *raw\_results*: str*[](#OutputFileParser.raw_results "Link to this definition") Raw result data. For convenience, specific data can also be extracted using available methods. - *property *residual\_times*: Dict\[int, Dict\[str, List\[float]]]*[](#OutputFileParser.residual_times "Link to this definition") Returns the residual times. Structure of dictionary: ``` { vertical number: int: { Time: List[float] Settlement: List[float] ... } } ``` * *property *vertical\_results*: Dict\[int, Dict\[str, Any]]*[](#OutputFileParser.vertical_results "Link to this definition") Returns results for all verticals. Structure of dictionary: ``` { vertical number: int: { coordinates: { x: float z: float }, time_settlement_per_load: { time_step_count: int load_step_count: int time: List[float] [days] load_1: List[float] [kPa] load_2: List[float] [kPa] ... (depending on model) }, depths: List[float] leakages: List[float] -> empty for some models drained_layers: List[float] -> empty for some models stresses: { -> empty for some models initial_total_stress: List[float] ... (depending on model) }, vertical_data: { time: float: { settlement: List[float] ... (depending on model) } }, } } ``` ## VerticalDrain[​](/sdk/api/external/dsettlement/.md#_VerticalDrain "Direct link to VerticalDrain") * *class *viktor.external.dsettlement.VerticalDrain(*drain\_type*, *range\_from*, *range\_to*, *bottom\_position*, *center\_to\_center*, *width\_diameter*, *thickness=None*, *position\_drain=None*, *grid=None*, *start\_of\_drainage=None*, *phreatic\_level\_in\_drain=None*, *schedule=None*)[](#VerticalDrain "Link to this definition") Data-class for setting vertical drain options. * Parameters: * **drain\_type** ([`DrainType`](#DrainType "viktor.external.dsettlement.DrainType")) – drain type. * **range\_from** (`float`) – range \[m] from which drainage takes place. * **range\_to** (`float`) – range \[m] to which drainage takes place. * **bottom\_position** (`float`) – position of bottom (depth) of drains \[m]. * **center\_to\_center** (`float`) – center-to-center distance of drains \[m]. * **width\_diameter** (`float`) – width (or diameter for drain\_type = COLUMN) of drains \[m]. * **thickness** (`float`) – thickness of strip \[m]. Must be set for drain\_type = STRIP. * **position\_drain** (`float`) – drain position \[m]. Must be set for drain\_type = SAND\_WALL (only if schedule is defined). * **grid** ([`DrainGrid`](#DrainGrid "viktor.external.dsettlement.DrainGrid")) – drain grid type. Must be set for drain\_type = STRIP | COLUMN. * **start\_of\_drainage** (`float`) – start time of drainage \[days]. Must be set for simple and no schedule. * **phreatic\_level\_in\_drain** (`float`) – phreatic level in drain \[m]. Must be set for simple and no schedule. * **schedule** (`Union`\[[`DrainageSimpleMode`](#DrainageSimpleMode "viktor.external.dsettlement.DrainageSimpleMode"), `List`\[`Tuple`\[`float`, `float`, `float`]]]) – DrainageSimpleMode for simple schedule; list of (time \[days], underpressure \[kPa], water head \[m] (if drain\_type = STRIP | COLUMN) / tube pressure \[kPa] (if drain\_type = SAND\_WALL)) for detailed schedule (default: no schedule). - *property *position\_drain*: float | None*[](#VerticalDrain.position_drain "Link to this definition") --- # viktor.external.dsheetpiling ## DSheetPilingAnalysis[​](/sdk/api/external/dsheetpiling/.md#_DSheetPilingAnalysis "Direct link to DSheetPilingAnalysis") * *class *viktor.external.dsheetpiling.DSheetPilingAnalysis(*input\_file*)[](#DSheetPilingAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DSheetPilingAnalysis can be used to perform an analysis using D-Sheet Piling on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DSheetPilingAnalysis.get_output_file "viktor.external.dsheetpiling.DSheetPilingAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` dsheetpiling_analysis = DSheetPilingAnalysis(input_file=input_file) dsheetpiling_analysis.execute(timeout=10) output_file = dsheetpiling_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – .shi input file. - get\_output\_file(*extension='.shd'*, *\**, *as\_file=False*)[](#DSheetPilingAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DSheetPilingAnalysis.get_output_file "viktor.external.dsheetpiling.DSheetPilingAnalysis.get_output_file") afterwards. * Parameters: * **extension** (`str`) – extension of the file you want to return; one of: ‘.shd’, ‘.shs’, ‘.shl’, ‘.sho’, ‘.error.log’, ‘.err’ * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.dstability ## DStabilityAnalysis[​](/sdk/api/external/dstability/.md#_DStabilityAnalysis "Direct link to DStabilityAnalysis") * *class *viktor.external.dstability.DStabilityAnalysis(*input\_file*)[](#DStabilityAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") DStabilityAnalysis can be used to perform an analysis using D-Stability on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#DStabilityAnalysis.get_output_file "viktor.external.dstability.DStabilityAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Example usage: ``` file = File() # create a writable File object path = Path(file.source) # request its path dstability_model.serialize(path) # let GEOLIB write to the file analysis = DStabilityAnalysis(input_file=file) # pass the file with content to DStabilityAnalysis analysis.execute(timeout=10) output_file = analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – File object with the body of the .stix input file. - get\_output\_file(*extension='.stix'*)[](#DStabilityAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#DStabilityAnalysis.get_output_file "viktor.external.dstability.DStabilityAnalysis.get_output_file") afterwards. * Parameters: **extension** (`str`) – extension of the file you want to return; ‘.stix’ * Return type: `Optional`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")] --- # viktor.external.dynamo ## DynamoAnalysis[​](/sdk/api/external/dynamo/.md#_DynamoAnalysis "Direct link to DynamoAnalysis") * *class *viktor.external.dynamo.DynamoAnalysis(*files=None*, *executable\_key='dynamo'*, *output\_filenames=None*)[](#DynamoAnalysis "Link to this definition") Bases: [`GenericAnalysis`](/sdk/api/external/generic/.md#GenericAnalysis "viktor.external.generic.GenericAnalysis") New in 14.17.0 DynamoAnalysis can be used to evaluate a matlab script on third-party infrastructure. The script is expected to be blocking, i.e. if the executable is invoked from command prompt, it should wait until the script is finished. For security purposes the executable that should be called has to be defined in the configuration file of the worker. Usage: ``` files = [ ('input1.txt', file1), ('input2.txt', file2) ] analysis = DynamoAnalysis(files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **files** (`Optional`\[`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]]) – Files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **executable\_key** (`str`) – The key of the executable that needs to be evaluated. This key should be present in the configuration file of the worker, defaults to run\_matlab. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the SDK. This filename is relative to the working directory. At least one of the attributes above should be included in the call. * Raises: **ValueError** – when no attribute is included in call. ## DynamoFile[​](/sdk/api/external/dynamo/.md#_DynamoFile "Direct link to DynamoFile") * *class *viktor.external.dynamo.DynamoFile(*file*)[](#DynamoFile "Link to this definition") Dynamo file instantiated from an existing input .dyn file. This class allows for easy transformation of input nodes by means of the [`update()`](#DynamoFile.update "viktor.external.dynamo.DynamoFile.update") method. * Parameters: **file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Dynamo input file (.dyn). - generate()[](#DynamoFile.generate "Link to this definition") Generate the (updated) Dynamo input file. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * get\_node\_id(*name*)[](#DynamoFile.get_node_id "Link to this definition") Retrieve the unique node id by name. * Parameters: **name** (`str`) – Name of the node. * Return type: `str` - update(*name*, *value*)[](#DynamoFile.update "Link to this definition") Update the value of an input node with specified name. * Parameters: * **name** (`str`) – Name of the input node. * **value** (`Any`) – New input value. * Return type: `None` ## convert\_geometry\_to\_glb[​](/sdk/api/external/dynamo/.md#_convert_geometry_to_glb "Direct link to convert_geometry_to_glb") * viktor.external.dynamo.convert\_geometry\_to\_glb(*file*, *filter=None*)[](#convert_geometry_to_glb "Link to this definition") Convert a Dynamo geometry file (.json) to a GLB file, which can directly be used in a [`GeometryResult`](/sdk/api/views/.md#GeometryResult "viktor.views.GeometryResult"). Filter specific geometric objects by id, obtained by calling [`get_node_id()`](#DynamoFile.get_node_id "viktor.external.dynamo.DynamoFile.get_node_id"): ``` input_file = DynamoFile(file) sphere_id = input_file.get_node_id("Sphere") # geometry node called "Sphere" ... geometry_file = dynamo_analysis.get_output_file(filename='geometry.json', as_file=True) # viktor.external.dynamo.DynamoAnalysis glb_file = convert_geometry_to_glb(geometry_file, filter=[sphere_id]) ``` * Parameters: * **file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Dynamo geometry file (.json). * **filter** (`List`\[`str`]) – Filter geometric objects by id (default: include all). * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") ## get\_dynamo\_result[​](/sdk/api/external/dynamo/.md#_get_dynamo_result "Direct link to get_dynamo_result") * viktor.external.dynamo.get\_dynamo\_result(*file*, *id\_*)[](#get_dynamo_result "Link to this definition") Extract results from a Dynamo output file (.xml) by means of a node ‘id’, which can be obtained by calling [`get_node_id()`](#DynamoFile.get_node_id "viktor.external.dynamo.DynamoFile.get_node_id"). Example using BytesIO: ``` input_file = DynamoFile(file) output_id = input_file.get_node_id("Area") # output node called "Area" ... output_file = dynamo_analysis.get_output_file(filename='output.xml') # viktor.external.dynamo.DynamoAnalysis result = get_dynamo_result(output_file, id_=output_id) ``` Example using [`File`](/sdk/api/core/.md#File "viktor.core.File"): ``` input_file = DynamoFile(file) output_id = input_file.get_node_id("Area") # output node called "Area" ... output_file = dynamo_analysis.get_output_file(filename='output.xml', as_file=True) # viktor.external.dynamo.DynamoAnalysis with output_file.open_binary() as f: result = get_dynamo_result(f, id_=output_id) ``` * Parameters: * **file** (`BinaryIO`) – Dynamo output file (.xml). * **id** – Unique identifier of the output result node. * Return type: `str` --- # viktor.external.etabs ## ETABSAnalysis[​](/sdk/api/external/etabs/.md#_ETABSAnalysis "Direct link to ETABSAnalysis") * *class *viktor.external.etabs.ETABSAnalysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#ETABSAnalysis "Link to this definition") Bases: [`PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis") New in 14.17.0 ETABSAnalysis can be used to evaluate an ETABS-python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "run_etabs.py") files = [ ('input1.txt', file1), ] analysis = ETABSAnalysis(script=script, files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. --- # viktor.external.excel ## Excel[​](/sdk/api/external/excel/.md#_Excel "Direct link to Excel") * *class *viktor.external.excel.Excel(*template*, *named\_input\_cells=None*, *direct\_input\_cells=None*, *macros=None*, *named\_output\_cells=None*, *direct\_output\_cells=None*, *extension='.xlsm'*, *typed\_results=False*)[](#Excel "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Excel can be used to perform an analysis of an Excel sheet using a third-party worker. This Excel sheet may contain macros (i.e. .xlsm extension). To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_named_cell_result()`](#Excel.get_named_cell_result "viktor.external.excel.Excel.get_named_cell_result") or [`get_direct_cell_result()`](#Excel.get_direct_cell_result "viktor.external.excel.Excel.get_direct_cell_result"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Example: ``` named_input_cells = [NamedInputCell('x', x)] direct_output_cells = [DirectOutputCell('Sheet1', 'B', 3)] excel_analysis = Excel(template, named_input_cells=named_input_cells, direct_output_cells=direct_output_cells, extension='.xlsx') excel_analysis.execute(timeout=10) result = excel.get_direct_cell_result('Sheet1', 'B', 3) ``` * Parameters: * **template** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Excel template to be filled, executed and returned. * **named\_input\_cells** (`List`\[[`NamedInputCell`](/sdk/api/external/spreadsheet/.md#NamedInputCell "viktor.external.spreadsheet.NamedInputCell")]) – A list of named cells containing input values. * **direct\_input\_cells** (`List`\[[`DirectInputCell`](/sdk/api/external/spreadsheet/.md#DirectInputCell "viktor.external.spreadsheet.DirectInputCell")]) – A list of direct cells containing input values. * **macros** (`List`\[[`Macro`](#Macro "viktor.external.excel.Macro")]) – A list of macros to be executed. The order of the list is preserved. This means the first macro in the list will be executed first, the second macro wil be executed second, etc. * **named\_output\_cells** (`List`\[[`NamedOutputCell`](/sdk/api/external/spreadsheet/.md#NamedOutputCell "viktor.external.spreadsheet.NamedOutputCell")]) – A list of named cells of which the result after evaluation is desired. * **direct\_output\_cells** (`List`\[[`DirectOutputCell`](/sdk/api/external/spreadsheet/.md#DirectOutputCell "viktor.external.spreadsheet.DirectOutputCell")]) – A list of direct cells of which the result after evaluation is desired. * **extension** (`str`) – Extension of the file you want to evaluate: ‘.xlsm’ | ‘.xlsx’. * **typed\_results** (`bool`) – Cell results are of the same type as spreadsheet, if False, all values are str Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * *property *error\_message*: str | None*[](#Excel.error_message "Link to this definition") The error string containing information from the Excel worker when available, None otherwise. - execute(*timeout=30*)[](#Excel.execute "Link to this definition") Run method to start an external Excel analysis using a VIKTOR worker. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **timeout** (`int`) – Timeout period in seconds. * Raises: * TimeoutError when timeout has been exceeded * ConnectionError if no worker installed or connected * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError") if no license is available * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError") if the external program cannot execute with the provided inputs * Return type: `None` * *property *filled\_template*: BytesIO*[](#Excel.filled_template "Link to this definition") A BytesIO object which contains the filled template if available, otherwise raises a SpreadsheetError. - get\_direct\_cell\_result(*sheet\_name*, *column*, *row*)[](#Excel.get_direct_cell_result "Link to this definition") Function which may be called after excel.execute(). It can be used to fetch the result of a direct cell. * Parameters: * **sheet\_name** (`str`) – Name of the worksheet of the desired cell. * **column** (`str`) – Name of the column of the desired cell. * **row** (`int`) – Name of the row of the desired cell. * Returns: The result contained in the cell corresponding to (sheet\_name, column, row). * Return type: Check `worker_version` to know which type of result is expected: * worker\_version < 1 returns the result with type str. * worker version >= 1 returns the result with type depending on cell type: > * cell type integer / long returns integer > > * cell type single / double / currency / decimal returns float > > * cell type string returns string > > * cell type boolean returns boolean > > * cell type date returns RFC 3339 format string (e.g. “1998-02-23T00:00:00Z”) * get\_filled\_template()[](#Excel.get_filled_template "Link to this definition") New in v13.5.0 Retrieve the filled-in template if available, otherwise raises a SpreadsheetError. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") - get\_named\_cell\_result(*name*)[](#Excel.get_named_cell_result "Link to this definition") Function which may be called after excel.execute(). It can be used to fetch the result of a named cell. * Parameters: **name** (`str`) – Name of the named cell of which the result is desired. * Returns: The result contained in the named cell corresponding to name. * Return type: Check `worker_version` to know which type of result is expected: * worker\_version < 1 returns the result with type str. * worker version >= 1 returns the result with type depending on cell type: > * cell type integer / long returns integer > > * cell type single / double / currency / decimal returns float > > * cell type string returns string > > * cell type boolean returns boolean > > * cell type date returns RFC 3339 format string (e.g. “1998-02-23T00:00:00Z”) * result\_available()[](#Excel.result_available "Link to this definition") * Return type: `bool` * Returns: True if excel has returned a result. Warning! This does not necessarily have to be a successful result. - *property *success*: bool | None*[](#Excel.success "Link to this definition") True if excel has returned a successful result, False if excel has returned an unsuccessful result, None otherwise. ## Macro[​](/sdk/api/external/excel/.md#_Macro "Direct link to Macro") * *class *viktor.external.excel.Macro(*command*)[](#Macro "Link to this definition") Class for defining an Excel macro. * Parameters: **command** (`str`) – the name of the Excel Macro command. - serialize()[](#Macro.serialize "Link to this definition") * Return type: `dict` --- # viktor.external.external\_program ## ExternalProgram[​](/sdk/api/external/external-program/.md#_ExternalProgram "Direct link to ExternalProgram") * *class *viktor.external.external\_program.ExternalProgram(*queue\_name*, *version*)[](#ExternalProgram "Link to this definition") Bases: `ABC` Warning Do not use this class directly in an application! Base-class of an external analysis. * Parameters: * **queue\_name** (`str`) – Name of the external integration. * **version** (`int`) – Version of the API between SDK <-> worker. - execute(*timeout=25*)[](#ExternalProgram.execute "Link to this definition") Run method to start an external analysis using a VIKTOR worker. Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **timeout** (`int`) – Timeout period in seconds. * Raises: * TimeoutError when timeout has been exceeded * ConnectionError if no worker installed or connected * LicenseError if no license is available * ExecutionError if the external program cannot execute with the provided inputs * Return type: `None` ## OAuth2Integration[​](/sdk/api/external/external-program/.md#_OAuth2Integration "Direct link to OAuth2Integration") * *class *viktor.external.external\_program.OAuth2Integration(*name*)[](#OAuth2Integration "Link to this definition") New in 14.23.0 Third-party OAuth 2.0 integration. Usage: ``` integration = vkt.external.OAuth2Integration('my-oauth2-integration') access_token = integration.get_access_token() # use access_token to do request on host URL associated with integration 'my-oauth2-integration' ``` * get\_access\_token()[](#OAuth2Integration.get_access_token "Link to this definition") Obtain the personal access token * Raises: * PermissionDeniedError: needs login from user * ResourceNotFoundError: integration not found * PreconditionFailedError: integration not assigned to this app * Return type: `str` --- # viktor.external.generic ## GenericAnalysis[​](/sdk/api/external/generic/.md#_GenericAnalysis "Direct link to GenericAnalysis") * *class *viktor.external.generic.GenericAnalysis(*files=None*, *executable\_key=None*, *output\_filenames=None*)[](#GenericAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") GenericAnalysis can be used to evaluate an executable on third-party infrastructure. The executable is expected to be blocking, i.e. if the executable is invoked from command prompt, it should wait until the executable is finished. For security purposes the executable that should be called has to be defined in the configuration file of the worker. Usage: ``` files = [ ('input1.txt', file1), ('input2.txt', file2) ] generic_analysis = GenericAnalysis(files=files, executable_key="someexecutable", output_filenames=["output.txt"]) generic_analysis.execute(timeout=60) output_file = generic_analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **files** (`Optional`\[`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]]) – Files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **executable\_key** (`str`) – The key of the executable that needs to be evaluated. This key should be present in the configuration file of the worker. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. * Raises: **ValueError** – when no attribute is included in call. - get\_output\_file(*filename*, *\**, *as\_file=False*)[](#GenericAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#GenericAnalysis.get_output_file "viktor.external.generic.GenericAnalysis.get_output_file") afterwards. * Parameters: * **filename** (`str`) – The name of the file (including extension) that you want to get. * **as\_file** (`bool`) – Return as BytesIO (default) or File * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.grasshopper ## GrasshopperAnalysis[​](/sdk/api/external/grasshopper/.md#_GrasshopperAnalysis "Direct link to GrasshopperAnalysis") * *class *viktor.external.grasshopper.GrasshopperAnalysis(*\**, *script*, *input\_parameters=None*)[](#GrasshopperAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") New in v14.8.0 Perform an analysis using Grasshopper on a remote server by means of a worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the output, call [`get_output()`](#GrasshopperAnalysis.get_output "viktor.external.grasshopper.GrasshopperAnalysis.get_output"). Usage: ``` my_input_parameters = { 'my_int': 1, 'my_bool': True, 'my_string': "test", 'my_list': [1, 2, 3], 'my_dict': {'{0;0;0}': [1], '{0;1;1}': [1, 2, 3]} } grasshopper_analysis = GrasshopperAnalysis(script=my_grasshopper_script, input_parameters=my_input_parameters) grasshopper_analysis.execute(timeout=10) output = grasshopper_analysis.get_output() ``` Exceptions which can be raised during calculation: > * [`ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Grasshopper script (.gh) * **input\_parameters** (`Dict`\[`str`, `Any`]) – Input parameters to be passed to the grasshopper script in the form of a float dict. Key names will be matched with the Hops parameter names in Grasshopper and substituted accordingly - get\_output()[](#GrasshopperAnalysis.get_output "Link to this definition") Retrieve the output generated by running the Grasshopper analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output()`](#GrasshopperAnalysis.get_output "viktor.external.grasshopper.GrasshopperAnalysis.get_output") afterward. The output is in the form: ``` { "absolutetolerance": float, "angletolerance": float, "modelunits": str, "algo": str, "pointer": str, "cachesolve": bool, "recursionlevel": int, "values": list[dict] "warnings": list[str], "errors": list[str] } ``` * Return type: `dict` --- # viktor.external.grlweap ## GRLWeapAnalysis[​](/sdk/api/external/grlweap/.md#_GRLWeapAnalysis "Direct link to GRLWeapAnalysis") * *class *viktor.external.grlweap.GRLWeapAnalysis(*input\_file*)[](#GRLWeapAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") GRLWeapAnalysis can be used to perform an analysis using GRLWeap on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#GRLWeapAnalysis.get_output_file "viktor.external.grlweap.GRLWeapAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` grlweap_analysis = GRLWeapAnalysis(input_file=gwt_file) grlweap_analysis.execute(timeout=10) result = grlweap_analysis.get_output_file() ``` Exceptions which can be raised during calculation: - [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – .gwt input file. - get\_output\_file(*\**, *as\_file=False*)[](#GRLWeapAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#GRLWeapAnalysis.get_output_file "viktor.external.grlweap.GRLWeapAnalysis.get_output_file") afterwards. * Parameters: **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] --- # viktor.external.idea ## Beam[​](/sdk/api/external/idea/.md#_Beam "Direct link to Beam") * *class *viktor.external.idea\_rcs.idea\_rcs.Beam(*rcs*, *check\_section*)[](#Beam "Link to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_beam()`](#Model.create_beam "viktor.external.idea_rcs.idea_rcs.Model.create_beam"). ## CompressionMember[​](/sdk/api/external/idea/.md#_CompressionMember "Direct link to CompressionMember") * *class *viktor.external.idea\_rcs.idea\_rcs.CompressionMember(*rcs*, *check\_section*)[](#CompressionMember "Link to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_compression_member()`](#Model.create_compression_member "viktor.external.idea_rcs.idea_rcs.Model.create_compression_member"). ## GeneralShape[​](/sdk/api/external/idea/.md#_GeneralShape "Direct link to GeneralShape") * *class *viktor.external.idea\_rcs.idea\_rcs.GeneralShape(*outline*, *\**, *openings=None*)[](#GeneralShape "Link to this definition") Bases: [`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D") General cross-section, defined by a set of coordinates. * Parameters: * **outline** (`Sequence`\[`Tuple`\[`float`, `float`]]) – Vertices which define the outline of the section (y, z). A minimum of 3 vertices is required, the outline is automatically closed. * **openings** (`Sequence`\[`Sequence`\[`Tuple`\[`float`, `float`]]]) – One or multiple openings, defined by vertices (y, z). A minimum of 3 vertices per opening is required, the opening is automatically closed. ## IdeaRcsAnalysis[​](/sdk/api/external/idea/.md#_IdeaRcsAnalysis "Direct link to IdeaRcsAnalysis") * *class *viktor.external.idea\_rcs.idea\_rcs.IdeaRcsAnalysis(*input\_file*, *\**, *return\_result\_xml=None*, *return\_rcs\_file=None*)[](#IdeaRcsAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Can be used to perform an analysis using IDEA StatiCa RCS on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_output_file()`](#IdeaRcsAnalysis.get_output_file "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis.get_output_file"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` idea_rcs_file = File.from_data("idea rcs input file content") idea_rcs_analysis = IdeaRcsAnalysis(input_file=idea_rcs_file) idea_rcs_analysis.execute(timeout=10) result = idea_rcs_analysis.get_output_file() ``` Exceptions which can be raised during calculation: > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – IDEA (Open)Model input XML file. * **return\_result\_xml** (`bool`) – Result .xml file will be available if set to True (default: True). * **return\_rcs\_file** (`bool`) – Input .ideaRcs file will be available if set to True (default: False). - get\_idea\_rcs\_file(*\**, *as\_file=False*)[](#IdeaRcsAnalysis.get_idea_rcs_file "Link to this definition") Method can be used to retrieve the .ideaRcs file which is converted from the (Open)Model input XML. The file is only available when return\_rcs\_file=True. [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * Returns: * File, if as\_file = True * BytesIO, if as\_file = False (default) * get\_output\_file(*\**, *as\_file=False*)[](#IdeaRcsAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. The file is only available when return\_result\_xml=True. [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * Returns: * File (encoding=’utf-16’), if as\_file = True * BytesIO (encoding=’utf-16’), if as\_file = False (default) ## Member[​](/sdk/api/external/idea/.md#_Member "Direct link to Member") * *class *viktor.external.idea\_rcs.idea\_rcs.Member(*rcs*, *check\_section*)[](#Member "Link to this definition") Base class of all member types. * *property *bars*: List\[[ReinforcedBar](/sdk/api/external/idea/.md#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")]*[](#Member.bars "Link to this definition") - create\_bar(*coordinates*, *diameter*, *material*)[](#Member.create_bar "Link to this definition") Create a reinforced bar on the reinforced cross-section. * Parameters: * **coordinates** (`Tuple`\[`float`, `float`]) – (X, Y) coordinate of the bar \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](/sdk/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * Return type: `None` * create\_bar\_layer(*\**, *origin*, *diameter*, *material*, *number\_of\_bars*, *delta\_y=None*, *delta\_z=None*)[](#Member.create_bar_layer "Link to this definition") Create multiple reinforced bars on the reinforced cross-section, positioned on a line. * Parameters: * **origin** (`Tuple`\[`float`, `float`]) – Origin point (Y, Z) \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](/sdk/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **number\_of\_bars** (`int`) – Number of bars (minimum of 2). * **delta\_y** (`float`) – Distance between origin bar and the last bar in y-direction \[m]. * **delta\_z** (`float`) – Distance between origin bar and the last bar in z-direction \[m]. * Return type: `None` - create\_extreme(*\**, *description=None*, *accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*)[](#Member.create_extreme "Link to this definition") Create an extreme case with corresponding internal forces on the beam for checking. * Parameters: * **description** (`str`) – Description of the extreme (default: ‘{section\_name} - E {i}’). New in v14.6.0 * **accidental** ([`LoadingULS`](/sdk/api/external/idea/.md#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Accidental loading. * **fatigue** ([`FatigueLoading`](/sdk/api/external/idea/.md#FatigueLoading "viktor.external.idea_rcs.objects.FatigueLoading")) – Fatigue loading. * **frequent** ([`LoadingSLS`](/sdk/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Frequent loading. * **fundamental** ([`LoadingULS`](/sdk/api/external/idea/.md#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Fundamental loading. * **characteristic** ([`LoadingSLS`](/sdk/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Characteristic loading. * **quasi\_permanent** ([`LoadingSLS`](/sdk/api/external/idea/.md#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Quasi-Permanent loading. * Return type: `None` * create\_stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[](#Member.create_stirrup "Link to this definition") Create a stirrup on the reinforced cross-section. * Parameters: * **points** (`Sequence`\[`Union`\[`Tuple`\[`float`, `float`], `Tuple`\[`Tuple`\[`float`, `float`], `Tuple`\[`float`, `float`]]]]) – Sequence of (X, Y) coordinates \[m] of the stirrup vertices, connected by straight line segments. For arc-segments use ((X\_end, Y\_end), (X\_on\_arc, Y\_on\_arc)). * **diameter** (`float`) – Diameter of the stirrup \[m]. * **material** ([`MatReinforcement`](/sdk/api/external/idea/.md#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **distance** (`float`) – Longitudinal distance between stirrups \[m]. * **shear\_check** (`bool`) – Take stirrup into account in shear check (default: False). * **torsion\_check** (`bool`) – Take stirrup into account in torsion check (default: False). * **mandrel\_diameter\_factor** (`float`) – Inner diameter of mandrel as multiple of stirrup diameter \[-] (default: 1.0). * **anchorage\_length** (`float`) – Anchorage length \[m] (default: 0.0). * Return type: `None` - *property *extremes*: List\[[CheckSectionExtreme](/sdk/api/external/idea/.md#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")]*[](#Member.extremes "Link to this definition") * *property *stirrups*: List\[[Stirrup](/sdk/api/external/idea/.md#Stirrup "viktor.external.idea_rcs.objects.Stirrup")]*[](#Member.stirrups "Link to this definition") ## Model[​](/sdk/api/external/idea/.md#_Model "Direct link to Model") * *class *viktor.external.idea\_rcs.idea\_rcs.Model(*\**, *project\_data=None*, *code\_settings=None*)[](#Model "Link to this definition") Bases: `_Model` Can be used to construct an IDEA-RCS model and generate its corresponding input XML file. This file can in turn be used as input of [`IdeaRcsAnalysis`](#IdeaRcsAnalysis "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis"). For a more detailed elaboration, please see the guide. Alternatively, you can use [`OpenModel`](#OpenModel "viktor.external.idea_rcs.idea_rcs.OpenModel"). Warning Use this binding at own risk. Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The Model does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Example usage: ``` # Initialize the model. model = Model() # empty model, or optionally pass ProjectData and/or CodeSettings # Create the desired material(s). cs_mat = model.create_concrete_material(ConcreteMaterial.C12_15) mat_reinf = model.create_reinforcement_material(ReinforcementMaterial.B_400A) # Create a beam (or other type of member) to be checked. cross_section = RectSection(0.5, 1.0) beam = model.create_beam(cross_section, cs_mat) # Create bars (and stirrups) as desired bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): beam.create_bar(coords, diameter, mat_reinf) # Add extreme(s) freq = LoadingSLS(ResultOfInternalForces(N=-100000, My=210000)) fund = LoadingULS(ResultOfInternalForces(N=-99999, My=200000)) beam.create_extreme(frequent=freq, fundamental=fund) # Generate the input XML file. input_xml = model.generate_xml_input() ``` * Parameters: * **project\_data** ([`ProjectData`](/sdk/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData")) – project\_data (default: IDEA-RCS default project\_data) * **code\_settings** ([`CodeSettings`](/sdk/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings")) – code and calculation settings (default: IDEA-RCS default settings) - project\_data[](#Model.project_data "Link to this definition") * code\_settings[](#Model.code_settings "Link to this definition") - generate\_xml\_input(*\**, *as\_file=False*)[](#Model.generate_xml_input "Link to this definition") Generates the input file XML representation of the IDEA-RCS model. Warning Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * create\_beam(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *design\_member\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[](#Model.create_beam "Link to this definition") Create a beam section. * Parameters: * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross-section prototype. * **material** ([`MatConcrete`](/sdk/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross-section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** ([`CalculationSetup`](/sdk/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`str`) – Name of the cross-section (default: ‘S{i}’). * **rcs\_name** (`str`) – Name of the reinforced cross-section (default: ‘R{i}’). * **design\_member\_name** (`str`) – Name of the design member (default: ‘M {i}’). New in v14.6.0 * **exposure\_classes** ([`ExposureClassesDataEc2`](/sdk/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`float`) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`float`) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`float`) – Percentage of relative humidity (default: 65). * Return type: [`Beam`](#Beam "viktor.external.idea_rcs.idea_rcs.Beam") - create\_compression\_member(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *design\_member\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[](#Model.create_compression_member "Link to this definition") Create a compression member section. * Parameters: * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross-section prototype. * **material** ([`MatConcrete`](/sdk/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross-section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** ([`CalculationSetup`](/sdk/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`str`) – Name of the cross-section (default: ‘S{i}’). * **rcs\_name** (`str`) – Name of the reinforced cross-section (default: ‘R{i}’). * **design\_member\_name** (`str`) – Name of the design member (default: ‘M {i}’). New in v14.6.0 * **exposure\_classes** ([`ExposureClassesDataEc2`](/sdk/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`float`) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`float`) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`float`) – Percentage of relative humidity (default: 65). * Return type: [`CompressionMember`](#CompressionMember "viktor.external.idea_rcs.idea_rcs.CompressionMember") * create\_concrete\_material(*base\_material*, *name=None*, *\**, *unit\_mass=2500*, *fck=None*, *stone\_diameter=0.016*, *cement\_class=ConcCementClass.R*, *aggregate\_type=ConcAggregateType.QUARTZITE*, *diagram\_type=ConcDiagramType.PARABOLIC*, *silica\_fume=False*, *plain\_concrete\_diagram=False*, *dep\_params=None*)[](#Model.create_concrete_material "Link to this definition") Create a concrete material, to be used in [`create_beam()`](#Model.create_beam "viktor.external.idea_rcs.idea_rcs.Model.create_beam") and similar methods. * Parameters: * **base\_material** ([`ConcreteMaterial`](/sdk/api/external/idea/.md#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")) – IDEA-RCS base material to start with. * **name** (`str`) – Name of the material (default: base\_material name). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 2500 kg/m3). * **fck** (`float`) – Characteristic compressive cylinder strength of concrete at 28 days \[MPa] (default: base\_material fck). * **stone\_diameter** (`float`) – Aggregate size (default: 16 mm). * **cement\_class** ([`ConcCementClass`](/sdk/api/external/idea/.md#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")) – Cement class (default: R). * **aggregate\_type** ([`ConcAggregateType`](/sdk/api/external/idea/.md#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")) – Aggregate type (default: Quartzite). * **diagram\_type** ([`ConcDiagramType`](/sdk/api/external/idea/.md#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")) – Type of stress-strain diagram for ULS calculation (default: Parabolic). * **silica\_fume** (`bool`) – Contains silica fume (default: False) (EN 1992-2:2008-07 only). * **plain\_concrete\_diagram** (`bool`) – Stress strain diagram with tension part (default: False). * **dep\_params** ([`ConcDependentParams`](/sdk/api/external/idea/.md#ConcDependentParams "viktor.external.idea_rcs.objects.ConcDependentParams")) – Collection of a series of dependent parameters (see ConcDependentParams for more info). If None, values will be calculated based on ‘fck’ (default: None). * Return type: [`MatConcreteEc2`](/sdk/api/external/idea/.md#MatConcreteEc2 "viktor.external.idea_rcs.objects.MatConcreteEc2") - create\_one\_way\_slab(*cs*, *material*, *\**, *calculation\_control=None*, *name=None*, *rcs\_name=None*, *design\_member\_name=None*, *exposure\_classes=None*, *coeff\_kx=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[](#Model.create_one_way_slab "Link to this definition") Create a one-way slab member section. * Parameters: * **cs** ([`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D")) – Cross-section prototype. * **material** ([`MatConcrete`](/sdk/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material for the cross-section (created by [`create_concrete_material()`](#Model.create_concrete_material "viktor.external.idea_rcs.idea_rcs.Model.create_concrete_material")). * **calculation\_control** ([`CalculationSetup`](/sdk/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **name** (`str`) – Name of the cross-section (default: ‘S{i}’). * **rcs\_name** (`str`) – Name of the reinforced cross-section (default: ‘R{i}’). * **design\_member\_name** (`str`) – Name of the design member (default: ‘M {i}’). New in v14.6.0 * **exposure\_classes** ([`ExposureClassesDataEc2`](/sdk/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")) – Corrosion exposure classes (default: no corrosion). * **coeff\_kx** (`float`) – (Dutch annex only) Coefficient k\_x acc. 7.3.1 (default: 1.0). * **creep\_coefficient** (`float`) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`float`) – Percentage of relative humidity (default: 65). * Return type: [`OneWaySlab`](#OneWaySlab "viktor.external.idea_rcs.idea_rcs.OneWaySlab") * create\_reinforcement\_material(*base\_material*, *name=None*, *\**, *unit\_mass=7850*, *e\_modulus=200000*, *fyk=None*, *ftk\_by\_fyk=None*, *epsuk=None*, *type\_=ReinfType.BARS*, *bar\_surface=BarSurface.RIBBED*, *class\_=ReinfClass.B*, *fabrication=ReinfFabrication.HOT\_ROLLED*, *diagram\_type=ReinfDiagramType.BILINEAR\_INCLINED*)[](#Model.create_reinforcement_material "Link to this definition") Create a reinforcement material, to be used in `create_reinforcement_bar()`. * Parameters: * **base\_material** ([`ReinforcementMaterial`](/sdk/api/external/idea/.md#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")) – IDEA-RCS base material to start with. * **name** (`str`) – Name of the material (default: base\_material name). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 7850 kg/m3). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 200000 MPa). * **fyk** (`float`) – Characteristic yield strength of reinforcement (default: base\_material fyk). * **ftk\_by\_fyk** (`float`) – factor k = ratio ftk / fyk (default: base\_material k). * **epsuk** (`float`) – Characteristic strain of reinforcement at maximum load - εuk \[x 1e-4]. * **type** – Type of reinforcement (default: Bars). * **bar\_surface** ([`BarSurface`](/sdk/api/external/idea/.md#BarSurface "viktor.external.idea_rcs.objects.BarSurface")) – Bar surface (default: Ribbed). * **class** – Class of reinforcement (default: B). * **fabrication** ([`ReinfFabrication`](/sdk/api/external/idea/.md#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")) – Fabrication of reinforcement (default: Hot rolled). * **diagram\_type** ([`ReinfDiagramType`](/sdk/api/external/idea/.md#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")) – Type of material diagram (default: Bilinear with an inclined top branch). * Return type: [`MatReinforcementEc2`](/sdk/api/external/idea/.md#MatReinforcementEc2 "viktor.external.idea_rcs.objects.MatReinforcementEc2") ## OneWaySlab[​](/sdk/api/external/idea/.md#_OneWaySlab "Direct link to OneWaySlab") * *class *viktor.external.idea\_rcs.idea\_rcs.OneWaySlab(*rcs*, *check\_section*)[](#OneWaySlab "Link to this definition") Bases: [`Member`](#Member "viktor.external.idea_rcs.idea_rcs.Member") Do not use this \_\_init\_\_ directly, but create the object by [`Model.create_one_way_slab()`](#Model.create_one_way_slab "viktor.external.idea_rcs.idea_rcs.Model.create_one_way_slab"). ## OpenModel[​](/sdk/api/external/idea/.md#_OpenModel "Direct link to OpenModel") * *class *viktor.external.idea\_rcs.idea\_rcs.OpenModel(*\**, *project\_data=None*, *code\_settings=None*)[](#OpenModel "Link to this definition") Bases: `_Model` Can be used to construct an IDEA-RCS model and generate its corresponding input XML file. This file can in turn be used as input of [`IdeaRcsAnalysis`](#IdeaRcsAnalysis "viktor.external.idea_rcs.idea_rcs.IdeaRcsAnalysis"). For a more elaborate example implementation, please see the guide. The OpenModel follows IDEA’s underlying API. Alternatively, you can use [`Model`](#Model "viktor.external.idea_rcs.idea_rcs.Model"). Warning Use this binding at own risk. Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Example usage: ``` # Initialize the model. model = OpenModel() # empty model, or optionally pass ProjectData and/or CodeSettings # Create the concrete section. mat = model.create_matconcrete_ec2(ConcreteMaterial.C12_15) cs = model.create_cross_section_parameter(name='cs', cross_section_type=CrossSectionType.RECT, material=mat, Width=2.0, Height=2.0) # Create the reinforced cross-section. rcs = model.create_reinforced_cross_section(name='rcs', cross_section=cs) # Create bars (and stirrups) as desired mat_reinf = model.create_matreinforcement_ec2(ReinforcementMaterial.B_400A) bar_locations = [(-0.101, -0.175), (0.101, -0.175), (0.101, 0.175), (-0.101, 0.175)] bar_diameters = [0.016, 0.016, 0.016, 0.016] for coords, diameter in zip(bar_locations, bar_diameters): rcs.create_bar(coords, diameter, mat_reinf) # Create a CheckMember. member = model.create_check_member1d() # 'Assign' the CheckMember to a CheckSection with the previously defined reinforced section and add extremes. check_section = model.add_check_section(description='S 1', check_member=member, reinf_section=rcs) freq = LoadingSLS(ResultOfInternalForces(N=-100000, My=210000)) fund = LoadingULS(ResultOfInternalForces(N=-99999, My=200000)) check_section.create_extreme(frequent=freq, fundamental=fund) # 'Assign' the necessary additional data to the CheckMember. model.add_member_data_ec2(member, MemberType.BEAM_SLAB, TwoWaySlabType.SHELL_AS_PLATE) # Generate the input XML file. input_xml = model.generate_xml_input() ``` * Parameters: * **project\_data** ([`ProjectData`](/sdk/api/external/idea/.md#ProjectData "viktor.external.idea_rcs.objects.ProjectData")) – project\_data (default: IDEA-RCS default project\_data) * **code\_settings** ([`CodeSettings`](/sdk/api/external/idea/.md#CodeSettings "viktor.external.idea_rcs.objects.CodeSettings")) – code and calculation settings (default: IDEA-RCS default settings) - project\_data[](#OpenModel.project_data "Link to this definition") * code\_settings[](#OpenModel.code_settings "Link to this definition") - generate\_xml\_input(*\**, *as\_file=False*)[](#OpenModel.generate_xml_input "Link to this definition") Generates the input file XML representation of the IDEA-RCS model. Warning Whether an input XML file represents a valid model is dependent on many things, e.g. on the combination of certain parameters. The OpenModel does not give any guarantees on this. It is therefore important to always validate your model by hand thoroughly, before using it in an automated way within your app! Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **as\_file** (`bool`) – return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * add\_check\_section(*check\_member*, *reinf\_section*, *description=None*)[](#OpenModel.add_check_section "Link to this definition") Adds a single section check on the given CheckMember. Note that [`add_member_data_ec2()`](#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2") must be called subsequently. * Parameters: * **check\_member** ([`CheckMember`](/sdk/api/external/idea/.md#CheckMember "viktor.external.idea_rcs.objects.CheckMember")) – CheckMember (created by [`create_check_member1d()`](#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d")). * **reinf\_section** ([`ReinforcedCrossSection`](/sdk/api/external/idea/.md#ReinforcedCrossSection "viktor.external.idea_rcs.objects.ReinforcedCrossSection")) – Reinforcement of cross-section (created by [`create_reinforced_cross_section()`](#OpenModel.create_reinforced_cross_section "viktor.external.idea_rcs.idea_rcs.OpenModel.create_reinforced_cross_section")). * **description** (`str`) – Description/name of the section (default: ‘S{i}’). * Return type: [`CheckSection`](/sdk/api/external/idea/.md#CheckSection "viktor.external.idea_rcs.objects.CheckSection") - add\_member\_data\_ec2(*member*, *member\_type*, *two\_way\_slab\_type*, *\**, *calculation\_setup=None*, *coeff\_kx\_for\_wmax=None*, *exposure\_class\_data=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[](#OpenModel.add_member_data_ec2 "Link to this definition") Adds a concrete member Ec2 data to the model. * Parameters: * **member** ([`CheckMember`](/sdk/api/external/idea/.md#CheckMember "viktor.external.idea_rcs.objects.CheckMember")) – CheckMember (created by [`create_check_member1d()`](#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d")). Should be previously added to a check section via [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **member\_type** ([`MemberType`](/sdk/api/external/idea/.md#MemberType "viktor.external.idea_rcs.objects.MemberType")) – Structural type of member. Must be a valid type corresponding to the reinf\_section assigned to the member in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **two\_way\_slab\_type** ([`TwoWaySlabType`](/sdk/api/external/idea/.md#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")) – Two-way slab type. Must be a valid type corresponding to the reinf\_section assigned to the member in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). * **calculation\_setup** ([`CalculationSetup`](/sdk/api/external/idea/.md#CalculationSetup "viktor.external.idea_rcs.objects.CalculationSetup")) – Calculation control settings (default: Capacity N-M(-M) | Shear | Interaction | Stress Limitation | Crack width | Detailing). * **coeff\_kx\_for\_wmax** (`float`) – (Dutch annex only) Coefficient kx to increase limited concrete crack (default: 1.0). * **exposure\_class\_data** ([`ExposureClassesDataEc2`](/sdk/api/external/idea/.md#ExposureClassesDataEc2 "viktor.external.idea_rcs.objects.ExposureClassesDataEc2")) – Exposure classes (default: no corrosion). * **creep\_coefficient** (`float`) – Final value of creep coefficient (default: calculated by IDEA-RCS). * **relative\_humidity** (`float`) – Percentage of relative humidity (default: 65). * Return type: `None` * create\_check\_member1d(*name=None*)[](#OpenModel.create_check_member1d "Link to this definition") Create a member 1D check, which can be used in [`add_check_section()`](#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section") and [`add_member_data_ec2()`](#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2"). * Return type: [`CheckMember1D`](/sdk/api/external/idea/.md#CheckMember1D "viktor.external.idea_rcs.objects.CheckMember1D") - create\_cross\_section\_component(*name=None*)[](#OpenModel.create_cross_section_component "Link to this definition") Create a cross-section object defined by one or multiple components and add it to the model. * Parameters: **name** (`str`) – Name of cross-section (default: ‘’). * Return type: [`CrossSectionComponent`](/sdk/api/external/idea/.md#CrossSectionComponent "viktor.external.idea_rcs.objects.CrossSectionComponent") * create\_cross\_section\_parameter(*cross\_section\_type*, *material*, *name=None*, *\*\*parameters*)[](#OpenModel.create_cross_section_parameter "Link to this definition") Create a cross-section object defined by parameters and add it to the model. * Parameters: * **cross\_section\_type** ([`CrossSectionType`](/sdk/api/external/idea/.md#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")) – Type of cross-section. * **material** ([`MatConcrete`](/sdk/api/external/idea/.md#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material (created by [`create_matconcrete_ec2()`](#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2")). * **name** (`str`) – Name of cross-section (default: ‘’). * **parameters** (`Any`) – keyword naming should correspond to chosen cross\_section\_type(!). * Return type: [`CrossSectionParameter`](/sdk/api/external/idea/.md#CrossSectionParameter "viktor.external.idea_rcs.objects.CrossSectionParameter") The following combinations of cross\_section\_type and parameters can be used (see the IDEA StatiCa interface for the naming convention): * [`O`](/sdk/api/external/idea/.md#CrossSectionType.O "viktor.external.idea_rcs.objects.CrossSectionType.O"): D * [`RECT`](/sdk/api/external/idea/.md#CrossSectionType.RECT "viktor.external.idea_rcs.objects.CrossSectionType.RECT"): Width, Height * [`TRAPEZOID`](/sdk/api/external/idea/.md#CrossSectionType.TRAPEZOID "viktor.external.idea_rcs.objects.CrossSectionType.TRAPEZOID"): H, Bb, Bt * [`IGN`](/sdk/api/external/idea/.md#CrossSectionType.IGN "viktor.external.idea_rcs.objects.CrossSectionType.IGN"): H, Bh, Bs, Ts, Th, Tw * [`IGH`](/sdk/api/external/idea/.md#CrossSectionType.IGH "viktor.external.idea_rcs.objects.CrossSectionType.IGH"): H, Bh, Bs, Ts, Th, Tw, Bfh, Tfh * [`BEAM_SHAPE_I_HAUNCH_CHAMFER`](/sdk/api/external/idea/.md#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER "viktor.external.idea_rcs.objects.CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER"): Bbf, Hbf, Hbfh, Bw, H, Htfh, Htf, Btf, Bwh * [`TG`](/sdk/api/external/idea/.md#CrossSectionType.TG "viktor.external.idea_rcs.objects.CrossSectionType.TG"): Height, Width, TopFlangeWidth, WallWidth * [`TTFH`](/sdk/api/external/idea/.md#CrossSectionType.TTFH "viktor.external.idea_rcs.objects.CrossSectionType.TTFH"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch * [`TGREV`](/sdk/api/external/idea/.md#CrossSectionType.TGREV "viktor.external.idea_rcs.objects.CrossSectionType.TGREV"): Height, Width, TopFlangeWidth, WallWidth * [`TCHAMFER_1`](/sdk/api/external/idea/.md#CrossSectionType.TCHAMFER_1 "viktor.external.idea_rcs.objects.CrossSectionType.TCHAMFER_1"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch2, WallHaunch2 * [`TCHAMFER_2`](/sdk/api/external/idea/.md#CrossSectionType.TCHAMFER_2 "viktor.external.idea_rcs.objects.CrossSectionType.TCHAMFER_2"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch2, WallHaunch1, WallHaunch2 * [`TWH`](/sdk/api/external/idea/.md#CrossSectionType.TWH "viktor.external.idea_rcs.objects.CrossSectionType.TWH"): Height, Width, TopFlangeWidth, WallWidth, WallHaunch * [`TTFHREV`](/sdk/api/external/idea/.md#CrossSectionType.TTFHREV "viktor.external.idea_rcs.objects.CrossSectionType.TTFHREV"): Height, Width, TopFlangeWidth, WallWidth, TopFlangeHaunch * [`TWHREV`](/sdk/api/external/idea/.md#CrossSectionType.TWHREV "viktor.external.idea_rcs.objects.CrossSectionType.TWHREV"): Height, Width, TopFlangeWidth, WallWidth, WallHaunch - create\_matconcrete\_ec2(*base\_material*, *name=None*, *\**, *e\_modulus=32800*, *g\_modulus=13667*, *poisson=0.2*, *unit\_mass=2500*, *specific\_heat=0.6*, *thermal\_expansion=1e-05*, *thermal\_conductivity=45*, *is\_default=False*, *order\_in\_code=1*, *thermal\_state=None*, *fck\_28=None*, *stone\_diameter=0.016*, *cement\_class=ConcCementClass.R*, *aggregate\_type=ConcAggregateType.QUARTZITE*, *diagram\_type=ConcDiagramType.PARABOLIC*, *silica\_fume=False*, *plain\_concrete\_diagram=False*, *dep\_params=None*)[](#OpenModel.create_matconcrete_ec2 "Link to this definition") Create a material concrete Ec2 object and add it to the model. * Parameters: * **base\_material** ([`ConcreteMaterial`](/sdk/api/external/idea/.md#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")) – IDEA-RCS base material to start with. * **name** (`str`) – Name of the material (default: base\_material name). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 32800 MPa). * **g\_modulus** (`float`) – Shear modulus \[MPa] (default: 13667 MPa). * **poisson** (`float`) – Poisson’s ratio (default: 0.2). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 2500 kg/m3). * **specific\_heat** (`float`) – Specific heat capacity (default: 0.6). * **thermal\_expansion** (`float`) – Thermal expansion \[1/K] (default: 1e-05). * **thermal\_conductivity** (`float`) – Thermal conductivity (default: 45). * **is\_default** (`bool`) – True if material is default material in IDEA-RCS code (default: False). * **order\_in\_code** (`int`) – Order of this material in the IDEA-RCS code (default: 1). * **thermal\_state** ([`ThermalState`](/sdk/api/external/idea/.md#ThermalState "viktor.external.idea_rcs.objects.ThermalState")) – Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain curvatures (default: ThermalState()). * **fck\_28** (`float`) – Characteristic compressive cylinder strength of concrete at 28 days \[MPa] (default: base\_material fck). * **stone\_diameter** (`float`) – Aggregate size (default: 16 mm). * **cement\_class** ([`ConcCementClass`](/sdk/api/external/idea/.md#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")) – Cement class (default: R). * **aggregate\_type** ([`ConcAggregateType`](/sdk/api/external/idea/.md#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")) – Aggregate type (default: Quartzite). * **diagram\_type** ([`ConcDiagramType`](/sdk/api/external/idea/.md#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")) – Type of stress-strain diagram for ULS calculation (default: Parabolic). * **silica\_fume** (`bool`) – Contains silica fume (default: False) (EN 1992-2:2008-07 only). * **plain\_concrete\_diagram** (`bool`) – Stress strain diagram with tension part (default: False). * **dep\_params** ([`ConcDependentParams`](/sdk/api/external/idea/.md#ConcDependentParams "viktor.external.idea_rcs.objects.ConcDependentParams")) – Collection of a series of dependent parameters (see ConcDependentParams for more info). If None, values will be calculated based on ‘fck’ (default: None). * Return type: [`MatConcreteEc2`](/sdk/api/external/idea/.md#MatConcreteEc2 "viktor.external.idea_rcs.objects.MatConcreteEc2") * create\_matreinforcement\_ec2(*base\_material*, *name=None*, *\**, *e\_modulus=200000*, *g\_modulus=83333*, *poisson=0.2*, *unit\_mass=7850*, *specific\_heat=0.6*, *thermal\_expansion=1e-05*, *thermal\_conductivity=45*, *is\_default=False*, *order\_in\_code=1*, *thermal\_state=None*, *bar\_surface=BarSurface.RIBBED*, *fyk=None*, *ftk\_by\_fyk=None*, *epsuk=None*, *ftk=None*, *class\_=ReinfClass.B*, *type\_=ReinfType.BARS*, *fabrication=ReinfFabrication.HOT\_ROLLED*, *diagram\_type=ReinfDiagramType.BILINEAR\_INCLINED*)[](#OpenModel.create_matreinforcement_ec2 "Link to this definition") Create a material reinforcement Ec2 object and add it to the model. * Parameters: * **base\_material** ([`ReinforcementMaterial`](/sdk/api/external/idea/.md#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")) – IDEA-RCS base material to start with. * **name** (`str`) – Name of the material (default: base\_material name). * **e\_modulus** (`float`) – Young’s modulus \[MPa] (default: 200000 MPa). * **g\_modulus** (`float`) – Shear modulus \[MPa] (default: 83333 MPa). * **poisson** (`float`) – Poisson’s ratio (default: 0.2). * **unit\_mass** (`float`) – Unit mass \[kg/m3] (default: 7850 kg/m3). * **specific\_heat** (`float`) – Specific heat capacity (default: 0.6). * **thermal\_expansion** (`float`) – Thermal expansion \[1/K] (default: 1e-05). * **thermal\_conductivity** (`float`) – Thermal conductivity (default: 45). * **is\_default** (`bool`) – True if material is default material in IDEA-RCS code (default: False). * **order\_in\_code** (`int`) – Order of this material in the IDEA-RCS code (default: 1). * **thermal\_state** ([`ThermalState`](/sdk/api/external/idea/.md#ThermalState "viktor.external.idea_rcs.objects.ThermalState")) – Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain curvatures (default: ThermalState()). * **bar\_surface** ([`BarSurface`](/sdk/api/external/idea/.md#BarSurface "viktor.external.idea_rcs.objects.BarSurface")) – Bar surface (default: Ribbed). * **fyk** (`float`) – Characteristic yield strength of reinforcement (default: base\_material fyk). * **ftk\_by\_fyk** (`float`) – factor k = ratio ftk / fyk (default: base\_material k). * **epsuk** (`float`) – Characteristic strain of reinforcement at maximum load - εuk \[x 1e-4]. * **ftk** (`float`) – Characteristic tensile strength of reinforcement (default: base\_material ftk). * **class** – Class of reinforcement (default: B). * **type** – Type of reinforcement (default: Bars). * **fabrication** ([`ReinfFabrication`](/sdk/api/external/idea/.md#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")) – Fabrication of reinforcement (default: Hot rolled). * **diagram\_type** ([`ReinfDiagramType`](/sdk/api/external/idea/.md#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")) – Type of material diagram (default: Bilinear with an inclined top branch). * Return type: [`MatReinforcementEc2`](/sdk/api/external/idea/.md#MatReinforcementEc2 "viktor.external.idea_rcs.objects.MatReinforcementEc2") - create\_reinforced\_cross\_section(*cross\_section*, *name=None*)[](#OpenModel.create_reinforced_cross_section "Link to this definition") Create a reinforced cross-section object and add it to the model. * Parameters: * **cross\_section** ([`CrossSection`](/sdk/api/external/idea/.md#CrossSection "viktor.external.idea_rcs.objects.CrossSection")) – Cross-section (created by [`create_cross_section_parameter()`](#OpenModel.create_cross_section_parameter "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_parameter") or [`create_cross_section_component()`](#OpenModel.create_cross_section_component "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_component")). * **name** (`str`) – Name of cross-section (default: ‘R{i}’). * Return type: [`ReinforcedCrossSection`](/sdk/api/external/idea/.md#ReinforcedCrossSection "viktor.external.idea_rcs.objects.ReinforcedCrossSection") ## OutputFileParser[​](/sdk/api/external/idea/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.idea\_rcs.idea\_rcs.OutputFileParser(*xml\_file*)[](#OutputFileParser "Link to this definition") Helper class to extract results from a IDEA-RCS output file (.xml). Note, for very large result files we advise to make use of [`RcsOutputFileParser`](#RcsOutputFileParser "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser") instead. * Parameters: **xml\_file** (`StringIO`) – valid IDEA-RCS XML output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘xml\_file’ can not be parsed (not a valid format). Example usage: ``` parser = OutputFileParser(xml_file) for section in parser.section_ids: capacity_results = parser.capacity_results(section) ... ``` In case you require results which are not supported, you can retrieve the raw results using the [`raw_results()`](#OutputFileParser.raw_results "viktor.external.idea_rcs.idea_rcs.OutputFileParser.raw_results") method. * capacity\_results(*section\_id*)[](#OutputFileParser.capacity_results "Link to this definition") Get the result of applied internal forces of all extremes for the section with provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`Dict`\[`str`, `Any`]]] See [`capacity()`](#RcsOutputFileParser.SectionResult.capacity "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.capacity") for return format. - crack\_width\_results(*section\_id*)[](#OutputFileParser.crack_width_results "Link to this definition") Get the crack width (short/long) results for all extremes for the section with provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`Dict`\[`str`, `Any`]]]]] See [`crack_width()`](#RcsOutputFileParser.SectionResult.crack_width "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.crack_width") for return format. * detailing\_results(*section\_id*)[](#OutputFileParser.detailing_results "Link to this definition") Get the unity checks of the longitudinal reinforcement and shear reinforcement for all extremes for the section with provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`float`]]]] See [`detailing()`](#RcsOutputFileParser.SectionResult.detailing "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.detailing") for return format. - fatigue\_results(*section\_id*)[](#OutputFileParser.fatigue_results "Link to this definition") Get the fatigue results for all extremes for the provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`dict`]] See [`fatigue()`](#RcsOutputFileParser.SectionResult.fatigue "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.fatigue") for return format. * raw\_results()[](#OutputFileParser.raw_results "Link to this definition") Get the (complete) raw results in dict form. Can be used if results need to be extracted that are not supported by the available methods. * Return type: `dict` - *property *section\_ids*: List\[int]*[](#OutputFileParser.section_ids "Link to this definition") Get all section ids for which results are present in the result file. * shear\_results(*section\_id*)[](#OutputFileParser.shear_results "Link to this definition") Get the shear resistances for all extremes for the section with provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`Dict`\[`str`, `Any`]]] See [`shear()`](#RcsOutputFileParser.SectionResult.shear "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.shear") for return format. - stress\_limitation\_results(*section\_id*)[](#OutputFileParser.stress_limitation_results "Link to this definition") Get the short- and long-term stress limitation results for all extremes for provided ‘section\_id’. * Parameters: **section\_id** (`int`) – id of the check section. Must be present in the output file. * Raises: [**ParsingError**](/sdk/api/errors/.md#ParsingError "viktor.errors.ParsingError") – if ‘section\_id’ is not present in output file. * Return type: `List`\[`Optional`\[`Dict`\[`str`, `Optional`\[`float`]]]] See [`stress_limitation()`](#RcsOutputFileParser.SectionResult.stress_limitation "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.stress_limitation") for return format. ## RcsOutputFileParser[​](/sdk/api/external/idea/.md#_RcsOutputFileParser "Direct link to RcsOutputFileParser") * *class *viktor.external.idea\_rcs.idea\_rcs.RcsOutputFileParser(*xml\_file*)[](#RcsOutputFileParser "Link to this definition") Parser to extract results from an IDEA-RCS output file (.xml). Currently the following data can be extracted: > * [`capacity()`](#RcsOutputFileParser.SectionResult.capacity "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.capacity") > > * [`shear()`](#RcsOutputFileParser.SectionResult.shear "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.shear") > > * [`torsion()`](#RcsOutputFileParser.SectionResult.torsion "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.torsion") (new in v13.4.0) > > * [`interaction()`](#RcsOutputFileParser.SectionResult.interaction "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.interaction") (new in v13.4.0) > > * [`crack_width()`](#RcsOutputFileParser.SectionResult.crack_width "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.crack_width") > > * [`detailing()`](#RcsOutputFileParser.SectionResult.detailing "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.detailing") > > * [`stress_limitation()`](#RcsOutputFileParser.SectionResult.stress_limitation "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.stress_limitation") > > * [`fatigue()`](#RcsOutputFileParser.SectionResult.fatigue "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult.fatigue") Example using [`File`](/sdk/api/core/.md#File "viktor.core.File"): ``` xml_file = idea_rcs_analysis.get_output_file(as_file=True) with xml_file.open_binary() as f: parser = RcsOutputFileParser(f) # loop through all sections for section in parser.section_results(): capacity_results = section.capacity() shear_results = section.shear() # or get results for a single section section_4 = parser.section_result(4) ... # or loop through all extremes within a section for extreme in section_4.extremes(): capacity = extreme['capacity'] ... ``` Example using BytesIO: ``` xml_file = idea_rcs_analysis.get_output_file() parser = RcsOutputFileParser(xml_file) for section in parser.section_results(): ... ``` * Parameters: **xml\_file** (`BinaryIO`) – IDEA-RCS XML output file (.xml). - *class *SectionResult(*id\_*, *element*)[](#RcsOutputFileParser.SectionResult "Link to this definition") Parsed result section, on which specific results can be retrieved. Do not instantiate this object directly, but retrieve it through [`RcsOutputFileParser.section_results()`](#RcsOutputFileParser.section_results "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.section_results"). * capacity()[](#RcsOutputFileParser.SectionResult.capacity "Link to this definition") Get the capacity results of all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Fu': { 'N': , 'Qy': , 'Qz': , 'Mx': , 'My': , 'Mz': }, 'Fu1': { ... # see 'Fu' } | None, 'Fu2': { ... # see 'Fu' } | None, 'CheckValue': , 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] - crack\_width()[](#RcsOutputFileParser.SectionResult.crack_width "Link to this definition") Get the crack width (short/long) results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'short': { 'N': , 'My': , 'Mz': , 'W': , 'Wlim': , 'CheckValue': , 'Result': # new in v13.4.0 } | None, 'long': { ... # see 'short' } | None, } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] * detailing()[](#RcsOutputFileParser.SectionResult.detailing "Link to this definition") Get the unity checks of the longitudinal reinforcement and shear reinforcement for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'longitudinal': | None, 'shear': | None, 'CheckValue': , # new in v13.4.0 'CheckValueLongReinf': , # new in v13.4.0 'CheckValueShearReinf': , # new in v13.4.0 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] - extremes()[](#RcsOutputFileParser.SectionResult.extremes "Link to this definition") Get all results combined per extreme for the current section. Returns a list of dictionaries in the following format: ``` [ { 'capacity': {...} | None, 'shear': {...} | None, 'torsion': {...} | None, # new in v13.4.0 'interaction': {...} | None, # new in v13.4.0 'crack_width': {...} | None, 'detailing': {...} | None, 'stress_limitation': {...} | None, 'fatigue': {...} | None, }, ... ] ``` * Return type: `List`\[`dict`] * fatigue()[](#RcsOutputFileParser.SectionResult.fatigue "Link to this definition") Get the fatigue results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'fatigue': { 'CheckValue': , 'DecisionMethod': , 'Result': # new in v13.4.0 }, 'shear': { 'max': { 'Ved': , 'Vrdc': , 'Vrd': , 'Vrdmax': , 'Vrdr': , 'Vrds': , 'CheckValue': , 'Result': # new in v13.4.0 }, 'min': { ... # see 'max' }, } } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] - *property *id\_*: int*[](#RcsOutputFileParser.SectionResult.id_ "Link to this definition") Returns the ‘SectionId’ of current section. * interaction()[](#RcsOutputFileParser.SectionResult.interaction "Link to this definition") New in v13.4.0 Get the interaction results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ned': , 'Medy': , 'Medz': , 'Ved': , 'Ted': , 'CheckValue': , 'CheckValueShearAndTorsion': , 'CheckValueShearTorsionAndBending': , 'Result': } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] - shear()[](#RcsOutputFileParser.SectionResult.shear "Link to this definition") Get the shear resistances for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ved': , 'Vrdc': , 'Vrd': , 'Vrdmax': , 'Vrdr': , 'Vrds': , 'CheckValue': , 'Result': # new in v13.4.0 } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] * stress\_limitation()[](#RcsOutputFileParser.SectionResult.stress_limitation "Link to this definition") Get the short- and long-term stress limitation results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Check_7_2_2_Concrete_fck': { # new in v13.4.0 'short': { 'Stress': | None, 'CheckValue': , 'Result': } | None, 'long': { ... # see 'short' } | None } | None, 'Check_7_2_3_Concrete_fck': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_7_2_5_Tendons_fpk': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_7_2_5_ReinforcementBars_fyk': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_5_10_3_2_Tendons': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'Check_5_10_2_1_1_Tendons': { # new in v13.4.0 ... # see 'Check_7_2_2_Concrete_fck' } | None, 'short': { 'Check_7_2_2_Concrete_fck': | None, ... # see above for all keys } | None, 'long': { 'Check_7_2_2_Concrete_fck': | None, ... # see above for all keys } | None, } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] - torsion()[](#RcsOutputFileParser.SectionResult.torsion "Link to this definition") New in v13.4.0 Get the torsion results for all extremes for the current section. Returns a list of dictionaries (or None if not present for a certain extreme) in the following format: ``` [ { 'Ted': , 'Trdc': , 'Trdmax': , 'Trds': , 'Trd': , 'CheckValue': , 'Result': } | None, ... ] ``` * Return type: `List`\[`Optional`\[`dict`]] * section\_result(*id\_*)[](#RcsOutputFileParser.section_result "Link to this definition") Retrieve the section result of the provided id. * Return type: [`SectionResult`](#RcsOutputFileParser.SectionResult "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult") - section\_results()[](#RcsOutputFileParser.section_results "Link to this definition") Iterates through all section results. Usage: ``` for section in parser.section_results(): capacity_results = section.capacity() if section.id_ == 3: ... ``` * Return type: `Iterator`\[[`SectionResult`](#RcsOutputFileParser.SectionResult "viktor.external.idea_rcs.idea_rcs.RcsOutputFileParser.SectionResult")] ## RectSection[​](/sdk/api/external/idea/.md#_RectSection "Direct link to RectSection") * *class *viktor.external.idea\_rcs.idea\_rcs.RectSection(*width*, *height*)[](#RectSection "Link to this definition") Bases: [`SectionPrototype1D`](#SectionPrototype1D "viktor.external.idea_rcs.idea_rcs.SectionPrototype1D") Rectangular section. The origin is located in the centroid of this section. * Parameters: * **width** (`float`) – Width of the section. * **height** (`float`) – Height of the section. ## SectionPrototype1D[​](/sdk/api/external/idea/.md#_SectionPrototype1D "Direct link to SectionPrototype1D") * *class *viktor.external.idea\_rcs.idea\_rcs.SectionPrototype1D[](#SectionPrototype1D "Link to this definition") Bases: `_SectionPrototype`, `ABC` Abstract base class of all 1D (beam-like) section prototypes. ## BarSurface[​](/sdk/api/external/idea/.md#_BarSurface "Direct link to BarSurface") * *class *viktor.external.idea\_rcs.objects.BarSurface(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#BarSurface "Link to this definition") Bases: `Enum` * RIBBED*: [`BarSurface`](#BarSurface "viktor.external.idea_rcs.objects.BarSurface")** = 1*[](#BarSurface.RIBBED "Link to this definition") - SMOOTH*: [`BarSurface`](#BarSurface "viktor.external.idea_rcs.objects.BarSurface")** = 0*[](#BarSurface.SMOOTH "Link to this definition") ## CalculationSetup[​](/sdk/api/external/idea/.md#_CalculationSetup "Direct link to CalculationSetup") * *class *viktor.external.idea\_rcs.objects.CalculationSetup(*\**, *uls\_response=None*, *uls\_diagram=None*, *uls\_shear=None*, *uls\_torsion=None*, *uls\_interaction=None*, *sls\_crack=None*, *sls\_stress\_limitation=None*, *sls\_stiffnesses=None*, *detailing=None*, *m\_n\_kappa\_diagram=None*, *fatigue=None*, *cross\_section\_characteristics=None*)[](#CalculationSetup "Link to this definition") Bases: `_OpenObject` Concrete calculation setup. * Parameters: * **uls\_response** (`bool`) – Response N-M(-M) (default: False). * **uls\_diagram** (`bool`) – Capacity N-M(-M) (default: True). * **uls\_shear** (`bool`) – Shear (default: True). * **uls\_torsion** (`bool`) – Torsion (default: True). * **uls\_interaction** (`bool`) – Interaction (default: True). * **sls\_crack** (`bool`) – Crack width (default: True). * **sls\_stress\_limitation** (`bool`) – Stress limitation (default: True). * **sls\_stiffnesses** (`bool`) – Stiffnesses (default: False). * **detailing** (`bool`) – Detailing (default: True). * **m\_n\_kappa\_diagram** (`bool`) – M-N-κ diagram (default: False). * **fatigue** (`bool`) – Fatigue (default: True). * **cross\_section\_characteristics** (`bool`) – Cross-section characteristics (default: IDEA-RCS default). ## CheckMember[​](/sdk/api/external/idea/.md#_CheckMember "Direct link to CheckMember") * *class *viktor.external.idea\_rcs.objects.CheckMember(*id\_*)[](#CheckMember "Link to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all check members. ## CheckMember1D[​](/sdk/api/external/idea/.md#_CheckMember1D "Direct link to CheckMember1D") * *class *viktor.external.idea\_rcs.objects.CheckMember1D(*id\_*, *name*)[](#CheckMember1D "Link to this definition") Bases: [`CheckMember`](#CheckMember "viktor.external.idea_rcs.objects.CheckMember") Do not use this \_\_init\_\_ directly, but create the object by [`create_check_member1d()`](/sdk/api/external/idea/.md#OpenModel.create_check_member1d "viktor.external.idea_rcs.idea_rcs.OpenModel.create_check_member1d"). ## CheckSection[​](/sdk/api/external/idea/.md#_CheckSection "Direct link to CheckSection") * *class *viktor.external.idea\_rcs.objects.CheckSection(*id\_*, *description*, *check\_member*, *reinf\_section*, *extremes=None*)[](#CheckSection "Link to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all check sections. * create\_extreme(*\**, *description=None*, *accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*)[](#CheckSection.create_extreme "Link to this definition") Create an extreme case with corresponding internal forces on the section for checking. * Parameters: * **description** (`str`) – Description of the extreme (default: ‘{section\_name} - E {i}’). New in v14.6.0 * **accidental** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Accidental loading. * **fatigue** ([`FatigueLoading`](#FatigueLoading "viktor.external.idea_rcs.objects.FatigueLoading")) – Fatigue loading. * **frequent** ([`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Frequent loading. * **fundamental** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Fundamental loading. * **characteristic** ([`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Characteristic loading. * **quasi\_permanent** ([`LoadingSLS`](#LoadingSLS "viktor.external.idea_rcs.objects.LoadingSLS")) – Quasi-Permanent loading. * Return type: `None` - *property *extremes*: List\[[CheckSectionExtreme](#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme")]*[](#CheckSection.extremes "Link to this definition") ## CheckSectionExtreme[​](/sdk/api/external/idea/.md#_CheckSectionExtreme "Direct link to CheckSectionExtreme") * *class *viktor.external.idea\_rcs.objects.CheckSectionExtreme(*accidental=None*, *fatigue=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*, *\**, *description*)[](#CheckSectionExtreme "Link to this definition") Bases: `_OpenObject` Abstract base class of all check section extremes. ## CodeSettings[​](/sdk/api/external/idea/.md#_CodeSettings "Direct link to CodeSettings") * *class *viktor.external.idea\_rcs.objects.CodeSettings(*\**, *evaluation\_interaction\_diagram=None*, *theta=None*, *theta\_min=None*, *theta\_max=None*, *n\_cycles\_fatigue=None*, *no\_resistance\_concrete\_tension\_1d=None*, *type\_sls\_calculation=None*)[](#CodeSettings "Link to this definition") Bases: `_OpenObject` Code and calculation settings. * Parameters: * **evaluation\_interaction\_diagram** ([`EvaluationInteractionDiagram`](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")) – evaluation of interaction diagram (default: NuMuMu) * **theta** (`float`) – angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **theta\_min** (`float`) – minimum angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **theta\_max** (`float`) – maximum angle \[deg] between the concrete compression strut and the beam axis perpendicular to the shear force (default: set by IDEA) * **n\_cycles\_fatigue** (`float`) – number of fatigue cycles (\* 10⁶) (default: set by IDEA) * **no\_resistance\_concrete\_tension\_1d** ([`NoResistanceConcreteTension1d`](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")) – no resistance of concrete in tension - members 1D (default: Extreme) * **type\_sls\_calculation** ([`TypeSLSCalculation`](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")) – type of SLS calculation (default: Both) ## ConcAggregateType[​](/sdk/api/external/idea/.md#_ConcAggregateType "Direct link to ConcAggregateType") * *class *viktor.external.idea\_rcs.objects.ConcAggregateType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConcAggregateType "Link to this definition") Bases: `Enum` * BASALT*: [`ConcAggregateType`](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 3*[](#ConcAggregateType.BASALT "Link to this definition") - LIMESTONE*: [`ConcAggregateType`](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 1*[](#ConcAggregateType.LIMESTONE "Link to this definition") * QUARTZITE*: [`ConcAggregateType`](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 0*[](#ConcAggregateType.QUARTZITE "Link to this definition") - SANDSTONE*: [`ConcAggregateType`](#ConcAggregateType "viktor.external.idea_rcs.objects.ConcAggregateType")** = 2*[](#ConcAggregateType.SANDSTONE "Link to this definition") ## ConcCementClass[​](/sdk/api/external/idea/.md#_ConcCementClass "Direct link to ConcCementClass") * *class *viktor.external.idea\_rcs.objects.ConcCementClass(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConcCementClass "Link to this definition") Bases: `Enum` * N*: [`ConcCementClass`](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 2*[](#ConcCementClass.N "Link to this definition") - R*: [`ConcCementClass`](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 1*[](#ConcCementClass.R "Link to this definition") * S*: [`ConcCementClass`](#ConcCementClass "viktor.external.idea_rcs.objects.ConcCementClass")** = 0*[](#ConcCementClass.S "Link to this definition") ## ConcDependentParams[​](/sdk/api/external/idea/.md#_ConcDependentParams "Direct link to ConcDependentParams") * *class *viktor.external.idea\_rcs.objects.ConcDependentParams(*E\_cm*, *eps\_c1*, *eps\_c2*, *eps\_c3*, *eps\_cu1*, *eps\_cu2*, *eps\_cu3*, *F\_ctm*, *F\_ctk\_0\_05*, *F\_ctk\_0\_95*, *n\_factor*, *F\_cm*)[](#ConcDependentParams "Link to this definition") Bases: `_OpenObject` Collection of all MatConcreteEc2 dependent parameters. * Parameters: * **E\_cm** (`float`) – Secant modulus of elasticity of concrete \[MPa] * **eps\_c1** (`float`) – Compressive strain in the concrete - εc1 \[-] * **eps\_c2** (`float`) – Compressive strain in the concrete - εc2 \[-] * **eps\_c3** (`float`) – Compressive strain in the concrete - εc3 \[-] * **eps\_cu1** (`float`) – Ultimate compressive strain in the concrete - εcu1 \[-] * **eps\_cu2** (`float`) – Ultimate compressive strain in the concrete - εcu2 \[-] * **eps\_cu3** (`float`) – Ultimate compressive strain in the concrete - εcu3 \[-] * **F\_ctm** (`float`) – Mean value of axial tensile strength of concrete \[MPa] * **F\_ctk\_0\_05** (`float`) – Characteristic axial tensile strength of concrete 5% quantile \[MPa] * **F\_ctk\_0\_95** (`float`) – Characteristic axial tensile strength of concrete 95% quantile \[MPa] * **n\_factor** (`float`) – Coefficient n-factor - necessary parabolic part of stress-strain diagram - n \[-] * **F\_cm** (`float`) – Mean value of concrete cylinder compressive strength \[MPa] ## ConcDiagramType[​](/sdk/api/external/idea/.md#_ConcDiagramType "Direct link to ConcDiagramType") * *class *viktor.external.idea\_rcs.objects.ConcDiagramType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConcDiagramType "Link to this definition") Bases: `Enum` * BILINEAR*: [`ConcDiagramType`](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 0*[](#ConcDiagramType.BILINEAR "Link to this definition") - PARABOLIC*: [`ConcDiagramType`](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 1*[](#ConcDiagramType.PARABOLIC "Link to this definition") * USER*: [`ConcDiagramType`](#ConcDiagramType "viktor.external.idea_rcs.objects.ConcDiagramType")** = 2*[](#ConcDiagramType.USER "Link to this definition") ## ConcreteMaterial[​](/sdk/api/external/idea/.md#_ConcreteMaterial "Direct link to ConcreteMaterial") * *class *viktor.external.idea\_rcs.objects.ConcreteMaterial(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ConcreteMaterial "Link to this definition") Bases: `Enum` * C100\_115*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 15*[](#ConcreteMaterial.C100_115 "Link to this definition") - C12\_15*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 1*[](#ConcreteMaterial.C12_15 "Link to this definition") * C16\_20*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 2*[](#ConcreteMaterial.C16_20 "Link to this definition") - C20\_25*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 3*[](#ConcreteMaterial.C20_25 "Link to this definition") * C25\_30*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 4*[](#ConcreteMaterial.C25_30 "Link to this definition") - C30\_37*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 5*[](#ConcreteMaterial.C30_37 "Link to this definition") * C35\_45*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 6*[](#ConcreteMaterial.C35_45 "Link to this definition") - C40\_50*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 7*[](#ConcreteMaterial.C40_50 "Link to this definition") * C45\_55*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 8*[](#ConcreteMaterial.C45_55 "Link to this definition") - C50\_60*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 9*[](#ConcreteMaterial.C50_60 "Link to this definition") * C55\_67*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 10*[](#ConcreteMaterial.C55_67 "Link to this definition") - C60\_75*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 11*[](#ConcreteMaterial.C60_75 "Link to this definition") * C70\_85*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 12*[](#ConcreteMaterial.C70_85 "Link to this definition") - C80\_95*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 13*[](#ConcreteMaterial.C80_95 "Link to this definition") * C90\_105*: [`ConcreteMaterial`](#ConcreteMaterial "viktor.external.idea_rcs.objects.ConcreteMaterial")** = 14*[](#ConcreteMaterial.C90_105 "Link to this definition") ## ConcreteMemberData[​](/sdk/api/external/idea/.md#_ConcreteMemberData "Direct link to ConcreteMemberData") * *class *viktor.external.idea\_rcs.objects.ConcreteMemberData(*element*, *member\_type*, *two\_way\_slab\_type*, *calculation\_setup=None*)[](#ConcreteMemberData "Link to this definition") Bases: `_OpenObject`, `ABC` Abstract base class of all concrete member data. ## ConcreteMemberDataEc2[​](/sdk/api/external/idea/.md#_ConcreteMemberDataEc2 "Direct link to ConcreteMemberDataEc2") * *class *viktor.external.idea\_rcs.objects.ConcreteMemberDataEc2(*element*, *member\_type*, *two\_way\_slab\_type*, *calculation\_setup=None*, *coeff\_kx\_for\_wmax=None*, *exposure\_class\_data=None*, *creep\_coefficient=None*, *relative\_humidity=None*)[](#ConcreteMemberDataEc2 "Link to this definition") Bases: [`ConcreteMemberData`](#ConcreteMemberData "viktor.external.idea_rcs.objects.ConcreteMemberData") Do not use this \_\_init\_\_ directly, but create the object by [`add_member_data_ec2()`](/sdk/api/external/idea/.md#OpenModel.add_member_data_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.add_member_data_ec2"). ## CrossSection[​](/sdk/api/external/idea/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.idea\_rcs.objects.CrossSection(*id\_*, *name*)[](#CrossSection "Link to this definition") Bases: `_OpenElementId`, `ABC` Abstract base class of all cross-sections. ## CrossSectionComponent[​](/sdk/api/external/idea/.md#_CrossSectionComponent "Direct link to CrossSectionComponent") * *class *viktor.external.idea\_rcs.objects.CrossSectionComponent(*id\_*, *name*)[](#CrossSectionComponent "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.idea_rcs.objects.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_section_component()`](/sdk/api/external/idea/.md#OpenModel.create_cross_section_component "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_component"). * create\_component(*outline*, *material*, *\**, *openings=None*)[](#CrossSectionComponent.create_component "Link to this definition") Create a component to build up the cross-section. * Parameters: * **outline** (`Sequence`\[`Tuple`\[`float`, `float`]]) – Vertices which define the outline of the section (y, z). A minimum of 3 vertices is required, the outline is automatically closed. * **material** ([`MatConcrete`](#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete")) – Material (created by [`create_matconcrete_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2")). * **openings** (`Sequence`\[`Sequence`\[`Tuple`\[`float`, `float`]]]) – One or multiple openings, defined by vertices (y, z). A minimum of 3 vertices per opening is required, the opening is automatically closed. * Return type: `None` ## CrossSectionParameter[​](/sdk/api/external/idea/.md#_CrossSectionParameter "Direct link to CrossSectionParameter") * *class *viktor.external.idea\_rcs.objects.CrossSectionParameter(*id\_*, *name*, *cross\_section\_type*, *material*, *\*\*parameters*)[](#CrossSectionParameter "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.idea_rcs.objects.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_section_parameter()`](/sdk/api/external/idea/.md#OpenModel.create_cross_section_parameter "viktor.external.idea_rcs.idea_rcs.OpenModel.create_cross_section_parameter"). ## CrossSectionType[​](/sdk/api/external/idea/.md#_CrossSectionType "Direct link to CrossSectionType") * *class *viktor.external.idea\_rcs.objects.CrossSectionType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CrossSectionType "Link to this definition") Bases: `Enum` * BEAM\_SHAPE\_BOX*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 79*[](#CrossSectionType.BEAM_SHAPE_BOX "Link to this definition") - BEAM\_SHAPE\_BOX\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 80*[](#CrossSectionType.BEAM_SHAPE_BOX_1 "Link to this definition") * BEAM\_SHAPE\_IREV\_DEGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 83*[](#CrossSectionType.BEAM_SHAPE_IREV_DEGEN "Link to this definition") - BEAM\_SHAPE\_IREV\_DEGEN\_ADD*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 84*[](#CrossSectionType.BEAM_SHAPE_IREV_DEGEN_ADD "Link to this definition") * BEAM\_SHAPE\_I\_HAUNCH\_CHAMFER*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 76*[](#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER "Link to this definition") - BEAM\_SHAPE\_I\_HAUNCH\_CHAMFER\_ASYM*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 77*[](#CrossSectionType.BEAM_SHAPE_I_HAUNCH_CHAMFER_ASYM "Link to this definition") * BEAM\_SHAPE\_I\_Z\_DEGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 88*[](#CrossSectionType.BEAM_SHAPE_I_Z_DEGEN "Link to this definition") - BEAM\_SHAPE\_L\_DEGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 89*[](#CrossSectionType.BEAM_SHAPE_L_DEGEN "Link to this definition") * BEAM\_SHAPE\_REV\_U*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 78*[](#CrossSectionType.BEAM_SHAPE_REV_U "Link to this definition") - BEAM\_SHAPE\_TREV\_CHAMFER\_HAUNCH\_D*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 82*[](#CrossSectionType.BEAM_SHAPE_TREV_CHAMFER_HAUNCH_D "Link to this definition") * BEAM\_SHAPE\_TREV\_CHAMFER\_HAUNCH\_S*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 81*[](#CrossSectionType.BEAM_SHAPE_TREV_CHAMFER_HAUNCH_S "Link to this definition") - BEAM\_SHAPE\_TREV\_DEGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 85*[](#CrossSectionType.BEAM_SHAPE_TREV_DEGEN "Link to this definition") * BEAM\_SHAPE\_TREV\_DEGEN\_ADD*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 86*[](#CrossSectionType.BEAM_SHAPE_TREV_DEGEN_ADD "Link to this definition") - BEAM\_SHAPE\_Z\_DEGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 87*[](#CrossSectionType.BEAM_SHAPE_Z_DEGEN "Link to this definition") * BOX\_2I*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 18*[](#CrossSectionType.BOX_2I "Link to this definition") - BOX\_2L*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 21*[](#CrossSectionType.BOX_2L "Link to this definition") * BOX\_2U*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 19*[](#CrossSectionType.BOX_2U "Link to this definition") - BOX\_2U\_2PI*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 20*[](#CrossSectionType.BOX_2U_2PI "Link to this definition") * BOX\_4L*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 22*[](#CrossSectionType.BOX_4L "Link to this definition") - BOX\_FL*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 16*[](#CrossSectionType.BOX_FL "Link to this definition") * BOX\_WEB*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 17*[](#CrossSectionType.BOX_WEB "Link to this definition") - CHS\_G*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 34*[](#CrossSectionType.CHS_G "Link to this definition") * CHS\_PAR*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 101*[](#CrossSectionType.CHS_PAR "Link to this definition") - COMPOSITE\_BEAM\_BOX*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 53*[](#CrossSectionType.COMPOSITE_BEAM_BOX "Link to this definition") * COMPOSITE\_BEAM\_BOX\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 54*[](#CrossSectionType.COMPOSITE_BEAM_BOX_1 "Link to this definition") - COMPOSITE\_BEAM\_IGEN\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 55*[](#CrossSectionType.COMPOSITE_BEAM_IGEN_T "Link to this definition") * COMPOSITE\_BEAM\_L\_LEFT*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 56*[](#CrossSectionType.COMPOSITE_BEAM_L_LEFT "Link to this definition") - COMPOSITE\_BEAM\_PLATE*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 57*[](#CrossSectionType.COMPOSITE_BEAM_PLATE "Link to this definition") * COMPOSITE\_BEAM\_R\_RES\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 58*[](#CrossSectionType.COMPOSITE_BEAM_R_RES_T "Link to this definition") - COMPOSITE\_BEAM\_R\_RES\_T\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 59*[](#CrossSectionType.COMPOSITE_BEAM_R_RES_T_1 "Link to this definition") * COMPOSITE\_BEAM\_R\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 60*[](#CrossSectionType.COMPOSITE_BEAM_R_T "Link to this definition") - COMPOSITE\_BEAM\_SHAPE\_CHAMF*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 61*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_CHAMF "Link to this definition") * COMPOSITE\_BEAM\_SHAPE\_CHAMF\_ASYM*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 62*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_CHAMF_ASYM "Link to this definition") - COMPOSITE\_BEAM\_SHAPE\_IGEN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 63*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_IGEN "Link to this definition") * COMPOSITE\_BEAM\_SHAPE\_I\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 64*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_I_T "Link to this definition") - COMPOSITE\_BEAM\_SHAPE\_I\_T\_ASYM*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 65*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_I_T_ASYM "Link to this definition") * COMPOSITE\_BEAM\_SHAPE\_T\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 75*[](#CrossSectionType.COMPOSITE_BEAM_SHAPE_T_T "Link to this definition") - COMPOSITE\_BEAM\_TRAPEZOID*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 67*[](#CrossSectionType.COMPOSITE_BEAM_TRAPEZOID "Link to this definition") * COMPOSITE\_BEAM\_TRES\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 68*[](#CrossSectionType.COMPOSITE_BEAM_TRES_T "Link to this definition") - COMPOSITE\_BEAM\_TREV*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 69*[](#CrossSectionType.COMPOSITE_BEAM_TREV "Link to this definition") * COMPOSITE\_BEAM\_TREV\_RES\_I*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 70*[](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_I "Link to this definition") - COMPOSITE\_BEAM\_TREV\_RES\_I\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 71*[](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_I_1 "Link to this definition") * COMPOSITE\_BEAM\_TREV\_RES\_R*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 72*[](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_R "Link to this definition") - COMPOSITE\_BEAM\_TREV\_RES\_R\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 73*[](#CrossSectionType.COMPOSITE_BEAM_TREV_RES_R_1 "Link to this definition") * COMPOSITE\_BEAM\_TREV\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 74*[](#CrossSectionType.COMPOSITE_BEAM_TREV_T "Link to this definition") - COMPOSITE\_BEAM\_T\_LEFT*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 66*[](#CrossSectionType.COMPOSITE_BEAM_T_LEFT "Link to this definition") * GENERAL*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 38*[](#CrossSectionType.GENERAL "Link to this definition") - GENERAL\_CONCRETE*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 52*[](#CrossSectionType.GENERAL_CONCRETE "Link to this definition") * GENERAL\_STEEL*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 51*[](#CrossSectionType.GENERAL_STEEL "Link to this definition") - IGH*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 29*[](#CrossSectionType.IGH "Link to this definition") * IGN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 28*[](#CrossSectionType.IGN "Link to this definition") - IW*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 23*[](#CrossSectionType.IW "Link to this definition") * IWN*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 24*[](#CrossSectionType.IWN "Link to this definition") - LG*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 31*[](#CrossSectionType.LG "Link to this definition") * LG\_MIRRORED*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 32*[](#CrossSectionType.LG_MIRRORED "Link to this definition") - O*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 26*[](#CrossSectionType.O "Link to this definition") * ONE\_COMPONENT\_CSS*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 0*[](#CrossSectionType.ONE_COMPONENT_CSS "Link to this definition") - OVAL*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 37*[](#CrossSectionType.OVAL "Link to this definition") * RECT*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 27*[](#CrossSectionType.RECT "Link to this definition") - RHS\_G*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 36*[](#CrossSectionType.RHS_G "Link to this definition") * ROLLED\_2I*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 39*[](#CrossSectionType.ROLLED_2I "Link to this definition") - ROLLED\_ANGLE*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 2*[](#CrossSectionType.ROLLED_ANGLE "Link to this definition") * ROLLED\_CHS*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 5*[](#CrossSectionType.ROLLED_CHS "Link to this definition") - ROLLED\_DOUBLE\_LT*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 10*[](#CrossSectionType.ROLLED_DOUBLE_LT "Link to this definition") * ROLLED\_DOUBLE\_LU*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 11*[](#CrossSectionType.ROLLED_DOUBLE_LU "Link to this definition") - ROLLED\_DOUBLE\_UC*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 8*[](#CrossSectionType.ROLLED_DOUBLE_UC "Link to this definition") * ROLLED\_DOUBLE\_UO*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 7*[](#CrossSectionType.ROLLED_DOUBLE_UO "Link to this definition") - ROLLED\_I*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 1*[](#CrossSectionType.ROLLED_I "Link to this definition") * ROLLED\_I\_PAR*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 13*[](#CrossSectionType.ROLLED_I_PAR "Link to this definition") - ROLLED\_L\_PAR*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 15*[](#CrossSectionType.ROLLED_L_PAR "Link to this definition") * ROLLED\_RHS*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 6*[](#CrossSectionType.ROLLED_RHS "Link to this definition") - ROLLED\_T*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 3*[](#CrossSectionType.ROLLED_T "Link to this definition") * ROLLED\_TI*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 12*[](#CrossSectionType.ROLLED_TI "Link to this definition") - ROLLED\_U*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 4*[](#CrossSectionType.ROLLED_U "Link to this definition") * ROLLED\_U\_PAR*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 14*[](#CrossSectionType.ROLLED_U_PAR "Link to this definition") - SG*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 50*[](#CrossSectionType.SG "Link to this definition") * TCHAMFER\_1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 46*[](#CrossSectionType.TCHAMFER_1 "Link to this definition") - TCHAMFER\_2*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 47*[](#CrossSectionType.TCHAMFER_2 "Link to this definition") * TG*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 30*[](#CrossSectionType.TG "Link to this definition") - TGREV*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 43*[](#CrossSectionType.TGREV "Link to this definition") * TRAPEZOID*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 40*[](#CrossSectionType.TRAPEZOID "Link to this definition") - TT*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 48*[](#CrossSectionType.TT "Link to this definition") * TT1*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 49*[](#CrossSectionType.TT1 "Link to this definition") - TTFH*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 41*[](#CrossSectionType.TTFH "Link to this definition") * TTFHREV*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 44*[](#CrossSectionType.TTFHREV "Link to this definition") - TW*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 25*[](#CrossSectionType.TW "Link to this definition") * TWH*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 42*[](#CrossSectionType.TWH "Link to this definition") - TWHREV*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 45*[](#CrossSectionType.TWHREV "Link to this definition") * UG*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 33*[](#CrossSectionType.UG "Link to this definition") - UNIQUE\_NAME*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 1001*[](#CrossSectionType.UNIQUE_NAME "Link to this definition") * ZG*: [`CrossSectionType`](#CrossSectionType "viktor.external.idea_rcs.objects.CrossSectionType")** = 35*[](#CrossSectionType.ZG "Link to this definition") ## EvaluationInteractionDiagram[​](/sdk/api/external/idea/.md#_EvaluationInteractionDiagram "Direct link to EvaluationInteractionDiagram") * *class *viktor.external.idea\_rcs.objects.EvaluationInteractionDiagram(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#EvaluationInteractionDiagram "Link to this definition") Bases: `Enum` * NU\_MU\_MU*: [`EvaluationInteractionDiagram`](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 0*[](#EvaluationInteractionDiagram.NU_MU_MU "Link to this definition") - NU\_M\_M*: [`EvaluationInteractionDiagram`](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 1*[](#EvaluationInteractionDiagram.NU_M_M "Link to this definition") * N\_MU\_MU*: [`EvaluationInteractionDiagram`](#EvaluationInteractionDiagram "viktor.external.idea_rcs.objects.EvaluationInteractionDiagram")** = 2*[](#EvaluationInteractionDiagram.N_MU_MU "Link to this definition") ## ExposureClassEc2Carbonation[​](/sdk/api/external/idea/.md#_ExposureClassEc2Carbonation "Direct link to ExposureClassEc2Carbonation") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2Carbonation(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ExposureClassEc2Carbonation "Link to this definition") Bases: `Enum` * XC1*: [`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 1*[](#ExposureClassEc2Carbonation.XC1 "Link to this definition") - XC2*: [`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 2*[](#ExposureClassEc2Carbonation.XC2 "Link to this definition") * XC3*: [`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 3*[](#ExposureClassEc2Carbonation.XC3 "Link to this definition") - XC4*: [`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")** = 4*[](#ExposureClassEc2Carbonation.XC4 "Link to this definition") ## ExposureClassEc2ChemicalAttack[​](/sdk/api/external/idea/.md#_ExposureClassEc2ChemicalAttack "Direct link to ExposureClassEc2ChemicalAttack") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2ChemicalAttack(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ExposureClassEc2ChemicalAttack "Link to this definition") Bases: `Enum` * XA1*: [`ExposureClassEc2ChemicalAttack`](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 1*[](#ExposureClassEc2ChemicalAttack.XA1 "Link to this definition") - XA2*: [`ExposureClassEc2ChemicalAttack`](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 2*[](#ExposureClassEc2ChemicalAttack.XA2 "Link to this definition") * XA3*: [`ExposureClassEc2ChemicalAttack`](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")** = 3*[](#ExposureClassEc2ChemicalAttack.XA3 "Link to this definition") ## ExposureClassEc2Chlorides[​](/sdk/api/external/idea/.md#_ExposureClassEc2Chlorides "Direct link to ExposureClassEc2Chlorides") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2Chlorides(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ExposureClassEc2Chlorides "Link to this definition") Bases: `Enum` * XD1*: [`ExposureClassEc2Chlorides`](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 1*[](#ExposureClassEc2Chlorides.XD1 "Link to this definition") - XD2*: [`ExposureClassEc2Chlorides`](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 2*[](#ExposureClassEc2Chlorides.XD2 "Link to this definition") * XD3*: [`ExposureClassEc2Chlorides`](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")** = 3*[](#ExposureClassEc2Chlorides.XD3 "Link to this definition") ## ExposureClassEc2ChloridesFromSea[​](/sdk/api/external/idea/.md#_ExposureClassEc2ChloridesFromSea "Direct link to ExposureClassEc2ChloridesFromSea") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2ChloridesFromSea(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ExposureClassEc2ChloridesFromSea "Link to this definition") Bases: `Enum` * XS1*: [`ExposureClassEc2ChloridesFromSea`](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 1*[](#ExposureClassEc2ChloridesFromSea.XS1 "Link to this definition") - XS2*: [`ExposureClassEc2ChloridesFromSea`](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 2*[](#ExposureClassEc2ChloridesFromSea.XS2 "Link to this definition") * XS3*: [`ExposureClassEc2ChloridesFromSea`](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")** = 3*[](#ExposureClassEc2ChloridesFromSea.XS3 "Link to this definition") ## ExposureClassEc2FreezeAttack[​](/sdk/api/external/idea/.md#_ExposureClassEc2FreezeAttack "Direct link to ExposureClassEc2FreezeAttack") * *class *viktor.external.idea\_rcs.objects.ExposureClassEc2FreezeAttack(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ExposureClassEc2FreezeAttack "Link to this definition") Bases: `Enum` * XF1*: [`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 1*[](#ExposureClassEc2FreezeAttack.XF1 "Link to this definition") - XF2*: [`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 2*[](#ExposureClassEc2FreezeAttack.XF2 "Link to this definition") * XF3*: [`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 3*[](#ExposureClassEc2FreezeAttack.XF3 "Link to this definition") - XF4*: [`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")** = 4*[](#ExposureClassEc2FreezeAttack.XF4 "Link to this definition") ## ExposureClassesDataEc2[​](/sdk/api/external/idea/.md#_ExposureClassesDataEc2 "Direct link to ExposureClassesDataEc2") * *class *viktor.external.idea\_rcs.objects.ExposureClassesDataEc2(*\**, *carbonation=None*, *chlorides=None*, *chlorides\_from\_sea=None*, *freeze\_attack=None*, *chemical\_attack=None*)[](#ExposureClassesDataEc2 "Link to this definition") Bases: `_OpenObject` Exposure Classes Ec2. * Parameters: * **carbonation** ([`ExposureClassEc2Carbonation`](#ExposureClassEc2Carbonation "viktor.external.idea_rcs.objects.ExposureClassEc2Carbonation")) – Carbonation (default: None). * **chlorides** ([`ExposureClassEc2Chlorides`](#ExposureClassEc2Chlorides "viktor.external.idea_rcs.objects.ExposureClassEc2Chlorides")) – Chlorides (default: None). * **chlorides\_from\_sea** ([`ExposureClassEc2ChloridesFromSea`](#ExposureClassEc2ChloridesFromSea "viktor.external.idea_rcs.objects.ExposureClassEc2ChloridesFromSea")) – Chlorides from sea (default: None). * **freeze\_attack** ([`ExposureClassEc2FreezeAttack`](#ExposureClassEc2FreezeAttack "viktor.external.idea_rcs.objects.ExposureClassEc2FreezeAttack")) – Freeze/Thaw Attack (default: None). * **chemical\_attack** ([`ExposureClassEc2ChemicalAttack`](#ExposureClassEc2ChemicalAttack "viktor.external.idea_rcs.objects.ExposureClassEc2ChemicalAttack")) – Chemical Attack (default: None). ## FatigueLoading[​](/sdk/api/external/idea/.md#_FatigueLoading "Direct link to FatigueLoading") * *class *viktor.external.idea\_rcs.objects.FatigueLoading(*max\_loading*, *min\_loading*)[](#FatigueLoading "Link to this definition") Bases: `_OpenObject` Fatigue loading. * Parameters: * **max\_loading** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Max. cyclic loading. * **min\_loading** ([`LoadingULS`](#LoadingULS "viktor.external.idea_rcs.objects.LoadingULS")) – Min. cyclic loading. ## LoadingSLS[​](/sdk/api/external/idea/.md#_LoadingSLS "Direct link to LoadingSLS") * *class *viktor.external.idea\_rcs.objects.LoadingSLS(*internal\_forces*, *internal\_forces\_imperfection=None*)[](#LoadingSLS "Link to this definition") Bases: `_OpenObject` Loading SLS. * Parameters: * **internal\_forces** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal force in section. * **internal\_forces\_imperfection** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal forces of imperfection effect. ## LoadingULS[​](/sdk/api/external/idea/.md#_LoadingULS "Direct link to LoadingULS") * *class *viktor.external.idea\_rcs.objects.LoadingULS(*internal\_forces*, *internal\_forces\_second\_order=None*, *internal\_forces\_begin=None*, *internal\_forces\_end=None*, *internal\_forces\_imperfection=None*)[](#LoadingULS "Link to this definition") Bases: `_OpenObject` Loading ULS. * Parameters: * **internal\_forces** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal force in section. * **internal\_forces\_second\_order** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal forces of 2nd order effect. * **internal\_forces\_begin** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal forces at the beginning. * **internal\_forces\_end** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal forces at the end. * **internal\_forces\_imperfection** ([`ResultOfInternalForces`](#ResultOfInternalForces "viktor.external.idea_rcs.objects.ResultOfInternalForces")) – Internal forces of imperfection effect. ## MatConcrete[​](/sdk/api/external/idea/.md#_MatConcrete "Direct link to MatConcrete") * *class *viktor.external.idea\_rcs.objects.MatConcrete(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*)[](#MatConcrete "Link to this definition") Bases: `_Material`, `ABC` Abstract base class of all concrete materials. ## MatConcreteEc2[​](/sdk/api/external/idea/.md#_MatConcreteEc2 "Direct link to MatConcreteEc2") * *class *viktor.external.idea\_rcs.objects.MatConcreteEc2(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *fck*, *stone\_diameter*, *cement\_class*, *aggregate\_type*, *diagram\_type*, *silica\_fume*, *plain\_concrete\_diagram*, *dep\_params=None*)[](#MatConcreteEc2 "Link to this definition") Bases: [`MatConcrete`](#MatConcrete "viktor.external.idea_rcs.objects.MatConcrete") Do not use this \_\_init\_\_ directly, but create the object by [`create_matconcrete_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matconcrete_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matconcrete_ec2"). ## MatReinforcement[​](/sdk/api/external/idea/.md#_MatReinforcement "Direct link to MatReinforcement") * *class *viktor.external.idea\_rcs.objects.MatReinforcement(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *bar\_surface*)[](#MatReinforcement "Link to this definition") Bases: `_Material`, `ABC` Abstract base class of all material reinforcements. ## MatReinforcementEc2[​](/sdk/api/external/idea/.md#_MatReinforcementEc2 "Direct link to MatReinforcementEc2") * *class *viktor.external.idea\_rcs.objects.MatReinforcementEc2(*id\_*, *name*, *e\_modulus*, *g\_modulus*, *poisson*, *unit\_mass*, *specific\_heat*, *thermal\_expansion*, *thermal\_conductivity*, *is\_default*, *order\_in\_code*, *thermal\_state*, *bar\_surface*, *fyk*, *ftk\_by\_fyk*, *epsuk*, *ftk*, *class\_*, *type\_*, *fabrication*, *diagram\_type*)[](#MatReinforcementEc2 "Link to this definition") Bases: [`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement") Do not use this \_\_init\_\_ directly, but create the object by [`create_matreinforcement_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2"). ## MemberType[​](/sdk/api/external/idea/.md#_MemberType "Direct link to MemberType") * *class *viktor.external.idea\_rcs.objects.MemberType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#MemberType "Link to this definition") Bases: `Enum` * BEAM*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 1*[](#MemberType.BEAM "Link to this definition") - BEAM\_SLAB*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 4*[](#MemberType.BEAM_SLAB "Link to this definition") * COLUMN*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 2*[](#MemberType.COLUMN "Link to this definition") - HOLLOW\_CORE\_SLAB*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 8*[](#MemberType.HOLLOW_CORE_SLAB "Link to this definition") * PLATE*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 32*[](#MemberType.PLATE "Link to this definition") - TWO\_WAY\_SLAB*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 16*[](#MemberType.TWO_WAY_SLAB "Link to this definition") * UNDEFINED*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 0*[](#MemberType.UNDEFINED "Link to this definition") - WALL*: [`MemberType`](#MemberType "viktor.external.idea_rcs.objects.MemberType")** = 64*[](#MemberType.WALL "Link to this definition") ## NationalAnnex[​](/sdk/api/external/idea/.md#_NationalAnnex "Direct link to NationalAnnex") * *class *viktor.external.idea\_rcs.objects.NationalAnnex(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#NationalAnnex "Link to this definition") Bases: `Enum` * BELGIUM*: [`NationalAnnex`](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'Belgian'*[](#NationalAnnex.BELGIUM "Link to this definition") - DUTCH*: [`NationalAnnex`](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'Dutch'*[](#NationalAnnex.DUTCH "Link to this definition") * NO\_ANNEX*: [`NationalAnnex`](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")** = 'NoAnnex'*[](#NationalAnnex.NO_ANNEX "Link to this definition") ## NoResistanceConcreteTension1d[​](/sdk/api/external/idea/.md#_NoResistanceConcreteTension1d "Direct link to NoResistanceConcreteTension1d") * *class *viktor.external.idea\_rcs.objects.NoResistanceConcreteTension1d(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#NoResistanceConcreteTension1d "Link to this definition") Bases: `Enum` * ALWAYS*: [`NoResistanceConcreteTension1d`](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 2*[](#NoResistanceConcreteTension1d.ALWAYS "Link to this definition") - EXTREME*: [`NoResistanceConcreteTension1d`](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 0*[](#NoResistanceConcreteTension1d.EXTREME "Link to this definition") * SECTION*: [`NoResistanceConcreteTension1d`](#NoResistanceConcreteTension1d "viktor.external.idea_rcs.objects.NoResistanceConcreteTension1d")** = 1*[](#NoResistanceConcreteTension1d.SECTION "Link to this definition") ## ProjectData[​](/sdk/api/external/idea/.md#_ProjectData "Direct link to ProjectData") * *class *viktor.external.idea\_rcs.objects.ProjectData(*\**, *national\_annex=None*, *fatigue\_check=False*, *name=None*, *number=None*, *description=None*, *author=None*, *date=None*, *design\_working\_life=None*)[](#ProjectData "Link to this definition") Bases: `_OpenObject` Project data. * Parameters: * **name** (`str`) – Project name New in v14.6.0 * **number** (`str`) – Project number New in v14.6.0 * **description** (`str`) – Project description New in v14.6.0 * **author** (`str`) – Author New in v14.6.0 * **date** (`date`) – Date (default: today) New in v14.6.0 * **national\_annex** ([`NationalAnnex`](#NationalAnnex "viktor.external.idea_rcs.objects.NationalAnnex")) – national annex (default: No national annex (EN)) * **fatigue\_check** (`bool`) – functionality - fatigue (default: false) * **design\_working\_life** (`Literal`\[`50`, `75`, `100`]) – Design working life (default: 50) New in v14.6.0 ## ReinfClass[​](/sdk/api/external/idea/.md#_ReinfClass "Direct link to ReinfClass") * *class *viktor.external.idea\_rcs.objects.ReinfClass(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ReinfClass "Link to this definition") Bases: `Enum` * A*: [`ReinfClass`](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 0*[](#ReinfClass.A "Link to this definition") - B*: [`ReinfClass`](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 1*[](#ReinfClass.B "Link to this definition") * C*: [`ReinfClass`](#ReinfClass "viktor.external.idea_rcs.objects.ReinfClass")** = 2*[](#ReinfClass.C "Link to this definition") ## ReinfDiagramType[​](/sdk/api/external/idea/.md#_ReinfDiagramType "Direct link to ReinfDiagramType") * *class *viktor.external.idea\_rcs.objects.ReinfDiagramType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ReinfDiagramType "Link to this definition") Bases: `Enum` * BILINEAR\_INCLINED*: [`ReinfDiagramType`](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 0*[](#ReinfDiagramType.BILINEAR_INCLINED "Link to this definition") - BILINEAR\_NOT\_INCLINED*: [`ReinfDiagramType`](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 1*[](#ReinfDiagramType.BILINEAR_NOT_INCLINED "Link to this definition") * USER*: [`ReinfDiagramType`](#ReinfDiagramType "viktor.external.idea_rcs.objects.ReinfDiagramType")** = 2*[](#ReinfDiagramType.USER "Link to this definition") ## ReinfFabrication[​](/sdk/api/external/idea/.md#_ReinfFabrication "Direct link to ReinfFabrication") * *class *viktor.external.idea\_rcs.objects.ReinfFabrication(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ReinfFabrication "Link to this definition") Bases: `Enum` * COLD\_WORKED*: [`ReinfFabrication`](#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")** = 1*[](#ReinfFabrication.COLD_WORKED "Link to this definition") - HOT\_ROLLED*: [`ReinfFabrication`](#ReinfFabrication "viktor.external.idea_rcs.objects.ReinfFabrication")** = 0*[](#ReinfFabrication.HOT_ROLLED "Link to this definition") ## ReinfType[​](/sdk/api/external/idea/.md#_ReinfType "Direct link to ReinfType") * *class *viktor.external.idea\_rcs.objects.ReinfType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ReinfType "Link to this definition") Bases: `Enum` * BARS*: [`ReinfType`](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 0*[](#ReinfType.BARS "Link to this definition") - DECOILED\_RODS*: [`ReinfType`](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 1*[](#ReinfType.DECOILED_RODS "Link to this definition") * LATTICE\_GIRDERS*: [`ReinfType`](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 3*[](#ReinfType.LATTICE_GIRDERS "Link to this definition") - WIRE\_FABRICS*: [`ReinfType`](#ReinfType "viktor.external.idea_rcs.objects.ReinfType")** = 2*[](#ReinfType.WIRE_FABRICS "Link to this definition") ## ReinforcedBar[​](/sdk/api/external/idea/.md#_ReinforcedBar "Direct link to ReinforcedBar") * *class *viktor.external.idea\_rcs.objects.ReinforcedBar(*coordinates*, *diameter*, *material*)[](#ReinforcedBar "Link to this definition") Bases: `_OpenObject` Do not use this \_\_init\_\_ directly, but create the object by [`ReinforcedCrossSection.create_bar()`](#ReinforcedCrossSection.create_bar "viktor.external.idea_rcs.objects.ReinforcedCrossSection.create_bar"). * *property *coordinates*: Tuple\[float, float]*[](#ReinforcedBar.coordinates "Link to this definition") - *property *diameter*: float*[](#ReinforcedBar.diameter "Link to this definition") * *property *material\_id*: int*[](#ReinforcedBar.material_id "Link to this definition") ## ReinforcedCrossSection[​](/sdk/api/external/idea/.md#_ReinforcedCrossSection "Direct link to ReinforcedCrossSection") * *class *viktor.external.idea\_rcs.objects.ReinforcedCrossSection(*id\_*, *name*, *cross\_section*, *bars=None*, *stirrups=None*)[](#ReinforcedCrossSection "Link to this definition") Bases: `_OpenElementId` Do not use this \_\_init\_\_ directly, but create the object by [`create_reinforced_cross_section()`](/sdk/api/external/idea/.md#OpenModel.create_reinforced_cross_section "viktor.external.idea_rcs.idea_rcs.OpenModel.create_reinforced_cross_section"). * *property *bars*: List\[[ReinforcedBar](#ReinforcedBar "viktor.external.idea_rcs.objects.ReinforcedBar")]*[](#ReinforcedCrossSection.bars "Link to this definition") - create\_bar(*coordinates*, *diameter*, *material*)[](#ReinforcedCrossSection.create_bar "Link to this definition") Create a reinforced bar on the reinforced cross-section. * Parameters: * **coordinates** (`Tuple`\[`float`, `float`]) – (X, Y) coordinate of the bar \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * Return type: `None` * create\_bar\_layer(*\**, *origin*, *diameter*, *material*, *number\_of\_bars*, *delta\_y=None*, *delta\_z=None*)[](#ReinforcedCrossSection.create_bar_layer "Link to this definition") Create multiple reinforced bars on the reinforced cross-section, positioned on a line. * Parameters: * **origin** (`Tuple`\[`float`, `float`]) – Origin point (Y, Z) \[m]. * **diameter** (`float`) – Diameter of the bar \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **number\_of\_bars** (`int`) – Number of bars (minimum of 2). * **delta\_y** (`float`) – Distance between origin bar and the last bar in y-direction \[m]. * **delta\_z** (`float`) – Distance between origin bar and the last bar in z-direction \[m]. * Return type: `None` - create\_stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[](#ReinforcedCrossSection.create_stirrup "Link to this definition") Create a stirrup on the reinforced cross-section. * Parameters: * **points** (`Sequence`\[`Union`\[`Tuple`\[`float`, `float`], `Tuple`\[`Tuple`\[`float`, `float`], `Tuple`\[`float`, `float`]]]]) – Sequence of (X, Y) coordinates \[m] of the stirrup vertices, connected by straight line segments. For arc-segments use ((X\_end, Y\_end), (X\_on\_arc, Y\_on\_arc)). * **diameter** (`float`) – Diameter of the stirrup \[m]. * **material** ([`MatReinforcement`](#MatReinforcement "viktor.external.idea_rcs.objects.MatReinforcement")) – Reinforcement material (created by [`create_matreinforcement_ec2()`](/sdk/api/external/idea/.md#OpenModel.create_matreinforcement_ec2 "viktor.external.idea_rcs.idea_rcs.OpenModel.create_matreinforcement_ec2")). * **distance** (`float`) – Longitudinal distance between stirrups \[m]. * **shear\_check** (`bool`) – Take stirrup into account in shear check (default: False). * **torsion\_check** (`bool`) – Take stirrup into account in torsion check (default: False). * **mandrel\_diameter\_factor** (`float`) – Inner diameter of mandrel as multiple of stirrup diameter \[-] (default: 1.0). * **anchorage\_length** (`float`) – Anchorage length \[m] (default: 0.0). * Return type: `None` * *property *stirrups*: List\[[Stirrup](#Stirrup "viktor.external.idea_rcs.objects.Stirrup")]*[](#ReinforcedCrossSection.stirrups "Link to this definition") ## ReinforcementMaterial[​](/sdk/api/external/idea/.md#_ReinforcementMaterial "Direct link to ReinforcementMaterial") * *class *viktor.external.idea\_rcs.objects.ReinforcementMaterial(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ReinforcementMaterial "Link to this definition") Bases: `Enum` * B\_400A*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 1*[](#ReinforcementMaterial.B_400A "Link to this definition") - B\_400B*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 4*[](#ReinforcementMaterial.B_400B "Link to this definition") * B\_400C*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 7*[](#ReinforcementMaterial.B_400C "Link to this definition") - B\_500A*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 2*[](#ReinforcementMaterial.B_500A "Link to this definition") * B\_500B*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 5*[](#ReinforcementMaterial.B_500B "Link to this definition") - B\_500C*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 8*[](#ReinforcementMaterial.B_500C "Link to this definition") * B\_550A*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 10*[](#ReinforcementMaterial.B_550A "Link to this definition") - B\_550B*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 11*[](#ReinforcementMaterial.B_550B "Link to this definition") * B\_600A*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 3*[](#ReinforcementMaterial.B_600A "Link to this definition") - B\_600B*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 6*[](#ReinforcementMaterial.B_600B "Link to this definition") * B\_600C*: [`ReinforcementMaterial`](#ReinforcementMaterial "viktor.external.idea_rcs.objects.ReinforcementMaterial")** = 9*[](#ReinforcementMaterial.B_600C "Link to this definition") ## ResultOfInternalForces[​](/sdk/api/external/idea/.md#_ResultOfInternalForces "Direct link to ResultOfInternalForces") * *class *viktor.external.idea\_rcs.objects.ResultOfInternalForces(*N=0.0*, *Qy=0.0*, *Qz=0.0*, *Mx=0.0*, *My=0.0*, *Mz=0.0*)[](#ResultOfInternalForces "Link to this definition") Bases: `_OpenObject` Result of internal forces at a certain location. * Parameters: * **N** (`float`) – Normal force (default: 0.0). * **Qy** (`float`) – Shear force in y direction (default: 0.0). * **Qz** (`float`) – Shear force in z direction (default: 0.0). * **Mx** (`float`) – Bending moment around x-axis (default: 0.0). * **My** (`float`) – Bending moment around y-axis (default: 0.0). * **Mz** (`float`) – Bending moment around z-axis (default: 0.0). ## StandardCheckSection[​](/sdk/api/external/idea/.md#_StandardCheckSection "Direct link to StandardCheckSection") * *class *viktor.external.idea\_rcs.objects.StandardCheckSection(*id\_*, *description*, *check\_member*, *reinf\_section*, *extremes=None*)[](#StandardCheckSection "Link to this definition") Bases: [`CheckSection`](#CheckSection "viktor.external.idea_rcs.objects.CheckSection") Do not use this \_\_init\_\_ directly, but create the object by [`add_check_section()`](/sdk/api/external/idea/.md#OpenModel.add_check_section "viktor.external.idea_rcs.idea_rcs.OpenModel.add_check_section"). ## StandardCheckSectionExtreme[​](/sdk/api/external/idea/.md#_StandardCheckSectionExtreme "Direct link to StandardCheckSectionExtreme") * *class *viktor.external.idea\_rcs.objects.StandardCheckSectionExtreme(*\**, *accidental=None*, *frequent=None*, *fundamental=None*, *characteristic=None*, *quasi\_permanent=None*, *fatigue=None*, *description*)[](#StandardCheckSectionExtreme "Link to this definition") Bases: [`CheckSectionExtreme`](#CheckSectionExtreme "viktor.external.idea_rcs.objects.CheckSectionExtreme") Do not use this \_\_init\_\_ directly, but create the object by [`CheckSection.create_extreme()`](#CheckSection.create_extreme "viktor.external.idea_rcs.objects.CheckSection.create_extreme"). ## Stirrup[​](/sdk/api/external/idea/.md#_Stirrup "Direct link to Stirrup") * *class *viktor.external.idea\_rcs.objects.Stirrup(*points*, *diameter*, *material*, *distance*, *shear\_check=None*, *torsion\_check=None*, *mandrel\_diameter\_factor=None*, *anchorage\_length=None*)[](#Stirrup "Link to this definition") Bases: `_OpenObject` Do not use this \_\_init\_\_ directly, but create the object by [`ReinforcedCrossSection.create_stirrup()`](#ReinforcedCrossSection.create_stirrup "viktor.external.idea_rcs.objects.ReinforcedCrossSection.create_stirrup"). * *property *anchorage\_length*: float*[](#Stirrup.anchorage_length "Link to this definition") - *property *mandrel\_diameter\_factor*: float*[](#Stirrup.mandrel_diameter_factor "Link to this definition") * *property *material\_id*: int*[](#Stirrup.material_id "Link to this definition") - *property *points*: Sequence\[Tuple\[float, float] | Tuple\[Tuple\[float, float], Tuple\[float, float]]]*[](#Stirrup.points "Link to this definition") * *property *shear\_check*: bool*[](#Stirrup.shear_check "Link to this definition") - *property *torsion\_check*: bool*[](#Stirrup.torsion_check "Link to this definition") ## ThermalState[​](/sdk/api/external/idea/.md#_ThermalState "Direct link to ThermalState") * *class *viktor.external.idea\_rcs.objects.ThermalState(*expansion=ThermalStateType.NONE*, *conductivity=ThermalStateType.NONE*, *specific\_heat=ThermalStateType.NONE*, *stress\_strain=ThermalStateType.NONE*, *strain=ThermalStateType.NONE*)[](#ThermalState "Link to this definition") Bases: `_OpenObject` Collection of thermal states for expansion, conductivity, specific heat, stress-strain and strain. * Parameters: * **expansion** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal expansion curvature. * **conductivity** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal conductivity curvature. * **specific\_heat** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal specific heat curvature. * **stress\_strain** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal specific stress-strain curvature. * **strain** ([`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")) – state of thermal strain curvature. ## ThermalStateType[​](/sdk/api/external/idea/.md#_ThermalStateType "Direct link to ThermalStateType") * *class *viktor.external.idea\_rcs.objects.ThermalStateType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ThermalStateType "Link to this definition") Bases: `Enum` * CODE*: [`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 1*[](#ThermalStateType.CODE "Link to this definition") - NONE*: [`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 0*[](#ThermalStateType.NONE "Link to this definition") * USER*: [`ThermalStateType`](#ThermalStateType "viktor.external.idea_rcs.objects.ThermalStateType")** = 5*[](#ThermalStateType.USER "Link to this definition") ## TwoWaySlabType[​](/sdk/api/external/idea/.md#_TwoWaySlabType "Direct link to TwoWaySlabType") * *class *viktor.external.idea\_rcs.objects.TwoWaySlabType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#TwoWaySlabType "Link to this definition") Bases: `Enum` * DEEP\_BEAM*: [`TwoWaySlabType`](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 2*[](#TwoWaySlabType.DEEP_BEAM "Link to this definition") - SHELL\_AS\_PLATE*: [`TwoWaySlabType`](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 3*[](#TwoWaySlabType.SHELL_AS_PLATE "Link to this definition") * SHELL\_AS\_WALL*: [`TwoWaySlabType`](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 4*[](#TwoWaySlabType.SHELL_AS_WALL "Link to this definition") - SLAB*: [`TwoWaySlabType`](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 0*[](#TwoWaySlabType.SLAB "Link to this definition") * WALL*: [`TwoWaySlabType`](#TwoWaySlabType "viktor.external.idea_rcs.objects.TwoWaySlabType")** = 1*[](#TwoWaySlabType.WALL "Link to this definition") ## TypeSLSCalculation[​](/sdk/api/external/idea/.md#_TypeSLSCalculation "Direct link to TypeSLSCalculation") * *class *viktor.external.idea\_rcs.objects.TypeSLSCalculation(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#TypeSLSCalculation "Link to this definition") Bases: `Enum` * BOTH*: [`TypeSLSCalculation`](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 0*[](#TypeSLSCalculation.BOTH "Link to this definition") - LONG\_TERM*: [`TypeSLSCalculation`](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 2*[](#TypeSLSCalculation.LONG_TERM "Link to this definition") * SHORT\_TERM*: [`TypeSLSCalculation`](#TypeSLSCalculation "viktor.external.idea_rcs.objects.TypeSLSCalculation")** = 1*[](#TypeSLSCalculation.SHORT_TERM "Link to this definition") --- # viktor.external.matlab ## MatlabAnalysis[​](/sdk/api/external/matlab/.md#_MatlabAnalysis "Direct link to MatlabAnalysis") * *class *viktor.external.matlab.MatlabAnalysis(*files=None*, *executable\_key='matlab'*, *output\_filenames=None*)[](#MatlabAnalysis "Link to this definition") Bases: [`GenericAnalysis`](/sdk/api/external/generic/.md#GenericAnalysis "viktor.external.generic.GenericAnalysis") New in 14.17.0 MatlabAnalysis can be used to evaluate a matlab script on third-party infrastructure. The script is expected to be blocking, i.e. if the executable is invoked from command prompt, it should wait until the script is finished. For security purposes the executable that should be called has to be defined in the configuration file of the worker. Usage: ``` files = [ ('input1.txt', file1), ('input2.txt', file2) ] analysis = MatlabAnalysis(files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **files** (`Optional`\[`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]]) – Files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **executable\_key** (`str`) – The key of the executable that needs to be evaluated. This key should be present in the configuration file of the worker, defaults to run\_matlab. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the SDK. This filename is relative to the working directory. * Raises: **ValueError** – when no attribute is included in call. --- # viktor.external.plaxis ## PlaxisAnalysis[​](/sdk/api/external/plaxis/.md#_PlaxisAnalysis "Direct link to PlaxisAnalysis") * *class *viktor.external.plaxis.PlaxisAnalysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#PlaxisAnalysis "Link to this definition") Bases: [`PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis") New in 14.17.0 PlaxisAnalysis can be used to evaluate a plaxis-python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "run_plaxis.py") files = [ ('input1.txt', file1), ] analysis = PlaxisAnalysis(script=script, files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. --- # viktor.external.python ## PythonAnalysis[​](/sdk/api/external/python/.md#_PythonAnalysis "Direct link to PythonAnalysis") * *class *viktor.external.python.PythonAnalysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#PythonAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") New in 14.17.0 PythonAnalysis can be used to evaluate a python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "my_script.py") files = [ ('input1.txt', file1), ] python_analysis = PythonAnalysis(script=script, files=files, output_filenames=["output.txt"]) python_analysis.execute(timeout=60) output_file = python_analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. - get\_output\_file(*filename*)[](#PythonAnalysis.get_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. Call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_output_file()`](#PythonAnalysis.get_output_file "viktor.external.python.PythonAnalysis.get_output_file") afterwards. * Parameters: **filename** (`str`) – The name of the file (including extension) that you want to get. * Return type: `Optional`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")] --- # viktor.external.revit ## RevitAnalysis[​](/sdk/api/external/revit/.md#_RevitAnalysis "Direct link to RevitAnalysis") * *class *viktor.external.revit.RevitAnalysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#RevitAnalysis "Link to this definition") Bases: [`PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis") New in 14.17.0 RevitAnalysis can be used to evaluate a revit-python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "run_revit.py") files = [ ('input1.txt', file1), ('input2.txt', file2) ] analysis = RevitAnalysis(script=script, files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt", as_file=True) ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. --- # viktor.external.rfem ## CopyNodalLoadAction[​](/sdk/api/external/rfem/.md#_CopyNodalLoadAction "Direct link to CopyNodalLoadAction") * *class *viktor.external.rfem.CopyNodalLoadAction(*copy\_from\_to*, *loading\_type=LoadingType.LOAD\_CASE*, *\**, *factor=1.0*)[](#CopyNodalLoadAction "Link to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") Copy the nodal load from one load case to the other, applying a factor on the magnitude. * Note: only the 1st nodal load is copied from and to each load case/combination, other loads are ignored. Make sure that at least 1 such nodal load exists in both the copy-from and copy-to load cases/combinations. - Parameters: * **copy\_from\_to** (`List`\[`Tuple`\[`int`, `int`]]) – a list of load case/combination numbers to copy (from, to) * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘copy\_from\_to’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) * **factor** (`float`) – factor to be applied on the nodal load magnitude (default: 1.0) ## EnergyOptimizationAction[​](/sdk/api/external/rfem/.md#_EnergyOptimizationAction "Direct link to EnergyOptimizationAction") * *class *viktor.external.rfem.EnergyOptimizationAction(*load\_cases*, *loading\_type=LoadingType.LOAD\_CASE*, *\**, *goal*, *accuracy*)[](#EnergyOptimizationAction "Link to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") * Performs an iterative analysis (consisting of a series of RFEM analyses) to solve for the magnitude of the 1st nodal load, such that the energy at that node (approximately) equals the ‘goal’. The iteration comes to a finish if the change in displacement at the node is lower than the specified ‘accuracy’. This is done for each of the load cases specified. - Parameters: * **load\_cases** (`List`\[`int`]) – a list of load cases/combinations to do a energy optimization calculation for. None for all load cases/combinations (default: None). * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘load\_cases’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) * **goal** (`float`) – energy level \[Nm] for which the calculation tries to solve the 1st nodal load. Same goal is used for all load cases/combinations. * **accuracy** (`float`) – change in displacement \[m] of the node corresponding to the 1st nodal load at which the iteration will successfully return. A lower accuracy in general means more iterations. Same accuracy is used for all load cases/combinations. ## LoadingType[​](/sdk/api/external/rfem/.md#_LoadingType "Direct link to LoadingType") * *class *viktor.external.rfem.LoadingType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadingType "Link to this definition") Bases: `Enum` * LOAD\_CASE*: [`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")** = 1*[](#LoadingType.LOAD_CASE "Link to this definition") - LOAD\_COMBINATION*: [`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")** = 2*[](#LoadingType.LOAD_COMBINATION "Link to this definition") ## RFEMAction[​](/sdk/api/external/rfem/.md#_RFEMAction "Direct link to RFEMAction") * *class *viktor.external.rfem.RFEMAction(*id\_*)[](#RFEMAction "Link to this definition") Bases: `ABC` Abstract base class of all RFEM action objects. ## RFEMAnalysis[​](/sdk/api/external/rfem/.md#_RFEMAnalysis "Direct link to RFEMAnalysis") * *class *viktor.external.rfem.RFEMAnalysis(*rfx\_file*, *actions*)[](#RFEMAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") RFEMAnalysis can be used to perform an analysis with RFEM on third-party infrastructure. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the model call [`get_model()`](#RFEMAnalysis.get_model "viktor.external.rfem.RFEMAnalysis.get_model") and for results call [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result") for the desired load combination (only after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute")). Exceptions which can be raised during calculation: > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information Example usage: ``` # SLS sls_cases = [1, 2, 3] sls_optimization = EnergyOptimizationAction(sls_cases, goal=10000, accuracy=0.1) # goal = 10 kNm, accuracy = 10 cm # ALS als_cases = [4, 5, 6] als_optimization = EnergyOptimizationAction(als_cases, goal=15000, accuracy=0.1) # goal = 15 kNm, accuracy = 10 cm # ULS uls_cases = [7, 8, 9] uls_creation = CopyNodalLoadAction(list(zip(sls_cases, uls_cases)), factor=1.5) # ULS = SLS x 1.5 # Write action write_result_action = WriteResultsAction(sls_cases + als_cases + uls_cases) # or can be left empty = all cases actions = [sls_optimization, als_optimization, uls_creation, write_result_action] rfem_analysis = RFEMAnalysis(rfx_file=my_rfx_file, actions=actions) # my_rfx_file contains the desired load cases and nodal loads rfem_analysis.execute(timeout=300) model = rfem_analysis.get_model() result_lc1 = rfem_analysis.get_result(1) result_lc2 = rfem_analysis.get_result(2) ``` * Parameters: * **rfx\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – RFEM input file * **actions** (`List`\[[`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction")]) – list of actions to be performed sequentially. Possible actions are: * [`EnergyOptimizationAction`](#EnergyOptimizationAction "viktor.external.rfem.EnergyOptimizationAction") * [`CopyNodalLoadAction`](#CopyNodalLoadAction "viktor.external.rfem.CopyNodalLoadAction") * [`WriteResultsAction`](#WriteResultsAction "viktor.external.rfem.WriteResultsAction") (required for [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result")) - get\_model(*\**, *as\_file=False*)[](#RFEMAnalysis.get_model "Link to this definition") Get the model that is returned after the RFEM analysis. * Parameters: **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * get\_result(*load\_case*, *\**, *as\_file=False*)[](#RFEMAnalysis.get_result "Link to this definition") Get the nodal deformations (X, Y, Z) \[m] and member internal forces (Location \[m], My and Mz \[Nm], Fy and Fz \[N]) for a certain load case/combination number. * Parameters: * **load\_case** (`int`) – number of the load case/combination to get the result for. A ‘WriteResultsAction’ must have been performed on the corresponding load case/combination to be available. * **as\_file** (`bool`) – Return as BytesIO (default) or File New in v13.5.0 * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] ## WriteResultsAction[​](/sdk/api/external/rfem/.md#_WriteResultsAction "Direct link to WriteResultsAction") * *class *viktor.external.rfem.WriteResultsAction(*load\_cases=None*, *loading\_type=LoadingType.LOAD\_CASE*)[](#WriteResultsAction "Link to this definition") Bases: [`RFEMAction`](#RFEMAction "viktor.external.rfem.RFEMAction") Write all nodal deformations (X, Y, Z) and member internal forces (Location, My, Mz, Fy, Fz) for the model in current state, for each of the load cases/combinations requested, so that it is available in [`get_result()`](#RFEMAnalysis.get_result "viktor.external.rfem.RFEMAnalysis.get_result"). * Parameters: * **load\_cases** (`List`\[`int`]) – a list of load cases/combinations to write the results for. None for all load cases/combinations (default: None). * **loading\_type** ([`LoadingType`](#LoadingType "viktor.external.rfem.LoadingType")) – defines if integers in ‘load\_cases’ must be interpreted as load case (LOAD\_CASE) or load combination (LOAD\_COMBINATION) numbers (default: LOAD\_CASE) --- # viktor.external.robot ## RobotAnalysis[​](/sdk/api/external/robot/.md#_RobotAnalysis "Direct link to RobotAnalysis") * *class *viktor.external.robot.RobotAnalysis(*input\_file*, *\**, *return\_model=True*, *return\_results=True*, *requested\_results=None*)[](#RobotAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") Perform an analysis using Autodesk Robot on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the results call the method [`get_results()`](#RobotAnalysis.get_results "viktor.external.robot.RobotAnalysis.get_results"), after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). The evaluated model file can be retrieved by calling [`get_model_file()`](#RobotAnalysis.get_model_file "viktor.external.robot.RobotAnalysis.get_model_file"). Usage: ``` robot_analysis = RobotAnalysis(input_file, return_model=True) robot_analysis.execute(timeout=10) results = robot_analysis.get_results() model_file = robot_analysis.get_model_file() ``` Exceptions which can be raised during calculation: > * [`ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **input\_file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Robot input file in STR format * **return\_results** (`bool`) – If True, an analysis will be run and the result file is returned. * **return\_model** (`bool`) – If True, the model file (.rtd) is returned. * **requested\_results** (`dict`) – (optional) Dictionary containing the requested results. If requested\_results is None and return\_results is True, the worker will return all results. For the allowed components see the Autodesk Robot SDK documentation. The dictionary should be formatted as follows: ``` { "bar_forces": List[string], "bar_displacements": List[string], "bar_stresses": List[string], "bar_deflections": List[string], "node_reactions": List[string], "node_displacements": List[string], } ``` * get\_model\_file()[](#RobotAnalysis.get_model_file "Link to this definition") Retrieve the model file (only if return\_model = True) in .rtd format. [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") must be called first. * Return type: `Optional`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")] - get\_results()[](#RobotAnalysis.get_results "Link to this definition") Retrieve the results (only if return\_results = True). `execute()` must be called first. The format of the returned dictionary is: ``` { 'bar_forces': { '1': { # case id '1': { # bar id '0.000000': { # positions 'FX': 26070.462297973572 # components } } } }, 'bar_displacements': { '1': { '1': { '0.000000': { 'RX': 0 } } } }, 'bar_stresses': { '1': { '1': { '0.000000': { 'FXSX': 19750.350225737555 } } } }, 'bar_deflections': { '1': { '1': { '0.000000': { 'PosUX': 0 } } } }, 'node_reactions': { '1': { # case id '1': { # node id 'FX': -9.89530235528946e-09 # components } } }, 'node_displacements': { '1': { '1': { 'RX': 0 } } } } ``` * Return type: `Optional`\[`dict`] --- # viktor.external.sap2000 ## SAP2000Analysis[​](/sdk/api/external/sap2000/.md#_SAP2000Analysis "Direct link to SAP2000Analysis") * *class *viktor.external.sap2000.SAP2000Analysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#SAP2000Analysis "Link to this definition") Bases: [`PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis") New in 14.17.0 SAP2000Analysis can be used to evaluate a SAP2000-python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "run_sap2000.py") files = [ ('input1.txt', file1), ] analysis = SAP2000Analysis(script=script, files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. --- # viktor.external.scia ## CalcSetting[​](/sdk/api/external/scia/.md#_CalcSetting "Direct link to CalcSetting") * *class *viktor.external.scia.scia.CalcSetting(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#CalcSetting "Link to this definition") Bases: `Enum` Enumeration of calculation settings: * CSS*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'CSS'*[](#CalcSetting.CSS "Link to this definition") - EIG*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'EIG'*[](#CalcSetting.EIG "Link to this definition") * INF*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'INF'*[](#CalcSetting.INF "Link to this definition") - LIN*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'LIN'*[](#CalcSetting.LIN "Link to this definition") * MOB*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'MOB'*[](#CalcSetting.MOB "Link to this definition") - NEL*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NEL'*[](#CalcSetting.NEL "Link to this definition") * NOC*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NOC'*[](#CalcSetting.NOC "Link to this definition") - NONE*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NONE'*[](#CalcSetting.NONE "Link to this definition") * NPH*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NPH'*[](#CalcSetting.NPH "Link to this definition") - NST*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'NST'*[](#CalcSetting.NST "Link to this definition") * PHA*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'PHA'*[](#CalcSetting.PHA "Link to this definition") - SLN*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'SLN'*[](#CalcSetting.SLN "Link to this definition") * STB*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'STB'*[](#CalcSetting.STB "Link to this definition") - TDA*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'TDA'*[](#CalcSetting.TDA "Link to this definition") * TID*: [`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")** = 'TID'*[](#CalcSetting.TID "Link to this definition") ## Model[​](/sdk/api/external/scia/.md#_Model "Direct link to Model") * *class *viktor.external.scia.scia.Model(*\**, *mesh\_setup=None*, *solver\_setup=None*, *project\_data=None*)[](#Model "Link to this definition") This Model can be used to construct a SCIA model and generate its corresponding input XML file. This file can in turn be used as input of [`SciaAnalysis`](#SciaAnalysis "viktor.external.scia.scia.SciaAnalysis"). For a more detailed elaboration, please see the tutorial. Example usage: ``` # Initialize the model model = Model() # Construct the geometry n1 = model.create_node('K:1', 0, 0, 0) n2 = model.create_node('K:2', 1, 0, 0) css = model.create_circular_cross_section('css', Material(123, 'some_material'), 100) beam = model.create_beam(n1, n2, css) #Construct the boundary conditions freedom = (PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID, PointSupport.Freedom.RIGID) model.create_point_support('Sn1', n1, PointSupport.Type.STANDARD, freedom, (0, 0, 0, 0, 0, 0), PointSupport.CSys.GLOBAL) # Construct a load combination load_group = model.create_load_group('LG1', LoadGroup.LoadOption.VARIABLE, LoadGroup.RelationOption.STANDARD, LoadGroup.LoadTypeOption.CAT_A) load_case = model.create_variable_load_case('LC1', 'My first load case', load_group, LoadCase.VariableLoadType.STATIC, LoadCase.Specification.STANDARD, LoadCase.Duration.SHORT) model.create_load_combination('C1', LoadCombination.Type.ENVELOPE_ULTIMATE, {load_case: 1}) # Generate the input XML file input_xml = model.generate_xml_input() ``` * Parameters: * **mesh\_setup** ([`MeshSetup`](/sdk/api/external/scia/.md#MeshSetup "viktor.external.scia.object.MeshSetup")) – Optional mesh settings. * **solver\_setup** ([`SolverSetup`](/sdk/api/external/scia/.md#SolverSetup "viktor.external.scia.object.SolverSetup")) – Optional solver settings New in v13.1.0 . * **project\_data** ([`ProjectData`](/sdk/api/external/scia/.md#ProjectData "viktor.external.scia.object.ProjectData")) – Optional project settings New in v13.1.0 . - *property *arbitrary\_profiles*: Tuple\[[ArbitraryProfile](/sdk/api/external/scia/.md#ArbitraryProfile "viktor.external.scia.object.ArbitraryProfile"), ...]*[](#Model.arbitrary_profiles "Link to this definition") * *property *averaging\_strips*: Tuple\[[AveragingStrip](/sdk/api/external/scia/.md#AveragingStrip "viktor.external.scia.object.AveragingStrip"), ...]*[](#Model.averaging_strips "Link to this definition") - *property *beams*: Tuple\[[Beam](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam"), ...]*[](#Model.beams "Link to this definition") * *property *concrete\_materials*: Tuple\[[Concrete](/sdk/api/external/scia/.md#Concrete "viktor.external.scia.object.Concrete"), ...]*[](#Model.concrete_materials "Link to this definition") - create\_arbitrary\_profile(*name*, *beam*, *c\_def*, *cross\_section*, *spans*)[](#Model.create_arbitrary_profile "Link to this definition") Method to construct an arbitrary profile. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")) – enumeration of coordinate definition types * **cross\_section** ([`CrossSection`](/sdk/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object * **spans** (`List`\[[`ArbitraryProfileSpan`](/sdk/api/external/scia/.md#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan")]) – list of arbitrary profile span objects ([`create_arbitrary_profile_span()`](#Model.create_arbitrary_profile_span "viktor.external.scia.scia.Model.create_arbitrary_profile_span")). * Return type: [`ArbitraryProfile`](/sdk/api/external/scia/.md#ArbitraryProfile "viktor.external.scia.object.ArbitraryProfile") * create\_arbitrary\_profile\_span(*length*, *type\_of\_css*, *cross\_section\_start*, *cross\_section\_end*, *alignment*)[](#Model.create_arbitrary_profile_span "Link to this definition") Method to construct an arbitrary profile span, which is necessary to construct an arbitrary profile. * Parameters: * **length** (`float`) – length of the span * **type\_of\_css** ([`TypeOfCss`](/sdk/api/external/scia/.md#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")) – enumeration of cross-section types * **cross\_section\_start** ([`CrossSection`](/sdk/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object at the start point * **cross\_section\_end** ([`CrossSection`](/sdk/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object at the end point * **alignment** ([`Alignment`](/sdk/api/external/scia/.md#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")) – enumeration of alignment types * Return type: [`ArbitraryProfileSpan`](/sdk/api/external/scia/.md#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan") - create\_averaging\_strip(*plane*, *\**, *strip\_type*, *point\_1*, *width*, *length*, *angle*, *direction*, *name=None*)[](#Model.create_averaging_strip "Link to this definition") New in v14.3.0 Method to construct an averaging strip, which can be used for the automatic averaging of peak results. * Parameters: * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")). * **strip\_type** ([`Type`](/sdk/api/external/scia/.md#AveragingStrip.Type "viktor.external.scia.object.AveragingStrip.Type")) – Currently only Point type is supported * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the center position in \[m] * **width** (`float`) – width of the strip in \[m] * **length** (`float`) – length of the strip in \[m] * **angle** (`float`) – defines the direction of the strip \[deg] * **direction** ([`Direction`](/sdk/api/external/scia/.md#AveragingStrip.Direction "viktor.external.scia.object.AveragingStrip.Direction")) – direction in which the averaging is to be calculated * **name** (`str`) – name which will be shown in SCIA (default: ‘RS{i}’) * Return type: [`AveragingStrip`](/sdk/api/external/scia/.md#AveragingStrip "viktor.external.scia.object.AveragingStrip") * create\_beam(*begin\_node*, *end\_node*, *cross\_section*, *\**, *name=None*, *ez=None*, *lcs\_rotation=None*, *layer=None*)[](#Model.create_beam "Link to this definition") Method to construct a beam. * Parameters: * **begin\_node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the start of the beam. * **end\_node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the end of the beam. * **cross\_section** ([`CrossSection`](/sdk/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection")) – previously created cross-section object * **name** (`str`) – name which will be shown in SCIA (default: ‘B{i}’) * **ez** (`float`) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **lcs\_rotation** (`float`) – rotation of local coordinate system \[deg] (default: 0) * **layer** ([`Layer`](/sdk/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the beam will be added * Return type: [`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam") - create\_circular\_composed\_cross\_section(*name*, *material*, *material\_2*, *diameter*, *thickness*)[](#Model.create_circular_composed_cross_section "Link to this definition") Method to construct a circular cross-section, composed of two materials. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – outer material of the cross-section * **material\_2** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – inner material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * **thickness** (`float`) – thickness in \[m] * Return type: [`CircularComposedCrossSection`](/sdk/api/external/scia/.md#CircularComposedCrossSection "viktor.external.scia.object.CircularComposedCrossSection") * create\_circular\_cross\_section(*name*, *material*, *diameter*)[](#Model.create_circular_cross_section "Link to this definition") Method to construct a circular cross-section. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * Return type: [`CircularCrossSection`](/sdk/api/external/scia/.md#CircularCrossSection "viktor.external.scia.object.CircularCrossSection") - create\_circular\_hollow\_cross\_section(*name*, *material*, *diameter*, *thickness*)[](#Model.create_circular_hollow_cross_section "Link to this definition") Method to construct a circular hollow cross-section. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **diameter** (`float`) – diameter of the cross-section in \[m] * **thickness** (`float`) – thickness in \[m] * Return type: [`CircularHollowCrossSection`](/sdk/api/external/scia/.md#CircularHollowCrossSection "viktor.external.scia.object.CircularHollowCrossSection") * create\_circular\_plane(*center\_node*, *diameter*, *thickness*, *\**, *material*, *axis=None*, *name=None*, *plane\_type=None*, *layer=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*)[](#Model.create_circular_plane "Link to this definition") Method to construct a circular 2D member. * Parameters: * **center\_node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) located at the center of the plane * **diameter** (`float`) – diameter of the plane \[m] * **thickness** (`float`) – thickness of the plane \[m] * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – `Material` of the plane * **axis** (`Union`\[[`Vector`](/sdk/api/geometry/.md#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – axis direction (default: (0, 0, 1)) * **name** (`str`) – name which will be shown in SCIA (default: ‘S{i}’) * **plane\_type** ([`Type`](/sdk/api/external/scia/.md#Plane.Type "viktor.external.scia.object.Plane.Type")) – enumeration of plane types (default: PLATE) * **layer** ([`Layer`](/sdk/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the plane will be added * **internal\_nodes** (`List`\[[`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of internal node objects (default: None) * **swap\_orientation** (`bool`) – whereas to swap the plate orientation (default: False) * **lcs\_rotation** (`float`) – rotation of the local coordinate system \[deg] (default: 0.0) * **fem\_model** ([`FEMModel`](/sdk/api/external/scia/.md#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")) – FEM model to be used in the calculation (default: isotropic) * **orthotropy** ([`Orthotropy`](/sdk/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy")) – type of orthotropy (only for fem\_model = ORTHOTROPIC) * Return type: [`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane") - create\_cross\_link(*beam\_1*, *beam\_2*, *\**, *name=None*)[](#Model.create_cross_link "Link to this definition") New in v13.1.0 Method to construct a cross-link, connecting two beams. * Parameters: * **beam\_1** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – first beam ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) * **beam\_2** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – second beam ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) * **name** (`str`) – name which will be shown in SCIA (default: ‘CL{i}’) * Return type: [`CrossLink`](/sdk/api/external/scia/.md#CrossLink "viktor.external.scia.object.CrossLink") * create\_free\_line\_load(*name*, *load\_case*, *point\_1*, *point\_2*, *direction*, *magnitude\_1*, *magnitude\_2*)[](#Model.create_free_line_load "Link to this definition") Method to construct a free line load. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **point\_1** (`Tuple`\[`float`, `float`]) – XY coordinate of the first point * **point\_2** (`Tuple`\[`float`, `float`]) – XY coordinate of the second point * **direction** ([`Direction`](/sdk/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – enumeration of direction options * **magnitude\_1** (`float`) – magnitude of the load in point\_1 in \[N] * **magnitude\_2** (`float`) – magnitude of the load in point\_2 in \[N] * Return type: [`FreeLineLoad`](/sdk/api/external/scia/.md#FreeLineLoad "viktor.external.scia.object.FreeLineLoad") - create\_free\_point\_load(*name*, *load\_case*, *direction*, *magnitude*, *position*)[](#Model.create_free_point_load "Link to this definition") Method to construct a free point load. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **direction** ([`Direction`](/sdk/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – enumeration of direction options * **magnitude** (`float`) – magnitude of the load in \[N] * **position** (`Tuple`\[`float`, `float`]) – XY coordinate of the load * Return type: [`FreePointLoad`](/sdk/api/external/scia/.md#FreePointLoad "viktor.external.scia.object.FreePointLoad") * create\_free\_surface\_load(*name*, *load\_case*, *direction*, *q1*, *q2=None*, *q3=None*, *points=None*, *\**, *distribution=None*, *selection=None*)[](#Model.create_free_surface_load "Link to this definition") Method to construct a free surface load. Note: can only be defined in XY-plane. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **direction** ([`Direction`](/sdk/api/external/scia/.md#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")) – direction of the load * **q1** (`float`) – magnitude of the load in the first point in \[N] * **q2** (`float`) – magnitude of the load in the second point in \[N] (distribution = DIR\_X | DIR\_Y | POINTS only) * **q3** (`float`) – magnitude of the load in the third point in \[N] (distribution = POINTS only) * **points** (`List`\[`Tuple`\[`float`, `float`]]) – list of XY coordinates (at least 3). If distribution = DIR\_X | DIR\_Y: q1 and q2 are applied to points\[0] and points\[1] respectively. If distribution = POINTS: q1, q2 and q3 are applied to points\[0], points\[1] and points\[2] respectively. * **distribution** ([`Distribution`](/sdk/api/external/scia/.md#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")) – distribution of the load (default: POINTS) * **selection** (`List`\[[`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")]) – selection of 1 or more planes ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to generate the load on (default: select = auto) * Return type: [`FreeSurfaceLoad`](/sdk/api/external/scia/.md#FreeSurfaceLoad "viktor.external.scia.object.FreeSurfaceLoad") - create\_general\_cross\_section(*elements*, *\**, *name=None*)[](#Model.create_general_cross_section "Link to this definition") New in v14.7.0 Construct a general cross-section. * Parameters: * **name** (`str`) – name of the cross-section (default: ‘CS{i}’) * **elements** (`Sequence`\[[`GeneralCrossSectionElement`](/sdk/api/external/scia/.md#GeneralCrossSectionElement "viktor.external.scia.object.GeneralCrossSectionElement")]) – elements (polygon + openings) that build up the cross-section * Return type: [`GeneralCrossSection`](/sdk/api/external/scia/.md#GeneralCrossSection "viktor.external.scia.object.GeneralCrossSection") * create\_general\_cross\_section\_element(*name*, *element\_type*, *points*, *\**, *material=None*)[](#Model.create_general_cross_section_element "Link to this definition") New in v14.7.0 Construct a general cross-section element, which is necessary to construct a general cross-section. * Parameters: * **name** (`str`) – name of the element * **element\_type** ([`Type`](/sdk/api/external/scia/.md#GeneralCrossSectionElement.Type "viktor.external.scia.object.GeneralCrossSectionElement.Type")) – element type * **points** (`Sequence`\[`Tuple`\[`float`, `float`]]) – outline of the element * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the element * Return type: [`GeneralCrossSectionElement`](/sdk/api/external/scia/.md#GeneralCrossSectionElement "viktor.external.scia.object.GeneralCrossSectionElement") - create\_hinge\_on\_beam(*beam*, *position*, *\**, *name=None*, *freedom\_ux=Freedom.RIGID*, *freedom\_uy=Freedom.RIGID*, *freedom\_uz=Freedom.RIGID*, *freedom\_fix=Freedom.RIGID*, *freedom\_fiy=Freedom.FREE*, *freedom\_fiz=Freedom.RIGID*, *stiffness\_ux=0*, *stiffness\_uy=0*, *stiffness\_uz=0*, *stiffness\_fix=0*, *stiffness\_fiy=0*, *stiffness\_fiz=0*)[](#Model.create_hinge_on_beam "Link to this definition") Create a hinge on a beam. * Parameters: * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – Beam of appliance ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **position** ([`Position`](/sdk/api/external/scia/.md#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")) – Position of appliance. * **name** (`str`) – Name of the hinge (default: ‘H{i}’). * **freedom\_ux** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in ux (default: rigid). * **freedom\_uy** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in uy (default: rigid). * **freedom\_uz** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in uz (default: rigid). * **freedom\_fix** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fix (default: rigid). * **freedom\_fiy** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fiy (default: free). * **freedom\_fiz** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")) – Freedom in fiz (default: rigid). * **stiffness\_ux** (`float`) – Stiffness in ux \[N/m], only used if freedom in ux = flexible (default: 0.0). * **stiffness\_uy** (`float`) – Stiffness in uy \[N/m], only used if freedom in uy = flexible (default: 0.0). * **stiffness\_uz** (`float`) – Stiffness in uz \[N/m], only used if freedom in uz = flexible (default: 0.0). * **stiffness\_fix** (`float`) – Stiffness in fix \[Nm/rad], only used if freedom in fix = flexible (default: 0.0). * **stiffness\_fiy** (`float`) – Stiffness in fiy \[Nm/rad], only used if freedom in fiy = flexible (default: 0.0). * **stiffness\_fiz** (`float`) – Stiffness in fiz \[Nm/rad], only used if freedom in fiz = flexible (default: 0.0). * Return type: [`HingeOnBeam`](/sdk/api/external/scia/.md#HingeOnBeam "viktor.external.scia.object.HingeOnBeam") * create\_hinge\_on\_plane(*edge*, *\**, *name=None*, *ux=None*, *stiffness\_ux=None*, *uy=None*, *stiffness\_uy=None*, *uz=None*, *stiffness\_uz=None*, *fix=None*, *stiffness\_fix=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_hinge_on_plane "Link to this definition") Method to construct a hinge on a plane edge. * Parameters: * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of a plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the hinge will be attached (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **name** (`str`) – name which will be shown in SCIA (default: ‘L{i}’) * **ux** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")) – Freedom in ux (default: RIGID). * **stiffness\_ux** (`float`) – Stiffness in ux \[N/m2], only used if freedom in ux = flexible (default: 0.0). * **uy** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")) – Freedom in uy (default: RIGID). * **stiffness\_uy** (`float`) – Stiffness in uy \[N/m2], only used if freedom in uy = flexible (default: 0.0). * **uz** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")) – Freedom in uz (default: RIGID). * **stiffness\_uz** (`float`) – Stiffness in uz \[N/m2], only used if freedom in uz = flexible (default: 0.0). * **fix** ([`Freedom`](/sdk/api/external/scia/.md#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")) – Freedom in fix (default: FREE). * **stiffness\_fix** (`float`) – Stiffness in fix \[Nm/m/rad], only used if freedom in fix = flexible (default: 0.0). * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`HingeOnPlane`](/sdk/api/external/scia/.md#HingeOnPlane "viktor.external.scia.object.HingeOnPlane") - create\_integration\_strip(*plane*, *point\_1*, *point\_2*, *width*)[](#Model.create_integration_strip "Link to this definition") Method to construct an integration strip, which can be used to receive calculation results on its position. * Parameters: * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")). * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the start position in \[m] * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the end position in \[m] * **width** (`float`) – width of the strip in \[m] * Return type: [`IntegrationStrip`](/sdk/api/external/scia/.md#IntegrationStrip "viktor.external.scia.object.IntegrationStrip") * create\_internal\_edge(*plane*, *node\_1*, *node\_2*, *\**, *name=None*)[](#Model.create_internal_edge "Link to this definition") Method to construct an internal edge in a 2D member. * Parameters: * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) * **node\_1** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the start of the edge * **node\_2** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) at the end of the edge * **name** (`str`) – name which will be shown in SCIA (default: ‘ES{i}’) * Return type: [`InternalEdge`](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge") - create\_layer(*name=None*, *\**, *comment=None*, *structural\_model\_only=None*, *current\_used\_activity=None*)[](#Model.create_layer "Link to this definition") Method to construct a layer. Duplicate layer names are not allowed. * Parameters: * **name** (`str`) – name of the layer (default: ‘Layer{i}’) * **comment** (`str`) – optional comment * **structural\_model\_only** (`bool`) – when ‘True’, the layer is NOT taken into account for the calculation (default: False) * **current\_used\_activity** (`bool`) – defines if the layer is visible or not on the screen (default: True) * Return type: [`Layer`](/sdk/api/external/scia/.md#Layer "viktor.external.scia.object.Layer") * create\_library\_cross\_section(*section*, *profile*, *material*, *\**, *name=None*)[](#Model.create_library_cross_section "Link to this definition") New in v13.1.0 Method to construct a cross-section that is part of the cross-section library. * Parameters: * **section** ([`Section`](/sdk/api/external/scia/.md#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")) – section type (e.g. LibraryCrossSection.Section.I) * **profile** (`str`) – profile name including dimensions (e.g. “SHS30/30/2.0”) * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **name** (`str`) – name of the cross-section (default: ‘CS{i}’) * Return type: [`LibraryCrossSection`](/sdk/api/external/scia/.md#LibraryCrossSection "viktor.external.scia.object.LibraryCrossSection") - create\_line\_load(*name*, *load\_case*, *beam*, *load\_type*, *distribution*, *load\_start*, *load\_end*, *direction*, *position\_start*, *position\_end*, *c\_def*, *c\_sys*, *origin*, *ey*, *ez*)[](#Model.create_line_load "Link to this definition") Method to construct a line load on a beam. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **load\_type** ([`Type`](/sdk/api/external/scia/.md#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")) – enumeration of load types * **distribution** ([`Distribution`](/sdk/api/external/scia/.md#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")) – enumeration of distribution options * **load\_start** (`float`) – magnitude of the load at the start point in \[N] * **load\_end** (`float`) – magnitude of the load at the end point in \[N] * **direction** ([`Direction`](/sdk/api/external/scia/.md#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")) – enumeration of directions * **position\_start** (`float`) – position of the start point on the beam in \[m] * **position\_end** (`float`) – position of the end point on the beam in \[m] * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")) – enumeration of coordinate definition types * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")) – enumeration of coordinate system types * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")) – enumeration of origin types * **ey** (`float`) – eccentricity in Y-direction w\.r.t. the beam’s center line in \[m] * **ez** (`float`) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] * Return type: [`LineLoad`](/sdk/api/external/scia/.md#LineLoad "viktor.external.scia.object.LineLoad") * create\_line\_load\_on\_plane(*edge*, *p1*, *p2=None*, *\**, *load\_case*, *direction=None*, *name=None*, *location=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_line_load_on_plane "Link to this definition") Method to construct a line load on a plane edge. * Parameters: * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of a plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load will be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **p1** (`float`) – magnitude of the load \[N/m] on point 1 * **p2** (`float`) – magnitude of the load \[N/m] on point 2. None for uniform load (with magnitude p1) (default: None) * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **direction** ([`Direction`](/sdk/api/external/scia/.md#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")) – direction of the load (default: Z) * **name** (`str`) – name which will be shown in SCIA (default: ‘LFS{i}’) * **location** ([`Location`](/sdk/api/external/scia/.md#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")) – location type (default: LENGTH) * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")) – coordinate system (default: LOCAL) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`LineForceSurface`](/sdk/api/external/scia/.md#LineForceSurface "viktor.external.scia.object.LineForceSurface") - create\_line\_moment\_on\_beam(*beam*, *load\_case*, *m1*, *m2=None*, *\**, *name=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_line_moment_on_beam "Link to this definition") Method to construct a line moment on a beam. * Parameters: * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **m1** (`float`) – magnitude of the moment \[Nm/m] on point 1 * **m2** (`float`) – magnitude of the moment \[Nm/m] on point 2. None for uniform load (with magnitude m1) (default: None) * **name** (`str`) – name which will be shown in SCIA (default: ‘LM{i}’) * **direction** ([`Direction`](/sdk/api/external/scia/.md#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")) – direction of the moment (default: Z) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – position of p1 along the beam with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – position of p2 along the beam with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`LineMomentOnBeam`](/sdk/api/external/scia/.md#LineMomentOnBeam "viktor.external.scia.object.LineMomentOnBeam") * create\_line\_moment\_on\_plane(*edge*, *m1*, *m2=None*, *\**, *load\_case*, *name=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_line_moment_on_plane "Link to this definition") Method to construct a line moment on a plane edge. * Parameters: * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of the plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load should be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **m1** (`float`) – magnitude of the moment \[Nm/m] on point 1 * **m2** (`float`) – magnitude of the moment \[Nm/m] on point 2. None for uniform load (with magnitude m1) (default: None) * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be applied * **name** (`str`) – name which will be shown in SCIA (default: ‘LMS{i}’) * **direction** ([`Direction`](/sdk/api/external/scia/.md#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")) – direction of the moment (default: Z) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – position of p1 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – position of p2 along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`LineMomentOnPlane`](/sdk/api/external/scia/.md#LineMomentOnPlane "viktor.external.scia.object.LineMomentOnPlane") - create\_line\_support\_on\_beam(*beam*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *extent=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_line_support_on_beam "Link to this definition") Method to construct a line support on a beam. * Parameters: * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the line support will be applied * **name** (`str`) – name which will be shown in SCIA (default: ‘Slb{i}’) * **x** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in X-direction (default: RIGID) * **stiffness\_x** (`float`) – stiffness in X-direction \[N/m2] (only for x = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_x** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in X-direction (only for x = NONLINEAR) * **y** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Y-direction (default: RIGID) * **stiffness\_y** (`float`) – stiffness in Y-direction \[N/m2] (only for y = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_y** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in Y-direction (only for y = NONLINEAR) * **z** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Z-direction (default: RIGID) * **stiffness\_z** (`float`) – stiffness in Z-direction \[N/m2] (only for z = FLEXIBLE | FLEXIBLE\_PRESS\_ONLY | FLEXIBLE\_TENSION\_ONLY | NONLINEAR) * **function\_z** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in Z-direction (only for z = NONLINEAR) * **rx** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in X-rotation (default: RIGID) * **stiffness\_rx** (`float`) – stiffness in X-rotation \[Nm/m/rad] (only for rx = FLEXIBLE | NONLINEAR) * **function\_rx** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in X-rotation (only for rx = NONLINEAR) * **ry** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Y-rotation (default: RIGID) * **stiffness\_ry** (`float`) – stiffness in Y-rotation \[Nm/m/rad] (only for ry = FLEXIBLE | NONLINEAR) * **function\_ry** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in Y-rotation (only for ry = NONLINEAR) * **rz** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Z-rotation (default: RIGID) * **stiffness\_rz** (`float`) – stiffness in Z-rotation \[Nm/m/rad] (only for rz = FLEXIBLE | NONLINEAR) * **function\_rz** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – non-linear function in Z-rotation (only for rz = NONLINEAR) * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")) – coordinate system (default: LOCAL) * **extent** ([`Extent`](/sdk/api/external/scia/.md#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")) – extension of support (default: FULL) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – start of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – end of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`LineSupportLine`](/sdk/api/external/scia/.md#LineSupportLine "viktor.external.scia.object.LineSupportLine") * create\_line\_support\_on\_plane(*edge*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#Model.create_line_support_on_plane "Link to this definition") Method to construct a line support on a plane edge. * Parameters: * **edge** (`Union`\[`Tuple`\[[`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), `int`], [`InternalEdge`](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge")]) – tuple of the plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) and edge number to which the load should be applied (1 = between plane.corner\_nodes\[0] and plane.corner\_nodes\[1], etc.), or InternalEdge ([`create_internal_edge()`](#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge")) * **name** (`str`) – name which will be shown in SCIA (default: ‘Sle{i}’) * **x** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in X-direction (default: FREE) * **stiffness\_x** (`float`) – stiffness in X-direction \[N/m2] (only for x = FLEXIBLE) * **y** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Y-direction (default: FREE) * **stiffness\_y** (`float`) – stiffness in Y-direction \[N/m2] (only for y = FLEXIBLE) * **z** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Z-direction (default: FREE) * **stiffness\_z** (`float`) – stiffness in Z-direction \[N/m2] (only for z = FLEXIBLE) * **rx** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in X-rotation (default: FREE) * **stiffness\_rx** (`float`) – stiffness in X-rotation \[Nm/m/rad] (only for rx = FLEXIBLE) * **ry** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Y-rotation (default: FREE) * **stiffness\_ry** (`float`) – stiffness in Y-rotation \[Nm/m/rad] (only for ry = FLEXIBLE) * **rz** ([`Freedom`](/sdk/api/external/scia/.md#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")) – constraint type in Z-rotation (default: FREE) * **stiffness\_rz** (`float`) – stiffness in Z-rotation \[Nm/m/rad] (only for rz = FLEXIBLE) * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")) – coordinate system (default: GLOBAL) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")) – coordinate definition (default: RELATIVE) * **position\_x1** (`float`) – start of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0.0) * **position\_x2** (`float`) – end of support along the edge with respect to origin (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 1.0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")) – reference for position\_x1 and position\_x2 (default: FROM\_START) * Return type: [`LineSupportSurface`](/sdk/api/external/scia/.md#LineSupportSurface "viktor.external.scia.object.LineSupportSurface") - create\_load\_combination(*name*, *load\_type*, *load\_cases*, *\**, *description=None*)[](#Model.create_load_combination "Link to this definition") Method to construct a load combination. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_type** ([`Type`](/sdk/api/external/scia/.md#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")) – enumeration of load types * **load\_cases** (`Dict`\[[`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), `float`]) – dictionary of previously created load case object(s) with corresponding coefficient * **description** (`str`) – description of the load combination New in v13.1.0 * Return type: [`LoadCombination`](/sdk/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination") * create\_load\_group(*name*, *load\_option*, *relation=None*, *load\_type=None*)[](#Model.create_load_group "Link to this definition") Method to construct a load group. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_option** ([`LoadOption`](/sdk/api/external/scia/.md#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")) – enumeration of load option types * **relation** ([`RelationOption`](/sdk/api/external/scia/.md#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")) – enumeration of relation types * **load\_type** ([`LoadTypeOption`](/sdk/api/external/scia/.md#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")) – enumeration of load types * Return type: [`LoadGroup`](/sdk/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup") - create\_node(*name*, *x*, *y*, *z*)[](#Model.create_node "Link to this definition") Method to construct a node. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **x** (`float`) – X-coordinate in \[m] * **y** (`float`) – Y-coordinate in \[m] * **z** (`float`) – Z-coordinate in \[m] * Return type: [`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node") * create\_nonlinear\_function(*name*, *function\_type*, *positive\_end*, *negative\_end*, *impulse*)[](#Model.create_nonlinear_function "Link to this definition") Method to construct a non-linear function. * Parameters: * **name** (`str`) – name of the function * **function\_type** ([`Type`](/sdk/api/external/scia/.md#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")) – type of function * **positive\_end** ([`Support`](/sdk/api/external/scia/.md#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")) – type of support at positive end * **negative\_end** ([`Support`](/sdk/api/external/scia/.md#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")) – type of support at negative end * **impulse** (`List`\[`Tuple`\[`float`, `float`]]) – impulse function X-Y values in \[m, N] (if function\_type = TRANSLATION), \[rad, Nm] (if function\_type = ROTATION), or \[m, Pa] (if function\_type = NONLINEAR\_SUBSOIL) * Return type: [`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") - create\_nonlinear\_load\_combination(*load\_type*, *load\_cases*, *\**, *name=None*, *description=None*)[](#Model.create_nonlinear_load_combination "Link to this definition") Create a non-linear load combination. * Parameters: * **load\_type** ([`Type`](/sdk/api/external/scia/.md#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")) – type of combination * **load\_cases** (`Dict`\[[`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), `float`]) – dictionary of previously created load case object(s) with corresponding coefficient * **name** (`str`) – name which will be shown in SCIA (default: ‘NC{i}’) * **description** (`str`) – description of the load combination New in v13.1.0 * Return type: [`NonLinearLoadCombination`](/sdk/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination") * create\_numerical\_cross\_section(*name*, *material*, *\**, *A=None*, *Ay=None*, *Az=None*, *AL=None*, *AD=None*, *cYUCS=None*, *cZUCS=None*, *alpha=None*, *Iy=None*, *Iz=None*, *Wely=None*, *Welz=None*, *Wply=None*, *Wplz=None*, *Mply\_plus=None*, *Mply\_min=None*, *Mplz\_plus=None*, *Mplz\_min=None*, *dy=None*, *dz=None*, *It=None*, *Iw=None*, *beta\_y=None*, *beta\_z=None*)[](#Model.create_numerical_cross_section "Link to this definition") Method to construct a numerical cross-section. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **A** (`float`) – cross-sectional area \[m²] * **Ay** (`float`) – shear area in y-direction \[m²] * **Az** (`float`) – shear area in z-direction \[m²] * **AL** (`float`) – circumference per unit length \[m²/m] * **AD** (`float`) – drying surface per unit length \[m²/m] * **cYUCS** (`float`) – centroid in y-direction of input axis system \[mm] * **cZUCS** (`float`) – centroid in z-direction of input axis system \[mm] * **alpha** (`float`) – rotation angle of axis system \[deg] * **Iy** (`float`) – moment of inertia about the y-axis \[m⁴] * **Iz** (`float`) – moment of inertia about the z-axis \[m⁴] * **Wely** (`float`) – elastic section modulus about the y-axis \[m³] * **Welz** (`float`) – elastic section modulus about the z-axis \[m³] * **Wply** (`float`) – plastic section modulus about the y-axis \[m³] * **Wplz** (`float`) – plastic section modulus about the z-axis \[m³] * **Mply\_plus** (`float`) – plastic moment about the y-axis for positive My moment \[Nm] * **Mply\_min** (`float`) – plastic moment about the y-axis for negative My moment \[Nm] * **Mplz\_plus** (`float`) – plastic moment about the z-axis for positive My moment \[Nm] * **Mplz\_min** (`float`) – plastic moment about the z-axis for negative My moment \[Nm] * **dy** (`float`) – shear center coordinate in y-axis, measured from centroid \[mm] * **dz** (`float`) – shear center coordinate in z-axis, measured from centroid \[mm] * **It** (`float`) – torsional constant \[m⁴] * **Iw** (`float`) – warping constant \[m⁶] * **beta\_y** (`float`) – mono-symmetry constant about the y-axis \[mm] * **beta\_z** (`float`) – mono-symmetry constant about the z-axis \[mm] * Return type: [`NumericalCrossSection`](/sdk/api/external/scia/.md#NumericalCrossSection "viktor.external.scia.object.NumericalCrossSection") - create\_open\_slab(*name*, *plane*, *corner\_nodes*)[](#Model.create_open_slab "Link to this definition") Method to construct an open slab in a 2D member. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")). * **corner\_nodes** (`List`\[[`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of node objects located at the corners * Return type: [`OpenSlab`](/sdk/api/external/scia/.md#OpenSlab "viktor.external.scia.object.OpenSlab") * create\_orthotropy(*name*, *material*, *thickness*, *D11=None*, *D22=None*, *D12=None*, *D33=None*, *D44=None*, *D55=None*, *d11=None*, *d22=None*, *d12=None*, *d33=None*, *kxy=None*, *kyx=None*)[](#Model.create_orthotropy "Link to this definition") Method to construct a type of orthotropy. * Parameters: * **name** (`str`) – name of the orthotropy * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material * **thickness** (`float`) – thickness of the plate / wall \[m] * **D11** (`float`) – (plate) stiffness matrix parameter \[Nm] * **D22** (`float`) – (plate) stiffness matrix parameter \[Nm] * **D12** (`float`) – (plate) stiffness matrix parameter \[Nm] * **D33** (`float`) – (plate) stiffness matrix parameter \[Nm] * **D44** (`float`) – (plate) stiffness matrix parameter \[N/m] * **D55** (`float`) – (plate) stiffness matrix parameter \[N/m] * **d11** (`float`) – (membrane) stiffness matrix parameter \[N/m] * **d22** (`float`) – (membrane) stiffness matrix parameter \[N/m] * **d12** (`float`) – (membrane) stiffness matrix parameter \[N/m] * **d33** (`float`) – (membrane) stiffness matrix parameter \[N/m] * **kxy** (`float`) – stiffness coefficient \[N/m] * **kyx** (`float`) – stiffness coefficient \[N/m] * Return type: [`Orthotropy`](/sdk/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy") - create\_permanent\_load\_case(*name*, *description*, *load\_group*, *load\_type*, *direction=None*, *primary\_effect=None*)[](#Model.create_permanent_load_case "Link to this definition") Method to construct a permanent load case. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **description** (`str`) – description which will be shown in SCIA * **load\_group** ([`LoadGroup`](/sdk/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup")) – load group object ([`create_load_group()`](#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group")) in which the load case should be placed. * **load\_type** ([`PermanentLoadType`](/sdk/api/external/scia/.md#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")) – permanent load types * **direction** ([`Direction`](/sdk/api/external/scia/.md#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")) – load direction in case of a *SELF\_WEIGHT* load type (default: NEG\_Z) * **primary\_effect** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in case the selected load type is *PRIMARY\_EFFECT* * Return type: [`PermanentLoadCase`](/sdk/api/external/scia/.md#PermanentLoadCase "viktor.external.scia.object.PermanentLoadCase") * create\_plane(*corner\_nodes*, *thickness*, *\**, *material*, *name=None*, *plane\_type=None*, *layer=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*)[](#Model.create_plane "Link to this definition") Method to construct a 2D member. * Parameters: * **corner\_nodes** (`List`\[[`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of node objects located at the corners * **thickness** (`float`) – thickness of the plane in \[m] * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – `Material` of the plane * **name** (`str`) – name which will be shown in SCIA (default: ‘S{i}’) * **plane\_type** ([`Type`](/sdk/api/external/scia/.md#Plane.Type "viktor.external.scia.object.Plane.Type")) – enumeration of plane types (default: PLATE) * **layer** ([`Layer`](/sdk/api/external/scia/.md#Layer "viktor.external.scia.object.Layer")) – layer object ([`create_layer()`](#Model.create_layer "viktor.external.scia.scia.Model.create_layer")) to which the plane will be added * **internal\_nodes** (`List`\[[`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")]) – list of internal node objects (default: None) * **swap\_orientation** (`bool`) – whereas to swap the plate orientation (default: False) * **lcs\_rotation** (`float`) – rotation of the local coordinate system \[deg] (default: 0.0) * **fem\_model** ([`FEMModel`](/sdk/api/external/scia/.md#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")) – FEM model to be used in the calculation (default: isotropic) * **orthotropy** ([`Orthotropy`](/sdk/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy")) – type of orthotropy (only for fem\_model = ORTHOTROPIC) * Return type: [`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane") - create\_point\_load(*name*, *load\_case*, *beam*, *direction*, *load\_type*, *load\_value*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *ey=None*, *ez=None*, *\**, *angle=None*)[](#Model.create_point_load "Link to this definition") Method to construct a point load on a beam. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **direction** ([`Direction`](/sdk/api/external/scia/.md#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")) – enumeration of directions * **load\_type** ([`Type`](/sdk/api/external/scia/.md#PointLoad.Type "viktor.external.scia.object.PointLoad.Type")) – enumeration of load types * **load\_value** (`float`) – magnitude of the load in \[N] * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")) – enumeration of coordinate system types (default: global) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")) – enumeration of coordinate definition types (default: relative) * **position\_x** (`float`) – position of the load (default: 0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")) – enumeration of origin types (default: from start) * **repeat** (`int`) – number of loads acting on the beam, distributed uniformly (default: 1) * **ey** (`float`) – eccentricity in Y-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **ez** (`float`) – eccentricity in Z-direction w\.r.t. the beam’s center line in \[m] (default: 0) * **angle** (`Tuple`\[`float`, `float`, `float`]) – angle (Rx, Ry, Rz) \[deg] of the load around the respective X-, Y- and Z-axis (default: 0) * Return type: [`PointLoad`](/sdk/api/external/scia/.md#PointLoad "viktor.external.scia.object.PointLoad") * create\_point\_load\_node(*node*, *load\_case*, *load*, *\**, *name=None*, *direction=None*, *c\_sys=None*, *angle=None*)[](#Model.create_point_load_node "Link to this definition") Method to construct a point load in a node. * Parameters: * **node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) on which the load should be applied * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **load** (`float`) – magnitude of the load in \[N] * **name** (`str`) – name which will be shown in SCIA (default: ‘F{i}’) * **direction** ([`Direction`](/sdk/api/external/scia/.md#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")) – direction of the load (default: Z) * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")) – coordinate system (default: global) * **angle** (`Tuple`\[`float`, `float`, `float`]) – angle (Rx, Ry, Rz) \[deg] of the load around the respective global X-, Y- and Z-axis * Return type: [`PointLoadNode`](/sdk/api/external/scia/.md#PointLoadNode "viktor.external.scia.object.PointLoadNode") - create\_point\_moment\_node(*node*, *load\_case*, *load*, *direction*, *name=None*, *c\_sys=CSys.GLOBAL*)[](#Model.create_point_moment_node "Link to this definition") Create a point moment on an existing node. * Parameters: * **node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – Node of appliance ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – Previously created load case of appliance. * **load** (`float`) – Magnitude of the load \[Nm]. * **direction** ([`Direction`](/sdk/api/external/scia/.md#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")) – Direction of the load. * **name** (`str`) – Name of the load in SCIA (default: ‘M{i}’). * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")) – Coordinate system (default: global). * Return type: [`PointMomentNode`](/sdk/api/external/scia/.md#PointMomentNode "viktor.external.scia.object.PointMomentNode") * create\_point\_support(*name*, *node*, *spring\_type*, *freedom*, *stiffness*, *c\_sys*, *default\_size=0.2*, *\**, *angle=None*)[](#Model.create_point_support "Link to this definition") Method to construct a point support. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")) to which the support will be attached. * **spring\_type** ([`Type`](/sdk/api/external/scia/.md#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")) – enumeration of spring types * **freedom** (`Tuple`\[[`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom"), [`Freedom`](/sdk/api/external/scia/.md#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")]) – tuple of component constraints in the order (X, Y, Z, Rx, Ry, Rz) * **stiffness** (`Tuple`\[`float`, `float`, `float`, `float`, `float`, `float`]) – tuple of component stiffness in the order (X, Y, Z, Rx, Ry, Rz) in \[N/m] * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")) – enumeration of coordinate system types * **default\_size** (`float`) – default size in \[m] * **angle** (`Tuple`\[`float`, `float`, `float`]) – angle (Rx, Ry, Rz) \[deg] of the support around the respective global X-, Y- and Z-axis * Return type: [`PointSupport`](/sdk/api/external/scia/.md#PointSupport "viktor.external.scia.object.PointSupport") - create\_point\_support\_on\_beam(*beam*, *\**, *name=None*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *default\_size=None*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *delta\_x=None*)[](#Model.create_point_support_on_beam "Link to this definition") Method to construct a point support on a beam. * Parameters: * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the line support will be applied * **name** (`str`) – name which will be shown in SCIA (default: ‘Sb{i}’) * **x** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in X-direction (default: RIGID) * **stiffness\_x** (`float`) – stiffness in X-direction \[N/m] (only for x = FLEXIBLE) * **y** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in Y-direction (default: RIGID) * **stiffness\_y** (`float`) – stiffness in Y-direction \[N/m] (only for y = FLEXIBLE) * **z** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in Z-direction (default: RIGID) * **stiffness\_z** (`float`) – stiffness in Z-direction \[N/m] (only for z = FLEXIBLE) * **rx** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in X-rotation (default: RIGID) * **stiffness\_rx** (`float`) – stiffness in X-rotation \[Nm/rad] (only for rx = FLEXIBLE) * **ry** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in Y-rotation (default: RIGID) * **stiffness\_ry** (`float`) – stiffness in Y-rotation \[Nm/rad] (only for ry = FLEXIBLE) * **rz** ([`Freedom`](/sdk/api/external/scia/.md#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")) – constraint type in Z-rotation (default: RIGID) * **stiffness\_rz** (`float`) – stiffness in Z-rotation \[Nm/rad] (only for rz = FLEXIBLE) * **default\_size** (`float`) – size of the support \[m] (default: 0.2) * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")) – coordinate system (default: GLOBAL) * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")) – c\_def: coordinate definition (default: RELATIVE) * **position\_x** (`float`) – position of the load (\[m] if c\_def = ABSOLUTE, else \[-]) (default: 0) * **origin** ([`Origin`](/sdk/api/external/scia/.md#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")) – reference for position\_x (default: FROM\_START) * **repeat** (`int`) – number of uniformly distributed supports (default: 1) * **delta\_x** (`float`) – distance between supports (\[m] if c\_def = ABSOLUTE, else \[-]) (only for repeat > 1) * Return type: [`PointSupportLine`](/sdk/api/external/scia/.md#PointSupportLine "viktor.external.scia.object.PointSupportLine") * create\_rectangular\_cross\_section(*name*, *material*, *width*, *height*)[](#Model.create_rectangular_cross_section "Link to this definition") Method to construct a rectangular cross-section. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **material** ([`Material`](/sdk/api/external/scia/.md#Material "viktor.external.scia.object.Material")) – material of the cross-section * **width** (`float`) – width of the cross-section in \[m] * **height** (`float`) – height of the cross-section in \[m] * Return type: [`RectangularCrossSection`](/sdk/api/external/scia/.md#RectangularCrossSection "viktor.external.scia.object.RectangularCrossSection") - create\_result\_class(*name*, *combinations=None*, *nonlinear\_combinations=None*)[](#Model.create_result_class "Link to this definition") Method to construct a result class. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **combinations** (`List`\[[`LoadCombination`](/sdk/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination")]) – list of load combination objects ([`create_load_combination()`](#Model.create_load_combination "viktor.external.scia.scia.Model.create_load_combination")) * **nonlinear\_combinations** (`List`\[[`NonLinearLoadCombination`](/sdk/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination")]) – list of nonlinear load combination objects ([`create_nonlinear_load_combination()`](#Model.create_nonlinear_load_combination "viktor.external.scia.scia.Model.create_nonlinear_load_combination")) * Return type: [`ResultClass`](/sdk/api/external/scia/.md#ResultClass "viktor.external.scia.object.ResultClass") * create\_rigid\_arm(*name*, *master\_node*, *slave\_node*, *hinge\_on\_master*, *hinge\_on\_slave*)[](#Model.create_rigid_arm "Link to this definition") Method to construct a rigid arm. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **master\_node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **slave\_node** ([`Node`](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node")) – node object ([`create_node()`](#Model.create_node "viktor.external.scia.scia.Model.create_node")). * **hinge\_on\_master** (`bool`) – True to insert a hinge on the master node * **hinge\_on\_slave** (`bool`) – True to insert a hinge on the slave node * Return type: [`RigidArm`](/sdk/api/external/scia/.md#RigidArm "viktor.external.scia.object.RigidArm") - create\_section\_on\_beam(*name*, *beam*, *c\_def*, *position\_x*, *origin*, *repeat*, *delta\_x*)[](#Model.create_section_on_beam "Link to this definition") Method to construct a section on a beam, which can be used to receive calculation results on its position. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")). * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")) – enumeration of coordinate definition types * **position\_x** (`float`) – position of the section on the beam * **origin** ([`Origin`](/sdk/api/external/scia/.md#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")) – enumeration of origin types * **repeat** (`int`) – number of section defined at the same time * **delta\_x** (`float`) – if repeat is greater than 1, this value defines the distance between individual sections * Return type: [`SectionOnBeam`](/sdk/api/external/scia/.md#SectionOnBeam "viktor.external.scia.object.SectionOnBeam") * create\_section\_on\_plane(*point\_1*, *point\_2*, *\**, *name*, *draw=None*, *direction\_of\_cut=None*)[](#Model.create_section_on_plane "Link to this definition") Method to construct a section on a plane, which can be used to receive calculation results on its position. * Parameters: * **point\_1** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the start position in \[m] * **point\_2** (`Tuple`\[`float`, `float`, `float`]) – tuple of coordinates (x, y, z) of the end position in \[m] * **name** (`str`) – name which will be shown in SCIA (default: SE{i}) * **draw** ([`Draw`](/sdk/api/external/scia/.md#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")) – defines the plane in which the section is drawn (default: Z\_DIRECTION) * **direction\_of\_cut** (`Tuple`\[`float`, `float`, `float`]) – in-plane vector (x, y, z) which defines the direction of cut in \[m] (default: (0, 0, 1)) * Return type: [`SectionOnPlane`](/sdk/api/external/scia/.md#SectionOnPlane "viktor.external.scia.object.SectionOnPlane") - create\_selection(*name*, *objects*)[](#Model.create_selection "Link to this definition") New in v14.1.0 Method to construct a named selection. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **objects** (`List`\[[`SciaObject`](/sdk/api/external/scia/.md#SciaObject "viktor.external.scia.object.SciaObject")]) – object(s) created within this model * Return type: [`Selection`](/sdk/api/external/scia/.md#Selection "viktor.external.scia.object.Selection") * create\_subsoil(*name*, *\**, *stiffness*, *c1x=None*, *c1y=None*, *c1z=None*, *nonlinear\_function=None*, *c2x=None*, *c2y=None*, *is\_drained=None*, *water\_air\_in\_clay\_subgrade=None*, *specific\_weight=None*, *fi=None*, *sigma\_oc=None*, *c=None*, *cu=None*)[](#Model.create_subsoil "Link to this definition") Method to construct a subsoil. * Parameters: * **name** (`str`) – name of the subsoil * **stiffness** (`float`) – stiffness c1z \[N/m3] * **c1x** (`float`) – stiffness c1x \[N/m3] (default: 50000000) * **c1y** (`float`) – stiffness c1y \[N/m3] (default: 50000000) * **c1z** ([`C1z`](/sdk/api/external/scia/.md#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")) – type for c1z (default: FLEXIBLE) * **nonlinear\_function** ([`NonLinearFunction`](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction")) – nonlinear function ([`create_nonlinear_function()`](#Model.create_nonlinear_function "viktor.external.scia.scia.Model.create_nonlinear_function")) (c1z = NONLINEAR\_FUNCTION only) * **c2x** (`float`) – \[N/m] * **c2y** (`float`) – \[N/m] * **is\_drained** (`bool`) – True for ‘drained’, False for ‘undrained’ (default: False) * **water\_air\_in\_clay\_subgrade** (`bool`) – (default: False) * **specific\_weight** (`float`) – specific weight \[kg/m3] (default: 0.0) * **fi** (`float`) – fi’ \[deg] (default: 0.0) * **sigma\_oc** (`float`) – sigma oc \[Pa] (default: 0.0) * **c** (`float`) – c’ \[Pa] (default: 0.0) * **cu** (`float`) – \[Pa] (default: 0.0) * Return type: [`Subsoil`](/sdk/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil") - create\_surface\_load(*name*, *load\_case*, *plane*, *direction*, *load\_type*, *load\_value*, *c\_sys*, *location*)[](#Model.create_surface_load "Link to this definition") Method to construct a surface load on a plane. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the load should be applied * **direction** ([`Direction`](/sdk/api/external/scia/.md#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")) – enumeration of directions * **load\_type** ([`Type`](/sdk/api/external/scia/.md#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")) – enumeration of load types * **load\_value** (`float`) – magnitude of the load in \[N] * **c\_sys** ([`CSys`](/sdk/api/external/scia/.md#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")) – enumeration of coordinate system types * **location** ([`Location`](/sdk/api/external/scia/.md#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")) – enumeration of location options * Return type: [`SurfaceLoad`](/sdk/api/external/scia/.md#SurfaceLoad "viktor.external.scia.object.SurfaceLoad") * create\_surface\_support(*plane*, *subsoil*, *\**, *name=None*)[](#Model.create_surface_support "Link to this definition") Method to construct a surface support. * Parameters: * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the support will be attached * **subsoil** ([`Subsoil`](/sdk/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil")) – subsoil object ([`create_subsoil()`](#Model.create_subsoil "viktor.external.scia.scia.Model.create_subsoil")) representing the support * **name** (`str`) – name which will be shown in SCIA * Return type: [`SurfaceSupportSurface`](/sdk/api/external/scia/.md#SurfaceSupportSurface "viktor.external.scia.object.SurfaceSupportSurface") - create\_thermal\_load(*name*, *load\_case*, *beam*, *distribution*, *delta*, *left\_delta*, *right\_delta*, *top\_delta*, *bottom\_delta*, *position\_start*, *position\_end*, *c\_def*, *origin*)[](#Model.create_thermal_load "Link to this definition") Method to construct a temperature load on a beam. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **beam** ([`Beam`](/sdk/api/external/scia/.md#Beam "viktor.external.scia.object.Beam")) – beam object ([`create_beam()`](#Model.create_beam "viktor.external.scia.scia.Model.create_beam")) to which the load should be applied * **distribution** ([`Distribution`](/sdk/api/external/scia/.md#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")) – enumeration of distribution options * **delta** (`float`) – temperature difference in case of a *CONSTANT* distribution * **left\_delta** (`float`) – temperature difference in +Y direction * **right\_delta** (`float`) – temperature difference in -Y direction * **top\_delta** (`float`) – temperature difference in +Z direction * **bottom\_delta** (`float`) – temperature difference in -Z direction * **position\_start** (`float`) – position of the start point on the beam in \[m] * **position\_end** (`float`) – position of the end point on the beam in \[m] * **c\_def** ([`CDef`](/sdk/api/external/scia/.md#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")) – enumeration of coordinate definition types * **origin** ([`Origin`](/sdk/api/external/scia/.md#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")) – enumeration of origin types * Return type: [`ThermalLoad`](/sdk/api/external/scia/.md#ThermalLoad "viktor.external.scia.object.ThermalLoad") * create\_thermal\_surface\_load(*name*, *load\_case*, *plane*, *delta=None*, *top\_delta=None*, *bottom\_delta=None*)[](#Model.create_thermal_surface_load "Link to this definition") Method to construct a temperature load on a plane. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **load\_case** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in which the load should be placed * **plane** ([`Plane`](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane")) – plane object ([`create_plane()`](#Model.create_plane "viktor.external.scia.scia.Model.create_plane")) to which the load should be applied * **delta** (`float`) – temperature difference in case of a constant distribution * **top\_delta** (`float`) – temperature difference in +Z direction * **bottom\_delta** (`float`) – temperature difference in -Z direction * Return type: [`ThermalSurfaceLoad`](/sdk/api/external/scia/.md#ThermalSurfaceLoad "viktor.external.scia.object.ThermalSurfaceLoad") - create\_variable\_load\_case(*name*, *description*, *load\_group*, *load\_type*, *specification=None*, *duration=None*, *primary\_effect=None*)[](#Model.create_variable_load_case "Link to this definition") Method to construct a variable load case. * Parameters: * **name** (`str`) – name which will be shown in SCIA * **description** (`str`) – description which will be shown in SCIA * **load\_group** ([`LoadGroup`](/sdk/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup")) – load group object ([`create_load_group()`](#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group")) in which the load case should be placed. * **load\_type** ([`VariableLoadType`](/sdk/api/external/scia/.md#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")) – enumeration of variable load types * **specification** ([`Specification`](/sdk/api/external/scia/.md#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")) – enumeration of specification types * **duration** ([`Duration`](/sdk/api/external/scia/.md#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")) – enumeration of duration types * **primary\_effect** ([`LoadCase`](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase")) – previously created load case object in case the selected load type is *PRIMARY\_EFFECT* * Return type: [`VariableLoadCase`](/sdk/api/external/scia/.md#VariableLoadCase "viktor.external.scia.object.VariableLoadCase") * *property *cross\_links*: Tuple\[[CrossLink](/sdk/api/external/scia/.md#CrossLink "viktor.external.scia.object.CrossLink"), ...]*[](#Model.cross_links "Link to this definition") New in v13.1.0 - *property *cross\_sections*: Tuple\[[CrossSection](/sdk/api/external/scia/.md#CrossSection "viktor.external.scia.object.CrossSection"), ...]*[](#Model.cross_sections "Link to this definition") * *property *free\_line\_loads*: Tuple\[[FreeLineLoad](/sdk/api/external/scia/.md#FreeLineLoad "viktor.external.scia.object.FreeLineLoad"), ...]*[](#Model.free_line_loads "Link to this definition") - *property *free\_point\_loads*: Tuple\[[FreePointLoad](/sdk/api/external/scia/.md#FreePointLoad "viktor.external.scia.object.FreePointLoad"), ...]*[](#Model.free_point_loads "Link to this definition") * *property *free\_surface\_loads*: Tuple\[[FreeSurfaceLoad](/sdk/api/external/scia/.md#FreeSurfaceLoad "viktor.external.scia.object.FreeSurfaceLoad"), ...]*[](#Model.free_surface_loads "Link to this definition") - generate\_xml\_input(*as\_file=False*)[](#Model.generate_xml_input "Link to this definition") Returns the input file XML representation of the SCIA model and corresponding .def file. Note This method needs to be mocked in (automated) unit and integration tests. * Return type: `Union`\[`Tuple`\[`BytesIO`, `BytesIO`], `Tuple`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), [`File`](/sdk/api/core/.md#File "viktor.core.File")]] * Returns: * File if as\_file = True * BytesIO if as\_file = False (default) * *property *hinges\_on\_beam*: Tuple\[[HingeOnBeam](/sdk/api/external/scia/.md#HingeOnBeam "viktor.external.scia.object.HingeOnBeam"), ...]*[](#Model.hinges_on_beam "Link to this definition") - *property *hinges\_on\_plane*: Tuple\[[HingeOnPlane](/sdk/api/external/scia/.md#HingeOnPlane "viktor.external.scia.object.HingeOnPlane"), ...]*[](#Model.hinges_on_plane "Link to this definition") * *property *integration\_strips*: Tuple\[[IntegrationStrip](/sdk/api/external/scia/.md#IntegrationStrip "viktor.external.scia.object.IntegrationStrip"), ...]*[](#Model.integration_strips "Link to this definition") - *property *internal\_edges*: Tuple\[[InternalEdge](/sdk/api/external/scia/.md#InternalEdge "viktor.external.scia.object.InternalEdge"), ...]*[](#Model.internal_edges "Link to this definition") * *property *layers*: Tuple\[[Layer](/sdk/api/external/scia/.md#Layer "viktor.external.scia.object.Layer"), ...]*[](#Model.layers "Link to this definition") - *property *line\_force\_surface\_list*: Tuple\[[LineForceSurface](/sdk/api/external/scia/.md#LineForceSurface "viktor.external.scia.object.LineForceSurface"), ...]*[](#Model.line_force_surface_list "Link to this definition") * *property *line\_loads*: Tuple\[[LineLoad](/sdk/api/external/scia/.md#LineLoad "viktor.external.scia.object.LineLoad"), ...]*[](#Model.line_loads "Link to this definition") - *property *line\_moments\_on\_beam*: Tuple\[[LineMomentOnBeam](/sdk/api/external/scia/.md#LineMomentOnBeam "viktor.external.scia.object.LineMomentOnBeam"), ...]*[](#Model.line_moments_on_beam "Link to this definition") * *property *line\_moments\_on\_plane*: Tuple\[[LineMomentOnPlane](/sdk/api/external/scia/.md#LineMomentOnPlane "viktor.external.scia.object.LineMomentOnPlane"), ...]*[](#Model.line_moments_on_plane "Link to this definition") - *property *line\_supports\_line*: Tuple\[[LineSupportLine](/sdk/api/external/scia/.md#LineSupportLine "viktor.external.scia.object.LineSupportLine"), ...]*[](#Model.line_supports_line "Link to this definition") * *property *line\_supports\_surface*: Tuple\[[LineSupportSurface](/sdk/api/external/scia/.md#LineSupportSurface "viktor.external.scia.object.LineSupportSurface"), ...]*[](#Model.line_supports_surface "Link to this definition") - *property *load\_cases*: Tuple\[[LoadCase](/sdk/api/external/scia/.md#LoadCase "viktor.external.scia.object.LoadCase"), ...]*[](#Model.load_cases "Link to this definition") * *property *load\_combinations*: Tuple\[[LoadCombination](/sdk/api/external/scia/.md#LoadCombination "viktor.external.scia.object.LoadCombination"), ...]*[](#Model.load_combinations "Link to this definition") - *property *load\_groups*: Tuple\[[LoadGroup](/sdk/api/external/scia/.md#LoadGroup "viktor.external.scia.object.LoadGroup"), ...]*[](#Model.load_groups "Link to this definition") * *property *mesh\_setup*: [MeshSetup](/sdk/api/external/scia/.md#MeshSetup "viktor.external.scia.object.MeshSetup")*[](#Model.mesh_setup "Link to this definition") - *property *nodes*: Tuple\[[Node](/sdk/api/external/scia/.md#Node "viktor.external.scia.object.Node"), ...]*[](#Model.nodes "Link to this definition") * *property *nonlinear\_functions*: Tuple\[[NonLinearFunction](/sdk/api/external/scia/.md#NonLinearFunction "viktor.external.scia.object.NonLinearFunction"), ...]*[](#Model.nonlinear_functions "Link to this definition") - *property *nonlinear\_load\_combinations*: Tuple\[[NonLinearLoadCombination](/sdk/api/external/scia/.md#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination"), ...]*[](#Model.nonlinear_load_combinations "Link to this definition") * *property *open\_slabs*: Tuple\[[OpenSlab](/sdk/api/external/scia/.md#OpenSlab "viktor.external.scia.object.OpenSlab"), ...]*[](#Model.open_slabs "Link to this definition") - *property *orthotropy\_objects*: Tuple\[[Orthotropy](/sdk/api/external/scia/.md#Orthotropy "viktor.external.scia.object.Orthotropy"), ...]*[](#Model.orthotropy_objects "Link to this definition") * *property *planes*: Tuple\[[Plane](/sdk/api/external/scia/.md#Plane "viktor.external.scia.object.Plane"), ...]*[](#Model.planes "Link to this definition") - *property *point\_loads*: Tuple\[[PointLoad](/sdk/api/external/scia/.md#PointLoad "viktor.external.scia.object.PointLoad"), ...]*[](#Model.point_loads "Link to this definition") * *property *point\_loads\_node*: Tuple\[[PointLoadNode](/sdk/api/external/scia/.md#PointLoadNode "viktor.external.scia.object.PointLoadNode"), ...]*[](#Model.point_loads_node "Link to this definition") - *property *point\_moments\_node*: Tuple\[[PointMomentNode](/sdk/api/external/scia/.md#PointMomentNode "viktor.external.scia.object.PointMomentNode"), ...]*[](#Model.point_moments_node "Link to this definition") * *property *point\_supports*: Tuple\[[PointSupport](/sdk/api/external/scia/.md#PointSupport "viktor.external.scia.object.PointSupport"), ...]*[](#Model.point_supports "Link to this definition") - *property *point\_supports\_line*: Tuple\[[PointSupportLine](/sdk/api/external/scia/.md#PointSupportLine "viktor.external.scia.object.PointSupportLine"), ...]*[](#Model.point_supports_line "Link to this definition") * *property *project\_data*: [ProjectData](/sdk/api/external/scia/.md#ProjectData "viktor.external.scia.object.ProjectData")*[](#Model.project_data "Link to this definition") New in v13.1.0 - *property *result\_classes*: Tuple\[[ResultClass](/sdk/api/external/scia/.md#ResultClass "viktor.external.scia.object.ResultClass"), ...]*[](#Model.result_classes "Link to this definition") * *property *rigid\_arms*: Tuple\[[RigidArm](/sdk/api/external/scia/.md#RigidArm "viktor.external.scia.object.RigidArm"), ...]*[](#Model.rigid_arms "Link to this definition") - *property *sections\_on\_beam*: Tuple\[[SectionOnBeam](/sdk/api/external/scia/.md#SectionOnBeam "viktor.external.scia.object.SectionOnBeam"), ...]*[](#Model.sections_on_beam "Link to this definition") * *property *sections\_on\_plane*: Tuple\[[SectionOnPlane](/sdk/api/external/scia/.md#SectionOnPlane "viktor.external.scia.object.SectionOnPlane"), ...]*[](#Model.sections_on_plane "Link to this definition") - *property *selections*: Tuple\[[Selection](/sdk/api/external/scia/.md#Selection "viktor.external.scia.object.Selection"), ...]*[](#Model.selections "Link to this definition") * *property *solver\_setup*: [SolverSetup](/sdk/api/external/scia/.md#SolverSetup "viktor.external.scia.object.SolverSetup")*[](#Model.solver_setup "Link to this definition") New in v13.1.0 - *property *subsoils*: Tuple\[[Subsoil](/sdk/api/external/scia/.md#Subsoil "viktor.external.scia.object.Subsoil"), ...]*[](#Model.subsoils "Link to this definition") * *property *surface\_loads*: Tuple\[[SurfaceLoad](/sdk/api/external/scia/.md#SurfaceLoad "viktor.external.scia.object.SurfaceLoad"), ...]*[](#Model.surface_loads "Link to this definition") - *property *surface\_supports*: Tuple\[[SurfaceSupportSurface](/sdk/api/external/scia/.md#SurfaceSupportSurface "viktor.external.scia.object.SurfaceSupportSurface"), ...]*[](#Model.surface_supports "Link to this definition") * *property *thermal\_loads*: Tuple\[[ThermalLoad](/sdk/api/external/scia/.md#ThermalLoad "viktor.external.scia.object.ThermalLoad"), ...]*[](#Model.thermal_loads "Link to this definition") - *property *thermal\_surface\_loads*: Tuple\[[ThermalSurfaceLoad](/sdk/api/external/scia/.md#ThermalSurfaceLoad "viktor.external.scia.object.ThermalSurfaceLoad"), ...]*[](#Model.thermal_surface_loads "Link to this definition") * update\_concrete\_material(*object\_id*, *name*, *part*, *thermal\_expansion=None*, *unit\_mass=None*, *wet\_density=None*, *e\_modulus=None*, *poisson=None*, *g\_modulus=None*, *log\_decrement=None*, *specific\_heat=None*, *thermal\_conductivity=None*, *\**, *fck=None*)[](#Model.update_concrete_material "Link to this definition") This method can update specific properties of an already existing concrete material in the \*.esa model. * Parameters: * **object\_id** (`int`) – id of the material in SCIA * **name** (`str`) – name which will be shown in SCIA * **part** ([`ECPart`](/sdk/api/external/scia/.md#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")) – enumeration of concrete types * **thermal\_expansion** (`float`) – thermal expansion in \[m/mK] * **unit\_mass** (`float`) – density in \[kg/m3] * **wet\_density** (`float`) – wet density in \[kg/m3] * **e\_modulus** (`float`) – Young’s modulus in \[Pa] * **poisson** (`float`) – Poisson ratio * **g\_modulus** (`float`) – shear modulus in \[Pa] * **log\_decrement** (`float`) – log. decrement * **specific\_heat** (`float`) – specific heat in \[J/kgK] * **thermal\_conductivity** (`float`) – thermal conductivity in \[W/mK] * **fck** (`float`) – characteristic compressive cylinder strength \[Pa] * Return type: [`Concrete`](/sdk/api/external/scia/.md#Concrete "viktor.external.scia.object.Concrete") ## OutputFileParser[​](/sdk/api/external/scia/.md#_OutputFileParser "Direct link to OutputFileParser") * *class *viktor.external.scia.scia.OutputFileParser[](#OutputFileParser "Link to this definition") Helper class to extract results from a SCIA output file (.xml). Example using BytesIO: ``` xml_output_file = scia_analysis.get_xml_output_file() result_table = OutputFileParser.get_result(xml_output_file, 'Reactions') another_result_table = OutputFileParser.get_result(xml_output_file, '2D internal forces') ``` Example using [`File`](/sdk/api/core/.md#File "viktor.core.File"): ``` xml_output_file = scia_analysis.get_xml_output_file(as_file=True) with xml_output_file.open_binary() as f: result_table = OutputFileParser.get_result(f, 'Reactions') another_result_table = OutputFileParser.get_result(f, '2D internal forces') ``` * *classmethod *get\_result(*file*, *table\_name*, *\**, *parent=None*)[](#OutputFileParser.get_result "Link to this definition") Retrieve the results of an output XML by ‘table\_name’. This corresponds to the ‘name’ attribute that is found in the XML table, e.g. “Result classes - UGT” in the example below: ```
``` In case indenting has been used in the SCIA I/O doc, multiple tables with the name ‘table\_name’ will be found. A parent name can be specified as input to account for this indenting (up to 1 indent level). If indenting is used but no parent name is specified, this method will return the first ‘table\_name’ table it can find. * Parameters: * **file** (`BinaryIO`) – SCIA output file (.xml). * **table\_name** (`str`) – Name of the result table to be extracted from the output XML. * **parent** (`str`) – Name of the parent, e.g. a result class. * Return type: `Dict`\[`str`, `dict`] - :raises [`viktor.errors.SciaParsingError`](/sdk/api/errors/.md#SciaParsingError "viktor.errors.SciaParsingError"): * if table ‘table\_name’ could not be found in the provided output file * if no results were found in the XML table ‘table\_name’ ## ResultType[​](/sdk/api/external/scia/.md#_ResultType "Direct link to ResultType") * *class *viktor.external.scia.scia.ResultType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ResultType "Link to this definition") Bases: `Enum` Enumeration of result types: * ENGINEERING\_REPORT*: [`ResultType`](#ResultType "viktor.external.scia.scia.ResultType")** = 'ENGINEERING\_REPORT'*[](#ResultType.ENGINEERING_REPORT "Link to this definition") - MODEL*: [`ResultType`](#ResultType "viktor.external.scia.scia.ResultType")** = 'MODEL'*[](#ResultType.MODEL "Link to this definition") * NONE*: [`ResultType`](#ResultType "viktor.external.scia.scia.ResultType")** = 'XML'*[](#ResultType.NONE "Link to this definition") ## SciaAnalysis[​](/sdk/api/external/scia/.md#_SciaAnalysis "Direct link to SciaAnalysis") * *class *viktor.external.scia.scia.SciaAnalysis(*input\_file*, *xml\_def\_file*, *scia\_model*, *calculation\_setting=CalcSetting.LIN*, *xml\_doc\_name='output'*, *\**, *result\_type=ResultType.MODEL*, *output\_document=''*)[](#SciaAnalysis "Link to this definition") Bases: [`ExternalProgram`](/sdk/api/external/external-program/.md#ExternalProgram "viktor.external.external_program.ExternalProgram") SciaAnalysis can be used to perform an analysis using SCIA on a third-party worker. To start an analysis call the method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"), with an appropriate timeout (in seconds). To retrieve the output file call the method [`get_xml_output_file()`](#SciaAnalysis.get_xml_output_file "viktor.external.scia.scia.SciaAnalysis.get_xml_output_file") after [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute"). Usage: ``` input_file = BytesIO("scia input file content".encode()) xml_def_file = BytesIO("scia xml def file content".encode()) scia_model = BytesIO("scia model content".encode()) scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model) scia_analysis.execute(timeout=600) xml_output_file = scia_analysis.get_xml_output_file() ``` Besides the output XML file, you can also retrieve the updated SCIA model. This is achieved using the result\_type: ``` scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model, result_type=ResultType.MODEL) scia_analysis.execute(timeout=600) updated_esa_file = scia_analysis.get_updated_esa_model() ``` or the Engineering Report: ``` scia_analysis = SciaAnalysis(input_file=input_file, xml_def_file=xml_def_file, scia_model=scia_model, result_type=ResultType.ENGINEERING_REPORT, output_document='report1') scia_analysis.execute(timeout=600) engineering_report = scia_analysis.get_engineering_report() ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **input\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – SCIA input .xml file. * **xml\_def\_file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – SCIA input .def file. * **scia\_model** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – SCIA .esa model. * **calculation\_setting** ([`CalcSetting`](#CalcSetting "viktor.external.scia.scia.CalcSetting")) – Available calculation settings according to the documentation of ESA\_XML.exe: * NONE = without any recalculations * NOC = No calculation * LIN = Linear calculation (Delete all calculated results when exists) * NEL = Nonlinear calculation * CON = Nonlinear concrete calculation * EIG = Eigen frequencies calculation * STB = Stability calculation * INF = Influence lines calculation * MOB = Mobile loads calculation * TDA = TDA calculation * SLN = Soilin calculation * PHA = Phases calculation * NPH = Nonlinear phases * CSS = Recalculation of cross sections * NST = Nonlinear stability * TID = Test of input data - solver link only * **xml\_doc\_name** (`str`) – Name of XML IO document for export. * **result\_type** ([`ResultType`](#ResultType "viktor.external.scia.scia.ResultType")) – Type of output which should be returned besides the output.xml: * ResultType.NONE returns nothing * ResultType.MODEL returns the updated SCIA model (.esa) after calculation * ResultType.ENGINEERING\_REPORT returns the specified engineering report * **output\_document** (`str`) – Document name of the report which should be returned. This name should match the exact name of the report as defined in the .esa model. * Raises: **ValueError** – if Engineering Report is selected as result\_type, but no output\_document is specified. - get\_engineering\_report(*as\_file=False*)[](#SciaAnalysis.get_engineering_report "Link to this definition") Method can be used to retrieve the Engineering Report (.pdf). Make sure to call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_engineering_report()`](#SciaAnalysis.get_engineering_report "viktor.external.scia.scia.SciaAnalysis.get_engineering_report") afterwards. * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * Returns: * File, if as\_file = True * BytesIO, if as\_file = False (default) * get\_updated\_esa\_model(*as\_file=False*)[](#SciaAnalysis.get_updated_esa_model "Link to this definition") Method can be used to retrieve the updated SCIA model file (.esa), which contains the data that is read into the model while calling ESA\_XML.exe. Make sure to call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_updated_esa_model()`](#SciaAnalysis.get_updated_esa_model "viktor.external.scia.scia.SciaAnalysis.get_updated_esa_model") afterwards. * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * Returns: * File, if as\_file = True * BytesIO, if as\_file = False (default) - *static *get\_xml\_def\_name(*input\_file*)[](#SciaAnalysis.get_xml_def_name "Link to this definition") * Return type: `str` * get\_xml\_output\_file(*as\_file=False*)[](#SciaAnalysis.get_xml_output_file "Link to this definition") Method can be used to retrieve the results generated by running an external analysis. This method returns the output XML file that is generated by SCIA. Make sure to call method [`execute()`](/sdk/api/external/external-program/.md#ExternalProgram.execute "viktor.external.external_program.ExternalProgram.execute") first and [`get_xml_output_file()`](#SciaAnalysis.get_xml_output_file "viktor.external.scia.scia.SciaAnalysis.get_xml_output_file") afterwards. * Return type: `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `None`] * Returns: * File, if as\_file = True * BytesIO, if as\_file = False (default) ## ArbitraryProfile[​](/sdk/api/external/scia/.md#_ArbitraryProfile "Direct link to ArbitraryProfile") * *class *viktor.external.scia.object.ArbitraryProfile(*object\_id*, *name*, *beam*, *c\_def*, *cross\_section*, *spans*)[](#ArbitraryProfile "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_arbitrary_profile()`](/sdk/api/external/scia/.md#Model.create_arbitrary_profile "viktor.external.scia.scia.Model.create_arbitrary_profile") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ArbitraryProfile.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute * **RELATIVE** - relative - ABSOLUTE*: [`CDef`](#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")** = 0*[](#ArbitraryProfile.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#ArbitraryProfile.CDef "viktor.external.scia.object.ArbitraryProfile.CDef")** = 1*[](#ArbitraryProfile.CDef.RELATIVE "Link to this definition") - *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#ArbitraryProfile.beam "Link to this definition") * *property *cross\_section*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[](#ArbitraryProfile.cross_section "Link to this definition") - *property *spans*: List\[[ArbitraryProfileSpan](#ArbitraryProfileSpan "viktor.external.scia.object.ArbitraryProfileSpan")]*[](#ArbitraryProfile.spans "Link to this definition") ## ArbitraryProfileSpan[​](/sdk/api/external/scia/.md#_ArbitraryProfileSpan "Direct link to ArbitraryProfileSpan") * *class *viktor.external.scia.object.ArbitraryProfileSpan(*length*, *type\_of\_css*, *cross\_section\_start*, *cross\_section\_end*, *alignment*)[](#ArbitraryProfileSpan "Link to this definition") Do not use this \_\_init\_\_ directly, but create the object by [`create_arbitrary_profile_span()`](/sdk/api/external/scia/.md#Model.create_arbitrary_profile_span "viktor.external.scia.scia.Model.create_arbitrary_profile_span") * *class *Alignment(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ArbitraryProfileSpan.Alignment "Link to this definition") Bases: `Enum` * **DEFAULT** - see “Default” at * **CENTER\_LINE** - see “Centre line” at * **TOP\_SURFACE** - see “Top surface” at * **BOTTOM\_SURFACE** - see “Bottom surface” at * **LEFT\_SURFACE** - see “Left surface” at * **RIGHT\_SURFACE** - see “Right surface” at * **TOP\_LEFT** - * **TOP\_RIGHT** - * **BOTTOM\_LEFT** - * **BOTTOM\_RIGHT** - - BOTTOM\_LEFT*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 8*[](#ArbitraryProfileSpan.Alignment.BOTTOM_LEFT "Link to this definition") * BOTTOM\_RIGHT*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 9*[](#ArbitraryProfileSpan.Alignment.BOTTOM_RIGHT "Link to this definition") - BOTTOM\_SURFACE*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 3*[](#ArbitraryProfileSpan.Alignment.BOTTOM_SURFACE "Link to this definition") * CENTER\_LINE*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 1*[](#ArbitraryProfileSpan.Alignment.CENTER_LINE "Link to this definition") - DEFAULT*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 0*[](#ArbitraryProfileSpan.Alignment.DEFAULT "Link to this definition") * LEFT\_SURFACE*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 4*[](#ArbitraryProfileSpan.Alignment.LEFT_SURFACE "Link to this definition") - RIGHT\_SURFACE*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 5*[](#ArbitraryProfileSpan.Alignment.RIGHT_SURFACE "Link to this definition") * TOP\_LEFT*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 6*[](#ArbitraryProfileSpan.Alignment.TOP_LEFT "Link to this definition") - TOP\_RIGHT*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 7*[](#ArbitraryProfileSpan.Alignment.TOP_RIGHT "Link to this definition") * TOP\_SURFACE*: [`Alignment`](#ArbitraryProfileSpan.Alignment "viktor.external.scia.object.ArbitraryProfileSpan.Alignment")** = 2*[](#ArbitraryProfileSpan.Alignment.TOP_SURFACE "Link to this definition") - *class *TypeOfCss(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ArbitraryProfileSpan.TypeOfCss "Link to this definition") Bases: `Enum` * **PRISMATIC** - The cross-section of the span is constant. * **PARAM\_HAUNCH** - A standard haunch is inserted into the span. * **TWO\_CSS** - Two cross-sections corresponding to the two end-points of the span are defined. The cross-section varies over the span from one section to the other. - PARAM\_HAUNCH*: [`TypeOfCss`](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 1*[](#ArbitraryProfileSpan.TypeOfCss.PARAM_HAUNCH "Link to this definition") * PRISMATIC*: [`TypeOfCss`](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 0*[](#ArbitraryProfileSpan.TypeOfCss.PRISMATIC "Link to this definition") - TWO\_CSS*: [`TypeOfCss`](#ArbitraryProfileSpan.TypeOfCss "viktor.external.scia.object.ArbitraryProfileSpan.TypeOfCss")** = 2*[](#ArbitraryProfileSpan.TypeOfCss.TWO_CSS "Link to this definition") * *property *cross\_section\_end*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[](#ArbitraryProfileSpan.cross_section_end "Link to this definition") - *property *cross\_section\_start*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[](#ArbitraryProfileSpan.cross_section_start "Link to this definition") ## AveragingStrip[​](/sdk/api/external/scia/.md#_AveragingStrip "Direct link to AveragingStrip") * *class *viktor.external.scia.object.AveragingStrip(*object\_id*, *name*, *plane*, *strip\_type*, *point\_1*, *width*, *length*, *angle*, *direction*)[](#AveragingStrip "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_averaging_strip()`](/sdk/api/external/scia/.md#Model.create_averaging_strip "viktor.external.scia.scia.Model.create_averaging_strip") * *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#AveragingStrip.Direction "Link to this definition") Bases: `Enum` * BOTH*: [`Direction`](#AveragingStrip.Direction "viktor.external.scia.object.AveragingStrip.Direction")** = 2*[](#AveragingStrip.Direction.BOTH "Link to this definition") - LONGITUDINAL*: [`Direction`](#AveragingStrip.Direction "viktor.external.scia.object.AveragingStrip.Direction")** = 0*[](#AveragingStrip.Direction.LONGITUDINAL "Link to this definition") * NONE*: [`Direction`](#AveragingStrip.Direction "viktor.external.scia.object.AveragingStrip.Direction")** = 3*[](#AveragingStrip.Direction.NONE "Link to this definition") - PERPENDICULAR*: [`Direction`](#AveragingStrip.Direction "viktor.external.scia.object.AveragingStrip.Direction")** = 1*[](#AveragingStrip.Direction.PERPENDICULAR "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#AveragingStrip.Type "Link to this definition") Bases: `Enum` * POINT*: AveragingStrip.POINT** = 1*[](#AveragingStrip.Type.POINT "Link to this definition") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#AveragingStrip.plane "Link to this definition") ## Beam[​](/sdk/api/external/scia/.md#_Beam "Direct link to Beam") * *class *viktor.external.scia.object.Beam(*object\_id*, *name*, *begin\_node*, *end\_node*, *cross\_section*, *ez=None*, *lcs\_rotation=None*, *layer=None*)[](#Beam "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_beam()`](/sdk/api/external/scia/.md#Model.create_beam "viktor.external.scia.scia.Model.create_beam") * *property *begin\_node*: [Node](#Node "viktor.external.scia.object.Node")*[](#Beam.begin_node "Link to this definition") - *property *cross\_section*: [CrossSection](#CrossSection "viktor.external.scia.object.CrossSection")*[](#Beam.cross_section "Link to this definition") * *property *end\_node*: [Node](#Node "viktor.external.scia.object.Node")*[](#Beam.end_node "Link to this definition") - *property *ez*: float*[](#Beam.ez "Link to this definition") ## CircularComposedCrossSection[​](/sdk/api/external/scia/.md#_CircularComposedCrossSection "Direct link to CircularComposedCrossSection") * *class *viktor.external.scia.object.CircularComposedCrossSection(*object\_id*, *name*, *material*, *material\_2*, *diameter*, *thickness*)[](#CircularComposedCrossSection "Link to this definition") Bases: [`ComposedCrossSection`](#ComposedCrossSection "viktor.external.scia.object.ComposedCrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_composed_cross_section()`](/sdk/api/external/scia/.md#Model.create_circular_composed_cross_section "viktor.external.scia.scia.Model.create_circular_composed_cross_section") ## CircularCrossSection[​](/sdk/api/external/scia/.md#_CircularCrossSection "Direct link to CircularCrossSection") * *class *viktor.external.scia.object.CircularCrossSection(*object\_id*, *name*, *material*, *diameter*)[](#CircularCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_cross_section()`](/sdk/api/external/scia/.md#Model.create_circular_cross_section "viktor.external.scia.scia.Model.create_circular_cross_section") ## CircularHollowCrossSection[​](/sdk/api/external/scia/.md#_CircularHollowCrossSection "Direct link to CircularHollowCrossSection") * *class *viktor.external.scia.object.CircularHollowCrossSection(*object\_id*, *name*, *material*, *diameter*, *thickness*)[](#CircularHollowCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_circular_hollow_cross_section()`](/sdk/api/external/scia/.md#Model.create_circular_hollow_cross_section "viktor.external.scia.scia.Model.create_circular_hollow_cross_section") ## ComposedCrossSection[​](/sdk/api/external/scia/.md#_ComposedCrossSection "Direct link to ComposedCrossSection") * *class *viktor.external.scia.object.ComposedCrossSection(*object\_id*, *name*, *material*, *material\_2*)[](#ComposedCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Abstract base class of all cross sections, composed of two materials. ## Concrete[​](/sdk/api/external/scia/.md#_Concrete "Direct link to Concrete") * *class *viktor.external.scia.object.Concrete(*object\_id*, *name*, *part*, *thermal\_expansion=None*, *unit\_mass=None*, *wet\_density=None*, *e\_modulus=None*, *poisson=None*, *g\_modulus=None*, *log\_decrement=None*, *specific\_heat=None*, *thermal\_conductivity=None*, *\**, *fck=None*)[](#Concrete "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`update_concrete_material()`](/sdk/api/external/scia/.md#Model.update_concrete_material "viktor.external.scia.scia.Model.update_concrete_material") * *class *ECPart(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Concrete.ECPart "Link to this definition") Bases: `Enum` * **GENERAL** - concrete EN 1992-1-1 * **BRIDGES** - concrete EN 1992-2 - BRIDGES*: [`ECPart`](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")** = 1*[](#Concrete.ECPart.BRIDGES "Link to this definition") * GENERAL*: [`ECPart`](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")** = 0*[](#Concrete.ECPart.GENERAL "Link to this definition") - *property *ec\_part*: [ECPart](#Concrete.ECPart "viktor.external.scia.object.Concrete.ECPart")*[](#Concrete.ec_part "Link to this definition") ## CrossLink[​](/sdk/api/external/scia/.md#_CrossLink "Direct link to CrossLink") * *class *viktor.external.scia.object.CrossLink(*object\_id*, *name*, *beam\_1*, *beam\_2*)[](#CrossLink "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_cross_link()`](/sdk/api/external/scia/.md#Model.create_cross_link "viktor.external.scia.scia.Model.create_cross_link") ## CrossSection[​](/sdk/api/external/scia/.md#_CrossSection "Direct link to CrossSection") * *class *viktor.external.scia.object.CrossSection(*object\_id*, *name*, *material*)[](#CrossSection "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Abstract base class of all cross sections. ## FreeLineLoad[​](/sdk/api/external/scia/.md#_FreeLineLoad "Direct link to FreeLineLoad") * *class *viktor.external.scia.object.FreeLineLoad(*object\_id*, *name*, *load\_case*, *point\_1*, *point\_2*, *direction*, *magnitude\_1*, *magnitude\_2*, *distribution=Distribution.TRAPEZOIDAL*, *validity=Validity.ALL*, *load\_type=Type.FORCE*, *select=Select.AUTO*, *system=CSys.GLOBAL*, *location=Location.LENGTH*)[](#FreeLineLoad "Link to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_line_load()`](/sdk/api/external/scia/.md#Model.create_free_line_load "viktor.external.scia.scia.Model.create_free_line_load") * *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLineLoad.Distribution "Link to this definition") Bases: `Enum` * TRAPEZOIDAL*: [`Distribution`](#FreeLineLoad.Distribution "viktor.external.scia.object.FreeLineLoad.Distribution")** = 1*[](#FreeLineLoad.Distribution.TRAPEZOIDAL "Link to this definition") - UNIFORM*: [`Distribution`](#FreeLineLoad.Distribution "viktor.external.scia.object.FreeLineLoad.Distribution")** = 0*[](#FreeLineLoad.Distribution.UNIFORM "Link to this definition") ## FreeLoad[​](/sdk/api/external/scia/.md#_FreeLoad "Direct link to FreeLoad") * *class *viktor.external.scia.object.FreeLoad(*object\_id*, *name*, *load\_case*, *direction*, *select*, *validity=None*, *load\_type=None*, *c\_sys=None*)[](#FreeLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Abstract base class of all free loads. * Do not use this \_\_init\_\_ directly, but create the object by [`create_free_point_load()`](/sdk/api/external/scia/.md#Model.create_free_point_load "viktor.external.scia.scia.Model.create_free_point_load"), [`create_free_line_load()`](/sdk/api/external/scia/.md#Model.create_free_line_load "viktor.external.scia.scia.Model.create_free_line_load") or [`create_free_surface_load()`](/sdk/api/external/scia/.md#Model.create_free_surface_load "viktor.external.scia.scia.Model.create_free_surface_load") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 0*[](#FreeLoad.CSys.GLOBAL "Link to this definition") - LOAD\_LCS*: [`CSys`](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 2*[](#FreeLoad.CSys.LOAD_LCS "Link to this definition") * MEMBER\_LCS*: [`CSys`](#FreeLoad.CSys "viktor.external.scia.object.FreeLoad.CSys")** = 1*[](#FreeLoad.CSys.MEMBER_LCS "Link to this definition") * *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 0*[](#FreeLoad.Direction.X "Link to this definition") - Y*: [`Direction`](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 1*[](#FreeLoad.Direction.Y "Link to this definition") * Z*: [`Direction`](#FreeLoad.Direction "viktor.external.scia.object.FreeLoad.Direction")** = 2*[](#FreeLoad.Direction.Z "Link to this definition") - *class *Location(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.Location "Link to this definition") Bases: `Enum` * LENGTH*: [`Location`](#FreeLoad.Location "viktor.external.scia.object.FreeLoad.Location")** = 0*[](#FreeLoad.Location.LENGTH "Link to this definition") - PROJECTION*: [`Location`](#FreeLoad.Location "viktor.external.scia.object.FreeLoad.Location")** = 1*[](#FreeLoad.Location.PROJECTION "Link to this definition") * *class *Select(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.Select "Link to this definition") Bases: `Enum` * AUTO*: [`Select`](#FreeLoad.Select "viktor.external.scia.object.FreeLoad.Select")** = 0*[](#FreeLoad.Select.AUTO "Link to this definition") - SELECT*: [`Select`](#FreeLoad.Select "viktor.external.scia.object.FreeLoad.Select")** = 1*[](#FreeLoad.Select.SELECT "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.Type "Link to this definition") Bases: `Enum` * FORCE*: [`Type`](#FreeLoad.Type "viktor.external.scia.object.FreeLoad.Type")** = 0*[](#FreeLoad.Type.FORCE "Link to this definition") * *class *Validity(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeLoad.Validity "Link to this definition") Bases: `Enum` * ALL*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 0*[](#FreeLoad.Validity.ALL "Link to this definition") - FROM\_TO*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 3*[](#FreeLoad.Validity.FROM_TO "Link to this definition") * NEG\_Z*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 1*[](#FreeLoad.Validity.NEG_Z "Link to this definition") - NEG\_Z\_INCL\_ZERO*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 5*[](#FreeLoad.Validity.NEG_Z_INCL_ZERO "Link to this definition") * POS\_Z*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 2*[](#FreeLoad.Validity.POS_Z "Link to this definition") - POS\_Z\_INCL\_ZERO*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 6*[](#FreeLoad.Validity.POS_Z_INCL_ZERO "Link to this definition") * ZERO\_Z*: [`Validity`](#FreeLoad.Validity "viktor.external.scia.object.FreeLoad.Validity")** = 4*[](#FreeLoad.Validity.ZERO_Z "Link to this definition") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#FreeLoad.load_case "Link to this definition") ## FreePointLoad[​](/sdk/api/external/scia/.md#_FreePointLoad "Direct link to FreePointLoad") * *class *viktor.external.scia.object.FreePointLoad(*object\_id*, *name*, *load\_case*, *direction*, *magnitude*, *position*, *load\_type=Type.FORCE*, *validity=Validity.ALL*, *select=Select.AUTO*, *system=CSys.GLOBAL*)[](#FreePointLoad "Link to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_point_load()`](/sdk/api/external/scia/.md#Model.create_free_point_load "viktor.external.scia.scia.Model.create_free_point_load") ## FreeSurfaceLoad[​](/sdk/api/external/scia/.md#_FreeSurfaceLoad "Direct link to FreeSurfaceLoad") * *class *viktor.external.scia.object.FreeSurfaceLoad(*object\_id*, *name*, *load\_case*, *direction*, *q1*, *q2=None*, *q3=None*, *points=None*, *distribution=None*, *load\_type=None*, *validity=None*, *system=None*, *location=None*, *selection=None*)[](#FreeSurfaceLoad "Link to this definition") Bases: [`FreeLoad`](#FreeLoad "viktor.external.scia.object.FreeLoad") Do not use this \_\_init\_\_ directly, but create the object by [`create_free_surface_load()`](/sdk/api/external/scia/.md#Model.create_free_surface_load "viktor.external.scia.scia.Model.create_free_surface_load") * *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#FreeSurfaceLoad.Distribution "Link to this definition") Bases: `Enum` * DIR\_X*: [`Distribution`](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 1*[](#FreeSurfaceLoad.Distribution.DIR_X "Link to this definition") - DIR\_Y*: [`Distribution`](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 2*[](#FreeSurfaceLoad.Distribution.DIR_Y "Link to this definition") * POINTS*: [`Distribution`](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 3*[](#FreeSurfaceLoad.Distribution.POINTS "Link to this definition") - UNIFORM*: [`Distribution`](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")** = 0*[](#FreeSurfaceLoad.Distribution.UNIFORM "Link to this definition") - *property *distribution*: [Distribution](#FreeSurfaceLoad.Distribution "viktor.external.scia.object.FreeSurfaceLoad.Distribution")*[](#FreeSurfaceLoad.distribution "Link to this definition") * *property *points*: List\[Tuple\[float, float]] | None*[](#FreeSurfaceLoad.points "Link to this definition") - *property *q2*: float | None*[](#FreeSurfaceLoad.q2 "Link to this definition") * *property *q3*: float | None*[](#FreeSurfaceLoad.q3 "Link to this definition") - *property *selection*: List\[[Plane](#Plane "viktor.external.scia.object.Plane")] | None*[](#FreeSurfaceLoad.selection "Link to this definition") ## GeneralCrossSection[​](/sdk/api/external/scia/.md#_GeneralCrossSection "Direct link to GeneralCrossSection") * *class *viktor.external.scia.object.GeneralCrossSection(*object\_id*, *name*, *material*, *elements*)[](#GeneralCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_general_cross_section()`](/sdk/api/external/scia/.md#Model.create_general_cross_section "viktor.external.scia.scia.Model.create_general_cross_section") ## GeneralCrossSectionElement[​](/sdk/api/external/scia/.md#_GeneralCrossSectionElement "Direct link to GeneralCrossSectionElement") * *class *viktor.external.scia.object.GeneralCrossSectionElement(*name*, *element\_type*, *points*, *\**, *material=None*)[](#GeneralCrossSectionElement "Link to this definition") Do not use this \_\_init\_\_ directly, but create the object by [`create_general_cross_section_element()`](/sdk/api/external/scia/.md#Model.create_general_cross_section_element "viktor.external.scia.scia.Model.create_general_cross_section_element") * *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#GeneralCrossSectionElement.Type "Link to this definition") Bases: `Enum` * OPENING*: [`Type`](#GeneralCrossSectionElement.Type "viktor.external.scia.object.GeneralCrossSectionElement.Type")** = 1*[](#GeneralCrossSectionElement.Type.OPENING "Link to this definition") - POLYGON*: [`Type`](#GeneralCrossSectionElement.Type "viktor.external.scia.object.GeneralCrossSectionElement.Type")** = 0*[](#GeneralCrossSectionElement.Type.POLYGON "Link to this definition") ## HingeOnBeam[​](/sdk/api/external/scia/.md#_HingeOnBeam "Direct link to HingeOnBeam") * *class *viktor.external.scia.object.HingeOnBeam(*object\_id*, *name*, *beam*, *position*, *freedom\_ux=Freedom.FREE*, *freedom\_uy=Freedom.FREE*, *freedom\_uz=Freedom.FREE*, *freedom\_fix=Freedom.FREE*, *freedom\_fiy=Freedom.FREE*, *freedom\_fiz=Freedom.FREE*, *stiffness\_ux=0*, *stiffness\_uy=0*, *stiffness\_uz=0*, *stiffness\_fix=0*, *stiffness\_fiy=0*, *stiffness\_fiz=0*)[](#HingeOnBeam "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_hinge_on_beam()`](/sdk/api/external/scia/.md#Model.create_hinge_on_beam "viktor.external.scia.scia.Model.create_hinge_on_beam"). * *class *Freedom(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#HingeOnBeam.Freedom "Link to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FLEXIBLE*: [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 2*[](#HingeOnBeam.Freedom.FLEXIBLE "Link to this definition") * FREE*: [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 0*[](#HingeOnBeam.Freedom.FREE "Link to this definition") - RIGID*: [`Freedom`](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")** = 1*[](#HingeOnBeam.Freedom.RIGID "Link to this definition") - *class *Position(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#HingeOnBeam.Position "Link to this definition") Bases: `Enum` * BEGIN*: [`Position`](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 0*[](#HingeOnBeam.Position.BEGIN "Link to this definition") - BOTH*: [`Position`](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 2*[](#HingeOnBeam.Position.BOTH "Link to this definition") * END*: [`Position`](#HingeOnBeam.Position "viktor.external.scia.object.HingeOnBeam.Position")** = 1*[](#HingeOnBeam.Position.END "Link to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#HingeOnBeam.beam "Link to this definition") - *property *freedom*: Tuple\[[Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom"), [Freedom](#HingeOnBeam.Freedom "viktor.external.scia.object.HingeOnBeam.Freedom")]*[](#HingeOnBeam.freedom "Link to this definition") ux, uy, uz, fix, fiy, fiz * *property *stiffness*: Tuple\[float, float, float, float, float, float]*[](#HingeOnBeam.stiffness "Link to this definition") ux, uy, uz, fix, fiy, fiz ## HingeOnPlane[​](/sdk/api/external/scia/.md#_HingeOnPlane "Direct link to HingeOnPlane") * *class *viktor.external.scia.object.HingeOnPlane(*object\_id*, *name*, *edge*, *ux=None*, *stiffness\_ux=None*, *uy=None*, *stiffness\_uy=None*, *uz=None*, *stiffness\_uz=None*, *fix=None*, *stiffness\_fix=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#HingeOnPlane "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_hinge_on_plane()`](/sdk/api/external/scia/.md#Model.create_hinge_on_plane "viktor.external.scia.scia.Model.create_hinge_on_plane"). * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#HingeOnPlane.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")** = 0*[](#HingeOnPlane.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#HingeOnPlane.CDef "viktor.external.scia.object.HingeOnPlane.CDef")** = 1*[](#HingeOnPlane.CDef.RELATIVE "Link to this definition") - *class *Freedom(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#HingeOnPlane.Freedom "Link to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FLEXIBLE*: [`Freedom`](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 2*[](#HingeOnPlane.Freedom.FLEXIBLE "Link to this definition") * FREE*: [`Freedom`](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 0*[](#HingeOnPlane.Freedom.FREE "Link to this definition") - RIGID*: [`Freedom`](#HingeOnPlane.Freedom "viktor.external.scia.object.HingeOnPlane.Freedom")** = 1*[](#HingeOnPlane.Freedom.RIGID "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#HingeOnPlane.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_END*: [`Origin`](#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")** = 1*[](#HingeOnPlane.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#HingeOnPlane.Origin "viktor.external.scia.object.HingeOnPlane.Origin")** = 0*[](#HingeOnPlane.Origin.FROM_START "Link to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#HingeOnPlane.plane "Link to this definition") ## IntegrationStrip[​](/sdk/api/external/scia/.md#_IntegrationStrip "Direct link to IntegrationStrip") * *class *viktor.external.scia.object.IntegrationStrip(*object\_id*, *name*, *plane*, *point\_1*, *point\_2*, *width*, *effective\_width\_geometry=\_EffectiveWidthGeometry.CONSTANT\_SYMMETRIC*, *effective\_width\_definition=\_EffectiveWidthDefinition.WIDTH*)[](#IntegrationStrip "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_integration_strip()`](/sdk/api/external/scia/.md#Model.create_integration_strip "viktor.external.scia.scia.Model.create_integration_strip") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#IntegrationStrip.plane "Link to this definition") ## InternalEdge[​](/sdk/api/external/scia/.md#_InternalEdge "Direct link to InternalEdge") * *class *viktor.external.scia.object.InternalEdge(*object\_id*, *name*, *plane*, *node\_1*, *node\_2*)[](#InternalEdge "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_internal_edge()`](/sdk/api/external/scia/.md#Model.create_internal_edge "viktor.external.scia.scia.Model.create_internal_edge") * *property *node\_1*: [Node](#Node "viktor.external.scia.object.Node")*[](#InternalEdge.node_1 "Link to this definition") - *property *node\_2*: [Node](#Node "viktor.external.scia.object.Node")*[](#InternalEdge.node_2 "Link to this definition") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#InternalEdge.plane "Link to this definition") ## Layer[​](/sdk/api/external/scia/.md#_Layer "Direct link to Layer") * *class *viktor.external.scia.object.Layer(*object\_id*, *name*, *comment=None*, *structural\_model\_only=None*, *current\_used\_activity=None*)[](#Layer "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_layer()`](/sdk/api/external/scia/.md#Model.create_layer "viktor.external.scia.scia.Model.create_layer") ## LibraryCrossSection[​](/sdk/api/external/scia/.md#_LibraryCrossSection "Direct link to LibraryCrossSection") * *class *viktor.external.scia.object.LibraryCrossSection(*object\_id*, *name*, *material*, *section*, *profile*)[](#LibraryCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_library_cross_section()`](/sdk/api/external/scia/.md#Model.create_library_cross_section "viktor.external.scia.scia.Model.create_library_cross_section") * *class *Section(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LibraryCrossSection.Section "Link to this definition") Bases: `Enum` * ASYMMETRIC\_I*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 101*[](#LibraryCrossSection.Section.ASYMMETRIC_I "Link to this definition") - CHANNEL*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 5*[](#LibraryCrossSection.Section.CHANNEL "Link to this definition") * CIRCULAR\_HOLLOW*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 3*[](#LibraryCrossSection.Section.CIRCULAR_HOLLOW "Link to this definition") - COLD\_FORMED\_2C*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 130*[](#LibraryCrossSection.Section.COLD_FORMED_2C "Link to this definition") * COLD\_FORMED\_ANGLE*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 111*[](#LibraryCrossSection.Section.COLD_FORMED_ANGLE "Link to this definition") - COLD\_FORMED\_C*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 114*[](#LibraryCrossSection.Section.COLD_FORMED_C "Link to this definition") * COLD\_FORMED\_CHANNEL*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 112*[](#LibraryCrossSection.Section.COLD_FORMED_CHANNEL "Link to this definition") - COLD\_FORMED\_C\_EAVES\_BEAM*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 116*[](#LibraryCrossSection.Section.COLD_FORMED_C_EAVES_BEAM "Link to this definition") * COLD\_FORMED\_C\_PLUS*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 117*[](#LibraryCrossSection.Section.COLD_FORMED_C_PLUS "Link to this definition") - COLD\_FORMED\_IS\_PLUS*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 128*[](#LibraryCrossSection.Section.COLD_FORMED_IS_PLUS "Link to this definition") * COLD\_FORMED\_I\_PLUS*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 127*[](#LibraryCrossSection.Section.COLD_FORMED_I_PLUS "Link to this definition") - COLD\_FORMED\_OMEGA*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 115*[](#LibraryCrossSection.Section.COLD_FORMED_OMEGA "Link to this definition") * COLD\_FORMED\_SIGMA*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 121*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA "Link to this definition") - COLD\_FORMED\_SIGMA\_ASYMMETRIC*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 129*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_ASYMMETRIC "Link to this definition") * COLD\_FORMED\_SIGMA\_EAVES\_BEAM*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 124*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_EAVES_BEAM "Link to this definition") - COLD\_FORMED\_SIGMA\_PLUS*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 123*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_PLUS "Link to this definition") * COLD\_FORMED\_SIGMA\_PLUS\_EAVES\_BEAM*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 125*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_PLUS_EAVES_BEAM "Link to this definition") - COLD\_FORMED\_SIGMA\_STIFFENED*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 122*[](#LibraryCrossSection.Section.COLD_FORMED_SIGMA_STIFFENED "Link to this definition") * COLD\_FORMED\_Z*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 113*[](#LibraryCrossSection.Section.COLD_FORMED_Z "Link to this definition") - COLD\_FORMED\_ZED*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 118*[](#LibraryCrossSection.Section.COLD_FORMED_ZED "Link to this definition") * COLD\_FORMED\_ZED\_ASYMMETRIC\_LIPS*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 119*[](#LibraryCrossSection.Section.COLD_FORMED_ZED_ASYMMETRIC_LIPS "Link to this definition") - COLD\_FORMED\_ZED\_BOTH\_LIPS\_INCLINED*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 126*[](#LibraryCrossSection.Section.COLD_FORMED_ZED_BOTH_LIPS_INCLINED "Link to this definition") * COLD\_FORMED\_ZED\_INCLINED\_LIP*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 120*[](#LibraryCrossSection.Section.COLD_FORMED_ZED_INCLINED_LIP "Link to this definition") - FULL\_CIRCULAR*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 11*[](#LibraryCrossSection.Section.FULL_CIRCULAR "Link to this definition") * FULL\_RECTANGULAR*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 7*[](#LibraryCrossSection.Section.FULL_RECTANGULAR "Link to this definition") - GENERAL\_COLD\_FORMED*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 110*[](#LibraryCrossSection.Section.GENERAL_COLD_FORMED "Link to this definition") * I*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 1*[](#LibraryCrossSection.Section.I "Link to this definition") - IFBA*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 154*[](#LibraryCrossSection.Section.IFBA "Link to this definition") * IFBB*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 155*[](#LibraryCrossSection.Section.IFBB "Link to this definition") - L*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 4*[](#LibraryCrossSection.Section.L "Link to this definition") * MINUS\_L*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 1002*[](#LibraryCrossSection.Section.MINUS_L "Link to this definition") - RAIL\_TYPE\_KA*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 150*[](#LibraryCrossSection.Section.RAIL_TYPE_KA "Link to this definition") * RAIL\_TYPE\_KF*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 151*[](#LibraryCrossSection.Section.RAIL_TYPE_KF "Link to this definition") - RAIL\_TYPE\_KG*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 152*[](#LibraryCrossSection.Section.RAIL_TYPE_KG "Link to this definition") * RECTANGULAR\_HOLLOW*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 2*[](#LibraryCrossSection.Section.RECTANGULAR_HOLLOW "Link to this definition") - ROLLED\_Z*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 102*[](#LibraryCrossSection.Section.ROLLED_Z "Link to this definition") * SFB*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 153*[](#LibraryCrossSection.Section.SFB "Link to this definition") - T*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 6*[](#LibraryCrossSection.Section.T "Link to this definition") * THQ*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 156*[](#LibraryCrossSection.Section.THQ "Link to this definition") - VIRTUAL\_JOIST*: [`Section`](#LibraryCrossSection.Section "viktor.external.scia.object.LibraryCrossSection.Section")** = 160*[](#LibraryCrossSection.Section.VIRTUAL_JOIST "Link to this definition") ## LineForceSurface[​](/sdk/api/external/scia/.md#_LineForceSurface "Direct link to LineForceSurface") * *class *viktor.external.scia.object.LineForceSurface(*object\_id*, *name*, *edge*, *load\_case*, *p1*, *p2=None*, *direction=None*, *location=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineForceSurface "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_load_on_plane()`](/sdk/api/external/scia/.md#Model.create_line_load_on_plane "viktor.external.scia.scia.Model.create_line_load_on_plane") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")** = 0*[](#LineForceSurface.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")** = 1*[](#LineForceSurface.CDef.RELATIVE "Link to this definition") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")** = 0*[](#LineForceSurface.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")** = 1*[](#LineForceSurface.CSys.LOCAL "Link to this definition") * *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 0*[](#LineForceSurface.Direction.X "Link to this definition") - Y*: [`Direction`](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 1*[](#LineForceSurface.Direction.Y "Link to this definition") * Z*: [`Direction`](#LineForceSurface.Direction "viktor.external.scia.object.LineForceSurface.Direction")** = 2*[](#LineForceSurface.Direction.Z "Link to this definition") - *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.Distribution "Link to this definition") Bases: `Enum` * TRAPEZOIDAL*: [`Distribution`](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")** = 1*[](#LineForceSurface.Distribution.TRAPEZOIDAL "Link to this definition") - UNIFORM*: [`Distribution`](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")** = 0*[](#LineForceSurface.Distribution.UNIFORM "Link to this definition") * *class *Location(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.Location "Link to this definition") Bases: `Enum` * LENGTH*: [`Location`](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")** = 0*[](#LineForceSurface.Location.LENGTH "Link to this definition") - PROJECTION*: [`Location`](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")** = 1*[](#LineForceSurface.Location.PROJECTION "Link to this definition") - *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineForceSurface.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_END*: [`Origin`](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")** = 1*[](#LineForceSurface.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")** = 0*[](#LineForceSurface.Origin.FROM_START "Link to this definition") * *property *c\_def*: [CDef](#LineForceSurface.CDef "viktor.external.scia.object.LineForceSurface.CDef")*[](#LineForceSurface.c_def "Link to this definition") - *property *c\_sys*: [CSys](#LineForceSurface.CSys "viktor.external.scia.object.LineForceSurface.CSys")*[](#LineForceSurface.c_sys "Link to this definition") * *property *distribution*: [Distribution](#LineForceSurface.Distribution "viktor.external.scia.object.LineForceSurface.Distribution")*[](#LineForceSurface.distribution "Link to this definition") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#LineForceSurface.load_case "Link to this definition") * *property *location*: [Location](#LineForceSurface.Location "viktor.external.scia.object.LineForceSurface.Location")*[](#LineForceSurface.location "Link to this definition") - *property *origin*: [Origin](#LineForceSurface.Origin "viktor.external.scia.object.LineForceSurface.Origin")*[](#LineForceSurface.origin "Link to this definition") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#LineForceSurface.plane "Link to this definition") - *property *position\_x1*: float | None*[](#LineForceSurface.position_x1 "Link to this definition") * *property *position\_x2*: float | None*[](#LineForceSurface.position_x2 "Link to this definition") ## LineLoad[​](/sdk/api/external/scia/.md#_LineLoad "Direct link to LineLoad") * *class *viktor.external.scia.object.LineLoad(*object\_id*, *name*, *load\_case*, *beam*, *load\_type*, *distribution*, *load\_start*, *load\_end*, *direction*, *c\_sys*, *position\_start*, *position\_end*, *c\_def*, *origin*, *ey*, *ez*)[](#LineLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_load()`](/sdk/api/external/scia/.md#Model.create_line_load "viktor.external.scia.scia.Model.create_line_load") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")** = 0*[](#LineLoad.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#LineLoad.CDef "viktor.external.scia.object.LineLoad.CDef")** = 1*[](#LineLoad.CDef.RELATIVE "Link to this definition") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")** = 0*[](#LineLoad.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#LineLoad.CSys "viktor.external.scia.object.LineLoad.CSys")** = 1*[](#LineLoad.CSys.LOCAL "Link to this definition") * *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 0*[](#LineLoad.Direction.X "Link to this definition") - Y*: [`Direction`](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 1*[](#LineLoad.Direction.Y "Link to this definition") * Z*: [`Direction`](#LineLoad.Direction "viktor.external.scia.object.LineLoad.Direction")** = 2*[](#LineLoad.Direction.Z "Link to this definition") - *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.Distribution "Link to this definition") Bases: `Enum` * TRAPEZOIDAL*: [`Distribution`](#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")** = 1*[](#LineLoad.Distribution.TRAPEZOIDAL "Link to this definition") - UNIFORM*: [`Distribution`](#LineLoad.Distribution "viktor.external.scia.object.LineLoad.Distribution")** = 0*[](#LineLoad.Distribution.UNIFORM "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")** = 1*[](#LineLoad.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#LineLoad.Origin "viktor.external.scia.object.LineLoad.Origin")** = 0*[](#LineLoad.Origin.FROM_START "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineLoad.Type "Link to this definition") Bases: `Enum` * FORCE*: [`Type`](#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")** = 0*[](#LineLoad.Type.FORCE "Link to this definition") - SELF\_WEIGHT*: [`Type`](#LineLoad.Type "viktor.external.scia.object.LineLoad.Type")** = 1*[](#LineLoad.Type.SELF_WEIGHT "Link to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#LineLoad.beam "Link to this definition") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#LineLoad.load_case "Link to this definition") ## LineMomentOnBeam[​](/sdk/api/external/scia/.md#_LineMomentOnBeam "Direct link to LineMomentOnBeam") * *class *viktor.external.scia.object.LineMomentOnBeam(*object\_id*, *name*, *beam*, *load\_case*, *m1*, *m2=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineMomentOnBeam "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_moment_on_beam()`](/sdk/api/external/scia/.md#Model.create_line_moment_on_beam "viktor.external.scia.scia.Model.create_line_moment_on_beam"). * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnBeam.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")** = 0*[](#LineMomentOnBeam.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#LineMomentOnBeam.CDef "viktor.external.scia.object.LineMomentOnBeam.CDef")** = 1*[](#LineMomentOnBeam.CDef.RELATIVE "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnBeam.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 0*[](#LineMomentOnBeam.Direction.X "Link to this definition") - Y*: [`Direction`](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 1*[](#LineMomentOnBeam.Direction.Y "Link to this definition") * Z*: [`Direction`](#LineMomentOnBeam.Direction "viktor.external.scia.object.LineMomentOnBeam.Direction")** = 2*[](#LineMomentOnBeam.Direction.Z "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnBeam.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")** = 1*[](#LineMomentOnBeam.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#LineMomentOnBeam.Origin "viktor.external.scia.object.LineMomentOnBeam.Origin")** = 0*[](#LineMomentOnBeam.Origin.FROM_START "Link to this definition") ## LineMomentOnPlane[​](/sdk/api/external/scia/.md#_LineMomentOnPlane "Direct link to LineMomentOnPlane") * *class *viktor.external.scia.object.LineMomentOnPlane(*object\_id*, *name*, *edge*, *load\_case*, *m1*, *m2=None*, *direction=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineMomentOnPlane "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_moment_on_plane()`](/sdk/api/external/scia/.md#Model.create_line_moment_on_plane "viktor.external.scia.scia.Model.create_line_moment_on_plane"). * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnPlane.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the plane edge * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")** = 0*[](#LineMomentOnPlane.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#LineMomentOnPlane.CDef "viktor.external.scia.object.LineMomentOnPlane.CDef")** = 1*[](#LineMomentOnPlane.CDef.RELATIVE "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnPlane.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 0*[](#LineMomentOnPlane.Direction.X "Link to this definition") - Y*: [`Direction`](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 1*[](#LineMomentOnPlane.Direction.Y "Link to this definition") * Z*: [`Direction`](#LineMomentOnPlane.Direction "viktor.external.scia.object.LineMomentOnPlane.Direction")** = 2*[](#LineMomentOnPlane.Direction.Z "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineMomentOnPlane.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the plane edge * **FROM\_END** - position is measured from the end of the plane edge - FROM\_END*: [`Origin`](#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")** = 1*[](#LineMomentOnPlane.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#LineMomentOnPlane.Origin "viktor.external.scia.object.LineMomentOnPlane.Origin")** = 0*[](#LineMomentOnPlane.Origin.FROM_START "Link to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#LineMomentOnPlane.plane "Link to this definition") ## LineSupport[​](/sdk/api/external/scia/.md#_LineSupport "Direct link to LineSupport") * *class *viktor.external.scia.object.LineSupport(*object\_id*, *name*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineSupport "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Abstract base class of all line supports. * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")** = 0*[](#LineSupport.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#LineSupport.CDef "viktor.external.scia.object.LineSupport.CDef")** = 1*[](#LineSupport.CDef.RELATIVE "Link to this definition") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")** = 0*[](#LineSupport.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#LineSupport.CSys "viktor.external.scia.object.LineSupport.CSys")** = 1*[](#LineSupport.CSys.LOCAL "Link to this definition") * *class *Constraint(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.Constraint "Link to this definition") Bases: `Enum` * CUSTOM*: [`Constraint`](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 3*[](#LineSupport.Constraint.CUSTOM "Link to this definition") - FIXED*: [`Constraint`](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 0*[](#LineSupport.Constraint.FIXED "Link to this definition") * HINGED*: [`Constraint`](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 1*[](#LineSupport.Constraint.HINGED "Link to this definition") - SLIDING*: [`Constraint`](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")** = 2*[](#LineSupport.Constraint.SLIDING "Link to this definition") - *class *Extent(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.Extent "Link to this definition") Bases: `Enum` * **FULL** - support across the full length * **SPAN** - support across a span - FULL*: [`Extent`](#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")** = 0*[](#LineSupport.Extent.FULL "Link to this definition") * SPAN*: [`Extent`](#LineSupport.Extent "viktor.external.scia.object.LineSupport.Extent")** = 1*[](#LineSupport.Extent.SPAN "Link to this definition") * *class *Freedom(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.Freedom "Link to this definition") Bases: `Enum` * FLEXIBLE*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 2*[](#LineSupport.Freedom.FLEXIBLE "Link to this definition") - FLEXIBLE\_PRESS\_ONLY*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 5*[](#LineSupport.Freedom.FLEXIBLE_PRESS_ONLY "Link to this definition") * FLEXIBLE\_TENSION\_ONLY*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 6*[](#LineSupport.Freedom.FLEXIBLE_TENSION_ONLY "Link to this definition") - FREE*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 0*[](#LineSupport.Freedom.FREE "Link to this definition") * NONLINEAR*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 7*[](#LineSupport.Freedom.NONLINEAR "Link to this definition") - RIGID*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 1*[](#LineSupport.Freedom.RIGID "Link to this definition") * RIGID\_PRESS\_ONLY*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 3*[](#LineSupport.Freedom.RIGID_PRESS_ONLY "Link to this definition") - RIGID\_TENSION\_ONLY*: [`Freedom`](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")** = 4*[](#LineSupport.Freedom.RIGID_TENSION_ONLY "Link to this definition") - *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")** = 1*[](#LineSupport.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#LineSupport.Origin "viktor.external.scia.object.LineSupport.Origin")** = 0*[](#LineSupport.Origin.FROM_START "Link to this definition") * *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LineSupport.Type "Link to this definition") Bases: `Enum` * FOUNDATION\_STRIP*: [`Type`](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 1*[](#LineSupport.Type.FOUNDATION_STRIP "Link to this definition") - LINE*: [`Type`](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 0*[](#LineSupport.Type.LINE "Link to this definition") * WALL*: [`Type`](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")** = 2*[](#LineSupport.Type.WALL "Link to this definition") - *property *constraint*: [Constraint](#LineSupport.Constraint "viktor.external.scia.object.LineSupport.Constraint")*[](#LineSupport.constraint "Link to this definition") * *property *freedom*: Tuple\[[Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom"), [Freedom](#LineSupport.Freedom "viktor.external.scia.object.LineSupport.Freedom")]*[](#LineSupport.freedom "Link to this definition") - *property *function\_rx*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_rx "Link to this definition") * *property *function\_ry*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_ry "Link to this definition") - *property *function\_rz*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_rz "Link to this definition") * *property *function\_x*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_x "Link to this definition") - *property *function\_y*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_y "Link to this definition") * *property *function\_z*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#LineSupport.function_z "Link to this definition") - *property *stiffness*: Tuple\[float | None, float | None, float | None, float | None, float | None, float | None]*[](#LineSupport.stiffness "Link to this definition") ## LineSupportLine[​](/sdk/api/external/scia/.md#_LineSupportLine "Direct link to LineSupportLine") * *class *viktor.external.scia.object.LineSupportLine(*object\_id*, *name*, *beam*, *x=None*, *stiffness\_x=None*, *function\_x=None*, *y=None*, *stiffness\_y=None*, *function\_y=None*, *z=None*, *stiffness\_z=None*, *function\_z=None*, *rx=None*, *stiffness\_rx=None*, *function\_rx=None*, *ry=None*, *stiffness\_ry=None*, *function\_ry=None*, *rz=None*, *stiffness\_rz=None*, *function\_rz=None*, *c\_sys=None*, *extent=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineSupportLine "Link to this definition") Bases: [`LineSupport`](#LineSupport "viktor.external.scia.object.LineSupport") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_support_on_beam()`](/sdk/api/external/scia/.md#Model.create_line_support_on_beam "viktor.external.scia.scia.Model.create_line_support_on_beam") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#LineSupportLine.beam "Link to this definition") - *property *spring\_type*: [Type](#LineSupport.Type "viktor.external.scia.object.LineSupport.Type")*[](#LineSupportLine.spring_type "Link to this definition") ## LineSupportSurface[​](/sdk/api/external/scia/.md#_LineSupportSurface "Direct link to LineSupportSurface") * *class *viktor.external.scia.object.LineSupportSurface(*object\_id*, *name*, *edge*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *c\_sys=None*, *c\_def=None*, *position\_x1=None*, *position\_x2=None*, *origin=None*)[](#LineSupportSurface "Link to this definition") Bases: [`LineSupport`](#LineSupport "viktor.external.scia.object.LineSupport") Do not use this \_\_init\_\_ directly, but create the object by [`create_line_support_on_plane()`](/sdk/api/external/scia/.md#Model.create_line_support_on_plane "viktor.external.scia.scia.Model.create_line_support_on_plane") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#LineSupportSurface.plane "Link to this definition") ## LoadCase[​](/sdk/api/external/scia/.md#_LoadCase "Direct link to LoadCase") * *class *viktor.external.scia.object.LoadCase(*object\_id*, *name*, *description*, *action\_type*, *load\_group*)[](#LoadCase "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Abstract base class of all load cases. * *class *ActionType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.ActionType "Link to this definition") Bases: `Enum` * PERMANENT*: [`ActionType`](#LoadCase.ActionType "viktor.external.scia.object.LoadCase.ActionType")** = 0*[](#LoadCase.ActionType.PERMANENT "Link to this definition") - VARIABLE*: [`ActionType`](#LoadCase.ActionType "viktor.external.scia.object.LoadCase.ActionType")** = 1*[](#LoadCase.ActionType.VARIABLE "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.Direction "Link to this definition") Bases: `Enum` * **NEG\_Z** - -Z * **POS\_Z** - +Z * **NEG\_Y** - -Y * **POS\_Y** - +Y * **NEG\_X** - -X * **POS\_X** - +X - NEG\_X*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 4*[](#LoadCase.Direction.NEG_X "Link to this definition") * NEG\_Y*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 2*[](#LoadCase.Direction.NEG_Y "Link to this definition") - NEG\_Z*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 0*[](#LoadCase.Direction.NEG_Z "Link to this definition") * POS\_X*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 5*[](#LoadCase.Direction.POS_X "Link to this definition") - POS\_Y*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 3*[](#LoadCase.Direction.POS_Y "Link to this definition") * POS\_Z*: [`Direction`](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction")** = 1*[](#LoadCase.Direction.POS_Z "Link to this definition") * *class *Duration(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.Duration "Link to this definition") Bases: `Enum` * INSTANTANEOUS*: [`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 3*[](#LoadCase.Duration.INSTANTANEOUS "Link to this definition") - LONG*: [`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 0*[](#LoadCase.Duration.LONG "Link to this definition") * MEDIUM*: [`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 1*[](#LoadCase.Duration.MEDIUM "Link to this definition") - SHORT*: [`Duration`](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration")** = 2*[](#LoadCase.Duration.SHORT "Link to this definition") - *class *PermanentLoadType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.PermanentLoadType "Link to this definition") Bases: `Enum` * PRIMARY\_EFFECT*: [`PermanentLoadType`](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 2*[](#LoadCase.PermanentLoadType.PRIMARY_EFFECT "Link to this definition") - SELF\_WEIGHT*: [`PermanentLoadType`](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 0*[](#LoadCase.PermanentLoadType.SELF_WEIGHT "Link to this definition") * STANDARD*: [`PermanentLoadType`](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")** = 1*[](#LoadCase.PermanentLoadType.STANDARD "Link to this definition") * *class *Specification(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.Specification "Link to this definition") Bases: `Enum` * EARTHQUAKE*: [`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 103*[](#LoadCase.Specification.EARTHQUAKE "Link to this definition") - SNOW*: [`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 104*[](#LoadCase.Specification.SNOW "Link to this definition") * STANDARD*: [`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 100*[](#LoadCase.Specification.STANDARD "Link to this definition") - STATIC\_WIND*: [`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 102*[](#LoadCase.Specification.STATIC_WIND "Link to this definition") * TEMPERATURE*: [`Specification`](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification")** = 101*[](#LoadCase.Specification.TEMPERATURE "Link to this definition") - *class *VariableLoadType(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCase.VariableLoadType "Link to this definition") Bases: `Enum` * PRIMARY\_EFFECT*: [`VariableLoadType`](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")** = 1*[](#LoadCase.VariableLoadType.PRIMARY_EFFECT "Link to this definition") - STATIC*: [`VariableLoadType`](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")** = 0*[](#LoadCase.VariableLoadType.STATIC "Link to this definition") * *abstract property *direction*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction") | None*[](#LoadCase.direction "Link to this definition") - *abstract property *duration*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration") | None*[](#LoadCase.duration "Link to this definition") * *property *load\_group*: [LoadGroup](#LoadGroup "viktor.external.scia.object.LoadGroup")*[](#LoadCase.load_group "Link to this definition") - *abstract property *load\_type*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType") | [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")*[](#LoadCase.load_type "Link to this definition") * *abstract property *master*: str | None*[](#LoadCase.master "Link to this definition") - *abstract property *primary\_effect*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase") | None*[](#LoadCase.primary_effect "Link to this definition") * *abstract property *specification*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification") | None*[](#LoadCase.specification "Link to this definition") ## LoadCombination[​](/sdk/api/external/scia/.md#_LoadCombination "Direct link to LoadCombination") * *class *viktor.external.scia.object.LoadCombination(*object\_id*, *name*, *combination\_type*, *load\_cases*, *\**, *description=None*)[](#LoadCombination "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_load_combination()`](/sdk/api/external/scia/.md#Model.create_load_combination "viktor.external.scia.scia.Model.create_load_combination") * *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadCombination.Type "Link to this definition") Bases: `Enum` * **ENVELOPE\_ULTIMATE** - Envelope - ultimate * **ENVELOPE\_SERVICEABILITY** - Envelope - serviceability * **LINEAR\_ULTIMATE** - Linear - ultimate * **LINEAR\_SERVICEABILITY** - Linear - serviceability * **EN\_ULS\_SET\_B** - EN-ULS (STR/GEO) Set B * **EN\_ACC\_ONE** - EN-Accidental 1 * **EN\_ACC\_TWO** - EN-Accidental 2 * **EN\_SEISMIC** - EN-Seismic * **EN\_SLS\_CHAR** - EN-SLS Characteristic * **EN\_SLS\_FREQ** - EN-SLS Frequent * **EN\_SLS\_QUASI** - EN-SLS Quasi-permanent * **EN\_ULS\_SET\_C** - EN-ULS (STR/GEO) Set C - ENVELOPE\_SERVICEABILITY*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 1*[](#LoadCombination.Type.ENVELOPE_SERVICEABILITY "Link to this definition") * ENVELOPE\_ULTIMATE*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 0*[](#LoadCombination.Type.ENVELOPE_ULTIMATE "Link to this definition") - EN\_ACC\_ONE*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 5*[](#LoadCombination.Type.EN_ACC_ONE "Link to this definition") * EN\_ACC\_TWO*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 6*[](#LoadCombination.Type.EN_ACC_TWO "Link to this definition") - EN\_SEISMIC*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 7*[](#LoadCombination.Type.EN_SEISMIC "Link to this definition") * EN\_SLS\_CHAR*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 8*[](#LoadCombination.Type.EN_SLS_CHAR "Link to this definition") - EN\_SLS\_FREQ*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 9*[](#LoadCombination.Type.EN_SLS_FREQ "Link to this definition") * EN\_SLS\_QUASI*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 10*[](#LoadCombination.Type.EN_SLS_QUASI "Link to this definition") - EN\_ULS\_SET\_B*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 4*[](#LoadCombination.Type.EN_ULS_SET_B "Link to this definition") * EN\_ULS\_SET\_C*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 11*[](#LoadCombination.Type.EN_ULS_SET_C "Link to this definition") - LINEAR\_SERVICEABILITY*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 3*[](#LoadCombination.Type.LINEAR_SERVICEABILITY "Link to this definition") * LINEAR\_ULTIMATE*: [`Type`](#LoadCombination.Type "viktor.external.scia.object.LoadCombination.Type")** = 2*[](#LoadCombination.Type.LINEAR_ULTIMATE "Link to this definition") - *property *load\_cases*: Dict\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase"), float]*[](#LoadCombination.load_cases "Link to this definition") ## LoadGroup[​](/sdk/api/external/scia/.md#_LoadGroup "Direct link to LoadGroup") * *class *viktor.external.scia.object.LoadGroup(*object\_id*, *name*, *load\_option*, *relation=None*, *load\_type=None*)[](#LoadGroup "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_load_group()`](/sdk/api/external/scia/.md#Model.create_load_group "viktor.external.scia.scia.Model.create_load_group") * *class *LoadOption(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadGroup.LoadOption "Link to this definition") Bases: `Enum` * ACCIDENTAL*: [`LoadOption`](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 2*[](#LoadGroup.LoadOption.ACCIDENTAL "Link to this definition") - PERMANENT*: [`LoadOption`](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 0*[](#LoadGroup.LoadOption.PERMANENT "Link to this definition") * SEISMIC*: [`LoadOption`](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 3*[](#LoadGroup.LoadOption.SEISMIC "Link to this definition") - VARIABLE*: [`LoadOption`](#LoadGroup.LoadOption "viktor.external.scia.object.LoadGroup.LoadOption")** = 1*[](#LoadGroup.LoadOption.VARIABLE "Link to this definition") - *class *LoadTypeOption(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadGroup.LoadTypeOption "Link to this definition") Bases: `Enum` * **CAT\_A** - Domestic * **CAT\_B** - Offices * **CAT\_C** - Congregation * **CAT\_D** - Shopping * **CAT\_E** - Storage * **CAT\_F** - Vehicle <30kN * **CAT\_G** - Vehicle >30kN * **CAT\_H** - Roofs * **SNOW** - Snow * **WIND** - Wind * **TEMPERATURE** - Temperature * **RAIN\_WATER** - Rain water * **CONSTRUCTION\_LOADS** - Construction loads - CAT\_A*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 0*[](#LoadGroup.LoadTypeOption.CAT_A "Link to this definition") * CAT\_B*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 1*[](#LoadGroup.LoadTypeOption.CAT_B "Link to this definition") - CAT\_C*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 2*[](#LoadGroup.LoadTypeOption.CAT_C "Link to this definition") * CAT\_D*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 3*[](#LoadGroup.LoadTypeOption.CAT_D "Link to this definition") - CAT\_E*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 4*[](#LoadGroup.LoadTypeOption.CAT_E "Link to this definition") * CAT\_F*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 5*[](#LoadGroup.LoadTypeOption.CAT_F "Link to this definition") - CAT\_G*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 6*[](#LoadGroup.LoadTypeOption.CAT_G "Link to this definition") * CAT\_H*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 7*[](#LoadGroup.LoadTypeOption.CAT_H "Link to this definition") - CONSTRUCTION\_LOADS*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 21*[](#LoadGroup.LoadTypeOption.CONSTRUCTION_LOADS "Link to this definition") * RAIN\_WATER*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 20*[](#LoadGroup.LoadTypeOption.RAIN_WATER "Link to this definition") - SNOW*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 8*[](#LoadGroup.LoadTypeOption.SNOW "Link to this definition") * TEMPERATURE*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 12*[](#LoadGroup.LoadTypeOption.TEMPERATURE "Link to this definition") - WIND*: [`LoadTypeOption`](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption")** = 11*[](#LoadGroup.LoadTypeOption.WIND "Link to this definition") * *class *RelationOption(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#LoadGroup.RelationOption "Link to this definition") Bases: `Enum` * EXCLUSIVE*: [`RelationOption`](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 1*[](#LoadGroup.RelationOption.EXCLUSIVE "Link to this definition") - STANDARD*: [`RelationOption`](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 0*[](#LoadGroup.RelationOption.STANDARD "Link to this definition") * TOGETHER*: [`RelationOption`](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption")** = 2*[](#LoadGroup.RelationOption.TOGETHER "Link to this definition") - *property *load\_type*: [LoadTypeOption](#LoadGroup.LoadTypeOption "viktor.external.scia.object.LoadGroup.LoadTypeOption") | None*[](#LoadGroup.load_type "Link to this definition") * *property *relation*: [RelationOption](#LoadGroup.RelationOption "viktor.external.scia.object.LoadGroup.RelationOption") | None*[](#LoadGroup.relation "Link to this definition") ## Material[​](/sdk/api/external/scia/.md#_Material "Direct link to Material") * *class *viktor.external.scia.object.Material(*object\_id*, *name*)[](#Material "Link to this definition") Reference to an existing material in the .esa template file in which the xml input file will be loaded. * Parameters: * **object\_id** (`int`) – ID of the existing material. * **name** (`str`) – name of the existing material. ## MeshSetup[​](/sdk/api/external/scia/.md#_MeshSetup "Direct link to MeshSetup") * *class *viktor.external.scia.object.MeshSetup(*\**, *average\_1d=1.0*, *average\_2d=1.0*, *division\_2d\_1d=50*)[](#MeshSetup "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Mesh settings parameters. * Parameters: * **average\_1d** (`float`) – Average size of cables, tendons, elements on subsoil, nonlinear soil spring \[m] (default: 1.0). * **average\_2d** (`float`) – Average size of 2d element/curved element \[m] (default: 1.0). * **division\_2d\_1d** (`int`) – Division for 2D-1D upgrade (default: 50). ## Node[​](/sdk/api/external/scia/.md#_Node "Direct link to Node") * *class *viktor.external.scia.object.Node(*object\_id*, *name*, *x*, *y*, *z*)[](#Node "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_node()`](/sdk/api/external/scia/.md#Model.create_node "viktor.external.scia.scia.Model.create_node") ## NonLinearFunction[​](/sdk/api/external/scia/.md#_NonLinearFunction "Direct link to NonLinearFunction") * *class *viktor.external.scia.object.NonLinearFunction(*object\_id*, *name*, *function\_type*, *positive\_end*, *negative\_end*, *impulse*)[](#NonLinearFunction "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_nonlinear_function()`](/sdk/api/external/scia/.md#Model.create_nonlinear_function "viktor.external.scia.scia.Model.create_nonlinear_function") * *class *Support(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#NonLinearFunction.Support "Link to this definition") Bases: `Enum` * FLEXIBLE*: [`Support`](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 2*[](#NonLinearFunction.Support.FLEXIBLE "Link to this definition") - FREE*: [`Support`](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 1*[](#NonLinearFunction.Support.FREE "Link to this definition") * RIGID*: [`Support`](#NonLinearFunction.Support "viktor.external.scia.object.NonLinearFunction.Support")** = 0*[](#NonLinearFunction.Support.RIGID "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#NonLinearFunction.Type "Link to this definition") Bases: `Enum` * NONLINEAR\_SUBSOIL*: [`Type`](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 2*[](#NonLinearFunction.Type.NONLINEAR_SUBSOIL "Link to this definition") - ROTATION*: [`Type`](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 1*[](#NonLinearFunction.Type.ROTATION "Link to this definition") * TRANSLATION*: [`Type`](#NonLinearFunction.Type "viktor.external.scia.object.NonLinearFunction.Type")** = 0*[](#NonLinearFunction.Type.TRANSLATION "Link to this definition") * *property *impulse*: List\[Tuple\[float, float]]*[](#NonLinearFunction.impulse "Link to this definition") ## NonLinearLoadCombination[​](/sdk/api/external/scia/.md#_NonLinearLoadCombination "Direct link to NonLinearLoadCombination") * *class *viktor.external.scia.object.NonLinearLoadCombination(*object\_id*, *name*, *combination\_type*, *load\_cases*, *\**, *description=None*)[](#NonLinearLoadCombination "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") * Do not use this \_\_init\_\_ directly, but create the object by [`create_nonlinear_load_combination()`](/sdk/api/external/scia/.md#Model.create_nonlinear_load_combination "viktor.external.scia.scia.Model.create_nonlinear_load_combination") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#NonLinearLoadCombination.Type "Link to this definition") Bases: `Enum` * SERVICEABILITY*: [`Type`](#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")** = 1*[](#NonLinearLoadCombination.Type.SERVICEABILITY "Link to this definition") - ULTIMATE*: [`Type`](#NonLinearLoadCombination.Type "viktor.external.scia.object.NonLinearLoadCombination.Type")** = 0*[](#NonLinearLoadCombination.Type.ULTIMATE "Link to this definition") * *property *load\_cases*: Dict\[[LoadCase](#LoadCase "viktor.external.scia.object.LoadCase"), float]*[](#NonLinearLoadCombination.load_cases "Link to this definition") ## NumericalCrossSection[​](/sdk/api/external/scia/.md#_NumericalCrossSection "Direct link to NumericalCrossSection") * *class *viktor.external.scia.object.NumericalCrossSection(*object\_id*, *name*, *material*, *\**, *A=None*, *Ay=None*, *Az=None*, *AL=None*, *AD=None*, *cYUCS=None*, *cZUCS=None*, *alpha=None*, *Iy=None*, *Iz=None*, *Wely=None*, *Welz=None*, *Wply=None*, *Wplz=None*, *Mply\_plus=None*, *Mply\_min=None*, *Mplz\_plus=None*, *Mplz\_min=None*, *dy=None*, *dz=None*, *It=None*, *Iw=None*, *beta\_y=None*, *beta\_z=None*)[](#NumericalCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_numerical_cross_section()`](/sdk/api/external/scia/.md#Model.create_numerical_cross_section "viktor.external.scia.scia.Model.create_numerical_cross_section") ## OpenSlab[​](/sdk/api/external/scia/.md#_OpenSlab "Direct link to OpenSlab") * *class *viktor.external.scia.object.OpenSlab(*object\_id*, *name*, *plane*, *corner\_nodes*)[](#OpenSlab "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_open_slab()`](/sdk/api/external/scia/.md#Model.create_open_slab "viktor.external.scia.scia.Model.create_open_slab") * *property *corner\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[](#OpenSlab.corner_nodes "Link to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#OpenSlab.plane "Link to this definition") ## Orthotropy[​](/sdk/api/external/scia/.md#_Orthotropy "Direct link to Orthotropy") * *class *viktor.external.scia.object.Orthotropy(*object\_id*, *name*, *material*, *thickness*, *D11=None*, *D22=None*, *D12=None*, *D33=None*, *D44=None*, *D55=None*, *d11=None*, *d22=None*, *d12=None*, *d33=None*, *kxy=None*, *kyx=None*)[](#Orthotropy "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_orthotropy()`](/sdk/api/external/scia/.md#Model.create_orthotropy "viktor.external.scia.scia.Model.create_orthotropy") ## PermanentLoadCase[​](/sdk/api/external/scia/.md#_PermanentLoadCase "Direct link to PermanentLoadCase") * *class *viktor.external.scia.object.PermanentLoadCase(*object\_id*, *name*, *description*, *load\_group*, *load\_type*, *direction=None*, *primary\_effect=None*)[](#PermanentLoadCase "Link to this definition") Bases: [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") Do not use this \_\_init\_\_ directly, but create the object by [`create_permanent_load_case()`](/sdk/api/external/scia/.md#Model.create_permanent_load_case "viktor.external.scia.scia.Model.create_permanent_load_case") * *property *direction*: [Direction](#LoadCase.Direction "viktor.external.scia.object.LoadCase.Direction") | None*[](#PermanentLoadCase.direction "Link to this definition") - *property *duration*: None*[](#PermanentLoadCase.duration "Link to this definition") * *property *load\_type*: [PermanentLoadType](#LoadCase.PermanentLoadType "viktor.external.scia.object.LoadCase.PermanentLoadType")*[](#PermanentLoadCase.load_type "Link to this definition") - *property *master*: None*[](#PermanentLoadCase.master "Link to this definition") * *property *primary\_effect*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase") | None*[](#PermanentLoadCase.primary_effect "Link to this definition") - *property *specification*: None*[](#PermanentLoadCase.specification "Link to this definition") ## Plane[​](/sdk/api/external/scia/.md#_Plane "Direct link to Plane") * *class *viktor.external.scia.object.Plane(*object\_id*, *name*, *thickness*, *material*, *\**, *plane\_type=None*, *layer=None*, *corner\_nodes=None*, *internal\_nodes=None*, *swap\_orientation=None*, *lcs\_rotation=None*, *fem\_model=None*, *orthotropy=None*, *center\_node=None*, *vertex\_node=None*, *axis=None*)[](#Plane "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_plane()`](/sdk/api/external/scia/.md#Model.create_plane "viktor.external.scia.scia.Model.create_plane") or [`create_circular_plane()`](/sdk/api/external/scia/.md#Model.create_circular_plane "viktor.external.scia.scia.Model.create_circular_plane") * *class *FEMModel(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Plane.FEMModel "Link to this definition") Bases: `Enum` * ISOTROPIC*: [`FEMModel`](#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")** = 0*[](#Plane.FEMModel.ISOTROPIC "Link to this definition") - ORTHOTROPIC*: [`FEMModel`](#Plane.FEMModel "viktor.external.scia.object.Plane.FEMModel")** = 1*[](#Plane.FEMModel.ORTHOTROPIC "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Plane.Type "Link to this definition") Bases: `Enum` * **PLATE** - A standard plate is a planar 2D member with an arbitrary number of edges that may be straight or curved. * **WALL** - A wall is a vertical 2D member whose base is either straight or curved. * **SHELL** - Shells are defined by border lines (i.e. border curves). The shape of the shell can be defined by four, three or two curves / straight lines. - PLATE*: [`Type`](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 0*[](#Plane.Type.PLATE "Link to this definition") * SHELL*: [`Type`](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 2*[](#Plane.Type.SHELL "Link to this definition") - WALL*: [`Type`](#Plane.Type "viktor.external.scia.object.Plane.Type")** = 1*[](#Plane.Type.WALL "Link to this definition") * *property *corner\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[](#Plane.corner_nodes "Link to this definition") - *property *internal\_nodes*: List\[[Node](#Node "viktor.external.scia.object.Node")]*[](#Plane.internal_nodes "Link to this definition") * *property *lcs\_rotation*: float*[](#Plane.lcs_rotation "Link to this definition") - *property *swap\_orientation*: bool*[](#Plane.swap_orientation "Link to this definition") ## PointLoad[​](/sdk/api/external/scia/.md#_PointLoad "Direct link to PointLoad") * *class *viktor.external.scia.object.PointLoad(*object\_id*, *name*, *load\_case*, *beam*, *direction*, *load\_type*, *load\_value*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *ey=None*, *ez=None*, *\**, *angle=None*)[](#PointLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_point_load()`](/sdk/api/external/scia/.md#Model.create_point_load "viktor.external.scia.scia.Model.create_point_load") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")** = 0*[](#PointLoad.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#PointLoad.CDef "viktor.external.scia.object.PointLoad.CDef")** = 1*[](#PointLoad.CDef.RELATIVE "Link to this definition") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")** = 0*[](#PointLoad.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#PointLoad.CSys "viktor.external.scia.object.PointLoad.CSys")** = 1*[](#PointLoad.CSys.LOCAL "Link to this definition") * *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 0*[](#PointLoad.Direction.X "Link to this definition") - Y*: [`Direction`](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 1*[](#PointLoad.Direction.Y "Link to this definition") * Z*: [`Direction`](#PointLoad.Direction "viktor.external.scia.object.PointLoad.Direction")** = 2*[](#PointLoad.Direction.Z "Link to this definition") - *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.Distribution "Link to this definition") Bases: `Enum` * TRAPEZOIDAL*: [`Distribution`](#PointLoad.Distribution "viktor.external.scia.object.PointLoad.Distribution")** = 1*[](#PointLoad.Distribution.TRAPEZOIDAL "Link to this definition") - UNIFORM*: [`Distribution`](#PointLoad.Distribution "viktor.external.scia.object.PointLoad.Distribution")** = 0*[](#PointLoad.Distribution.UNIFORM "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")** = 1*[](#PointLoad.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#PointLoad.Origin "viktor.external.scia.object.PointLoad.Origin")** = 0*[](#PointLoad.Origin.FROM_START "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoad.Type "Link to this definition") Bases: `Enum` * FORCE*: [`Type`](#PointLoad.Type "viktor.external.scia.object.PointLoad.Type")** = 0*[](#PointLoad.Type.FORCE "Link to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#PointLoad.beam "Link to this definition") - *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#PointLoad.load_case "Link to this definition") ## PointLoadNode[​](/sdk/api/external/scia/.md#_PointLoadNode "Direct link to PointLoadNode") * *class *viktor.external.scia.object.PointLoadNode(*object\_id*, *name*, *node*, *load\_case*, *load*, *direction=None*, *c\_sys=None*, *angle=None*)[](#PointLoadNode "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_point_load_node()`](/sdk/api/external/scia/.md#Model.create_point_load_node "viktor.external.scia.scia.Model.create_point_load_node") * *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoadNode.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")** = 0*[](#PointLoadNode.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#PointLoadNode.CSys "viktor.external.scia.object.PointLoadNode.CSys")** = 1*[](#PointLoadNode.CSys.LOCAL "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointLoadNode.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 0*[](#PointLoadNode.Direction.X "Link to this definition") - Y*: [`Direction`](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 1*[](#PointLoadNode.Direction.Y "Link to this definition") * Z*: [`Direction`](#PointLoadNode.Direction "viktor.external.scia.object.PointLoadNode.Direction")** = 2*[](#PointLoadNode.Direction.Z "Link to this definition") * *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#PointLoadNode.load_case "Link to this definition") - *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[](#PointLoadNode.node "Link to this definition") ## PointMomentNode[​](/sdk/api/external/scia/.md#_PointMomentNode "Direct link to PointMomentNode") * *class *viktor.external.scia.object.PointMomentNode(*object\_id*, *name*, *node*, *load\_case*, *load*, *direction*, *c\_sys*)[](#PointMomentNode "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_point_moment_node()`](/sdk/api/external/scia/.md#Model.create_point_moment_node "viktor.external.scia.scia.Model.create_point_moment_node"). * *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointMomentNode.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")** = 0*[](#PointMomentNode.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#PointMomentNode.CSys "viktor.external.scia.object.PointMomentNode.CSys")** = 1*[](#PointMomentNode.CSys.LOCAL "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointMomentNode.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 0*[](#PointMomentNode.Direction.X "Link to this definition") - Y*: [`Direction`](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 1*[](#PointMomentNode.Direction.Y "Link to this definition") * Z*: [`Direction`](#PointMomentNode.Direction "viktor.external.scia.object.PointMomentNode.Direction")** = 2*[](#PointMomentNode.Direction.Z "Link to this definition") * *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#PointMomentNode.load_case "Link to this definition") - *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[](#PointMomentNode.node "Link to this definition") ## PointSupport[​](/sdk/api/external/scia/.md#_PointSupport "Direct link to PointSupport") * *class *viktor.external.scia.object.PointSupport(*object\_id*, *name*, *node*, *spring\_type*, *freedom*, *stiffness*, *c\_sys*, *default\_size=0.2*, *angle=None*)[](#PointSupport "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_point_support()`](/sdk/api/external/scia/.md#Model.create_point_support "viktor.external.scia.scia.Model.create_point_support") * *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupport.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")** = 0*[](#PointSupport.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#PointSupport.CSys "viktor.external.scia.object.PointSupport.CSys")** = 1*[](#PointSupport.CSys.LOCAL "Link to this definition") - *class *Constraint(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupport.Constraint "Link to this definition") Bases: `Enum` * CUSTOM*: [`Constraint`](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 3*[](#PointSupport.Constraint.CUSTOM "Link to this definition") - FIXED*: [`Constraint`](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 0*[](#PointSupport.Constraint.FIXED "Link to this definition") * HINGED*: [`Constraint`](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 1*[](#PointSupport.Constraint.HINGED "Link to this definition") - SLIDING*: [`Constraint`](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")** = 2*[](#PointSupport.Constraint.SLIDING "Link to this definition") * *class *Freedom(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupport.Freedom "Link to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FLEXIBLE*: [`Freedom`](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 2*[](#PointSupport.Freedom.FLEXIBLE "Link to this definition") * FREE*: [`Freedom`](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 0*[](#PointSupport.Freedom.FREE "Link to this definition") - RIGID*: [`Freedom`](#PointSupport.Freedom "viktor.external.scia.object.PointSupport.Freedom")** = 1*[](#PointSupport.Freedom.RIGID "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupport.Type "Link to this definition") Bases: `Enum` * COLUMN*: [`Type`](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 2*[](#PointSupport.Type.COLUMN "Link to this definition") - PAD\_FOUNDATION*: [`Type`](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 1*[](#PointSupport.Type.PAD_FOUNDATION "Link to this definition") * STANDARD*: [`Type`](#PointSupport.Type "viktor.external.scia.object.PointSupport.Type")** = 0*[](#PointSupport.Type.STANDARD "Link to this definition") * *property *constraint*: [Constraint](#PointSupport.Constraint "viktor.external.scia.object.PointSupport.Constraint")*[](#PointSupport.constraint "Link to this definition") - *property *node*: [Node](#Node "viktor.external.scia.object.Node")*[](#PointSupport.node "Link to this definition") ## PointSupportLine[​](/sdk/api/external/scia/.md#_PointSupportLine "Direct link to PointSupportLine") * *class *viktor.external.scia.object.PointSupportLine(*object\_id*, *name*, *beam*, *x=None*, *stiffness\_x=None*, *y=None*, *stiffness\_y=None*, *z=None*, *stiffness\_z=None*, *rx=None*, *stiffness\_rx=None*, *ry=None*, *stiffness\_ry=None*, *rz=None*, *stiffness\_rz=None*, *default\_size=None*, *c\_sys=None*, *c\_def=None*, *position\_x=None*, *origin=None*, *repeat=None*, *delta\_x=None*)[](#PointSupportLine "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_point_support_on_beam()`](/sdk/api/external/scia/.md#Model.create_point_support_on_beam "viktor.external.scia.scia.Model.create_point_support_on_beam") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupportLine.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")** = 0*[](#PointSupportLine.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#PointSupportLine.CDef "viktor.external.scia.object.PointSupportLine.CDef")** = 1*[](#PointSupportLine.CDef.RELATIVE "Link to this definition") - *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupportLine.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")** = 0*[](#PointSupportLine.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#PointSupportLine.CSys "viktor.external.scia.object.PointSupportLine.CSys")** = 1*[](#PointSupportLine.CSys.LOCAL "Link to this definition") * *class *Freedom(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupportLine.Freedom "Link to this definition") Bases: `Enum` * **FREE** - The support is free in the specified direction. That is it imposes no constraint in the direction. * **RIGID** - The support in fully rigid in the specified direction. * **FLEXIBLE** - The support is flexible (elastic) in the specified direction. The user has to define the required stiffness of the support. - FLEXIBLE*: [`Freedom`](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 2*[](#PointSupportLine.Freedom.FLEXIBLE "Link to this definition") * FREE*: [`Freedom`](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 0*[](#PointSupportLine.Freedom.FREE "Link to this definition") - RIGID*: [`Freedom`](#PointSupportLine.Freedom "viktor.external.scia.object.PointSupportLine.Freedom")** = 1*[](#PointSupportLine.Freedom.RIGID "Link to this definition") - *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#PointSupportLine.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")** = 1*[](#PointSupportLine.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#PointSupportLine.Origin "viktor.external.scia.object.PointSupportLine.Origin")** = 0*[](#PointSupportLine.Origin.FROM_START "Link to this definition") ## ProjectData[​](/sdk/api/external/scia/.md#_ProjectData "Direct link to ProjectData") * *class *viktor.external.scia.object.ProjectData(*\**, *name=None*, *part=None*, *description=None*, *author=None*, *date=None*)[](#ProjectData "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") New in v13.1.0 Basic project data. * Parameters: * **name** (`str`) – Project name (default: as defined in ESA model) * **part** (`str`) – Project part name (default: as defined in ESA model) * **description** (`str`) – Project description (default: as defined in ESA model) * **author** (`str`) – Name of the author (default: as defined in ESA model) * **date** (`str`) – Date of the last modification (default: as defined in ESA model) ## RectangularCrossSection[​](/sdk/api/external/scia/.md#_RectangularCrossSection "Direct link to RectangularCrossSection") * *class *viktor.external.scia.object.RectangularCrossSection(*object\_id*, *name*, *material*, *width*, *height*)[](#RectangularCrossSection "Link to this definition") Bases: [`CrossSection`](#CrossSection "viktor.external.scia.object.CrossSection") Do not use this \_\_init\_\_ directly, but create the object by [`create_rectangular_cross_section()`](/sdk/api/external/scia/.md#Model.create_rectangular_cross_section "viktor.external.scia.scia.Model.create_rectangular_cross_section") ## ResultClass[​](/sdk/api/external/scia/.md#_ResultClass "Direct link to ResultClass") * *class *viktor.external.scia.object.ResultClass(*object\_id*, *name*, *combinations*, *nonlinear\_combinations*)[](#ResultClass "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_result_class()`](/sdk/api/external/scia/.md#Model.create_result_class "viktor.external.scia.scia.Model.create_result_class") * *property *combinations*: List\[[LoadCombination](#LoadCombination "viktor.external.scia.object.LoadCombination")]*[](#ResultClass.combinations "Link to this definition") - *property *nonlinear\_combinations*: List\[[NonLinearLoadCombination](#NonLinearLoadCombination "viktor.external.scia.object.NonLinearLoadCombination")]*[](#ResultClass.nonlinear_combinations "Link to this definition") ## RigidArm[​](/sdk/api/external/scia/.md#_RigidArm "Direct link to RigidArm") * *class *viktor.external.scia.object.RigidArm(*object\_id*, *name*, *master\_node*, *slave\_node*, *hinge\_on\_master*, *hinge\_on\_slave*)[](#RigidArm "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_rigid_arm()`](/sdk/api/external/scia/.md#Model.create_rigid_arm "viktor.external.scia.scia.Model.create_rigid_arm") * *property *master\_node*: [Node](#Node "viktor.external.scia.object.Node")*[](#RigidArm.master_node "Link to this definition") - *property *slave\_node*: [Node](#Node "viktor.external.scia.object.Node")*[](#RigidArm.slave_node "Link to this definition") ## SciaObject[​](/sdk/api/external/scia/.md#_SciaObject "Direct link to SciaObject") * *class *viktor.external.scia.object.SciaObject(*object\_id*, *name*)[](#SciaObject "Link to this definition") Bases: `ABC` * *property *name*: str*[](#SciaObject.name "Link to this definition") Name of the object in SCIA. - *property *object\_id*: int*[](#SciaObject.object_id "Link to this definition") ID of the object in SCIA. ## SectionOnBeam[​](/sdk/api/external/scia/.md#_SectionOnBeam "Direct link to SectionOnBeam") * *class *viktor.external.scia.object.SectionOnBeam(*object\_id*, *name*, *beam*, *c\_def*, *position\_x*, *origin*, *repeat*, *delta\_x*)[](#SectionOnBeam "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_section_on_beam()`](/sdk/api/external/scia/.md#Model.create_section_on_beam "viktor.external.scia.scia.Model.create_section_on_beam") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SectionOnBeam.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")** = 0*[](#SectionOnBeam.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#SectionOnBeam.CDef "viktor.external.scia.object.SectionOnBeam.CDef")** = 1*[](#SectionOnBeam.CDef.RELATIVE "Link to this definition") - *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SectionOnBeam.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")** = 1*[](#SectionOnBeam.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#SectionOnBeam.Origin "viktor.external.scia.object.SectionOnBeam.Origin")** = 0*[](#SectionOnBeam.Origin.FROM_START "Link to this definition") * *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#SectionOnBeam.beam "Link to this definition") ## SectionOnPlane[​](/sdk/api/external/scia/.md#_SectionOnPlane "Direct link to SectionOnPlane") * *class *viktor.external.scia.object.SectionOnPlane(*object\_id*, *name*, *point\_1*, *point\_2*, *draw=None*, *direction\_of\_cut=None*)[](#SectionOnPlane "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_section_on_plane()`](/sdk/api/external/scia/.md#Model.create_section_on_plane "viktor.external.scia.scia.Model.create_section_on_plane") * *class *Draw(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SectionOnPlane.Draw "Link to this definition") Bases: `Enum` * ELEMENT\_PLANE*: [`Draw`](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 1*[](#SectionOnPlane.Draw.ELEMENT_PLANE "Link to this definition") - UPRIGHT\_TO\_ELEMENT*: [`Draw`](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 0*[](#SectionOnPlane.Draw.UPRIGHT_TO_ELEMENT "Link to this definition") * X\_DIRECTION*: [`Draw`](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 2*[](#SectionOnPlane.Draw.X_DIRECTION "Link to this definition") - Y\_DIRECTION*: [`Draw`](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 3*[](#SectionOnPlane.Draw.Y_DIRECTION "Link to this definition") * Z\_DIRECTION*: [`Draw`](#SectionOnPlane.Draw "viktor.external.scia.object.SectionOnPlane.Draw")** = 4*[](#SectionOnPlane.Draw.Z_DIRECTION "Link to this definition") ## Selection[​](/sdk/api/external/scia/.md#_Selection "Direct link to Selection") * *class *viktor.external.scia.object.Selection(*object\_id*, *name*, *objects*)[](#Selection "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_selection()`](/sdk/api/external/scia/.md#Model.create_selection "viktor.external.scia.scia.Model.create_selection") ## SolverSetup[​](/sdk/api/external/scia/.md#_SolverSetup "Direct link to SolverSetup") * *class *viktor.external.scia.object.SolverSetup(*\**, *neglect\_shear\_force\_deformation=None*, *bending\_theory=None*, *solver\_type=None*, *number\_of\_sections=None*, *reinforcement\_coefficient=None*)[](#SolverSetup "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") New in v13.1.0 Solver setup. * Parameters: * **neglect\_shear\_force\_deformation** (`bool`) – Neglect shear force deformation (default: as defined in ESA model) * **bending\_theory** (`str`) – Bending theory of plate/shell analysis (‘mindlin’ | ‘kirchhoff’) (default: as defined in ESA model) * **solver\_type** (`str`) – Type of solver (‘direct’ | ‘iterative’) (default: as defined in ESA model) * **number\_of\_sections** (`float`) – Number of sections on average member (default: as defined in ESA model) * **reinforcement\_coefficient** (`float`) – Coefficient for reinforcement (default: as defined in ESA model) ## Subsoil[​](/sdk/api/external/scia/.md#_Subsoil "Direct link to Subsoil") * *class *viktor.external.scia.object.Subsoil(*object\_id*, *name*, *stiffness*, *c1x=None*, *c1y=None*, *c1z=None*, *nonlinear\_function=None*, *c2x=None*, *c2y=None*, *is\_drained=None*, *water\_air\_in\_clay\_subgrade=None*, *specific\_weight=None*, *fi=None*, *sigma\_oc=None*, *c=None*, *cu=None*)[](#Subsoil "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_subsoil()`](/sdk/api/external/scia/.md#Model.create_subsoil "viktor.external.scia.scia.Model.create_subsoil") * *class *C1z(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#Subsoil.C1z "Link to this definition") Bases: `Enum` * FLEXIBLE*: [`C1z`](#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")** = 0*[](#Subsoil.C1z.FLEXIBLE "Link to this definition") - NONLINEAR\_FUNCTION*: [`C1z`](#Subsoil.C1z "viktor.external.scia.object.Subsoil.C1z")** = 1*[](#Subsoil.C1z.NONLINEAR_FUNCTION "Link to this definition") - *property *nonlinear\_function*: [NonLinearFunction](#NonLinearFunction "viktor.external.scia.object.NonLinearFunction") | None*[](#Subsoil.nonlinear_function "Link to this definition") ## SurfaceLoad[​](/sdk/api/external/scia/.md#_SurfaceLoad "Direct link to SurfaceLoad") * *class *viktor.external.scia.object.SurfaceLoad(*object\_id*, *name*, *load\_case*, *plane*, *direction*, *load\_type*, *load\_value*, *c\_sys*, *location*)[](#SurfaceLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_surface_load()`](/sdk/api/external/scia/.md#Model.create_surface_load "viktor.external.scia.scia.Model.create_surface_load") * *class *CSys(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SurfaceLoad.CSys "Link to this definition") Bases: `Enum` * GLOBAL*: [`CSys`](#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")** = 0*[](#SurfaceLoad.CSys.GLOBAL "Link to this definition") - LOCAL*: [`CSys`](#SurfaceLoad.CSys "viktor.external.scia.object.SurfaceLoad.CSys")** = 1*[](#SurfaceLoad.CSys.LOCAL "Link to this definition") - *class *Direction(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SurfaceLoad.Direction "Link to this definition") Bases: `Enum` * X*: [`Direction`](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 0*[](#SurfaceLoad.Direction.X "Link to this definition") - Y*: [`Direction`](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 1*[](#SurfaceLoad.Direction.Y "Link to this definition") * Z*: [`Direction`](#SurfaceLoad.Direction "viktor.external.scia.object.SurfaceLoad.Direction")** = 2*[](#SurfaceLoad.Direction.Z "Link to this definition") * *class *Location(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SurfaceLoad.Location "Link to this definition") Bases: `Enum` * LENGTH*: [`Location`](#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")** = 0*[](#SurfaceLoad.Location.LENGTH "Link to this definition") - PROJECTION*: [`Location`](#SurfaceLoad.Location "viktor.external.scia.object.SurfaceLoad.Location")** = 1*[](#SurfaceLoad.Location.PROJECTION "Link to this definition") - *class *Type(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#SurfaceLoad.Type "Link to this definition") Bases: `Enum` * FORCE*: [`Type`](#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")** = 0*[](#SurfaceLoad.Type.FORCE "Link to this definition") - SELF\_WEIGHT*: [`Type`](#SurfaceLoad.Type "viktor.external.scia.object.SurfaceLoad.Type")** = 1*[](#SurfaceLoad.Type.SELF_WEIGHT "Link to this definition") * *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#SurfaceLoad.load_case "Link to this definition") - *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#SurfaceLoad.plane "Link to this definition") ## SurfaceSupportSurface[​](/sdk/api/external/scia/.md#_SurfaceSupportSurface "Direct link to SurfaceSupportSurface") * *class *viktor.external.scia.object.SurfaceSupportSurface(*object\_id*, *name*, *plane*, *subsoil*)[](#SurfaceSupportSurface "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_surface_support()`](/sdk/api/external/scia/.md#Model.create_surface_support "viktor.external.scia.scia.Model.create_surface_support") * *property *plane*: [Plane](#Plane "viktor.external.scia.object.Plane")*[](#SurfaceSupportSurface.plane "Link to this definition") - *property *subsoil*: [Subsoil](#Subsoil "viktor.external.scia.object.Subsoil")*[](#SurfaceSupportSurface.subsoil "Link to this definition") ## ThermalLoad[​](/sdk/api/external/scia/.md#_ThermalLoad "Direct link to ThermalLoad") * *class *viktor.external.scia.object.ThermalLoad(*object\_id*, *name*, *load\_case*, *beam*, *distribution*, *delta*, *left\_delta*, *right\_delta*, *top\_delta*, *bottom\_delta*, *position\_start*, *position\_end*, *c\_def*, *origin*)[](#ThermalLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_thermal_load()`](/sdk/api/external/scia/.md#Model.create_thermal_load "viktor.external.scia.scia.Model.create_thermal_load") * *class *CDef(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ThermalLoad.CDef "Link to this definition") Bases: `Enum` * **ABSOLUTE** - absolute, where the coordinate must lie between 0 and the length of the beam * **RELATIVE** - relative, where the coordinate must lie between 0 and 1 - ABSOLUTE*: [`CDef`](#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")** = 0*[](#ThermalLoad.CDef.ABSOLUTE "Link to this definition") * RELATIVE*: [`CDef`](#ThermalLoad.CDef "viktor.external.scia.object.ThermalLoad.CDef")** = 1*[](#ThermalLoad.CDef.RELATIVE "Link to this definition") - *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ThermalLoad.Distribution "Link to this definition") Bases: `Enum` * CONSTANT*: [`Distribution`](#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")** = 0*[](#ThermalLoad.Distribution.CONSTANT "Link to this definition") - LINEAR*: [`Distribution`](#ThermalLoad.Distribution "viktor.external.scia.object.ThermalLoad.Distribution")** = 1*[](#ThermalLoad.Distribution.LINEAR "Link to this definition") * *class *Origin(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ThermalLoad.Origin "Link to this definition") Bases: `Enum` * **FROM\_START** - position is measured from the beginning of the beam * **FROM\_END** - position is measured from the end of the beam - FROM\_END*: [`Origin`](#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")** = 1*[](#ThermalLoad.Origin.FROM_END "Link to this definition") * FROM\_START*: [`Origin`](#ThermalLoad.Origin "viktor.external.scia.object.ThermalLoad.Origin")** = 0*[](#ThermalLoad.Origin.FROM_START "Link to this definition") - *property *beam*: [Beam](#Beam "viktor.external.scia.object.Beam")*[](#ThermalLoad.beam "Link to this definition") * *property *load\_case*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase")*[](#ThermalLoad.load_case "Link to this definition") ## ThermalSurfaceLoad[​](/sdk/api/external/scia/.md#_ThermalSurfaceLoad "Direct link to ThermalSurfaceLoad") * *class *viktor.external.scia.object.ThermalSurfaceLoad(*object\_id*, *name*, *load\_case*, *plane*, *delta=None*, *top\_delta=None*, *bottom\_delta=None*)[](#ThermalSurfaceLoad "Link to this definition") Bases: [`SciaObject`](#SciaObject "viktor.external.scia.object.SciaObject") Do not use this \_\_init\_\_ directly, but create the object by [`create_thermal_surface_load()`](/sdk/api/external/scia/.md#Model.create_thermal_surface_load "viktor.external.scia.scia.Model.create_thermal_surface_load") * *class *Distribution(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#ThermalSurfaceLoad.Distribution "Link to this definition") Bases: `Enum` * CONSTANT*: [`Distribution`](#ThermalSurfaceLoad.Distribution "viktor.external.scia.object.ThermalSurfaceLoad.Distribution")** = 0*[](#ThermalSurfaceLoad.Distribution.CONSTANT "Link to this definition") - LINEAR*: [`Distribution`](#ThermalSurfaceLoad.Distribution "viktor.external.scia.object.ThermalSurfaceLoad.Distribution")** = 1*[](#ThermalSurfaceLoad.Distribution.LINEAR "Link to this definition") ## VariableLoadCase[​](/sdk/api/external/scia/.md#_VariableLoadCase "Direct link to VariableLoadCase") * *class *viktor.external.scia.object.VariableLoadCase(*object\_id*, *name*, *description*, *load\_group*, *load\_type*, *specification=None*, *duration=None*, *primary\_effect=None*, *master=None*)[](#VariableLoadCase "Link to this definition") Bases: [`LoadCase`](#LoadCase "viktor.external.scia.object.LoadCase") Do not use this \_\_init\_\_ directly, but create the object by [`create_variable_load_case()`](/sdk/api/external/scia/.md#Model.create_variable_load_case "viktor.external.scia.scia.Model.create_variable_load_case") * *property *direction*: None*[](#VariableLoadCase.direction "Link to this definition") - *property *duration*: [Duration](#LoadCase.Duration "viktor.external.scia.object.LoadCase.Duration") | None*[](#VariableLoadCase.duration "Link to this definition") * *property *load\_type*: [VariableLoadType](#LoadCase.VariableLoadType "viktor.external.scia.object.LoadCase.VariableLoadType")*[](#VariableLoadCase.load_type "Link to this definition") - *property *master*: str | None*[](#VariableLoadCase.master "Link to this definition") * *property *primary\_effect*: [LoadCase](#LoadCase "viktor.external.scia.object.LoadCase") | None*[](#VariableLoadCase.primary_effect "Link to this definition") - *property *specification*: [Specification](#LoadCase.Specification "viktor.external.scia.object.LoadCase.Specification") | None*[](#VariableLoadCase.specification "Link to this definition") --- # viktor.external.spreadsheet ## DirectInputCell[​](/sdk/api/external/spreadsheet/.md#_DirectInputCell "Direct link to DirectInputCell") * *class *viktor.external.spreadsheet.DirectInputCell(*sheet\_name*, *column*, *row*, *value*)[](#DirectInputCell "Link to this definition") Bases: `_DirectCellBaseClass` Class for defining a direct cell in which a value must be inserted If a rectangular block of data has to be inserted, use [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange") for more efficiency. * Parameters: * **sheet\_name** (`str`) – name of the sheet in which the cell is present. * **column** (`str`) – target column. * **row** (`int`) – target row. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. - serialize(*convert\_value\_to\_str=False*)[](#DirectInputCell.serialize "Link to this definition") * Parameters: **convert\_value\_to\_str** (`bool`) – convert value to str. Necessary when DirectInputCell is used in coupled Excel program (only old workers). * Return type: `dict` ## DirectOutputCell[​](/sdk/api/external/spreadsheet/.md#_DirectOutputCell "Direct link to DirectOutputCell") * *class *viktor.external.spreadsheet.DirectOutputCell(*sheet\_name*, *column*, *row*)[](#DirectOutputCell "Link to this definition") Bases: `_DirectCellBaseClass` Class for defining a direct cell of which an output is desired. Example usage: ``` direct_cell = DirectOutputCell('sheet_name', 'G', 3) excel = Excel(template, direct_output_cells=[direct_cell]) excel.execute() my_desired_value = direct_cell.result ``` * equals(*direct\_cell\_result*)[](#DirectOutputCell.equals "Link to this definition") * Return type: `bool` - *property *result*: Any*[](#DirectOutputCell.result "Link to this definition") * serialize()[](#DirectOutputCell.serialize "Link to this definition") * Return type: `dict` ## InputCellRange[​](/sdk/api/external/spreadsheet/.md#_InputCellRange "Direct link to InputCellRange") * *class *viktor.external.spreadsheet.InputCellRange(*sheet\_name*, *left\_column*, *top\_row*, *data*)[](#InputCellRange "Link to this definition") Convenience object to define a range of cells in row- and/or column direction. For single cells, use [`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell") Example: ``` data = [ [1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], ] cell_range = InputCellRange('Sheet1', left_column='B', top_row=3, data=data) ``` This produces the following sheet: > | | | | | | | > | - | - | - | - | - | - | > | | A | B | C | D | E | > | 1 | | | | | | > | 2 | | | | | | > | 3 | | 1 | 2 | 3 | | > | 4 | | 4 | 5 | 6 | | > | 5 | | a | b | c | | > | 6 | | | | | | * Parameters: * **sheet\_name** (`str`) – name of the sheet in which the data is inserted * **left\_column** (`str`) – column letter of the top left target of the data * **top\_row** (`int`) – row number of the top left target of the data * **data** (`List`\[`List`\[`Union`\[`float`, `str`]]]) – content which is filled in the cell range. the nested list structure should be rectangular (each list should have the same length) and not empty. - serialize()[](#InputCellRange.serialize "Link to this definition") * Return type: `dict` ## NamedInputCell[​](/sdk/api/external/spreadsheet/.md#_NamedInputCell "Direct link to NamedInputCell") * *class *viktor.external.spreadsheet.NamedInputCell(*name*, *value*)[](#NamedInputCell "Link to this definition") Bases: `_NamedCellBaseClass` Class for defining a named cell in which a value must be inserted. * Parameters: * **name** (`str`) – name of the cell. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. - serialize(*convert\_value\_to\_str=False*)[](#NamedInputCell.serialize "Link to this definition") * Parameters: **convert\_value\_to\_str** (`bool`) – convert value to str. Necessary when NamedInputCell is used in coupled Excel program (only old workers). * Return type: `dict` * serialize\_for\_fill\_spreadsheet()[](#NamedInputCell.serialize_for_fill_spreadsheet "Link to this definition") * Return type: `dict` ## NamedOutputCell[​](/sdk/api/external/spreadsheet/.md#_NamedOutputCell "Direct link to NamedOutputCell") * *class *viktor.external.spreadsheet.NamedOutputCell(*name*)[](#NamedOutputCell "Link to this definition") Bases: `_NamedCellBaseClass` Class for defining named cells of which the output is desired. Example usage: ``` named_cell = NamedOutputCell('my_name') excel = Excel(template, named_output_cells=[named_cell]) excel.execute() my_desired_value = named_cell.result ``` * equals(*named\_cell\_result*)[](#NamedOutputCell.equals "Link to this definition") * Return type: `bool` - *property *result*: Any*[](#NamedOutputCell.result "Link to this definition") Property that returns the result of this cell. May be called after Excel has been executed. * Returns: the result of this cell after excel execution * serialize()[](#NamedOutputCell.serialize "Link to this definition") * Return type: `dict` ## SpreadsheetCalculation[​](/sdk/api/external/spreadsheet/.md#_SpreadsheetCalculation "Direct link to SpreadsheetCalculation") * *class *viktor.external.spreadsheet.SpreadsheetCalculation(*file*, *inputs*)[](#SpreadsheetCalculation "Link to this definition") Using a spreadsheet for calculations, inserting inputs and reading outputs. This spreadsheet should not contain macros. See the excel module for spreadsheet calculations with macros. Example usage: ``` inputs = [ SpreadsheetCalculationInput('x', 1), SpreadsheetCalculationInput('y', 2), ] spreadsheet = SpreadsheetCalculation(spreadsheet, inputs) result = spreadsheet.evaluate(include_filled_file=False) values = result.values ``` * Parameters: **file** (`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – spreadsheet file - evaluate(*include\_filled\_file=False*)[](#SpreadsheetCalculation.evaluate "Link to this definition") This function enters the values provided into the input tab of the sheet. The sheet evaluates the input and returns a dictionary containing key value pairs of the result parameters Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **include\_filled\_file** (`bool`) – when True, the SpreadsheetResult will contain the filled in spreadsheet. * Return type: [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") * *property *file*: [File](/sdk/api/core/.md#File "viktor.core.File")*[](#SpreadsheetCalculation.file "Link to this definition") New in v14.14.0 Returns a File object of the to-be-calculated spreadsheet. - *classmethod *from\_path(*file\_path*, *inputs*)[](#SpreadsheetCalculation.from_path "Link to this definition") * Parameters: * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **inputs** (`List`\[[`SpreadsheetCalculationInput`](#SpreadsheetCalculationInput "viktor.external.spreadsheet.SpreadsheetCalculationInput")]) * Return type: [`SpreadsheetCalculation`](#SpreadsheetCalculation "viktor.external.spreadsheet.SpreadsheetCalculation") * *property *result*: [SpreadsheetResult](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult")*[](#SpreadsheetCalculation.result "Link to this definition") ## SpreadsheetCalculationInput[​](/sdk/api/external/spreadsheet/.md#_SpreadsheetCalculationInput "Direct link to SpreadsheetCalculationInput") * *class *viktor.external.spreadsheet.SpreadsheetCalculationInput(*name*, *value*)[](#SpreadsheetCalculationInput "Link to this definition") Bases: [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell") This class is subclassed from NamedInputCell because the same functionality is needed. * Parameters: * **name** (`str`) – name of the cell. * **value** (`Union`\[`bool`, `int`, `str`, `float`]) – value to be placed in the cell. ## SpreadsheetResult[​](/sdk/api/external/spreadsheet/.md#_SpreadsheetResult "Direct link to SpreadsheetResult") * *class *viktor.external.spreadsheet.SpreadsheetResult(*\**, *values=None*, *file=None*)[](#SpreadsheetResult "Link to this definition") Wrapper around results obtained from spreadsheet services. Warning Do not instantiate this class directly, it is created by the spreadsheet service. * *property *file*: [File](/sdk/api/core/.md#File "viktor.core.File")*[](#SpreadsheetResult.file "Link to this definition") New in v14.14.0 Returns a File object of the resulting filled-in spreadsheet. - *property *file\_content*: bytes*[](#SpreadsheetResult.file_content "Link to this definition") * get\_value(*name*)[](#SpreadsheetResult.get_value "Link to this definition") * Return type: `Any` - *property *values*: dict*[](#SpreadsheetResult.values "Link to this definition") ## SpreadsheetTemplate[​](/sdk/api/external/spreadsheet/.md#_SpreadsheetTemplate "Direct link to SpreadsheetTemplate") * *class *viktor.external.spreadsheet.SpreadsheetTemplate(*file*, *input\_cells*)[](#SpreadsheetTemplate "Link to this definition") Note Prefer to use the function [`render_spreadsheet()`](#render_spreadsheet "viktor.external.spreadsheet.render_spreadsheet") instead. Fill spreadsheet with values/text. This can be done both with direct cells (e.g. A2), or named cells. Example usage: ``` cells = [ DirectInputCell('sheet1', 'A', 1, 5), NamedInputCell('named_cell_1', 'text_to_be_placed'), ] template = SpreadsheetTemplate(template, cells) result = template.render() filled_template = result.file_content ``` * Parameters: * **file** (`BytesIO`) – BytesIO object of the spreadsheet * **input\_cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – The cells to fill the file with. - *classmethod *from\_path(*file\_path*, *input\_cells*)[](#SpreadsheetTemplate.from_path "Link to this definition") * Parameters: * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **input\_cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – The cells to fill the file with * Return type: [`SpreadsheetTemplate`](#SpreadsheetTemplate "viktor.external.spreadsheet.SpreadsheetTemplate") * render()[](#SpreadsheetTemplate.render "Link to this definition") This function renders the SpreadsheetTemplate with cells. It returns a SpreadsheetResult object of the filled template. * Return type: [`SpreadsheetResult`](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult") * Returns: a SpreadsheetResult object containing the filled template - *property *result*: [SpreadsheetResult](#SpreadsheetResult "viktor.external.spreadsheet.SpreadsheetResult")*[](#SpreadsheetTemplate.result "Link to this definition") ## render\_spreadsheet[​](/sdk/api/external/spreadsheet/.md#_render_spreadsheet "Direct link to render_spreadsheet") * viktor.external.spreadsheet.render\_spreadsheet(*template*, *cells*)[](#render_spreadsheet "Link to this definition") Fill spreadsheet with values/text. This can be done both with direct cells (e.g. A2), or named cells. Example usage: ``` cells = [ DirectInputCell('sheet1', 'A', 1, 5), NamedInputCell('named_cell_1', 'text_to_be_placed'), ] template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.xlsx' with open(template_path, 'rb') as template: filled_spreadsheet = render_spreadsheet(template, cells) ``` * Parameters: * **template** (`BinaryIO`) – spreadsheet template file * **cells** (`List`\[`Union`\[[`DirectInputCell`](#DirectInputCell "viktor.external.spreadsheet.DirectInputCell"), [`NamedInputCell`](#NamedInputCell "viktor.external.spreadsheet.NamedInputCell"), [`InputCellRange`](#InputCellRange "viktor.external.spreadsheet.InputCellRange")]]) – cells to fill the template with * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing the rendered spreadsheet ## stringify\_value[​](/sdk/api/external/spreadsheet/.md#_stringify_value "Direct link to stringify_value") * viktor.external.spreadsheet.stringify\_value(*value*)[](#stringify_value "Link to this definition") Function that will create the correct string representation of python data types, in order for ‘value’ to be inserted in Excel correctly. * Parameters: **value** (`Union`\[`bool`, `int`, `str`, `float`]) – the value to be stringified. * Return type: `str` * Returns: a string representation of value. --- # viktor.external.tekla ## TeklaAnalysis[​](/sdk/api/external/tekla/.md#_TeklaAnalysis "Direct link to TeklaAnalysis") * *class *viktor.external.tekla.TeklaAnalysis(*script=None*, *script\_key=''*, *files=None*, *output\_filenames=None*)[](#TeklaAnalysis "Link to this definition") Bases: [`PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis") New in 14.17.0 TeklaAnalysis can be used to evaluate a tekla-python script on third-party infrastructure. The script is expected to be blocking, i.e. if the script is invoked from command prompt, it should wait until the executable is finished. The default behaviour, is that the python script is defined within the app and send to the worker to be executed on third-party infrastructure. If desired (due to security considerations) the worker can be configured to only run local scripts. These scripts must be defined the in worker configuration file and can be selected through the script\_key. Usage: ``` script = vkt.File.from_path(Path(__file__).parent / "run_tekla.py") files = [ ('input1.txt', file1), ] analysis = TeklaAnalysis(script=script, files=files, output_filenames=["output.txt"]) analysis.execute(timeout=60) output_file = analysis.get_output_file("output.txt") ``` Exceptions which can be raised during calculation: > * [`viktor.errors.LicenseError`](/sdk/api/errors/.md#LicenseError "viktor.errors.LicenseError"): no license available > > * [`viktor.errors.ExecutionError`](/sdk/api/errors/.md#ExecutionError "viktor.errors.ExecutionError"): generic error. Error message provides more information * Parameters: * **script** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Script file that is transferred to the working directory on the server. * **script\_key** (`str`) – The key of the script that needs to be run. Only use this when the worker is configured to run local scripts. This key should be present in the configuration file of the worker. * **files** (`List`\[`Tuple`\[`str`, `Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]]) – Additional files that are transferred to the working directory on the server. Each file is a tuple containing the content and the filename which is used to save on the infrastructure. * **output\_filenames** (`List`\[`str`]) – A list of filenames (including extension) that are to be transferred back to the app. This filename is relative to the working directory. Either one of ‘script’ or ‘script\_key’ should be defined. * Raises: **ValueError** – when neither ‘script’ or ‘script\_key’ is included OR when both are included. --- # viktor.external.word ## WordFileComponent[​](/sdk/api/external/word/.md#_WordFileComponent "Direct link to WordFileComponent") * *class *viktor.external.word.WordFileComponent(*identifier*)[](#WordFileComponent "Link to this definition") Bases: `ABC` Abstract base class for specific word file components, such as tags, images… ## WordFileImage[​](/sdk/api/external/word/.md#_WordFileImage "Direct link to WordFileImage") * *class *viktor.external.word.WordFileImage(*file*, *identifier*, *width=None*, *height=None*)[](#WordFileImage "Link to this definition") Bases: [`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent") Add an image in a Word file template. When neither width or height is provided, the original size is used. When only one is provided, the other is scaled. When both are provided, both are used and the original aspect ratio might be changed. * Parameters: * **file** (`BinaryIO`) – image to be placed at the tag location * **identifier** (`str`) – used to find the location in the template * **width** (`int`) – optional parameter for sizing. in Pt * **height** (`int`) – optional parameter for sizing. in Pt - *classmethod *from\_path(*file\_path*, *identifier*, *width=None*, *height=None*)[](#WordFileImage.from_path "Link to this definition") Create a WordFileImage from an image defined by its file path. * Return type: [`WordFileImage`](#WordFileImage "viktor.external.word.WordFileImage") ## WordFileResult[​](/sdk/api/external/word/.md#_WordFileResult "Direct link to WordFileResult") * *class *viktor.external.word.WordFileResult(*\**, *file\_content=None*)[](#WordFileResult "Link to this definition") * *property *file\_content*: bytes*[](#WordFileResult.file_content "Link to this definition") ## WordFileTag[​](/sdk/api/external/word/.md#_WordFileTag "Direct link to WordFileTag") * *class *viktor.external.word.WordFileTag(*identifier*, *value*)[](#WordFileTag "Link to this definition") Bases: [`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent") Add a value in a Word file template by tag. * Parameters: * **identifier** (`str`) – used to find the location in the template * **value** (`object`) – what needs to be placed at tag location ## WordFileTemplate[​](/sdk/api/external/word/.md#_WordFileTemplate "Direct link to WordFileTemplate") * *class *viktor.external.word.WordFileTemplate(*file*, *components*)[](#WordFileTemplate "Link to this definition") Note Prefer to use the function [`render_word_file()`](#render_word_file "viktor.external.word.render_word_file") instead. Fill wordfile template with components (e.g. text, image). Note that the template file should be a BytesIO object of a .docx file (not .doc). Example usage: ``` >>> file = BytesIO(b'file') >>> image = BytesIO(b'image') >>> >>> tags = [ >>> WordFileTag('x', 1), >>> WordFileTag('y', 2), >>> WordFileImage(image, 'fig_tag', width=300), >>> ] >>> word_file_template = WordFileTemplate(file, tags) >>> result = word_file_template.render() >>> word_file = result.file_content ``` * Parameters: * **file** (`BytesIO`) – BytesIO object of the Word template * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – items that need to be inserted in the template - *classmethod *from\_path(*file\_path*, *components*)[](#WordFileTemplate.from_path "Link to this definition") * Parameters: * **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Complete path including extension * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – items that need to be inserted in the template * Return type: [`WordFileTemplate`](#WordFileTemplate "viktor.external.word.WordFileTemplate") * render()[](#WordFileTemplate.render "Link to this definition") This function renders the docx template and returns the resulting file. :rtype: [`WordFileResult`](#WordFileResult "viktor.external.word.WordFileResult") Note This method needs to be mocked in (automated) unit and integration tests. - *property *result*: [WordFileResult](#WordFileResult "viktor.external.word.WordFileResult")*[](#WordFileTemplate.result "Link to this definition") ## render\_word\_file[​](/sdk/api/external/word/.md#_render_word_file "Direct link to render_word_file") * viktor.external.word.render\_word\_file(*template*, *components*)[](#render_word_file "Link to this definition") Fill Word file with components (e.g. text, image). Example usage: ``` components = [ WordFileTag('x', 1), WordFileImage(image, 'fig_tag', width=300), ] template_path = Path(__file__).parent / 'my' / 'relative' / 'path' / 'template.docx' with open(template_path, 'rb') as template: word_file = render_word_file(template, components) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **template** (`BinaryIO`) – Word file template of type .docx (not .doc) * **components** (`List`\[[`WordFileComponent`](#WordFileComponent "viktor.external.word.WordFileComponent")]) – components to fill the template with * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing the rendered Word file * Raises: [`viktor.errors.WordFileError`](/sdk/api/errors/.md#WordFileError "viktor.errors.WordFileError") when rendering fails --- # viktor.geo ## GEFData[​](/sdk/api/geo/.md#_GEFData "Direct link to GEFData") * *class *viktor.geo.GEFData(*gef\_dict*)[](#GEFData "Link to this definition") Initialize GEFData object to simplify working with GEF data. Every GEF has different header fields, and therefore only a limited amount of fields is compulsory. All other header fields are also added as attribute. Compulsory header fields are: > * name > > * ground\_level\_wrt\_reference Other header fields might be compulsory for methods on the object (e.g. get\_cone\_visualization). See docstring of the specific method for needed headers. The following measurement\_data fields are also compulsory and are implicitly parsed from the file (do NOT need to be specified explicitly): > * elevation > > * qc > > * Rf Examples of optional attributes from header are: > * height\_system > > * project\_name > > * project\_id > > * gef\_file\_date > > * gef\_version\_number > > * x\_y\_coordinates > > * coordinate\_system > > * excavation\_depth > > * measurement\_standard > > * surface\_area\_quotient\_tip > > * water\_level > > * cone\_tip\_area > > * cone\_type Measurement\_data fields that are optional are: > * u2 > > * fs > > * penetration\_length > > * corrected\_depth > > * inclination > > * inclination\_n\_s > > * inclination\_e\_w Example implementation to create GEFData object: ``` from viktor.core import ViktorController, ParamsFromFile from viktor.geo import GEFFile, GEFData class GEFFileController(ViktorController): ... @ParamsFromFile(file_types=['.gef']) def process_file(self, file, **kwargs) -> dict: file_content = file.getvalue(encoding="ISO-8859-1") gef_file = GEFFile(file_content) gef_data_object = gef_file.parse(additional_columns=['elevation', 'qc', 'Rf', 'fs', 'u2'], return_gef_data_obj=True) gef_dict = gef_data_object.serialize() return {'gef_dict': gef_dict} def get_gef_content_from_database(self) -> GEFData: # API call to right entity return GEFData(gef_file_entity.last_saved_params['gef_dict']) ``` * Parameters: **gef\_dict** (`Union`\[`dict`, `Munch`]) – dictionary with \[‘headers’] and \[‘measurement\_data’] keys - classify(*method*, *return\_soil\_layout\_obj=True*)[](#GEFData.classify "Link to this definition") Create SoilLayout object or dictionary by classifying the GEF measurement data, using either the Robertson method or a qualification table method. **RobertsonMethod** This method requires the GEFData object to at least contain the measurement data ‘corrected\_depth’. See [`GEFData`](#GEFData "viktor.geo.GEFData") for all possible measurement data columns. ``` from viktor.geo import RobertsonMethod soil_properties = [ {'name': 'Robertson zone unknown', 'extra_property1': 1, 'extra_property2': 2}, {'name': 'Robertson zone 1', 'extra_property1': 3, 'extra_property2': 4}, ] classification_method = RobertsonMethod(soil_properties) soil_layout_dict = gef_data.classify(method=classification_method, return_soil_layout_obj=False) ``` **TableMethod** For this method a qualification table has to be provided by the user, for example through a VIKTOR editor. Please refer to the docstring of [`TableMethod`](#TableMethod "viktor.geo.TableMethod") for the structure of this table. This table is usually controlled on a project-wide level, so in a parent entity. On the controller of the GEF file, you can use the API to retrieve the table content and pass it to the TableMethod: ``` from viktor.api_v1 import API api = API() parent_entity = api.get_entity(entity_id).parent() parent_params = parent.last_saved_params qualification_table = parent_params['material_properties'] ground_water_level = parent_params['ground_water_level'] classification_method = TableMethod(qualification_table, ground_water_level) soil_layout_obj = gef_data.classify(method=classification_method, return_soil_layout_obj=False) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **method** (`_ClassificationMethod`) – Specifies which method should be used for qualification: TableMethod | RobertsonMethod | NormalizedSoilBehaviourTypeIndexMethod. * **return\_soil\_layout\_obj** (`bool`) – Flag to return SoilLayout object or dictionary * Return type: `Union`\[`dict`, [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")] * Returns: SoilLayout object or dictionary (=SoilLayout.serialize()) * get\_cone\_visualization(*axes*)[](#GEFData.get_cone_visualization "Link to this definition") Modify (clean/empty) ‘axes’ input argument to plot cone resistance (with pore pressure if present in GEF data). * Parameters: **axes** (`Axes`) – Axes object that will be modified. * Return type: `None` The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference > > * ground\_level\_wrt\_reference > > * height\_system Example usage: ``` import matplotlib.pyplot as plt # Create main figure fig = plt.figure(figsize=(8.27, 11.69)) # Define contour (rectangle) for cone visualization, and create Axes object that can be modified by # functions rect_cone = [0.1, 0.1, 0.4, 0.9] # [left, bottom, width, height] cone_axes = plt.axes(rect_cone) # Modify created Axes objects self.gef_data.get_cone_visualization(cone_axes) # Convert to SVG for visualization svg_data = StringIO() fig.savefig(svg_data, format='svg', bbox_inches='tight', pad_inches=0.8) plt.close() gef_visualisation_data = svg_data.getvalue() ``` - get\_plotted\_denotation\_large\_qc\_values(*axes*, *x\_loc\_text*)[](#GEFData.get_plotted_denotation_large_qc_values "Link to this definition") Can be used to add text labels with the maximum qc value of a layer that exceeds the maximum value of the x-axis. * Parameters: * **axes** (`Axes`) – Axes object that will be modified. * **x\_loc\_text** (`float`) – Maximum qc value. * Return type: `None` The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference An example is shown below where the figure is capped at a maximum qc of 30 MPa (hence x\_loc\_text=30). [![/\_images/gefdata\_plot\_large\_qc.svg](/_images/gefdata_plot_large_qc.svg)](/_images/gefdata_plot_large_qc.svg) * get\_resistance\_visualization(*axes*)[](#GEFData.get_resistance_visualization "Link to this definition") Modify (clean/empty) ‘axes’ input argument to plot resistance number. * Parameters: **axes** (`Axes`) – Axes object that will be modified. * Return type: `None` The following header fields are compulsory and need to be specified when the GEFData object is created: > * max\_measurement\_depth\_wrt\_reference > > * ground\_level\_wrt\_reference Example usage: ``` import matplotlib.pyplot as plt # Create main figure fig = plt.figure(figsize=(8.27, 11.69)) # Define contour (rectangle) for resistance number visualization, and create Axes object that can be # modified by functions rect_resistance = [0.1, 0.1, 0.4, 0.9] # [left, bottom, width, height] resistance_axes = plt.axes(rect_resistance) # Modify created Axes objects self.gef_data.get_resistance_visualization(resistance_axes) # Convert to SVG for visualization svg_data = StringIO() fig.savefig(svg_data, format='svg', bbox_inches='tight', pad_inches=0.8) plt.close() gef_visualisation_data = svg_data.getvalue() ``` - serialize()[](#GEFData.serialize "Link to this definition") * Return type: `Union`\[`dict`, `Munch`] ## GEFFile[​](/sdk/api/geo/.md#_GEFFile "Direct link to GEFFile") * *class *viktor.geo.GEFFile(*file\_content*)[](#GEFFile "Link to this definition") * *classmethod *from\_file(*file\_path*, *encoding='ISO-8859-1'*)[](#GEFFile.from_file "Link to this definition") * Return type: [`GEFFile`](#GEFFile "viktor.geo.GEFFile") - parse(*additional\_columns=None*, *verbose=True*, *return\_gef\_data\_obj=True*)[](#GEFFile.parse "Link to this definition") Parse GEFFile, and return information from GEF in dict with \[‘headers’] and \[‘measurement data’] sub-dicts or a GEFData object. Example implementation: ``` from viktor.core import ViktorController, ParamsFromFile from viktor.geo import GEFFile, GEFData class GEFFileController(ViktorController): ... @ParamsFromFile(file_types=['.gef']) def process_file(self, file, **kwargs) -> dict: file_content = file.getvalue(encoding="ISO-8859-1") gef_file = GEFFile(file_content) gef_data_obj = gef_file.parse(additional_columns=['fs', 'u2'], return_gef_data_obj=True) soil_properties = [ {'name': Robertson zone unknown, 'extra_property1': 1, 'extra_property2': 2}, {'name': Robertson zone 1, 'extra_property1': 3, 'extra_property2': 4}, ] soil_layout_dict = gef_data_obj.classify(method=RobertsonMethod(soil_properties), return_soil_layout_obj=False) parsed_dict = gef_data_obj.serialize() parsed_dict['soils'] = soil_layout_dict return parsed_dict ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **additional\_columns** (`List`\[`str`]) – In order for a GEF file to be of use in VIKTOR, three columns are required: * elevation (corrected depth with respect to a specified datum) * qc (tip pressure as measured) * Rf (friction number, either measured or computed using qc and fs) These three columns will always be parsed and returned, additional columns can be parsed as well. Possible columns to request are: * ”penetration\_length” * ”corrected\_depth” * ”fs” * ”u2” (for more accuracy when qualifying layers using Robertson method) * ”inclination” * ”inclination\_n\_s” * ”inclination\_e\_w” * **verbose** (`bool`) – Boolean specifying if parsing should output warnings or work in silence * **return\_gef\_data\_obj** (`bool`) – Boolean to return GEFData or dictionary * Return type: `Union`\[`dict`, [`GEFData`](#GEFData "viktor.geo.GEFData")] * Returns: dictionary with GEF parameters or GEFData object with GEF parameters as attributes ## NormalizedSoilBehaviourTypeIndexMethod[​](/sdk/api/geo/.md#_NormalizedSoilBehaviourTypeIndexMethod "Direct link to NormalizedSoilBehaviourTypeIndexMethod") * *class *viktor.geo.NormalizedSoilBehaviourTypeIndexMethod(*ic\_table*, *ground\_water\_level*, *specific\_weight\_soil*, *resolution=None*)[](#NormalizedSoilBehaviourTypeIndexMethod "Link to this definition") Bases: `_ClassificationMethod` Class to classify soil based on the normalized soil behaviour type index Example: ``` ic_table = [ {'name': 'Zand', 'color': '0, 50, 255', 'ic_min': 0, 'ic_max': 3.5}, {'name': 'Klei', 'color': '80, 70, 25', 'ic_min': 3.5, 'cone_factor': 20}, ] ground_water_level = 0 specific_weight_soil = 17 method = NormalizedSoilBehaviourTypeIndexMethod(ic_table, ground_water_level, specific_weight_soil) ``` This method uses the assumption that the specific weight of all the soil layers is the same, this is a simplification. It is possible to calculate the specific weight from qc values. * Parameters: * **ic\_table** (`List`\[`dict`]) – Table with soil types that correspond to Ic values. Keys: name, ic\_min, ic\_max, color, cone\_factor * **ground\_water\_level** (`float`) – Ground water level used to compute qc\_norm * **specific\_weight\_soil** (`float`) – Specific weight of soil in kN/m^3 used to calculate sigma’ * **resolution** (`float`) – Resolution of the classification in m; if None classify each line of data - get\_method\_params()[](#NormalizedSoilBehaviourTypeIndexMethod.get_method_params "Link to this definition") * Return type: `dict` ## PiezoLine[​](/sdk/api/geo/.md#_PiezoLine "Direct link to PiezoLine") * *class *viktor.geo.PiezoLine(*points*, *phreatic=False*)[](#PiezoLine "Link to this definition") Bases: [`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline") Class to represent a Piezo line. Essentially, this is a polyline with a flag added to mark the phreatic polyline. * Parameters: * **points** (`List`\[[`Point`](/sdk/api/geometry/.md#Point "viktor.geometry.Point")]) – points of the polyline * **phreatic** (`bool`) – mark the phreatic waterline - *classmethod *from\_dict(*piezo\_line\_dict*)[](#PiezoLine.from_dict "Link to this definition") * Return type: [`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine") * *classmethod *from\_lines(*lines*, *phreatic=False*)[](#PiezoLine.from_lines "Link to this definition") create a polyline object from a list of lines the end of one line must always coincide with the start of the next * Parameters: * **lines** (`List`\[`Union`\[[`Line`](/sdk/api/geometry/.md#Line "viktor.geometry.Line"), [`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")]]) * **phreatic** (`bool`) * Return type: [`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine") - serialize()[](#PiezoLine.serialize "Link to this definition") Return a json serializable dict of form: ``` [ {'x': point_1.x, 'y': point_1.y}, {'x': point_2.x, 'y': point_2.y} ] ``` * Return type: `dict` ## PositionalSoilLayout[​](/sdk/api/geo/.md#_PositionalSoilLayout "Direct link to PositionalSoilLayout") * *class *viktor.geo.PositionalSoilLayout(*x*, *soil\_layers*)[](#PositionalSoilLayout "Link to this definition") Bases: [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") A subclass of SoilLayout that adds an x location. This can be useful to generate a Soil Layout 2D Generate a positional soil layout from an x location and a list of soil layers * Parameters: * **x** (`float`) * **soil\_layers** (`List`\[[`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")]) - *classmethod *from\_dict(*positional\_soil\_layout\_dict*)[](#PositionalSoilLayout.from_dict "Link to this definition") Instantiates a PositionalSoilLayout from the provided soil layout data. * Parameters: **positional\_soil\_layout\_dict** (`Union`\[`dict`, `Munch`]) – Soil layout data. * Return type: [`PositionalSoilLayout`](#PositionalSoilLayout "viktor.geo.PositionalSoilLayout") * serialize()[](#PositionalSoilLayout.serialize "Link to this definition") Generate a JSON serializable dict from this positional soil layout. * Return type: `dict` ## RobertsonMethod[​](/sdk/api/geo/.md#_RobertsonMethod "Direct link to RobertsonMethod") * *class *viktor.geo.RobertsonMethod(*soil\_properties*)[](#RobertsonMethod "Link to this definition") Bases: `_ClassificationMethod` Class to pass Robertson specific properties such as soil\_properties. Every list element at least requires a ‘name’ key that specifies the RobertsonZone. It is important that ‘name’ key matches with hardcoded RobertsonZone.name property. There are 9 Robertson zones and 1 Robertson zone unknown that can be specified By default, the colors as defined in (red, green, blue) for each zone are as shown in this figure: [![/\_images/robertson\_colors.png](/_images/robertson_colors.png)](/_images/robertson_colors.png) Example: ``` soil_properties = [ {'name': 'Robertson zone unknown', 'extra_property1': 1, 'extra_property2': 2}, {'name': 'Robertson zone 1', 'extra_property1': 3, 'extra_property2': 4}, ] method = RobertsonMethod(soil_properties) ``` * Parameters: **soil\_properties** (`List`\[`dict`]) – dictionary with soil properties - get\_method\_params()[](#RobertsonMethod.get_method_params "Link to this definition") * Return type: `dict` ## Soil[​](/sdk/api/geo/.md#_Soil "Direct link to Soil") * *class *viktor.geo.Soil(*name*, *color*, *properties=None*)[](#Soil "Link to this definition") Set name and color of Soil material. Extra properties can be added with dictionary, and keys are added as attribute via ‘munchify’. They are accessible as self.properties.{extra\_property\_name} * Parameters: * **name** (`str`) * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – color of soil used in plots * **properties** (`Union`\[`dict`, `Munch`]) – dict with optional extra parameters to be added to Soil - *property *color*: [Color](/sdk/api/core/.md#Color "viktor.core.Color")*[](#Soil.color "Link to this definition") * *classmethod *from\_dict(*d*)[](#Soil.from_dict "Link to this definition") * Return type: [`Soil`](#Soil "viktor.geo.Soil") - serialize()[](#Soil.serialize "Link to this definition") Serialize Soil in following dictionary structure: ``` { 'name', 'color', 'properties': { (..extra_properties..) }, } ``` * Return type: `dict` * Returns: dictionary with all properties of Soil * update\_properties(*properties*)[](#Soil.update_properties "Link to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters: **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type: `None` ## SoilLayer[​](/sdk/api/geo/.md#_SoilLayer "Direct link to SoilLayer") * *class *viktor.geo.SoilLayer(*soil*, *top\_of\_layer*, *bottom\_of\_layer*, *properties=None*)[](#SoilLayer "Link to this definition") Create a SoilLayer to be used in SoilLayout * Parameters: * **soil** ([`Soil`](#Soil "viktor.geo.Soil")) – Type of soil * **top\_of\_layer** (`float`) – Top of layer * **bottom\_of\_layer** (`float`) – Bottom of layer * **properties** (`Union`\[`dict`, `Munch`]) – dict with optional extra parameters to be added to SoilLayer - *classmethod *from\_dict(*soil\_layer\_dict*)[](#SoilLayer.from_dict "Link to this definition") * Return type: [`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer") * serialize()[](#SoilLayer.serialize "Link to this definition") Serialize SoilLayer in following dictionary structure: ``` { 'soil', 'top_of_layer', 'bottom_of_layer', } ``` * Return type: `dict` * Returns: dictionary with properties of SoilLayer - *property *thickness*: float*[](#SoilLayer.thickness "Link to this definition") * update\_properties(*properties*)[](#SoilLayer.update_properties "Link to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters: **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type: `None` - update\_soil\_properties(*properties*)[](#SoilLayer.update_soil_properties "Link to this definition") * Return type: `None` ## SoilLayer2D[​](/sdk/api/geo/.md#_SoilLayer2D "Direct link to SoilLayer2D") * *class *viktor.geo.SoilLayer2D(*soil*, *top\_profile*, *bottom\_profile*, *properties=None*, *piezo\_line\_top=None*, *piezo\_line\_bottom=None*)[](#SoilLayer2D "Link to this definition") A 2D representation of a soil layer A Soil layer 2d always consists of a soil and a top and bottom profile Optionally, properties and top and bottom pl lines can be added Top and bottom profiles need to be monotonic ascending in x-direction Top and bottom profiles need to have identical start x and end x coordinates. These will become the left and right boundaries Top and bottom profiles can overlap, but not intersect. The layer can have one or multiple ranges with zero thickness, but the top profile may never lie below the bottom profile * Parameters: * **soil** ([`Soil`](#Soil "viktor.geo.Soil")) * **top\_profile** ([`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")) * **bottom\_profile** ([`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")) * **properties** (`Union`\[`dict`, `Munch`]) * **piezo\_line\_top** ([`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")) * **piezo\_line\_bottom** ([`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")) - bottom\_y\_coordinate(*x*)[](#SoilLayer2D.bottom_y_coordinate "Link to this definition") Determine the y-coordinate along the bottom boundary, belonging to the x value used as input If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters: **x** (`float`) – The x-coordinate where the height is requested. * Return type: `float` * Returns: The y-coordinate of the top at the x-coordinate location. * *classmethod *from\_dict(*soil\_layer\_dict*)[](#SoilLayer2D.from_dict "Link to this definition") Instantiates a SoilLayer2D from the provided soil layer data. dict structure: ``` { 'soil': serialized Soil 'top_profile': serialized Polyline 'bottom_profile': serialized Polyline 'piezo_line_top': serialized PiezoLine 'piezo_line_bottom': serialized PiezoLine 'properties': Dict } ``` * Parameters: **soil\_layer\_dict** (`Union`\[`dict`, `Munch`]) – Soil layer data. * Return type: [`SoilLayer2D`](#SoilLayer2D "viktor.geo.SoilLayer2D") - height\_at\_x(*x*)[](#SoilLayer2D.height_at_x "Link to this definition") Returns the height at a specific x location. If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters: **x** (`float`) – The x-coordinate where the height is requested. * Return type: `float` * Returns: The height at the x-coordinate location. * *property *left\_boundary*: float*[](#SoilLayer2D.left_boundary "Link to this definition") - polygons()[](#SoilLayer2D.polygons "Link to this definition") Generate a list of polygons representing this soil layer. For every region of this soil layout that has a non-zero thickness, a polygon is generated. * Return type: `List`\[[`Polygon`](/sdk/api/geometry/.md#Polygon "viktor.geometry.Polygon")] * *property *right\_boundary*: float*[](#SoilLayer2D.right_boundary "Link to this definition") - serialize()[](#SoilLayer2D.serialize "Link to this definition") Serialize SoilLayer in following dictionary structure: ``` { 'soil': Soil 'top_profile': Polyline 'bottom_profile': Polyline 'piezo_line_top': serialized PiezoLine 'piezo_line_bottom': serialized PiezoLine 'properties': Dict } ``` * Return type: `dict` * Returns: dictionary with properties of SoilLayer * top\_y\_coordinate(*x*)[](#SoilLayer2D.top_y_coordinate "Link to this definition") Determine the y-coordinate along the top boundary, belonging to the x value used as input If a profile has a vertical section on the given x-location, this method will return the first touching point of the polyline with the vertical line * Parameters: **x** (`float`) – The x-coordinate where the height is requested. * Return type: `float` * Returns: The y-coordinate of the top at the x-coordinate location. - update\_properties(*properties*)[](#SoilLayer2D.update_properties "Link to this definition") Replace the current properties dict with the provided new one. For backwards compatibility, this function is kept with this functionality. In order to be able to update the existing properties dict, the properties property is public and mutable. * Parameters: **properties** (`Union`\[`dict`, `Munch`]) – dictionary with all SoilLayer properties * Return type: `None` * Returns: * update\_soil\_properties(*properties*)[](#SoilLayer2D.update_soil_properties "Link to this definition") Replace the current soil properties dict with a new one * Parameters: **properties** (`Union`\[`dict`, `Munch`]) * Return type: `None` * Returns: - visualize\_geometry(*visualize\_border=False*, *opacity=1*, *material=None*)[](#SoilLayer2D.visualize_geometry "Link to this definition") Returns the visualization elements (group, labels) of the SoilLayer2D which can be used in a GeometryView. * Parameters: * **visualize\_border** (`bool`) – visualize the border surrounding this soil layout with an extra line. * **opacity** (`float`) – float between 0 (transparent) - 1 (opaque) * **material** ([`Material`](/sdk/api/geometry/.md#Material "viktor.geometry.Material")) – optional material to be applied on the geometry. * Return type: `Tuple`\[[`Group`](/sdk/api/geometry/.md#Group "viktor.geometry.Group"), `List`\[[`Label`](/sdk/api/views/.md#Label "viktor.views.Label")]] ## SoilLayout[​](/sdk/api/geo/.md#_SoilLayout "Direct link to SoilLayout") * *class *viktor.geo.SoilLayout(*soil\_layers*)[](#SoilLayout "Link to this definition") Aggregation object of SoilLayer * Parameters: **soil\_layers** (`List`\[[`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")]) – list of SoilLayer objects - append(*layer*)[](#SoilLayout.append "Link to this definition") Add a layer to the bottom of the classification * Parameters: **layer** ([`SoilLayer`](#SoilLayer "viktor.geo.SoilLayer")) – SoilLayer instance * Return type: `None` * *property *bottom*: float*[](#SoilLayout.bottom "Link to this definition") Height level of the bottom of the layout. - filter\_layers\_on\_thickness(*min\_layer\_thickness*, *merge\_adjacent\_same\_soil\_layers=False*)[](#SoilLayout.filter_layers_on_thickness "Link to this definition") Collects layers that are thinner than min\_layer\_thickness in groups, and replaces them by one of two things: > * If the group is thinner than min\_layer\_thickness, it is removed from the soil layout and the layer above it is elongated to fill the gap. See explanation figure, situation A. > > * If the group is equal to or thicker than min\_layer\_thickness, a new layer with Soil and properties of the most dominant (based cumulative thickness) soiltype occurring within this block of layers that was replaced by the new layer. See explanation figure, situation B. After all replacements have been made, if merge\_adjacent\_same\_soil\_layers is specified as True (default is False), `_merge_adjacent_same_soil_layers()` is called, which merges adjacent soil layers that have the same soiltype and have the same set of parameters. Note that this merging results in a new layer that has the average value for all soil layer properties present in the layers that were merged. See the docstring of `_merge_adjacent_same_soil_layers()` for more detailed information about how this is done. * Parameters: * **min\_layer\_thickness** (`float`) – Minimum thickness * **merge\_adjacent\_same\_soil\_layers** (`bool`) – Try to merge adjacent layers that have the same soil type * Return type: [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") Note: this method alters the instance! [![/\_images/soil\_layout\_filtering\_explanation.svg](/_images/soil_layout_filtering_explanation.svg)](/_images/soil_layout_filtering_explanation.svg) * filter\_unique\_soils()[](#SoilLayout.filter_unique_soils "Link to this definition") * Return type: `List`\[[`Soil`](#Soil "viktor.geo.Soil")] - *classmethod *from\_dict(*soil\_layout\_dict*)[](#SoilLayout.from_dict "Link to this definition") Create SoilLayout with dictionary from SoilLayout.serialize(). Useful when SoilLayout needs to be created from dictionary from the database. Example usage: ``` class Controller(ViktorController): ... def get_soil_layout_from_database(self) -> SoilLayout: # API call to entity that stores complete SoilLayout layout_dict = entity.last_saved_params['layout_dict'] soil_layout = SoilLayout.from_dict(layout_dict) return soil_layout ``` * Parameters: **soil\_layout\_dict** (`Union`\[`Dict`\[`str`, `List`], `Munch`]) – dictionary with same structure as SoilLayout.serialize() * Return type: [`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout") * get\_visualization(*axes*)[](#SoilLayout.get_visualization "Link to this definition") Modify (clean/empty) ‘axes’ input argument to plot SoilLayout structure. Layers must be sorted from top to bottom. * Parameters: **axes** (`Axes`) – Axes object that will be modified * Return type: `None` - *property *number\_of\_layers*: int*[](#SoilLayout.number_of_layers "Link to this definition") Number of layers * serialize()[](#SoilLayout.serialize "Link to this definition") Serialize SoilLayout to dict (e.g. to store in database). The structure of dict is: ``` { 'layers': [...] } ``` * Return type: `dict` - *property *top*: float*[](#SoilLayout.top "Link to this definition") Height level of the top of the layout. * update\_layers()[](#SoilLayout.update_layers "Link to this definition") Merges adjacent layers that have the same soil type. The merged layer is assigned the average value of each SoilLayer’s individual properties. This average is calculated in ratio to the thickness of the layers. After merging layer depths are corrected by going from top to bottom and setting each bottom\_of\_layer equal to top\_of\_layer of next SoilLayer * Return type: `None` Example layer 1 has thickness 10 and for property A a value of 5 layer 2 has thickness 40 and for property A a value of 2 Resulting layer will have thickness 50, and property A = (10 \* 5 + 40 \* 2) / (10 + 40) = 2.6 - update\_soil\_properties(*df*)[](#SoilLayout.update_soil_properties "Link to this definition") Update SoilLayout with Soil properties * Parameters: **df** (`DataFrame`) – dataframe with soil properties by name (must at least have column ‘name’). * Return type: `None` * Returns: ## SoilLayout2D[​](/sdk/api/geo/.md#_SoilLayout2D "Direct link to SoilLayout2D") * *class *viktor.geo.SoilLayout2D(*soil\_layers*, *piezo\_lines=None*)[](#SoilLayout2D "Link to this definition") A 2D representation of a soil body build up from layers. A Soil Layout 2D basically consists of the following elements: * A list of soil layers: objects of the class SoilLayer2D * A list of piezo lines * A left and right boundary * A top and bottom profile Left and right boundaries, as well as top and bottom profiles, are automatically taken from the given soil layers The following requirements are to be met: * Each soil layer has to stretch all the way from the left boundary to the right boundary * The layers have to be stacked starting from bottom to top * There can be no holes in the soil layout 2d, meaning that the top profile of a previous layer always has to be identical to the bottom profile of the next layer * A layer can have zero thickness over (part of) the width of the soil layout 2d * All soil layers and piezo lines have to exactly identical ranges in x direction, meaning that they all range exactly from left boundary to right boundary A SoilLayout2D will have roughly the following shape, with each layer containing it’s own soil and soil properties: ``` | xxxxxxxxxx | |xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| | | | | | xxxxxxxx | |xxxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxxxxx| | xxx xxxxxx | | xxx | | | | | |xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxx| | xxxxxxxxxxxxxxxxxx | | | | xxxxxxxxxxxxxxx | |xxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| ``` The SoilLayout2D class is immutable. Any methods that alter or change properties of the class will return a new instance. * Parameters: * **soil\_layers** (`List`\[[`SoilLayer2D`](#SoilLayer2D "viktor.geo.SoilLayer2D")]) – an ordered dict of 2D soil layers. Starting from the bottom layer * **piezo\_lines** (`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]) – list of piezo lines - *property *bottom\_profile*: [Polyline](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")*[](#SoilLayout2D.bottom_profile "Link to this definition") bottom profile of the soil layout: Polyline * Type: return * *classmethod *combine\_soil\_layouts\_2d(*\*soil\_layouts\_2d*)[](#SoilLayout2D.combine_soil_layouts_2d "Link to this definition") Combine multiple SoilLayout2D’s in into one big SoilLayout2D All given soil layouts need to connect seemlessly, so that the resulting SoilLayout2D fullfills the requirement that it has got no holes and the top and bottom profile are monotonic ascending in x direction All layers will be continued (with zero thickness) to the new right and left boundaries * Parameters: **soil\_layouts\_2d** ([`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D")) * Return type: [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") * Returns: POSSIBLE COMBINATIONS: combining a left and a right soil layout 2d ``` _____________________ | |_______________________ | | | |-------------------|----------------------| | | | |___________________|----------------------| | | |______________________| ``` combining a top and bottom soil layout 2d ``` _____________________ | | |-------------------| | | |___________________|______________ | | |--------------------------| |__________________________| ``` combining n soil layouts, as long as there are no holes in the resulting soil layout, and it is possible to keep all layer profiles monotonic ascending in x-directions ``` _____________________ | |_______________________ | | | |-------------------|----------------------| | | | |___________________|______________________| | | |-------------------| |___________________| ``` IMPOSSIBLE COMBINATIONS: soillayouts without seem ``` _____________________ | | ________________________ | | | | |-------------------| |----------------------| | | | | |___________________| |----------------------| | | |______________________| ``` overlapping soil layouts ``` _____________________ | ________|_______________ | | | | |-----------|-------| | | |-------|--------------| |___________|_______| | | | |______________________| ``` the resulting soil layout does contain layers with profiles that are not monotonic ascending in x-direction ``` _____________________ | |_______________________ | | | |-------------------| | | |----------------------| |___________________| | | | ________|______________________| | | |-------------------| |___________________| ``` - *classmethod *from\_dict(*soil\_layout\_2d\_dict*)[](#SoilLayout2D.from_dict "Link to this definition") Create SoilLayout2D with dictionary from SoilLayout2D.serialize(). Useful when SoilLayout2D needs to be created from dictionary from the database. Example usage: ``` class Controller(ViktorController): ... def get_interpolated_soil_layout_from_database(self) -> SoilLayout2D: # API call to entity that stores complete SoilLayout2D layout_dict = entity.last_saved_params['layout_dict'] interpolated_soil_layout = SoilLayout2D.from_dict(layout_dict) return interpolated_soil_layout ``` * Parameters: **soil\_layout\_2d\_dict** (`Union`\[`dict`, `Munch`]) – dictionary with same structure as SoilLayout2D.serialize() * Return type: [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") * *classmethod *from\_positional\_soil\_layouts(*positional\_soil\_layouts*, *top\_profile*, *piezo\_lines=None*)[](#SoilLayout2D.from_positional_soil_layouts "Link to this definition") Instantiate a soil layout 2d from multiple 1d soil layouts combined with x locations and a ground profile all 1d soil layouts should have the same layers in the same order. Variation in height and thickness are possible the top profile has to be monotonic ascending in x direction * Parameters: * **positional\_soil\_layouts** (`List`\[[`PositionalSoilLayout`](#PositionalSoilLayout "viktor.geo.PositionalSoilLayout")]) – 1d soil layouts with x locations * **top\_profile** ([`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – a polyline representing the ground level * **piezo\_lines** (`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]) – list of piezo lines * Return type: [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") - *classmethod *from\_single\_soil\_layout(*soil\_layout*, *left\_boundary*, *right\_boundary*, *top\_profile*, *piezo\_lines=None*)[](#SoilLayout2D.from_single_soil_layout "Link to this definition") A special case when a 1D soil layout is stretched in the 2D plane. This class method will create a 2D layout with horizontal layers and a top\_profile. * Parameters: * **soil\_layout** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) * **top\_profile** ([`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")) * **left\_boundary** (`float`) * **right\_boundary** (`float`) * **piezo\_lines** (`List`\[[`PiezoLine`](#PiezoLine "viktor.geo.PiezoLine")]) * Return type: [`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D") * get\_left\_boundary\_polyline()[](#SoilLayout2D.get_left_boundary_polyline "Link to this definition") Get the polyline describing the left boundary This will always be a straight boundary This will contain a point on every boundary between layers * Return type: [`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline") * Returns: Polyline - get\_right\_boundary\_polyline()[](#SoilLayout2D.get_right_boundary_polyline "Link to this definition") Get the polyline describing the right boundary This will always be a straight boundary This will contain a point on every boundary between layers * Return type: [`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline") * Returns: Polyline * serialize()[](#SoilLayout2D.serialize "Link to this definition") Serialize to dict (e.g. to store in database). The structure of dict is: ``` {'layers': [layer.serialize} for layer in self.layers, 'piezo_lines': [line.serialize() for line in self.piezo_lines]} ``` * Return type: `dict` * Returns: dictionary with structure above - split(*\*split\_lines*)[](#SoilLayout2D.split "Link to this definition") Split the soil layout by given polylines. Each split line has to: > * have a start and end point that lies outside of this soil layout > > * intersect the soil layout in at least one region > > * be monotonic ascending in x-direction Split lines are allowed to cross each other one or multiple times. Examples: Single split line ``` ___________ ___________ ___________ ____________ | / | | / / | | / | ==> | / / | |-------/-------------| |-------/ /-------------| |______/______________| |______/ /______________| ``` Single split line with multiple intersections ``` /\ ___________/__\________ _______________________ | / \ | | / \ | | / \ | ==> | / \ | |-------/--------\----| |-------/ ____ \----| |______/__________\___| |______/ / \ \___| / \ / \ /--------\ /__________\ ``` Two crossing split lines ``` ____ ______ ____ ___________ _______ \ / ____________ | \ / | | \ \/ / | | \/ | ==> | \ / | |-------/\------------| |-------/ \------------| |______/__\___________| |______/ /\ \___________| /__\ ``` * Parameters: **split\_lines** ([`Polyline`](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")) – a list of polylines * Return type: `List`\[[`SoilLayout2D`](#SoilLayout2D "viktor.geo.SoilLayout2D")] * *property *top\_profile*: [Polyline](/sdk/api/geometry/.md#Polyline "viktor.geometry.Polyline")*[](#SoilLayout2D.top_profile "Link to this definition") top profile of the soil layout: Polyline * Type: return - visualize\_geometry(*visualize\_border=False*, *opacity=1*)[](#SoilLayout2D.visualize_geometry "Link to this definition") Returns the visualization elements (group, labels) of the SoilLayout2D which can be used in a GeometryView. * Parameters: * **visualize\_border** (`bool`) – visualize the border surrounding this soil layout with an extra line. * **opacity** (`float`) – float between 0 (transparent) - 1 (opaque) * Return type: `Tuple`\[[`Group`](/sdk/api/geometry/.md#Group "viktor.geometry.Group"), `List`\[[`Label`](/sdk/api/views/.md#Label "viktor.views.Label")]] ## TableMethod[​](/sdk/api/geo/.md#_TableMethod "Direct link to TableMethod") * *class *viktor.geo.TableMethod(*qualification\_table*, *ground\_water\_level*)[](#TableMethod "Link to this definition") Bases: `_ClassificationMethod` Class to pass TableMethod specific properties, such as a qualification\_table and ground\_water\_level. The qualification\_table is a list of dictionaries, containing for each user-specified soil type the accompanying qualification parameters (and possibly additional material properties). The required fields for each row are: > * name > > * color in r, g, b Also required fields, but can also be (partly) empty: > * qc\_min > > * qc\_max > > * qc\_norm\_min > > * qc\_norm\_max > > * rf\_min > > * rf\_max > > * gamma\_dry\_min > > * gamma\_dry\_max > > * gamma\_wet\_min > > * gamma\_wet\_max For more information about qc\_norm (qc\_normalized), see table 2.b in in NEN 9997-1+C1:2012, point g specifically. Besides the qualification table, a ground\_water\_level has to be provided as well, which is used to determine if gamma\_dry or gamma\_wet should be used to calculate qc\_norm for each entry in the GEF file. Example: ``` qualification_table = [ {'name': 'Peat', 'color': '166,42,42', 'qc_min': 0, 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 8, 'rf_max': '', 'gamma_dry_min': 10, 'gamma_wet_min': 10, }, {'name': 'Clay', 'color': '125,180,116', 'qc_min': '', 'qc_max': 2, 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 1, 'rf_max': 8, 'gamma_dry_min': 20, 'gamma_wet_min': 22, }, {'name': 'Loam', 'color': '125,150,116', 'qc_min': 2, 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': '', 'rf_min': 1, 'rf_max': 8, 'gamma_dry_min': 20, 'gamma_wet_min': 22, }, {'name': 'Sand', 'color': '239,255,12', 'qc_min': '', 'qc_max': '', 'qc_norm_min': 22, 'qc_norm_max': '', 'rf_min': 0, 'rf_max': 1, 'gamma_dry_min': 24, 'gamma_wet_min': 26, }, {'name': 'Gravel', 'color': '255,255,128', 'qc_min': '', 'qc_max': '', 'qc_norm_min': '', 'qc_norm_max': 22, 'rf_min': 0, 'rf_max': 1, 'gamma_dry_min': 24, 'gamma_wet_min': 26, } ] ground_water_level = -4.63 method = TableMethod(qualification_table, ground_water_level) ``` * Parameters: * **ground\_water\_level** (`float`) – Ground water level is used to compute qc\_norm using either gamma\_dry or gamma\_wet * **qualification\_table** (`List`\[`dict`]) – List containing rows defining a soil - get\_method\_params()[](#TableMethod.get_method_params "Link to this definition") * Return type: `dict` * get\_qualification\_table\_plot(*fileformat*)[](#TableMethod.get_qualification_table_plot "Link to this definition") Use this method to obtain a plot of the qualification table. On the x axis the Rf values are plotted, on the y axis Qc values are shown. Each line, representing a soil, is shown as an area in this plot. This allows for easy inspection of the qualification rules, showing areas of the plot that might still be empty, or soil areas that overlap (in which case the area on top will be chosen). Use the fileformat argument to specify if the result should be a BytesIO containing pdf or png bytes or a StringIO containing svg data * Parameters: **fileformat** (`str`) – specify if required fileformat is pdf, png or svg * Return type: `Union`\[`BytesIO`, `StringIO`] * Returns: qualification table plot as either BytesIO (‘pdf’ or ‘png’) or StringIO (‘svg’) object ## UndefinedSoil[​](/sdk/api/geo/.md#_UndefinedSoil "Direct link to UndefinedSoil") * *class *viktor.geo.UndefinedSoil[](#UndefinedSoil "Link to this definition") Bases: [`Soil`](#Soil "viktor.geo.Soil") Set name and color of Soil material. Extra properties can be added with dictionary, and keys are added as attribute via ‘munchify’. They are accessible as self.properties.{extra\_property\_name} * Parameters: * **name** * **color** – color of soil used in plots * **properties** – dict with optional extra parameters to be added to Soil ## gef\_visualization[​](/sdk/api/geo/.md#_gef_visualization "Direct link to gef_visualization") * viktor.geo.gef\_visualization(*gef\_data*, *soil\_layout\_original*, *soil\_layout\_user*, *\**, *as\_file=False*)[](#gef_visualization "Link to this definition") Standard visualization for GEF File. Example usage: ``` class Controller(ViktorController): ... @ImageView("GEF plot", duration_guess=2) def visualize(self, params, **kwargs): gef_data = ... soil_layout_original = ... soil_layout_user = ... svg_image = gef_visualization(gef_data, soil_layout_original, soil_layout_user) return ImageResult(svg_image) ``` * Parameters: * **gef\_data** ([`GEFData`](#GEFData "viktor.geo.GEFData")) – GEFData object to be visualized * **soil\_layout\_original** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) – SoilLayout from GEFData. Layers must be sorted from top to bottom. * **soil\_layout\_user** ([`SoilLayout`](#SoilLayout "viktor.geo.SoilLayout")) – SoilLayout that is filtered/modified by user. Layers must be sorted from top to bottom. * **as\_file** (`bool`) – return as str (default) or File New in v13.5.0 * Return type: `Union`\[`str`, [`File`](/sdk/api/core/.md#File "viktor.core.File")] * Returns: SVG image file --- # viktor.geometry ## Arc[​](/sdk/api/geometry/.md#_Arc "Direct link to Arc") * *class *viktor.geometry.Arc(*centre\_point*, *start\_point*, *end\_point*, *short\_arc=True*, *\**, *n\_segments=30*, *color=(0, 0, 0)*, *identifier=None*)[](#Arc "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Creates a constant radius arc in the xy plane. Clockwise rotation creates an outward surface. * Parameters: * **centre\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. * **start\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. Should have the same distance to centre\_point as end\_point. * **end\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point in xy plane. Should have the same distance to centre\_point as start\_point. * **short\_arc** (`bool`) – Angle of arc smaller than pi if True, larger than pi if False. * **n\_segments** (`int`) – Number of discrete segments of the arc (default: 30) New in v13.5.0 . * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *angle*: float*[](#Arc.angle "Link to this definition") Absolute angle of the arc in radians, which is the difference between theta1 and theta2. * *property *centre\_point*: [Point](#Point "viktor.geometry.Point")*[](#Arc.centre_point "Link to this definition") - discretize(*num=2*)[](#Arc.discretize "Link to this definition") Returns a discrete representation of the arc, as a list of Point objects. The amount of points can be specified using ‘num’, which should be larger than 1. * Return type: `List`\[[`Point`](#Point "viktor.geometry.Point")] * *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[](#Arc.end_point "Link to this definition") - *property *length*: float*[](#Arc.length "Link to this definition") Arc length. * *property *n\_segments*: int*[](#Arc.n_segments "Link to this definition") - *property *radius*: float*[](#Arc.radius "Link to this definition") * revolve(*\**, *rotation\_angle=None*, *material=None*, *identifier=None*, *\*\*kwargs*)[](#Arc.revolve "Link to this definition") Returns an ArcRevolve object, revolved around the global y-axis. * Parameters: * **rotation\_angle** (`float`) – Angle of the revolved object according to the right-hand-rule, with the start of the rotation in positive z-direction. Angle in radians. If not specified, 2 pi will be used. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) * Return type: [`ArcRevolve`](#ArcRevolve "viktor.geometry.ArcRevolve") - *property *short\_arc*: bool*[](#Arc.short_arc "Link to this definition") * *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[](#Arc.start_point "Link to this definition") - *property *theta1*: float*[](#Arc.theta1 "Link to this definition") Angle of the end point with respect to the x-axis in radians. * *property *theta1\_theta2*: Tuple\[float, float]*[](#Arc.theta1_theta2 "Link to this definition") Angles of the end (theta1) and start (theta2) points with respect to the x-axis in radians. - *property *theta2*: float*[](#Arc.theta2 "Link to this definition") Angle of the start point with respect to the x-axis in radians. ## ArcExtrusion[​](/sdk/api/geometry/.md#_ArcExtrusion "Direct link to ArcExtrusion") * *class *viktor.geometry.ArcExtrusion(*profile*, *arc*, *profile\_rotation=0*, *n\_segments=50*, *\**, *material=None*, *identifier=None*)[](#ArcExtrusion "Link to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Given an Arc and a cross-section of the extrusion, a discretized Extrusion object is returned. The coordinates of the profile are defined with respect to the Arc and have a LOCAL coordinate system: > * z-axis is in direction of the arc from start to end. > > * x-axis is in positive global z-axis. > > * y-axis follows from the right-hand-rule. Rotation of the profile is about the axis according to the right-hand-rule with LOCAL z-axis (see definition above). Example: ``` profile = [ Point(1, 1), Point(1, 2), Point(3, 2), Point(3, 1), Point(1, 1), ] arc = Arc(Point(1, 1, 0), Point(3, 1, 0), Point(1, 3, 0)) arc_ext = ArcExtrusion(profile, arc, profile_rotation=10, n_segments=10) ``` This will result in the following visualization, where the Arc itself is also shown in the xy plane: [![/\_images/arc-extrusion.png](/_images/arc-extrusion.png)](/_images/arc-extrusion.png) * Parameters: * **profile** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Coordinates of cross-section. * **arc** ([`Arc`](#Arc "viktor.geometry.Arc")) – An Arc object is used to define the direction of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around its local Z-axis in degrees. * **n\_segments** (`int`) – Number of discrete segments of the arc, which is 50 by default. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) ## ArcRevolve[​](/sdk/api/geometry/.md#_ArcRevolve "Direct link to ArcRevolve") * *class *viktor.geometry.ArcRevolve(*arc*, *\*args*, *rotation\_angle=None*, *material=None*, *identifier=None*, *\*\*kwargs*)[](#ArcRevolve "Link to this definition") Bases: [`Revolve`](#Revolve "viktor.geometry.Revolve") Returns a revolved object of an arc around the global y-axis. In the example below, rotation\_angle is equal to pi / 3: [![/\_images/arc-revolve.png](/_images/arc-revolve.png)](/_images/arc-revolve.png) * Parameters: * **arc** ([`Arc`](#Arc "viktor.geometry.Arc")) – Arc object. * **rotation\_angle** (`float`) – Angle of the revolved object according to the right-hand-rule, with the start of the rotation in positive z-direction. Angle in radians. If not specified, 2 pi will be used. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *arc*: [Arc](#Arc "viktor.geometry.Arc")*[](#ArcRevolve.arc "Link to this definition") [`Arc`](#Arc "viktor.geometry.Arc") * *property *height*: float*[](#ArcRevolve.height "Link to this definition") Height of the object. - *property *inner\_volume*: float*[](#ArcRevolve.inner_volume "Link to this definition") Returns the inner volume of the revolved object. This method will only return a value if the defined Arc meets the following conditions: > * it should be short, i.e. short\_arc=True > > * the start- and end-point are located on the same side w\.r.t. the y-axis of the center-point of the Arc > > * it is defined in clockwise direction * *property *surface\_area*: float*[](#ArcRevolve.surface_area "Link to this definition") Total exterior area of the object. - *property *uuid*: str*[](#ArcRevolve.uuid "Link to this definition") ## BidirectionalPattern[​](/sdk/api/geometry/.md#_BidirectionalPattern "Direct link to BidirectionalPattern") * *class *viktor.geometry.BidirectionalPattern(*base\_object*, *direction\_1*, *direction\_2*, *number\_of\_elements\_1*, *number\_of\_elements\_2*, *spacing\_1*, *spacing\_2*, *\**, *identifier=None*)[](#BidirectionalPattern "Link to this definition") Bases: [`Pattern`](#Pattern "viktor.geometry.Pattern") Instantiates a two-dimensional pattern, evenly spaced in two separate directions. If identifier has been set on the base-object, the identifiers of the objects within the pattern are suffixed with ‘-i’ (i = 1, 2, 3, …). * Parameters: * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **direction\_1** (`List`\[`float`]) – a unit vector specifying the first direction * **direction\_2** (`List`\[`float`]) – a unit vector specifying the second direction * **number\_of\_elements\_1** (`int`) – total amount of elements along direction 1 * **number\_of\_elements\_2** (`int`) – total amount of elements along direction 2 * **spacing\_1** (`float`) – the applied spacing in direction 1 * **spacing\_2** (`float`) – the applied spacing in direction 2 * **identifier** (`str`) – object identifier (new in v14.10.0) ## CartesianAxes[​](/sdk/api/geometry/.md#_CartesianAxes "Direct link to CartesianAxes") * *class *viktor.geometry.CartesianAxes(*origin=Point(0.000e+00, 0.000e+00, 0.000e+00)*, *axis\_length=1*, *axis\_diameter=0.05*)[](#CartesianAxes "Link to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Helper visualisation object to show positive x (red), y (green) and z (blue) axes. [![/\_images/cartesian-axes.png](/_images/cartesian-axes.png)](/_images/cartesian-axes.png) * Parameters: * **origin** ([`Point`](#Point "viktor.geometry.Point")) – Coordinates of the origin. * **axis\_length** (`float`) – Length of the axes. * **axis\_diameter** (`float`) – Diameter of the axes. ## CircularExtrusion[​](/sdk/api/geometry/.md#_CircularExtrusion "Direct link to CircularExtrusion") * *class *viktor.geometry.CircularExtrusion(*diameter*, *line*, *\**, *shell\_thickness=None*, *material=None*, *identifier=None*)[](#CircularExtrusion "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") This class is used to construct an extrusion which has a circular base, e.g. a circular foundation pile. * Parameters: * **diameter** (`float`) – Outer diameter of the cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object along which the circular cross-section is extruded. * **shell\_thickness** (`float`) – Optional shell thickness. None for solid (default: None) New in v13.6.0 . * **material** ([`Material`](#Material "viktor.geometry.Material")) – Optional material. * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *cross\_sectional\_area*: float*[](#CircularExtrusion.cross_sectional_area "Link to this definition") * *property *diameter*: float*[](#CircularExtrusion.diameter "Link to this definition") - *property *length*: float*[](#CircularExtrusion.length "Link to this definition") * *property *line*: [Line](#Line "viktor.geometry.Line")*[](#CircularExtrusion.line "Link to this definition") - *property *radius*: float*[](#CircularExtrusion.radius "Link to this definition") * *property *shell\_thickness*: float | None*[](#CircularExtrusion.shell_thickness "Link to this definition") ## Cone[​](/sdk/api/geometry/.md#_Cone "Direct link to Cone") * *class *viktor.geometry.Cone(*diameter*, *height*, *\**, *origin=None*, *orientation=None*, *material=None*, *identifier=None*)[](#Cone "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Creates a cone object. * Parameters: * **diameter** (`float`) – Diameter of the circular base surface. * **height** (`float`) – Height from base to tip. * **origin** ([`Point`](#Point "viktor.geometry.Point")) – Optional location of the centroid of the base surface (default: Point(0, 0, 0)). * **orientation** ([`Vector`](#Vector "viktor.geometry.Vector")) – Optional orientation from origin to the tip (default: Vector(0, 0, 1)). * **material** ([`Material`](#Material "viktor.geometry.Material")) – Optional material. * **identifier** (`str`) – object identifier (new in v14.10.0) - *classmethod *from\_line(*diameter*, *line*, *\**, *material=None*, *identifier=None*)[](#Cone.from_line "Link to this definition") Create a Cone object by a given base diameter and line. * Parameters: * **diameter** (`float`) – Diameter of the circular base surface. * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line from base to top of the cone. The start point of the line represents the location of the center of the base, and the end point represents the tip of the cone. * **material** ([`Material`](#Material "viktor.geometry.Material")) – Optional material. * **identifier** (`str`) – object identifier (new in v14.10.0) * Return type: [`Cone`](#Cone "viktor.geometry.Cone") ## Extrusion[​](/sdk/api/geometry/.md#_Extrusion "Direct link to Extrusion") * *class *viktor.geometry.Extrusion(*profile*, *line*, *profile\_rotation=0*, *\**, *material=None*, *identifier=None*)[](#Extrusion "Link to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Extruded object from a given set of points, which is called the profile. This profile should meet the following requirements: > * start point should be added at the end for closed profile > > * points should be defined in z=0 plane > > * circumference should be defined clockwise Note that the profile is defined with respect to the start point of the Line object, i.e. the profile is defined in the local coordinate system. An example is given below of two extrusions with the same dimensions. Their corresponding Line objects are also visualized. The extrusion have the following profile: ``` # black box profile_b = [ Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1), Point(1, 1), ] box_b = Extrusion(profile_b, Line(Point(4, 1, 0), Point(4, 1, 1))) # yellow box profile_y = [ Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5), Point(0.5, -0.5), Point(-0.5, -0.5), ] box_y = Extrusion(profile_y, Line(Point(2, 2, 0), Point(2, 2, 1))) ``` [![/\_images/extrusion-profile.png](/_images/extrusion-profile.png)](/_images/extrusion-profile.png) * Parameters: * **profile** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Coordinates of cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *length*: float*[](#Extrusion.length "Link to this definition") * *property *line*: [Line](#Line "viktor.geometry.Line")*[](#Extrusion.line "Link to this definition") - *property *material*: [Material](#Material "viktor.geometry.Material")*[](#Extrusion.material "Link to this definition") * *property *profile*: List\[[Point](#Point "viktor.geometry.Point")]*[](#Extrusion.profile "Link to this definition") ## GeoPoint[​](/sdk/api/geometry/.md#_GeoPoint "Direct link to GeoPoint") * *class *viktor.geometry.GeoPoint(*lat*, *lon*)[](#GeoPoint "Link to this definition") Geographical point on the Earth’s surface described by a latitude / longitude coordinate pair. This object can be created directly, or will be returned in the params when using a [`GeoPointField`](/sdk/api/parametrization/.md#GeoPointField "viktor.parametrization.GeoPointField"). * Parameters: * **lat** (`float`) – Latitude, between -90 and 90 degrees. * **lon** (`float`) – Longitude, between -180 and 180 degrees. - *classmethod *from\_rd(*coords*)[](#GeoPoint.from_rd "Link to this definition") Instantiates a GeoPoint from the provided RD coordinates. * Parameters: **coords** (`Tuple`\[`float`, `float`]) – RD coordinates (x, y). * Return type: [`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint") * *property *latitude*: float*[](#GeoPoint.latitude "Link to this definition") New in v14.22.0 - *property *longitude*: float*[](#GeoPoint.longitude "Link to this definition") New in v14.22.0 * *property *rd*: Tuple\[float, float]*[](#GeoPoint.rd "Link to this definition") RD representation (x, y) of the GeoPoint. ## GeoPolygon[​](/sdk/api/geometry/.md#_GeoPolygon "Direct link to GeoPolygon") * *class *viktor.geometry.GeoPolygon(*\*points*)[](#GeoPolygon "Link to this definition") Geographical polygon on the Earth’s surface described by a list of [`GeoPoints`](#GeoPoint "viktor.geometry.GeoPoint"). This object can be created directly, or will be returned in the params when using a [`GeoPolygonField`](/sdk/api/parametrization/.md#GeoPolygonField "viktor.parametrization.GeoPolygonField"). * Parameters: **points** ([`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")) – Geo points (minimum 3). The profile is automatically closed, so it is not necessary to add the start point at the end. - *property *points*: List\[[GeoPoint](#GeoPoint "viktor.geometry.GeoPoint")]*[](#GeoPolygon.points "Link to this definition") ## GeoPolyline[​](/sdk/api/geometry/.md#_GeoPolyline "Direct link to GeoPolyline") * *class *viktor.geometry.GeoPolyline(*\*points*)[](#GeoPolyline "Link to this definition") Geographical polyline on the Earth’s surface described by a list of [`GeoPoints`](#GeoPoint "viktor.geometry.GeoPoint"). This object can be created directly, or will be returned in the params when using a [`GeoPolylineField`](/sdk/api/parametrization/.md#GeoPolylineField "viktor.parametrization.GeoPolylineField"). * Parameters: **points** ([`GeoPoint`](#GeoPoint "viktor.geometry.GeoPoint")) – Geo points (minimum 2). - *property *points*: List\[[GeoPoint](#GeoPoint "viktor.geometry.GeoPoint")]*[](#GeoPolyline.points "Link to this definition") ## Group[​](/sdk/api/geometry/.md#_Group "Direct link to Group") * *class *viktor.geometry.Group(*objects*, *\**, *identifier=None*)[](#Group "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * Parameters: * **objects** (`Sequence`\[[`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")]) – Objects that are part of the group. * **identifier** (`str`) – object identifier (new in v14.10.0) - add(*objects*)[](#Group.add "Link to this definition") * Return type: `None` * *property *children*: List\[[TransformableObject](#TransformableObject "viktor.geometry.TransformableObject")]*[](#Group.children "Link to this definition") - duplicate()[](#Group.duplicate "Link to this definition") * Return type: [`Group`](#Group "viktor.geometry.Group") ## Line[​](/sdk/api/geometry/.md#_Line "Direct link to Line") * *class *viktor.geometry.Line(*start\_point*, *end\_point*, *\**, *color=(0, 0, 0)*, *identifier=None*)[](#Line "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * Parameters: * **start\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Start point of the line (cannot coincide with end\_point). * **end\_point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – End point of the line (cannot coincide with start\_point). * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . * **identifier** (`str`) – object identifier (new in v14.10.0) - collinear(*point*)[](#Line.collinear "Link to this definition") True if point is collinear (in line) with Line, else False. * Return type: `bool` * direction(*normalize=True*)[](#Line.direction "Link to this definition") Direction vector between start and end point. * Return type: [`Vector`](#Vector "viktor.geometry.Vector") - distance\_to\_point(*point*)[](#Line.distance_to_point "Link to this definition") Calculate the (minimal) distance from the given point to the (unbounded) line. * Return type: `float` * *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[](#Line.end_point "Link to this definition") - find\_overlap(*other*, *inclusive=False*)[](#Line.find_overlap "Link to this definition") Find the overlapping part of this line with another line. The returned value depends on the situation: * None, if no overlap is found or the two lines are not parallel * Point, if an overlap is found with length equal to 0 * Line, if an overlap is found with length larger than 0 - Parameters: * **other** ([`Line`](#Line "viktor.geometry.Line")) – Other Line object * **inclusive** (`bool`) – True to treat overlapping points as overlap - Return type: `Union`\[[`Point`](#Point "viktor.geometry.Point"), [`Line`](#Line "viktor.geometry.Line"), `None`] * get\_line\_function\_parameters()[](#Line.get_line_function_parameters "Link to this definition") Get parameters for y=ax+b definition of a line. * Return type: `Tuple`\[`float`, `float`] * Returns: (a, b) or (nan, nan) if line is vertical - *property *horizontal*: bool*[](#Line.horizontal "Link to this definition") * *property *length*: float*[](#Line.length "Link to this definition") - *property *length\_vector*: numpy.ndarray*[](#Line.length_vector "Link to this definition") * project\_point(*point*)[](#Line.project_point "Link to this definition") Project the point on the (unbounded) line. * Return type: [`Point`](#Point "viktor.geometry.Point") - revolve(*\**, *material=None*, *identifier=None*, *\*\*kwargs*)[](#Line.revolve "Link to this definition") Revolve line around y-axis, only possible for lines in x-y plane. * Parameters: * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) * Raises: **NotImplementedError** – when line is not in x-y plane * Return type: [`LineRevolve`](#LineRevolve "viktor.geometry.LineRevolve") * *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[](#Line.start_point "Link to this definition") - *property *unit\_vector*: numpy.ndarray*[](#Line.unit_vector "Link to this definition") * *property *vertical*: bool*[](#Line.vertical "Link to this definition") ## LineRevolve[​](/sdk/api/geometry/.md#_LineRevolve "Direct link to LineRevolve") * *class *viktor.geometry.LineRevolve(*line*, *\*args*, *material=None*, *identifier=None*, *\*\*kwargs*)[](#LineRevolve "Link to this definition") Bases: [`Revolve`](#Revolve "viktor.geometry.Revolve") Returns a revolved object of a Line around the global y-axis. An example revolve of a line between the point (1, 1, 0) and (3, 2, 0) is shown below, with the line object shown in black. ``` line = Line(Point(1, 1, 0), Point(3, 2, 0)) line_rev = LineRevolve(line) ``` [![/\_images/line-revolve.png](/_images/line-revolve.png)](/_images/line-revolve.png) * Parameters: * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object which is to be revolved. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *height*: float*[](#LineRevolve.height "Link to this definition") * *property *inner\_volume*: float*[](#LineRevolve.inner_volume "Link to this definition") Returns the inner volume of the revolved object. This method will only return a value if the defined Line meets the following conditions: > * it should NOT be horizontal, i.e. y\_start != y\_end > > * it should be defined in positive y-direction, i.e. y\_start < y\_end - *property *line*: [Line](#Line "viktor.geometry.Line")*[](#LineRevolve.line "Link to this definition") * *property *surface\_area*: float*[](#LineRevolve.surface_area "Link to this definition") Returns the total exterior area of the revolved object. - *property *uuid*: UUID*[](#LineRevolve.uuid "Link to this definition") ## LinearPattern[​](/sdk/api/geometry/.md#_LinearPattern "Direct link to LinearPattern") * *class *viktor.geometry.LinearPattern(*base\_object*, *direction*, *number\_of\_elements*, *spacing*, *\**, *identifier=None*)[](#LinearPattern "Link to this definition") Bases: [`Pattern`](#Pattern "viktor.geometry.Pattern") Instantiates a linear, evenly spaced, pattern along a single direction. If identifier has been set on the base-object, the identifiers of the objects within the pattern are suffixed with ‘-i’ (i = 1, 2, 3, …). * Parameters: * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **direction** (`List`\[`float`]) – a unit vector specifying in which direction the pattern propagates * **number\_of\_elements** (`int`) – total amount of elements in the pattern, including the base object * **spacing** (`float`) – the applied spacing * **identifier** (`str`) – object identifier (new in v14.10.0) ## Material[​](/sdk/api/geometry/.md#_Material "Direct link to Material") * *class *viktor.geometry.Material(*name=None*, *density=None*, *price=None*, *\**, *threejs\_type='MeshStandardMaterial'*, *roughness=1.0*, *metalness=0.5*, *opacity=1.0*, *color=(221, 221, 221)*)[](#Material "Link to this definition") Note The following properties were renamed since v14.5.0. If you are using a lower version, please use the old naming. * threejs\_roughness -> roughness * threejs\_metalness -> metalness * threejs\_opacity -> opacity **(new in v14.22.0)** Provide a hex value or tuple (r, g, b) as ‘color’. * Parameters: * **name** (`str`) – Optional name. * **density** (`float`) – Optional density. * **price** (`float`) – Optional price. * **threejs\_type** (`str`) – deprecated * **roughness** (`float`) – Between 0 - 1 where closer to 1 gives the material a rough texture. * **metalness** (`float`) – Between 0 - 1 where closer to 1 gives the material a shiny metal look. * **opacity** (`float`) – Between 0 - 1 where closer to 0 makes the material less visible. * **color** (`Union`\[`str`, `tuple`\[`int`, `int`, `int`], [`Color`](/sdk/api/core/.md#Color "viktor.core.Color")]) – Color of the material. ## Pattern[​](/sdk/api/geometry/.md#_Pattern "Direct link to Pattern") * *class *viktor.geometry.Pattern(*base\_object*, *duplicate\_translation\_list*, *\**, *identifier=None*)[](#Pattern "Link to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Instantiates a pattern based on a base object and several duplicates, each translated by an input vector. If identifier has been set on the base-object, the identifiers of the objects within the pattern are suffixed with ‘-i’ (i = 1, 2, 3, …). * Parameters: * **base\_object** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – the object to be duplicated * **duplicate\_translation\_list** (`List`\[`List`\[`float`]]) – a list of translation vectors, each of which generates a duplicate * **identifier** (`str`) – object identifier (new in v14.10.0) ## Point[​](/sdk/api/geometry/.md#_Point "Direct link to Point") * *class *viktor.geometry.Point(*x*, *y*, *z=0*)[](#Point "Link to this definition") This class represents a point object, which is instantiated by means of 3-dimensional coordinates X, Y, and Z. It forms a basis of many structural 2D and 3D objects. Example usage: ``` p1 = Point(1, 2) # create a 2D point p1.z # 0 p2 = Point(1, 2, 3) # create a 3D point p1.z # 3 ``` * Parameters: * **x** (`float`) – X-coordinate. * **y** (`float`) – Y-coordinate. * **z** (`float`) – (optional) Z-coordinate, defaults to 0. * Raises: **TypeError** – if the point is instantiated with a None value. - coincides\_with(*other*)[](#Point.coincides_with "Link to this definition") Given another Point object, this method determines whether the two points coincide. * Return type: `bool` * *property *coordinates*: numpy.ndarray*[](#Point.coordinates "Link to this definition") Coordinates of the Point as array (X, Y, Z). - copy()[](#Point.copy "Link to this definition") Returns a deep copy of the object. * Return type: [`Point`](#Point "viktor.geometry.Point") * get\_local\_coordinates(*local\_origin*, *spherical=False*)[](#Point.get_local_coordinates "Link to this definition") Method to determine the local coordinates of the current Point with respect to a ‘local origin’. * Return type: `ndarray` - vector\_to(*point*)[](#Point.vector_to "Link to this definition") Vector pointing from self to point. Example usage: ``` p1 = Point(1, 2, 3) p2 = Point(0, 0, 0) # origin v = p1.vector_to(p2) # vector from p1 to the origin v = p1.vector_to((0, 0, 0)) # short notation ``` * Return type: [`Vector`](#Vector "viktor.geometry.Vector") * *property *x*: float*[](#Point.x "Link to this definition") X-coordinate. - *property *y*: float*[](#Point.y "Link to this definition") Y-coordinate. * *property *z*: float*[](#Point.z "Link to this definition") Z-coordinate. ## Polygon[​](/sdk/api/geometry/.md#_Polygon "Direct link to Polygon") * *class *viktor.geometry.Polygon(*points*, *\**, *surface\_orientation=False*, *material=None*, *skip\_duplicate\_vertices\_check=False*, *identifier=None*)[](#Polygon "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") 2D closed polygon without holes in x-y plane. * Parameters: * **points** (`list`\[[`Point`](#Point "viktor.geometry.Point")]) – profile is automatically closed, do not add start point at the end. only the x and y coordinates are considered. left hand rule around circumference determines surface direction * **surface\_orientation** (`bool`) – * if True, the left hand rule around circumference determines surface direction * if False, surface always in +z direction * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **skip\_duplicate\_vertices\_check** (`bool`) – if True, duplicate vertices are not filtered on serialization of the triangles. This may boost performance (default: False). * **identifier** (`str`) – object identifier (new in v14.10.0) * Raises: **ValueError** – * if less than 3 points are provided. * if points contains duplicates. * if points form a polygon with self-intersecting lines. * if points are all collinear. - *property *centroid*: tuple\[float, float]*[](#Polygon.centroid "Link to this definition") Returns the centroid (X, Y) of the polygon. * *property *cross\_sectional\_area*: float*[](#Polygon.cross_sectional_area "Link to this definition") - extrude(*line*, *\**, *profile\_rotation=0*, *material=None*, *identifier=None*)[](#Polygon.extrude "Link to this definition") Extrude the Polygon in the direction of the given line. * Parameters: * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) * Return type: [`Extrusion`](#Extrusion "viktor.geometry.Extrusion") * has\_clockwise\_circumference()[](#Polygon.has_clockwise_circumference "Link to this definition") * Return type: `bool` - Method determines the direction of the input points, and returns: * True if the circumference is clockwise * False if the circumference is counter-clockwise - *property *moment\_of\_inertia*: tuple\[float, float]*[](#Polygon.moment_of_inertia "Link to this definition") Returns the moment of inertia (Ix, Iy) in xy-plane. ## Polyline[​](/sdk/api/geometry/.md#_Polyline "Direct link to Polyline") * *class *viktor.geometry.Polyline(*points*, *\**, *color=(0, 0, 0)*, *identifier=None*)[](#Polyline "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Representation of a polyline made up of multiple straight line segments. This class is immutable, meaning that all functions that perform changes on a polyline will return a mutated copy of the original polyline. * Parameters: * **points** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – List of points, which may contain duplicate points. Note that when calling the individual lines of the polyline, duplicate points are filtered (i.e. zero-length lines are omitted). * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – Visualization color New in v13.5.0 . * **identifier** (`str`) – object identifier (new in v14.10.0) - combine\_with(*other*)[](#Polyline.combine_with "Link to this definition") Given two polylines that have at least one point in common and together form one line without any side branches, combine those two polylines. The combined line will contain all points of both polylines. * Parameters: **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") * *property *end\_point*: [Point](#Point "viktor.geometry.Point")*[](#Polyline.end_point "Link to this definition") Last point in polyline.points - filter\_duplicate\_points()[](#Polyline.filter_duplicate_points "Link to this definition") Returns a new Polyline object. If two consecutive points in this polyline coincide, the second point will be omitted * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") * find\_overlaps(*other*)[](#Polyline.find_overlaps "Link to this definition") Find all overlapping regions of this polyline with another polyline. The returned overlapping regions will all point in the direction of this line. The overlap polylines will contain all points of both polylines, even if they only occur in one of the lines. If no overlaps are found, an empty list will be returned. * Parameters: **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) * Return type: `List`\[[`Polyline`](#Polyline "viktor.geometry.Polyline")] - *classmethod *from\_lines(*lines*)[](#Polyline.from_lines "Link to this definition") Create a polyline object from a list of lines. The end of one line must always coincide with the start of the next line. * Parameters: **lines** (`Sequence`\[[`Line`](#Line "viktor.geometry.Line")]) – Sequence of lines * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") * *classmethod *get\_lowest\_or\_highest\_profile\_x(*profile\_1*, *profile\_2*, *lowest*)[](#Polyline.get_lowest_or_highest_profile_x "Link to this definition") Given two polylines with n intersections, return a third polyline that will always follow the lowest (or highest) of the two lines the x locations of the points of the two polylines should be not descending (lines from left to right or vertical) the returned polyline will only cover the overlapping range in x coordinates. If one of the profiles is an empty polyline, an empty polyline will be returned. examples: ``` /----------------| / /-------|-------------------- profile_1: ----------------\ / / | \ / / |_____________________________ profile_2: -------------\-/ / \_________/ get_lowest_or_highest_profile_x(cls, profile_1, profile_2, lowest=True) will return: /-------| / | / |____________________ result: -------------\ / \_________/ ``` Note that only the overlapping region of the two profiles is returned! * Parameters: * **profile\_1** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) * **profile\_2** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) * **lowest** (`bool`) – switch to decide whether to return highest or lowest profile * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") Currently, this implementation is exclusive. Meaning that vertical line parts that lie on the start or end of the overlap region in x are not taken into account. - get\_polyline\_between(*start\_point*, *end\_point*, *inclusive=False*)[](#Polyline.get_polyline_between "Link to this definition") Given two points that both lie on a polyline, return the polyline that lies between those two points start\_point has to lie before end\_point on this polyline. If the given start point lies after the given end point on this polyline, an empty polyline will be returned. If the two given points are identical, it depends on the inclusive flag whether a polyline containing that point once, or an empty polyline will be returned. * Parameters: * **start\_point** ([`Point`](#Point "viktor.geometry.Point")) * **end\_point** ([`Point`](#Point "viktor.geometry.Point")) * **inclusive** (`bool`) – if true, the start and the end points will be added to the returned list * Raises: **ValueError** – when one of the two given points does not lie on this polyline * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") * get\_reversed\_polyline()[](#Polyline.get_reversed_polyline "Link to this definition") Returns a polyline that is the reverse of this one. * Return type: [`Polyline`](#Polyline "viktor.geometry.Polyline") - intersections\_with\_polyline(*other\_polyline*)[](#Polyline.intersections_with_polyline "Link to this definition") Find all intersections with another polyline and return them ordered according to the direction of this polyline If the polylines are partly parallel, the start and end points of the parallel section will be returned as intersections. If one of the polylines is a subset of the other, or the two lines are completely parallel, no intersections will be found. * Parameters: **other\_polyline** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) * Return type: `List`\[[`Point`](#Point "viktor.geometry.Point")] * intersections\_with\_x\_location(*x*)[](#Polyline.intersections_with_x_location "Link to this definition") Find all intersections of this polyline with a given x location. Ordered from start to end of this polyline. If this line is partly vertical, the start and end points of the vertical section will be returned as an intersection. If this line is completely vertical, no intersections will be found. * Parameters: **x** (`float`) * Return type: `List`\[[`Point`](#Point "viktor.geometry.Point")] - is\_equal\_to(*other*)[](#Polyline.is_equal_to "Link to this definition") Check if all points in this polyline coincide with all points of another polyline * Parameters: **other** ([`Polyline`](#Polyline "viktor.geometry.Polyline")) – Other polyline * Return type: `bool` * is\_monotonic\_ascending\_x(*strict=True*)[](#Polyline.is_monotonic_ascending_x "Link to this definition") Check if the x coordinates of the points of this polyline are ascending. * Parameters: **strict** (`bool`) – when set to false, equal x coordinates are accepted between points * Return type: `bool` - is\_monotonic\_ascending\_y(*strict=True*)[](#Polyline.is_monotonic_ascending_y "Link to this definition") Check if the y coordinates of the points of this polyline are ascending * Parameters: **strict** (`bool`) – when set to false, equal y coordinates are accepted between points * Return type: `bool` * *property *lines*: List\[[Line](#Line "viktor.geometry.Line")]*[](#Polyline.lines "Link to this definition") A list of lines connecting all polyline points. Lines between coincident points are skipped. - point\_is\_on\_polyline(*point*)[](#Polyline.point_is_on_polyline "Link to this definition") Check if a given point lies on this polyline * Parameters: **point** ([`Point`](#Point "viktor.geometry.Point")) * Return type: `bool` * *property *points*: List\[[Point](#Point "viktor.geometry.Point")]*[](#Polyline.points "Link to this definition") - serialize()[](#Polyline.serialize "Link to this definition") Return a json serializable dict of form: ``` [ {'x': point_1.x, 'y': point_1.y}, {'x': point_2.x, 'y': point_2.y} ] ``` * Return type: `List`\[`dict`] * split(*point*)[](#Polyline.split "Link to this definition") return the two separate parts of this polyline before and after the given point. * Parameters: **point** ([`Point`](#Point "viktor.geometry.Point")) * Raises: **ValueError** – if the provided point does not lie on this polyline. * Return type: `Tuple`\[[`Polyline`](#Polyline "viktor.geometry.Polyline"), [`Polyline`](#Polyline "viktor.geometry.Polyline")] - *property *start\_point*: [Point](#Point "viktor.geometry.Point")*[](#Polyline.start_point "Link to this definition") First point in polyline.points * *property *x\_max*: float | None*[](#Polyline.x_max "Link to this definition") The highest x-coordinate present within this polyline. - *property *x\_min*: float | None*[](#Polyline.x_min "Link to this definition") The lowest x-coordinate present within this polyline. * *property *y\_max*: float | None*[](#Polyline.y_max "Link to this definition") The highest y-coordinate present within this polyline. - *property *y\_min*: float | None*[](#Polyline.y_min "Link to this definition") The lowest y-coordinate present within this polyline. * *property *z\_max*: float | None*[](#Polyline.z_max "Link to this definition") The highest z-coordinate present within this polyline. - *property *z\_min*: float | None*[](#Polyline.z_min "Link to this definition") The lowest z-coordinate present within this polyline. ## RDWGSConverter[​](/sdk/api/geometry/.md#_RDWGSConverter "Direct link to RDWGSConverter") * *class *viktor.geometry.RDWGSConverter[](#RDWGSConverter "Link to this definition") Class that provides functions to translate latitude and longitude coordinates between the WGS system and RD system. The RD coordinate system is a cartesian coordinate system that is frequently used for in civil engineering to describe locations in the Netherlands. The origin is located in france, so that for all of the Netherlands, both x (m) and y (m) values are positive and y is always larger then x. The domain in which the RD coordinate system is valid is: * x: \[-7000, 300000] * y: \[289000, 629000] About the RD coordinate system: * X0* = 155000*[](#RDWGSConverter.X0 "Link to this definition") - Y0* = 463000*[](#RDWGSConverter.Y0 "Link to this definition") * *static *from\_rd\_to\_wgs(*coords*)[](#RDWGSConverter.from_rd_to_wgs "Link to this definition") Convert RD coordinates (x, y) to WGS coordinates \[latitude, longitude]. ``` lat, lon = RDWGSConverter.from_rd_to_wgs((100000, 400000)) ``` * Parameters: **coords** (`Tuple`\[`float`, `float`]) – RD coordinates (x, y) * Return type: `List`\[`float`] - *static *from\_wgs\_to\_rd(*coords*)[](#RDWGSConverter.from_wgs_to_rd "Link to this definition") Convert WGS coordinates (latitude, longitude) to RD coordinates \[x, y]. ``` x, y = RDWGSConverter.from_wgs_to_rd((51.58622, 4.59360)) ``` * Parameters: **coords** (`Tuple`\[`float`, `float`]) – WGS coordinates (latitude, longitude) * Return type: `List`\[`float`] * lam0* = 5.38720621*[](#RDWGSConverter.lam0 "Link to this definition") - phi0* = 52.1551744*[](#RDWGSConverter.phi0 "Link to this definition") ## RectangularExtrusion[​](/sdk/api/geometry/.md#_RectangularExtrusion "Direct link to RectangularExtrusion") * *class *viktor.geometry.RectangularExtrusion(*width*, *height*, *line*, *profile\_rotation=0*, *\**, *material=None*, *identifier=None*)[](#RectangularExtrusion "Link to this definition") Bases: [`Extrusion`](#Extrusion "viktor.geometry.Extrusion") Extruded object from a given set of points, which is called the profile. This profile should meet the following requirements: > * start point should be added at the end for closed profile > > * points should be defined in z=0 plane > > * circumference should be defined clockwise Note that the profile is defined with respect to the start point of the Line object, i.e. the profile is defined in the local coordinate system. An example is given below of two extrusions with the same dimensions. Their corresponding Line objects are also visualized. The extrusion have the following profile: ``` # black box profile_b = [ Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1), Point(1, 1), ] box_b = Extrusion(profile_b, Line(Point(4, 1, 0), Point(4, 1, 1))) # yellow box profile_y = [ Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5), Point(0.5, -0.5), Point(-0.5, -0.5), ] box_y = Extrusion(profile_y, Line(Point(2, 2, 0), Point(2, 2, 1))) ``` [![/\_images/extrusion-profile.png](/_images/extrusion-profile.png)](/_images/extrusion-profile.png) * Parameters: * **profile** – Coordinates of cross-section. * **line** ([`Line`](#Line "viktor.geometry.Line")) – A line object is used to define the length (thickness) of the extrusion. * **profile\_rotation** (`float`) – Rotation of the profile around the Z-axis in degrees. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *cross\_sectional\_area*: float*[](#RectangularExtrusion.cross_sectional_area "Link to this definition") Returns the area of the cross-section (width x height). * *property *height*: float*[](#RectangularExtrusion.height "Link to this definition") Height of the extrusion. - *property *inner\_volume*: float*[](#RectangularExtrusion.inner_volume "Link to this definition") Returns the inner volume of the extruded object. * *property *width*: float*[](#RectangularExtrusion.width "Link to this definition") Width of the extrusion. ## Revolve[​](/sdk/api/geometry/.md#_Revolve "Direct link to Revolve") * *class *viktor.geometry.Revolve(*\*args*, *rotation\_angle=None*, *material=None*, *identifier=None*, *\*\*kwargs*)[](#Revolve "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject"), `ABC` Abstract base class of a revolved object. * *abstract property *inner\_volume*: float*[](#Revolve.inner_volume "Link to this definition") - *property *mass*: float*[](#Revolve.mass "Link to this definition") Calculates the mass of the object as rho \* area \* thickness, with rho the density of the Material. * *abstract property *surface\_area*: float*[](#Revolve.surface_area "Link to this definition") - *property *thickness*: float*[](#Revolve.thickness "Link to this definition") ## Sphere[​](/sdk/api/geometry/.md#_Sphere "Direct link to Sphere") * *class *viktor.geometry.Sphere(*centre\_point*, *radius*, *width\_segments=30*, *height\_segments=30*, *material=None*, *\**, *identifier=None*)[](#Sphere "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") This class can be used to construct a spherical object around the specified coordinate. The smoothness of the edges can be altered by setting width\_segments and height\_segments. In the example below both the default smoothness of 30 (left) and a rough sphere with 5 segments (right) is shown: [![/\_images/sphere.png](/_images/sphere.png)](/_images/sphere.png) * Parameters: * **centre\_point** ([`Point`](#Point "viktor.geometry.Point")) – Center point of the sphere. * **radius** (`float`) – Radius of the sphere. * **width\_segments** (`float`) – Sets the smoothness in xz-plane. * **height\_segments** (`float`) – Sets the smoothness in yz-plane. * **material** ([`Material`](#Material "viktor.geometry.Material")) – Optionally a custom material can be set. * **identifier** (`str`) – object identifier (new in v14.10.0) - circumference()[](#Sphere.circumference "Link to this definition") * Return type: `float` * diameter()[](#Sphere.diameter "Link to this definition") * Return type: `float` - surface\_area()[](#Sphere.surface_area "Link to this definition") * Return type: `float` * volume()[](#Sphere.volume "Link to this definition") * Return type: `float` ## SquareBeam[​](/sdk/api/geometry/.md#_SquareBeam "Direct link to SquareBeam") * *class *viktor.geometry.SquareBeam(*length\_x*, *length\_y*, *length\_z*, *\**, *material=None*, *identifier=None*)[](#SquareBeam "Link to this definition") Bases: [`RectangularExtrusion`](#RectangularExtrusion "viktor.geometry.RectangularExtrusion") High level object to create a rectangular beam object around the origin. The centroid of the beam is located at the origin (0, 0, 0). * Parameters: * **length\_x** (`float`) – Width of the extrusion in x-direction. * **length\_y** (`float`) – Length of the extrusion in y-direction. * **length\_z** (`float`) – Height of the extrusion in z-direction. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) ## Torus[​](/sdk/api/geometry/.md#_Torus "Direct link to Torus") * *class *viktor.geometry.Torus(*radius\_cross\_section*, *radius\_rotation\_axis*, *rotation\_angle=6.283185307179586*, *\**, *material=None*, *identifier=None*)[](#Torus "Link to this definition") Bases: [`Group`](#Group "viktor.geometry.Group") Create a torus object * Parameters: * **radius\_cross\_section** (`float`) * **radius\_rotation\_axis** (`float`) – measured from central axis to centre of cross-section. * **rotation\_angle** (`float`) – optional argument to control how large of a torus section you want. 2pi for complete torus * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material * **identifier** (`str`) – object identifier (new in v14.10.0) - *property *inner\_volume*: float*[](#Torus.inner_volume "Link to this definition") * *property *material*: [Material](#Material "viktor.geometry.Material")*[](#Torus.material "Link to this definition") ## TransformableObject[​](/sdk/api/geometry/.md#_TransformableObject "Direct link to TransformableObject") * *class *viktor.geometry.TransformableObject(*\**, *identifier=None*)[](#TransformableObject "Link to this definition") Bases: `ABC` * mirror(*point*, *normal*)[](#TransformableObject.mirror "Link to this definition") Mirror an object on a plane defined by a point and normal vector. * Parameters: * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point within the mirror plane. * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Normal vector of the mirror plane. * Return type: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") - rotate(*angle*, *direction*, *point=None*)[](#TransformableObject.rotate "Link to this definition") Rotate an object along an axis (direction) by an angle. Direction will follow right hand rule. * Parameters: * **angle** (`float`) – Angle of desired rotation in radians. * **direction** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which rotation is to be performed. * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point through which the rotation vector runs. * Return type: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") * scale(*scaling\_vector*)[](#TransformableObject.scale "Link to this definition") Scale an object along a scaling vector. * Parameters: **scaling\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which scaling is to be performed. * Return type: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") - translate(*translation\_vector*)[](#TransformableObject.translate "Link to this definition") Translate an object along a translation vector. * Parameters: **translation\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector along which translation is to be performed. * Return type: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") ## Triangle[​](/sdk/api/geometry/.md#_Triangle "Direct link to Triangle") * *class *viktor.geometry.Triangle(*point1*, *point2*, *point3*)[](#Triangle "Link to this definition") Creates a Triangle object from 3D vertices. * Parameters: * **point1** ([`Point`](#Point "viktor.geometry.Point")) – First vertex. * **point2** ([`Point`](#Point "viktor.geometry.Point")) – Second vertex. * **point3** ([`Point`](#Point "viktor.geometry.Point")) – Third vertex. - area()[](#Triangle.area "Link to this definition") Returns the area of the triangle. * Return type: `float` * *property *centroid*: Tuple\[float, float, float]*[](#Triangle.centroid "Link to this definition") Returns the centroid (X, Y, Z) of the triangle. - *property *moment\_of\_inertia*: Tuple\[float, float]*[](#Triangle.moment_of_inertia "Link to this definition") Returns the moment of inertia (Ix, Iy) (only in x-y plane). ## TriangleAssembly[​](/sdk/api/geometry/.md#_TriangleAssembly "Direct link to TriangleAssembly") * *class *viktor.geometry.TriangleAssembly(*triangles*, *\**, *material=None*, *skip\_duplicate\_vertices\_check=False*, *identifier=None*)[](#TriangleAssembly "Link to this definition") Bases: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") Fundamental visualisation geometry, built up from triangles. Right hand rule on triangle circumference determines the surface direction. * Parameters: * **triangles** (`List`\[[`Triangle`](#Triangle "viktor.geometry.Triangle")]) – Triangles of the assembly. * **material** ([`Material`](#Material "viktor.geometry.Material")) – optional material. * **skip\_duplicate\_vertices\_check** (`bool`) – if True, duplicate vertices are not filtered on serialization of the triangles. This may boost performance (default: False). * **identifier** (`str`) – object identifier (new in v14.10.0) ## Vector[​](/sdk/api/geometry/.md#_Vector "Direct link to Vector") * *class *viktor.geometry.Vector(*x*, *y*, *z=0*)[](#Vector "Link to this definition") A 3-dimensional vector in space. The following operations are supported: * Negation > ``` > v1 = Vector(1, 2, 3) > v2 = -v1 # results in Vector(-1, -2, -3) > ``` * Addition > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > v3 = v1 + v2 # results in Vector(2, 4, 6) > ``` * Subtraction > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > v3 = v1 - v2 # results in Vector(0, 0, 0) > ``` * (reverse) Multiplication > ``` > v1 = Vector(1, 2, 3) > v2 = v1 * 3 # results in Vector(3, 6, 9) > v3 = 3 * v1 # results in Vector(3, 6, 9) > ``` * Dot product > ``` > v1 = Vector(1, 2, 3) > v2 = Vector(1, 2, 3) > res = v1.dot(v2) # results in 14 > ``` * Cross product > ``` > v1 = Vector(1, 0, 0) > v2 = Vector(0, 1, 0) > v3 = v1.cross(v2) # results in Vector(0, 0, 1) > ``` - Parameters: * **x** (`float`) – X-coordinate. * **y** (`float`) – Y-coordinate. * **z** (`float`) – Z-coordinate (default: 0). * *property *coordinates*: Tuple\[float, float, float]*[](#Vector.coordinates "Link to this definition") Coordinates of the Vector as tuple (X, Y, Z). - cross(*other*)[](#Vector.cross "Link to this definition") Vector product of two vectors. * Parameters: **other** ([`Vector`](#Vector "viktor.geometry.Vector")) – Second Vector * Return type: [`Vector`](#Vector "viktor.geometry.Vector") * dot(*other*)[](#Vector.dot "Link to this definition") Scalar product of two vectors. * Parameters: **other** ([`Vector`](#Vector "viktor.geometry.Vector")) – Second Vector * Return type: `float` - *property *magnitude*: float*[](#Vector.magnitude "Link to this definition") Magnitude of the Vector. * normalize()[](#Vector.normalize "Link to this definition") Return the normalized vector (with unit-length). * Raises: **ValueError** – if vector is a null-vector. * Return type: [`Vector`](#Vector "viktor.geometry.Vector") - *property *squared\_magnitude*: float*[](#Vector.squared_magnitude "Link to this definition") Vector magnitude without square root; faster than magnitude. ## add\_point[​](/sdk/api/geometry/.md#_add_point "Direct link to add_point") * viktor.geometry.add\_point(*unique\_points*, *point*)[](#add_point "Link to this definition") Adds a Point object to a unique list of Point objects. The point is only added when not already present in the list. * Parameters: * **unique\_points** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – List of point objects. * **point** ([`Point`](#Point "viktor.geometry.Point")) – Point object which has to be added. * Return type: `Tuple`\[`List`\[[`Point`](#Point "viktor.geometry.Point")], `int`] ## calculate\_distance\_vector[​](/sdk/api/geometry/.md#_calculate_distance_vector "Direct link to calculate_distance_vector") * viktor.geometry.calculate\_distance\_vector(*start\_point*, *end\_point*)[](#calculate_distance_vector "Link to this definition") Calculates the distance between start and end point in the direction start -> end. * Parameters: * **start\_point** ([`Point`](#Point "viktor.geometry.Point")) – Start position of the distance vector. * **end\_point** ([`Point`](#Point "viktor.geometry.Point")) – End position of the distance vector. * Return type: `ndarray` ## calculate\_intersection\_bounded\_line\_extended\_line[​](/sdk/api/geometry/.md#_calculate_intersection_bounded_line_extended_line "Direct link to calculate_intersection_bounded_line_extended_line") * viktor.geometry.calculate\_intersection\_bounded\_line\_extended\_line(*bounded\_line*, *extended\_line*, *inclusive=True*)[](#calculate_intersection_bounded_line_extended_line "Link to this definition") Calculate intersection between line with fixed endpoints and line which is indefinitely extended. * Parameters: * **bounded\_line** ([`Line`](#Line "viktor.geometry.Line")) – Bounded Line object. * **extended\_line** ([`Line`](#Line "viktor.geometry.Line")) – Extended Line object. * **inclusive** (`bool`) – If set to True, this method will also check for end points that are located on one of the line ends. * Return type: `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## calculate\_intersection\_bounded\_line\_with\_y[​](/sdk/api/geometry/.md#_calculate_intersection_bounded_line_with_y "Direct link to calculate_intersection_bounded_line_with_y") * viktor.geometry.calculate\_intersection\_bounded\_line\_with\_y(*line*, *y\_intersection*)[](#calculate_intersection_bounded_line_with_y "Link to this definition") Calculate x intersection between two points and y value. Return None if no intersection is found. ``` Returns x: Returns None: o / y-----/--- y--------- /: o / : / o x o ``` * Parameters: * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object. * **y\_intersection** (`float`) – y-value of the intersection line. * Return type: `Optional`\[`float`] ## calculate\_intersection\_bounded\_lines[​](/sdk/api/geometry/.md#_calculate_intersection_bounded_lines "Direct link to calculate_intersection_bounded_lines") * viktor.geometry.calculate\_intersection\_bounded\_lines(*bounded\_line1*, *bounded\_line2*, *inclusive=True*)[](#calculate_intersection_bounded_lines "Link to this definition") Calculate intersection between two lines with fixed endpoints (2D only, Z-coordinate is ignored!). * Parameters: * **bounded\_line1** ([`Line`](#Line "viktor.geometry.Line")) – First bounded Line object. * **bounded\_line2** ([`Line`](#Line "viktor.geometry.Line")) – Second bounded Line object. * **inclusive** (`bool`) – If set to True, intersections on the endpoint will also be taken into account. * Return type: `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## calculate\_intersection\_extended\_line\_with\_x[​](/sdk/api/geometry/.md#_calculate_intersection_extended_line_with_x "Direct link to calculate_intersection_extended_line_with_x") * viktor.geometry.calculate\_intersection\_extended\_line\_with\_x(*line*, *x*)[](#calculate_intersection_extended_line_with_x "Link to this definition") Returns the point at which a given line intersects a vertical axis at position x. ``` Returns P(x, y): Returns P(x, y): o / y-----P--- y-----P---- /: o: / : / : o x o x ``` * Parameters: * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line to be evaluated. * **x** (`float`) – x-value of the intersection line. * Return type: [`Point`](#Point "viktor.geometry.Point") ## calculate\_intersection\_extended\_line\_with\_y[​](/sdk/api/geometry/.md#_calculate_intersection_extended_line_with_y "Direct link to calculate_intersection_extended_line_with_y") * viktor.geometry.calculate\_intersection\_extended\_line\_with\_y(*line*, *y\_intersection*)[](#calculate_intersection_extended_line_with_y "Link to this definition") Calculates the intersection x value of a line at a given y value. ``` Returns x: Returns x: o / y-----/--- y---------- /: o: / : / : o x o x ``` * Parameters: * **line** ([`Line`](#Line "viktor.geometry.Line")) – Line object. * **y\_intersection** (`float`) – y-value of the intersection line. * Return type: `float` ## calculate\_intersection\_extended\_lines[​](/sdk/api/geometry/.md#_calculate_intersection_extended_lines "Direct link to calculate_intersection_extended_lines") * viktor.geometry.calculate\_intersection\_extended\_lines(*extended\_line1*, *extended\_line2*)[](#calculate_intersection_extended_lines "Link to this definition") Calculate intersection between two lines defined by start/end points. The lines are assumed to extend infinitely: bounds are not taken account. Returns None if lines are parallel (i.e. no intersection exists). ``` Returns P(x, y): Returns P(x, y): Returns None: o / o-----P---o o--o P o-----o / o / / o--o o o ``` * Parameters: * **extended\_line1** ([`Line`](#Line "viktor.geometry.Line")) – First Line object. * **extended\_line2** ([`Line`](#Line "viktor.geometry.Line")) – Second Line object. * Return type: `Optional`\[[`Point`](#Point "viktor.geometry.Point")] ## cartesian\_to\_cylindrical[​](/sdk/api/geometry/.md#_cartesian_to_cylindrical "Direct link to cartesian_to_cylindrical") * viktor.geometry.cartesian\_to\_cylindrical(*cartesian\_coordinates*)[](#cartesian_to_cylindrical "Link to this definition") Using ISO convention: Reference plane is former Cartesian xy-plane and cylindrical axis is the Cartesian z-axis. * Parameters: **cartesian\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cartesian coordinates (x, y, z). * Return type: `ndarray` * Returns: Cylindrical coordinates (rho, phi, z) with phi between -pi and +pi. ## cartesian\_to\_spherical[​](/sdk/api/geometry/.md#_cartesian_to_spherical "Direct link to cartesian_to_spherical") * viktor.geometry.cartesian\_to\_spherical(*cartesian\_coordinates*)[](#cartesian_to_spherical "Link to this definition") Using ISO/physical convention: * Parameters: **cartesian\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cartesian coordinates (x, y, z). * Return type: `ndarray` * Returns: Spherical coordinates (r, theta, phi). ## circumference\_is\_clockwise[​](/sdk/api/geometry/.md#_circumference_is_clockwise "Direct link to circumference_is_clockwise") * viktor.geometry.circumference\_is\_clockwise(*circumference*)[](#circumference_is_clockwise "Link to this definition") * Method determines the direction of a set of points, and returns: * True if the circumference is clockwise * False if the circumference is counter-clockwise - Parameters: **circumference** (`List`\[[`Point`](#Point "viktor.geometry.Point")]) – Circumference in x,y-plane. - Return type: `bool` ## convert\_points\_for\_lathe[​](/sdk/api/geometry/.md#_convert_points_for_lathe "Direct link to convert_points_for_lathe") * viktor.geometry.convert\_points\_for\_lathe(*points*)[](#convert_points_for_lathe "Link to this definition") Method can be used to convert Point objects to lists of dictionaries in the format: {‘x’: point.x, ‘y’: point.y} * Parameters: **points** (`Sequence`\[[`Point`](#Point "viktor.geometry.Point")]) – Point objects. * Return type: `List`\[`dict`] ## cylindrical\_to\_cartesian[​](/sdk/api/geometry/.md#_cylindrical_to_cartesian "Direct link to cylindrical_to_cartesian") * viktor.geometry.cylindrical\_to\_cartesian(*cylindrical\_coordinates*)[](#cylindrical_to_cartesian "Link to this definition") Using ISO convention: Reference plane is former Cartesian xy-plane and cylindrical axis is the Cartesian z-axis. * Parameters: **cylindrical\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Cylindrical coordinates (rho, phi, z). * Return type: `ndarray` * Returns: Cartesian coordinates (x, y, z). ## find\_overlap[​](/sdk/api/geometry/.md#_find_overlap "Direct link to find_overlap") * viktor.geometry.find\_overlap(*region\_a*, *region\_b*, *inclusive=False*)[](#find_overlap "Link to this definition") Given to regions with upper and lower boundary, check if there is overlap and if so return a tuple with the overlap found The direction of the given regions does not matter: (1, 2) will be handled exactly the same as (2, 1) The returned Tuple will always be in ascending order Example usage: ``` find_overlap((2, 4), (3, 5)) -> (3, 4) find_overlap((4, 2), (5, 3)) -> (3, 4) find_overlap((2, 3), (3, 4)) -> None find_overlap((2, 3), (3, 4), inclusive=True) -> (3, 3) ``` * Parameters: * **region\_a** (`Tuple`\[`float`, `float`]) – Tuple of values of the first region. * **region\_b** (`Tuple`\[`float`, `float`]) – Tuple of values of the second region. * **inclusive** (`bool`) – A flag to decide whether a point overlap is counted as overlap or not. * Return type: `Optional`\[`Tuple`\[`float`, `float`]] * Returns: A tuple with upper and lower bounds of the overlapping region, or None. ## get\_line\_function\_parameters[​](/sdk/api/geometry/.md#_get_line_function_parameters "Direct link to get_line_function_parameters") * viktor.geometry.get\_line\_function\_parameters(*line*)[](#get_line_function_parameters "Link to this definition") Returns the line function parameters (a, b) of a line (y = ax + b). * Return type: `Tuple`\[`float`, `float`] ## get\_vertices\_faces[​](/sdk/api/geometry/.md#_get_vertices_faces "Direct link to get_vertices_faces") * viktor.geometry.get\_vertices\_faces(*triangles*)[](#get_vertices_faces "Link to this definition") Returns the vertices and faces of a list of Triangle objects. * Parameters: **triangles** (`List`\[[`Triangle`](#Triangle "viktor.geometry.Triangle")]) – List of triangle objects. * Return type: `Tuple`\[`list`, `list`] ## line\_is\_horizontal[​](/sdk/api/geometry/.md#_line_is_horizontal "Direct link to line_is_horizontal") * viktor.geometry.line\_is\_horizontal(*line*)[](#line_is_horizontal "Link to this definition") Returns True if line is horizontal. * Return type: `bool` ## line\_is\_vertical[​](/sdk/api/geometry/.md#_line_is_vertical "Direct link to line_is_vertical") * viktor.geometry.line\_is\_vertical(*line*)[](#line_is_vertical "Link to this definition") Returns True if line is vertical. * Return type: `bool` ## lines\_in\_same\_plane[​](/sdk/api/geometry/.md#_lines_in_same_plane "Direct link to lines_in_same_plane") * viktor.geometry.lines\_in\_same\_plane(*line1*, *line2*)[](#lines_in_same_plane "Link to this definition") Method to determine whether two Line objects are located in a shared plane and hence are coplanar. * Parameters: * **line1** ([`Line`](#Line "viktor.geometry.Line")) – First line object. * **line2** ([`Line`](#Line "viktor.geometry.Line")) – Second line object. * Return type: `bool` ## mirror\_object[​](/sdk/api/geometry/.md#_mirror_object "Direct link to mirror_object") * viktor.geometry.mirror\_object(*obj*, *point*, *normal*)[](#mirror_object "Link to this definition") Function that mirrors an object through a plane. The plane is defined by a point and a normal vector. The return is a copy of the original object, mirrored over the specified plane. * Parameters: * **obj** ([`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject")) – Object that is to be mirrored * **point** ([`Point`](#Point "viktor.geometry.Point")) – Point object on the desired mirror plane * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Vector that denotes a normal vector of the desired mirror plane. * Return type: [`TransformableObject`](#TransformableObject "viktor.geometry.TransformableObject") ## point\_is\_on\_bounded\_line[​](/sdk/api/geometry/.md#_point_is_on_bounded_line "Direct link to point_is_on_bounded_line") * viktor.geometry.point\_is\_on\_bounded\_line(*point*, *line*, *inclusive=True*)[](#point_is_on_bounded_line "Link to this definition") Check whether a given Point object is within the ends of a Line. * Parameters: * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point to be evaluated. * **line** (`Union`\[[`Line`](#Line "viktor.geometry.Line"), `Tuple`\[`Tuple`\[`float`, `float`, `float`], `Tuple`\[`float`, `float`, `float`]]]) – Line object. * **inclusive** (`bool`) – If True, this method will also return True when the point is located on one of the line ends. * Return type: `bool` ## points\_are\_coplanar[​](/sdk/api/geometry/.md#_points_are_coplanar "Direct link to points_are_coplanar") * viktor.geometry.points\_are\_coplanar(*points*)[](#points_are_coplanar "Link to this definition") Determine whether all given points are coplanar (are on a two-dimensional plane). * Parameters: **points** (`Sequence`\[`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]]) – points to be evaluated (min. 3). * Return type: `bool` Example usage: ``` points = [[Point(0, 3, 1), Point(0, 5, 1), Point(2, 3, 4), Point(2, 5, 4)]] coplanar = points_are_coplanar(points) coplanar = points_are_coplanar([(0, 3, 1), (0, 5, 1), (2, 3, 4), (2, 5, 4)]) ``` ## reflection\_matrix[​](/sdk/api/geometry/.md#_reflection_matrix "Direct link to reflection_matrix") * viktor.geometry.reflection\_matrix(*point*, *normal*)[](#reflection_matrix "Link to this definition") Returns the reflection matrix to mirror at a plane defined by a point and a normal vector. * Parameters: * **point** (`Union`\[[`Point`](#Point "viktor.geometry.Point"), `Tuple`\[`float`, `float`, `float`]]) – Point object. * **normal** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Normal vector of the mirror plane. * Return type: `ndarray` ## rotation\_matrix[​](/sdk/api/geometry/.md#_rotation_matrix "Direct link to rotation_matrix") * viktor.geometry.rotation\_matrix(*angle*, *direction*, *point=None*)[](#rotation_matrix "Link to this definition") Returns the rotation matrix that corresponds to a rotation about an axis defined by a point and direction. Angle in radians, direction in accordance to right-hand rule. Example: ``` R = rotation_matrix(pi/2, [0, 0, 1], [1, 0, 0]) np.allclose(np.dot(R, [0, 0, 0, 1]), [1, -1, 0, 1]) # True ``` * Return type: `ndarray` ## scaling\_matrix[​](/sdk/api/geometry/.md#_scaling_matrix "Direct link to scaling_matrix") * viktor.geometry.scaling\_matrix(*scaling\_vector*)[](#scaling_matrix "Link to this definition") Returns the scaling matrix that corresponds to a given scaling vector (3D). * Parameters: **scaling\_vector** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Three-dimensional scaling vector. * Return type: `ndarray` ## spherical\_to\_cartesian[​](/sdk/api/geometry/.md#_spherical_to_cartesian "Direct link to spherical_to_cartesian") * viktor.geometry.spherical\_to\_cartesian(*spherical\_coordinates*)[](#spherical_to_cartesian "Link to this definition") Using ISO/physical convention: * Parameters: **spherical\_coordinates** (`Tuple`\[`float`, `float`, `float`]) – Spherical coordinates (r, theta, phi). * Return type: `ndarray` * Returns: Cartesian coordinates (x, y, z). ## surface\_area\_dome[​](/sdk/api/geometry/.md#_surface_area_dome "Direct link to surface_area_dome") * viktor.geometry.surface\_area\_dome(*theta1*, *theta2*, *r*, *R*)[](#surface_area_dome "Link to this definition") Computes the surface area of a dome (arc-revolve). * Parameters: * **theta1** (`float`) – Starting angle of arc in radians. * **theta2** (`float`) – Ending angle of arc in radians. * **r** (`float`) – Radius of arc. * **R** (`float`) – Distance from centre of arc to rotation line. * Return type: `float` * Returns: surface area of arc-revolve. ## surface\_cone\_without\_base[​](/sdk/api/geometry/.md#_surface_cone_without_base "Direct link to surface_cone_without_base") * viktor.geometry.surface\_cone\_without\_base(*r*, *h*)[](#surface_cone_without_base "Link to this definition") Calculates the exterior surface of the cone, excluding the area of the circular base. * Parameters: * **r** (`float`) – Radius of the base. * **h** (`float`) – Height of the cone. * Return type: `float` ## translation\_matrix[​](/sdk/api/geometry/.md#_translation_matrix "Direct link to translation_matrix") * viktor.geometry.translation\_matrix(*direction*)[](#translation_matrix "Link to this definition") Returns the translation matrix that corresponds to a give direction vector (3D). * Parameters: **direction** (`Union`\[[`Vector`](#Vector "viktor.geometry.Vector"), `Tuple`\[`float`, `float`, `float`]]) – Direction vector of the translation. * Return type: `ndarray` ## unit\_vector[​](/sdk/api/geometry/.md#_unit_vector "Direct link to unit_vector") * viktor.geometry.unit\_vector(*data*, *axis=None*, *out=None*)[](#unit_vector "Link to this definition") Returns the unit vector of a given vector. * Return type: `Optional`\[`ndarray`] ## volume\_cone[​](/sdk/api/geometry/.md#_volume_cone "Direct link to volume_cone") * viktor.geometry.volume\_cone(*r*, *h*)[](#volume_cone "Link to this definition") Calculates the volume of a cone. * Parameters: * **r** (`float`) – Radius of the base. * **h** (`float`) – Height of the cone. * Return type: `float` ## x\_between\_bounds[​](/sdk/api/geometry/.md#_x_between_bounds "Direct link to x_between_bounds") * viktor.geometry.x\_between\_bounds(*x*, *x1*, *x2*, *inclusive=True*)[](#x_between_bounds "Link to this definition") Method checks whether the x value is between the bounds x1 and x2. * Parameters: * **x** (`float`) – x-value to be evaluated. * **x1** (`float`) – Lower bound. * **x2** (`float`) – Upper bound. * **inclusive** (`bool`) – If set to True, this method will also return True when the x value is equal to either x1 or x2. * Return type: `bool` ## y\_between\_bounds[​](/sdk/api/geometry/.md#_y_between_bounds "Direct link to y_between_bounds") * viktor.geometry.y\_between\_bounds(*y*, *y1*, *y2*, *inclusive=True*)[](#y_between_bounds "Link to this definition") Method checks whether the y value is between the bounds y1 and y2. * Parameters: * **y** (`float`) – y-value to be evaluated. * **y1** (`float`) – Lower bound. * **y2** (`float`) – Upper bound. * **inclusive** (`bool`) – If set to True, this method will also return True when the y value is equal to either y1 or y2. * Return type: `bool` --- # viktor.parametrization ## ActionButton[​](/sdk/api/parametrization/.md#_ActionButton "Direct link to ActionButton") * *class *viktor.parametrization.ActionButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[](#ActionButton "Link to this definition") Bases: `_ActionButton` Action button which can be pressed to perform a (heavy) calculation without returning a result. Example usage: ``` # in parametrization: calculation_btn = ActionButton("Analysis", "calculation", longpoll=True) # in controller: def calculation(self, params, **kwargs): # perform calculation, no return necessary ``` * Parameters: * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – deprecated * **flex** (`int`) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** ([`Interaction`](#Interaction "viktor.parametrization.Interaction")) – Enable view interaction through this button New in v13.2.0 ## AnalyseButton[​](/sdk/api/parametrization/.md#_AnalyseButton "Direct link to AnalyseButton") * viktor.parametrization.AnalyseButton[](#AnalyseButton "Link to this definition") alias of [`ActionButton`](#ActionButton "viktor.parametrization.ActionButton") ## And[​](/sdk/api/parametrization/.md#_And "Direct link to And") * *class *viktor.parametrization.And(*\*operands*)[](#And "Link to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate multiple operands to be True. ``` field_1 = NumberField('Field 1') field_2 = BooleanField('Field 2') field_3 = NumberField('Field 3', visible=And(IsEqual(Lookup('field_1'), 5), Lookup('field_2'))) ``` * Parameters: **operands** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operands to be evaluated. ## AutocompleteField[​](/sdk/api/parametrization/.md#_AutocompleteField "Direct link to AutocompleteField") * *class *viktor.parametrization.AutocompleteField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*)[](#AutocompleteField "Link to this definition") Bases: `_SelectField` Similar to OptionField, except for two differences: * user can type to search for option * single option is not pre-selected Example usage: ``` field = AutocompleteField('Available options', options=['Option 1', 'Option 2'], default='Option 1') ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = AutocompleteField('Available options', options=_options, default='option_1') ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. Data: * type of selected option: integer, float or string * None when nothing is selected ## BoolOperator[​](/sdk/api/parametrization/.md#_BoolOperator "Direct link to BoolOperator") * *class *viktor.parametrization.BoolOperator[](#BoolOperator "Link to this definition") Bases: `ABC` Warning Do not use this class directly in an application. Base class for operators that can be used for field visibility and min/max. See the documentation of the subclasses for example implementations. ## BooleanField[​](/sdk/api/parametrization/.md#_BooleanField "Direct link to BooleanField") * *class *viktor.parametrization.BooleanField(*ui\_name*, *name=None*, *\**, *default=None*, *visible=True*, *flex=None*, *always\_available=False*, *description=None*)[](#BooleanField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters Additional parameters: * Parameters: **always\_available** (`bool`) – deprecated Data: * False or True ## Chat[​](/sdk/api/parametrization/.md#_Chat "Direct link to Chat") * *class *viktor.parametrization.Chat(*ui\_name*, *method*, *\**, *first\_message=None*, *placeholder=None*, *flex=None*, *visible=True*)[](#Chat "Link to this definition") Bases: `_ActionButton` New in v14.21.0 **This field is currently in BETA** Chat field, e.g. to enable an LLM conversation. Example usage: ``` # in parametrization: chat = vkt.Chat("Chatbot", method="call_llm", first_message="How can I help you?", placeholder="Ask anything") # in controller: def call_llm(self, params, **kwargs): conversation = params.chat text_stream = ... # dependent on full conversation obtained with conversation.get_messages() return vkt.ChatResult(conversation, text_stream) ``` Data: * [`ChatConversation`](/sdk/api/api-v1/.md#ChatConversation "viktor.api_v1.ChatConversation") - Parameters: * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **first\_message** (`str`) – First message that is shown in the chat (or None for default message) * **placeholder** (`str`) – Placeholder message in the prompt (or None for default message) * **flex** (`int`) – Width of the image as percentage of the parametrization component (value betweeb 0-100) * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. ## ChildEntityManager[​](/sdk/api/parametrization/.md#_ChildEntityManager "Direct link to ChildEntityManager") * *class *viktor.parametrization.ChildEntityManager(*entity\_type\_name*, *\**, *visible=True*)[](#ChildEntityManager "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") New in v14.2.0 Manager in which a user can create, inspect, and delete child entities of a specific type. * Parameters: * **entity\_type\_name** (`str`) – User will only be able to manage entities of specified type. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. ## ChildEntityMultiSelectField[​](/sdk/api/parametrization/.md#_ChildEntityMultiSelectField "Direct link to ChildEntityMultiSelectField") * *class *viktor.parametrization.ChildEntityMultiSelectField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[](#ChildEntityMultiSelectField "Link to this definition") Bases: `_EntityMultiSelectField` Field to select zero or more child entities of given type(s). Up to 5000 entities may be visualized in the dropdown in the interface. Data: * List\[[`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")] * Empty list when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. None = all entities. ## ChildEntityOptionField[​](/sdk/api/parametrization/.md#_ChildEntityOptionField "Direct link to ChildEntityOptionField") * *class *viktor.parametrization.ChildEntityOptionField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[](#ChildEntityOptionField "Link to this definition") Bases: `_EntityOptionField` Field to select a child entity of given type(s). Single option is not automatically pre-selected. Data: * [`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity") * None when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. None = all entities. ## ColorField[​](/sdk/api/parametrization/.md#_ColorField "Direct link to ColorField") * *class *viktor.parametrization.ColorField(*ui\_name*, *name=None*, *\**, *default=None*, *flex=None*, *visible=True*, *description=None*)[](#ColorField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") New in v14.0.0 See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional params: - Data: > * [`Color`](/sdk/api/core/.md#Color "viktor.core.Color") > > * None when empty ## DateField[​](/sdk/api/parametrization/.md#_DateField "Direct link to DateField") * *class *viktor.parametrization.DateField(*ui\_name*, *name=None*, *\**, *default=None*, *flex=None*, *visible=True*, *description=None*)[](#DateField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional params: - Data: * datetime.date object * None, when empty ## DownloadButton[​](/sdk/api/parametrization/.md#_DownloadButton "Direct link to DownloadButton") * *class *viktor.parametrization.DownloadButton(*ui\_name*, *method*, *longpoll=False*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[](#DownloadButton "Link to this definition") Bases: `_ActionButton` Action button which can be pressed to download a result to a file. Example usage: ``` # in parametrization: download_btn = DownloadButton("Download file", "get_download_result", longpoll=True) # in controller: def get_download_result(self, params, **kwargs): return DownloadResult(file_content='file_content', file_name='some_file.txt') ``` * Parameters: * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – deprecated * **flex** (`int`) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** ([`Interaction`](#Interaction "viktor.parametrization.Interaction")) – Enable view interaction through this button New in v13.2.0 ## DynamicArray[​](/sdk/api/parametrization/.md#_DynamicArray "Direct link to DynamicArray") * *class *viktor.parametrization.DynamicArray(*ui\_name*, *min=None*, *max=None*, *copylast=None*, *visible=True*, *default=None*, *\**, *name=None*, *description=None*, *row\_label=None*)[](#DynamicArray "Link to this definition") Bases: `_AttrGroup` Fields can be added under a dynamic array. Currently, it is not possible to add: > * [`ActionButton`](#ActionButton "viktor.parametrization.ActionButton") > > * [`ChildEntityManager`](#ChildEntityManager "viktor.parametrization.ChildEntityManager") > > * [`DownloadButton`](#DownloadButton "viktor.parametrization.DownloadButton") > > * [`HiddenField`](#HiddenField "viktor.parametrization.HiddenField") > > * [`Image`](#Image "viktor.parametrization.Image") > > * [`OptimizationButton`](#OptimizationButton "viktor.parametrization.OptimizationButton") > > * [`SetParamsButton`](#SetParamsButton "viktor.parametrization.SetParamsButton") > > * [`Text`](#Text "viktor.parametrization.Text") Example usage: ``` layers = DynamicArray("layers") layers.depth = NumberField("depth") layers.material = OptionField("material", options=my_options) ``` * Parameters: * **ui\_name** (`str`) – This string is visible in the VIKTOR user interface. * **min** (`Union`\[`int`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Minimum number of rows in the array. * **max** (`Union`\[`int`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Maximum number of rows in the array. * **copylast** (`bool`) – Copy the last row when clicking the + button. Takes precedence over field defaults. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. * **default** (`List`\[`dict`]) – Default values of complete array. Filled before user interaction. * **name** (`str`) – The position of the parameter in the database can be specified in this argument. New in v14.18.0 * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **row\_label** (`str`) – Label to be shown at each row. The row number is appended to the label (max. 30 characters). The default values of the DynamicArray are filled when the editor is entered for the first time (just like the other fields). The fields underneath the dynamic array can also have default values. These are filled when the user adds a new row. If copylast is True, the last values are copied, and the Field defaults are ignored. ``` array = DynamicArray('Dyn Array', default=[{'a': 1, 'b': 'hello'}, {'a': 2, 'b': 'there'}]) array.a = NumberField('A', default=99) array.b = TextField('B', default='foo') ``` When first entering the editor: | A | B | | - | ----- | | 1 | hello | | 2 | there | When adding a new row: | A | B | | -- | ----- | | 1 | hello | | 2 | there | | 99 | foo | When using copylast: ``` array = DynamicArray('Dyn Array', copylast=True, default=[{'a': 1, 'b': 'hello'}]) array.a = NumberField('A', default=99) array.b = TextField('B', default='foo') ``` When first entering the editor: | A | B | | - | ----- | | 1 | hello | When adding a new row: | A | B | | - | ----- | | 1 | hello | | 1 | hello | Data: * list of dictionaries: e.g. \[{‘a’: 1, ‘b’: ‘1’}, {‘a’: 2, ‘b’: ‘2’}] * empty list if there are no ‘rows’ * when fields are empty, the corresponding empty values are used (see documentation of specific field) ## DynamicArrayConstraint[​](/sdk/api/parametrization/.md#_DynamicArrayConstraint "Direct link to DynamicArrayConstraint") * *class *viktor.parametrization.DynamicArrayConstraint(*dynamic\_array\_name*, *operand*)[](#DynamicArrayConstraint "Link to this definition") This constraint facilitates usage of other constraints within a dynamic array row. Warning The DynamicArrayConstraint can currently only be used for the **visibility** of DynamicArray components. Example usage: ``` _show_y = DynamicArrayConstraint('array_name', IsTrue(Lookup('$row.param_x'))) array = DynamicArray('My array') array.param_x = BooleanField('X') array.param_y = NumberField('Y', visible=_show_y) ``` * Parameters: * **dynamic\_array\_name** (`str`) – name of the dynamic array on which the constraint should be applied. * **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup")]) – The inputs of the operand have to be altered to access the correct row within the dynamic array. The input for a target field becomes ‘$row.{field\_name}’. ## EntityMultiSelectField[​](/sdk/api/parametrization/.md#_EntityMultiSelectField "Direct link to EntityMultiSelectField") * *class *viktor.parametrization.EntityMultiSelectField(*ui\_name*, *entity\_type\_names*, *\**, *name=None*, *visible=True*, *flex=None*, *description=None*)[](#EntityMultiSelectField "Link to this definition") Bases: `_EntityMultiField` Field to select zero or more entities of given type(s). See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. Data: > * List\[[`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")] > > * Empty list when nothing is selected ## EntityOptionField[​](/sdk/api/parametrization/.md#_EntityOptionField "Direct link to EntityOptionField") * *class *viktor.parametrization.EntityOptionField(*ui\_name*, *entity\_type\_names*, *\**, *name=None*, *visible=True*, *flex=None*, *description=None*)[](#EntityOptionField "Link to this definition") Bases: `_EntitySelectField` Field to select any entity of given type(s). Single option is not automatically pre-selected. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of type(s) within this list. Data: > * [`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity") > > * None when nothing is selected ## Field[​](/sdk/api/parametrization/.md#_Field "Direct link to Field") * *class *viktor.parametrization.Field(*\**, *ui\_name*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *flex=None*, *visible=True*, *description=None*)[](#Field "Link to this definition") Bases: `_Field` * Parameters: * **ui\_name** (`str`) – This string is visible in the VIKTOR user interface. * **name** (`str`) – The position of the parameter in the database can be specified in this argument. * **prefix** (`str`) – A prefix will be put in front of the ui\_name to provide info such as a dollar sign. Note that this function does not yet work for input fields. * **suffix** (`str`) – A suffix will be put behind the ui\_name to provide additional information such as units. * **default** (`Any`) – The value or string that is specified here is filled in as a default input. * **flex** (`int`) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). ## FileField[​](/sdk/api/parametrization/.md#_FileField "Direct link to FileField") * *class *viktor.parametrization.FileField(*ui\_name*, *file\_types=None*, *\**, *max\_size=None*, *name=None*, *visible=True*, *flex=None*, *description=None*)[](#FileField "Link to this definition") Bases: `_FileField` FileField can be used to let the user upload a file. Data: * [`FileResource`](/sdk/api/api-v1/.md#FileResource "viktor.api_v1.FileResource") * None when nothing is uploaded See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: * **file\_types** (`Sequence`\[`str`]) – Optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]) (case-insensitive). * **max\_size** (`int`) – Optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). ## FunctionLookup[​](/sdk/api/parametrization/.md#_FunctionLookup "Direct link to FunctionLookup") * *class *viktor.parametrization.FunctionLookup(*func*, *\*func\_args*, *\*\*kwargs*)[](#FunctionLookup "Link to this definition") Defines a lookup constraint where the output value is any function of several input fields. Example usages: ``` def multiply(a, b=10): return a * b field_1 = NumberField('Field 1') field_2 = NumberField('Field 2') ``` Standard usage with two field arguments: ``` field_3 = NumberField('Field 3', min=FunctionLookup(multiply, Lookup('field_1'), Lookup('field_2'))) ``` Using the default value of argument b: ``` field_4 = NumberField('Field 4', min=FunctionLookup(multiply, Lookup('field_1'))) ``` Using a constant instead of a field for argument a: ``` field_5 = NumberField('Field 5', min=FunctionLookup(multiply, 8, Lookup('field_2'))) ``` * Parameters: * **func** (`Callable`) – Python function or lambda expression. The function can have arguments with default values. * **func\_args** (`Any`) – Arguments that are provided to the function. Arguments of type Lookup / BoolOperator are evaluated first (e.g. to refer to the value of a Field in the editor, a Lookup can be used). ## GeoPointField[​](/sdk/api/parametrization/.md#_GeoPointField "Direct link to GeoPointField") * *class *viktor.parametrization.GeoPointField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[](#GeoPointField "Link to this definition") Bases: `_GeoField` GeoPointField can be used for the selection of a geographical location on a MapView/GeoJSONView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPoint`](/sdk/api/geometry/.md#GeoPoint "viktor.geometry.GeoPoint") ## GeoPolygonField[​](/sdk/api/parametrization/.md#_GeoPolygonField "Direct link to GeoPolygonField") * *class *viktor.parametrization.GeoPolygonField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[](#GeoPolygonField "Link to this definition") Bases: `_GeoField` GeoPolygonField can be used for the selection of a geographical polygon on a MapView/GeoJSONView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPolygon`](/sdk/api/geometry/.md#GeoPolygon "viktor.geometry.GeoPolygon") ## GeoPolylineField[​](/sdk/api/parametrization/.md#_GeoPolylineField "Direct link to GeoPolylineField") * *class *viktor.parametrization.GeoPolylineField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *description=None*)[](#GeoPolylineField "Link to this definition") Bases: `_GeoField` GeoPolylineField can be used for the selection of a geographical (poly)line on a MapView/GeoJSONView. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: > * [`GeoPolyline`](/sdk/api/geometry/.md#GeoPolyline "viktor.geometry.GeoPolyline") ## GeometryMultiSelectField[​](/sdk/api/parametrization/.md#_GeometryMultiSelectField "Direct link to GeometryMultiSelectField") * *class *viktor.parametrization.GeometryMultiSelectField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *flex=None*, *description=None*, *view=None*, *min\_select=1*, *max\_select=None*)[](#GeometryMultiSelectField "Link to this definition") Bases: `_GeometryField` New in v14.10.0 GeometryMultiSelectField can be used to let the user select multiple geometry objects from a View. Data: * List\[str] * Empty list when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: * **view** (`str`) – View method to which the field is connected (default: first GeometryView / IFCView). * **min\_select** (`int`) – Minimum amount of objects the user needs to select. * **max\_select** (`int`) – Maximum amount of objects the user is allowed to select. ## GeometrySelectField[​](/sdk/api/parametrization/.md#_GeometrySelectField "Direct link to GeometrySelectField") * *class *viktor.parametrization.GeometrySelectField(*ui\_name*, *\**, *name=None*, *default=None*, *visible=True*, *flex=None*, *description=None*, *view=None*)[](#GeometrySelectField "Link to this definition") Bases: `_GeometryField` New in v14.10.0 GeometrySelectField can be used to let the user select a geometry object from a View. Data: * str * None when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **view** (`str`) – View method to which the field is connected (default: first GeometryView / IFCView). ## HiddenField[​](/sdk/api/parametrization/.md#_HiddenField "Direct link to HiddenField") * *class *viktor.parametrization.HiddenField(*ui\_name*, *name=None*)[](#HiddenField "Link to this definition") The purpose of a HiddenField is to store data in the parametrization, without the necessity to show this information in the editor. Warning Do NOT store tremendous amounts of data when it is not necessary, as this will make your application slow and perhaps unstable! * Parameters: * **ui\_name** (`str`) – User-defined name of the field. * **name** (`str`) – The position of the parameter in the database can be specified in this argument. ## Image[​](/sdk/api/parametrization/.md#_Image "Direct link to Image") * *class *viktor.parametrization.Image(*path*, *\**, *align='center'*, *caption=None*, *flex=100*, *max\_width=None*, *visible=True*)[](#Image "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") New in v14.3.0 Field that can be used to display a static image. * Parameters: * **path** (`str`) – Path to the image relative to the assets directory, note that path traversal is not allowed. * **align** (`Literal`\[`'left'`, `'center'`, `'right'`]) – Image alignment (“left” | “center” | “right”). * **caption** (`str`) – Image caption (max. 200 characters). * **flex** (`int`) – Width of the image as percentage of the parametrization component. * **max\_width** (`int`) – A maximum width (pixels) can be set to ensure an image does not end up pixelated. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. ## IntegerField[​](/sdk/api/parametrization/.md#_IntegerField "Direct link to IntegerField") * *class *viktor.parametrization.IntegerField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *step=None*, *min=None*, *max=None*, *visible=True*, *flex=None*, *description=None*)[](#IntegerField "Link to this definition") Bases: [`NumberField`](#NumberField "viktor.parametrization.NumberField") See [`NumberField`](#NumberField "viktor.parametrization.NumberField") for parameters Additional parameters: - Data: * integer, when filled * None, when empty ## Interaction[​](/sdk/api/parametrization/.md#_Interaction "Direct link to Interaction") * *class *viktor.parametrization.Interaction(*view*, *selection=None*)[](#Interaction "Link to this definition") Bases: `ABC` * Parameters: * **view** (`str`) – method name of the view to be interacted with. * **selection** (`Sequence`\[`str`]) – only features/objects within selected interaction groups can be interacted with. Interaction groups can be created on the view result (e.g. `MapResult`) using ‘interaction\_groups’. None, to enable interaction with all features/objects with ‘identifier’ assigned, ignoring interaction groups (default: None). ## IsEqual[​](/sdk/api/parametrization/.md#_IsEqual "Direct link to IsEqual") * *class *viktor.parametrization.IsEqual(*operand1*, *operand2*)[](#IsEqual "Link to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate two operands to be equal. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsEqual(Lookup('field_1'), 5)) ``` * Parameters: * **operand1** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – First operand to be evaluated. * **operand2** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Second operand to be evaluated. ## IsFalse[​](/sdk/api/parametrization/.md#_IsFalse "Direct link to IsFalse") * *class *viktor.parametrization.IsFalse(*operand*)[](#IsFalse "Link to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate an operand to be False. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsFalse(Lookup('field_1'))) ``` * Parameters: **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## IsNotEqual[​](/sdk/api/parametrization/.md#_IsNotEqual "Direct link to IsNotEqual") * *class *viktor.parametrization.IsNotEqual(*operand1*, *operand2*)[](#IsNotEqual "Link to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate two operands to be NOT equal. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotEqual(Lookup('field_1'), 5)) ``` * Parameters: * **operand1** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – First operand to be evaluated. * **operand2** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Second operand to be evaluated. ## IsNotNone[​](/sdk/api/parametrization/.md#_IsNotNone "Direct link to IsNotNone") * *class *viktor.parametrization.IsNotNone(*operand*)[](#IsNotNone "Link to this definition") Bases: [`IsNotEqual`](#IsNotEqual "viktor.parametrization.IsNotEqual") Can be used to evaluate an operand to be NOT None. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotNone(Lookup('field_1'))) ``` * Parameters: **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## IsTrue[​](/sdk/api/parametrization/.md#_IsTrue "Direct link to IsTrue") * *class *viktor.parametrization.IsTrue(*operand*)[](#IsTrue "Link to this definition") Bases: [`IsEqual`](#IsEqual "viktor.parametrization.IsEqual") Can be used to evaluate an operand to be True. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsTrue(Lookup('field_1'))) ``` * Parameters: **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `Any`]) – Operand to be evaluated. ## LineBreak[​](/sdk/api/parametrization/.md#_LineBreak "Direct link to LineBreak") * *class *viktor.parametrization.LineBreak[](#LineBreak "Link to this definition") Linebreaks can be used to force input fields to be placed in the next row to obtain a cleaner looking editor. Example usage: ``` field_1 = NumberField() new_line = LineBreak() field_2 = NumberField() ``` ## Lookup[​](/sdk/api/parametrization/.md#_Lookup "Direct link to Lookup") * *class *viktor.parametrization.Lookup(*target*)[](#Lookup "Link to this definition") Can be used to lookup the value of an input field. This can be used to set visibility of a field and to set a minimum and / or maximum boundary on a number field. Example usage on visibility: ``` field_1 = BooleanField('Field 1') field_2 = NumberField('Field 2', visible=Lookup('field_1')) ``` Example usage on min / max: ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', min=Lookup('field_1')) ``` * Parameters: **target** (`str`) – Name of input field. ## MapSelectInteraction[​](/sdk/api/parametrization/.md#_MapSelectInteraction "Direct link to MapSelectInteraction") * *class *viktor.parametrization.MapSelectInteraction(*view*, *\**, *selection=None*, *min\_select=1*, *max\_select=None*)[](#MapSelectInteraction "Link to this definition") Bases: [`Interaction`](#Interaction "viktor.parametrization.Interaction") New in v13.2.0 Interaction for the selection of feature(s) in a map view. See [`Interaction`](#Interaction "viktor.parametrization.Interaction") for parameters. Additional parameters: * Parameters: * **min\_select** (`int`) – minimum number of features a user must select (>=1). * **max\_select** (`int`) – maximum number of features a user may select. None for no limit (default: None). Example: ``` button = ActionButton(..., interaction=MapSelectInteraction('my_map_view', selection=['points'])) ``` ## MultiFileField[​](/sdk/api/parametrization/.md#_MultiFileField "Direct link to MultiFileField") * *class *viktor.parametrization.MultiFileField(*ui\_name*, *file\_types=None*, *\**, *max\_size=None*, *name=None*, *visible=True*, *flex=None*, *description=None*)[](#MultiFileField "Link to this definition") Bases: `_FileField` MultiFileField can be used to let the user upload multiple files. Data: * List\[[`FileResource`](/sdk/api/api-v1/.md#FileResource "viktor.api_v1.FileResource")] * Empty list when nothing is uploaded See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: * **file\_types** (`Sequence`\[`str`]) – Optional restriction on file type(s) (e.g. \[‘.png’, ‘.jpg’, ‘.jpeg’]) (case-insensitive). * **max\_size** (`int`) – Optional restriction on file size in bytes (e.g. 10\_000\_000 = 10 MB). ## MultiSelectField[​](/sdk/api/parametrization/.md#_MultiSelectField "Direct link to MultiSelectField") * *class *viktor.parametrization.MultiSelectField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*)[](#MultiSelectField "Link to this definition") Bases: `_SelectField` Present dropdown list with options for user, in which multiple options can be selected. If there is only one option, this option will not be automatically selected. Example usage: ``` field = MultiSelectField('Available options', options=['Option 1', 'Option 2'], default=['Option 1', 'Option 2']) ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = MultiSelectField('Available options', options=_options, default=['option_1', 'option_2']) ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. Data: * empty list if no options are selected * list with values of [`OptionListElements`](#OptionListElement "viktor.parametrization.OptionListElement"): integer, float or string ## MultipleSelectField[​](/sdk/api/parametrization/.md#_MultipleSelectField "Direct link to MultipleSelectField") * viktor.parametrization.MultipleSelectField[](#MultipleSelectField "Link to this definition") alias of [`MultiSelectField`](#MultiSelectField "viktor.parametrization.MultiSelectField") ## Not[​](/sdk/api/parametrization/.md#_Not "Direct link to Not") * *class *viktor.parametrization.Not(*operand*)[](#Not "Link to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate an operand to be False. ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=Not(IsEqual(Lookup('field_1'), 5))) ``` Note, above construction is the same as: ``` field_1 = NumberField('Field 1') field_2 = NumberField('Field 2', visible=IsNotEqual(Lookup('field_1'), 5)) ``` * Parameters: **operand** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operand to be evaluated. ## NumberField[​](/sdk/api/parametrization/.md#_NumberField "Direct link to NumberField") * *class *viktor.parametrization.NumberField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *step=None*, *min=None*, *max=None*, *num\_decimals=None*, *visible=True*, *flex=None*, *variant='standard'*, *description=None*)[](#NumberField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: * **step** (`float`) – Stepping interval when clicking up and down spinner buttons * **min** (`Union`\[`float`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Specifies a minimum value constraint. * **max** (`Union`\[`float`, [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Specifies a maximum value constraint. * **num\_decimals** (`int`) – Specifies the number of decimals. * **variant** (`str`) – Visually alter the input field. Possible options: * ’standard’: default [![/\_images/variant\_NumberField\_standard.png](/_images/variant_NumberField_standard.png)](/_images/variant_NumberField_standard.png) * ’slider’: slider (ignored in Table) [![/\_images/variant\_NumberField\_slider.png](/_images/variant_NumberField_slider.png)](/_images/variant_NumberField_slider.png) Data: * integer or float * None, when empty ## OptimiseButton[​](/sdk/api/parametrization/.md#_OptimiseButton "Direct link to OptimiseButton") * viktor.parametrization.OptimiseButton[](#OptimiseButton "Link to this definition") alias of [`OptimizationButton`](#OptimizationButton "viktor.parametrization.OptimizationButton") ## OptimizationButton[​](/sdk/api/parametrization/.md#_OptimizationButton "Direct link to OptimizationButton") * *class *viktor.parametrization.OptimizationButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[](#OptimizationButton "Link to this definition") Bases: `_ActionButton` Action button which can be pressed to perform an optimization routine. Example usage: ``` # in parametrization: optimize_btn = OptimizationButton("Optimization", "get_optimal_result", longpoll=True) # in controller: def get_optimal_result(self, params, **kwargs): # specific optimization routine ... return OptimizationResult(results) ``` * Parameters: * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – deprecated * **flex** (`int`) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** ([`Interaction`](#Interaction "viktor.parametrization.Interaction")) – Enable view interaction through this button New in v13.2.0 ## OptionField[​](/sdk/api/parametrization/.md#_OptionField "Direct link to OptionField") * *class *viktor.parametrization.OptionField(*ui\_name*, *options*, *name=None*, *prefix=None*, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *\**, *description=None*, *variant='standard'*, *autoselect\_single\_option=False*)[](#OptionField "Link to this definition") Bases: `_SelectField` Present dropdown list with options for user. If there is only one option, this option is automatically selected. If you want to enable multiple options to be select, use a MultiSelectField. Example usage: ``` field = OptionField('Available options', options=['Option 1', 'Option 2'], default='Option 1') ``` Or use an OptionListElement to obtain a value in the params which differs from the interface name: ``` _options = [OptionListElement('option_1', 'Option 1'), OptionListElement('option_2', 'Option 2')] field = OptionField('Available options', options=_options, default='option_1') ``` See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: * **options** (`Union`\[`List`\[`Union`\[`float`, `str`, [`OptionListElement`](#OptionListElement "viktor.parametrization.OptionListElement")]], `Callable`]) – Options should be defined as a list of numbers, strings, or OptionListElement objects. * **variant** (`str`) – Visually alter the input field. Possible options: * ’standard’: default ![/\_images/variant\_OptionField\_standard.png](/_images/variant_OptionField_standard.png) * ’radio’: radio buttons, vertically positioned (ignored in Table) ![/\_images/variant\_OptionField\_radio.png](/_images/variant_OptionField_radio.png) * ’radio-inline’: radio buttons, horizontally positioned (ignored in Table) ![/\_images/variant\_OptionField\_radio-inline.png](/_images/variant_OptionField_radio-inline.png) * **autoselect\_single\_option** (`bool`) – True to always automatically select when a single option is provided. This holds for static options as well as dynamic options (see examples below). When autoselect\_single\_option=False (default), expect the following behavior: | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚪ A | | options dynamically change to multiple options | ⚪ A, ⚪ B, ⚪ C | | user selects option B | ⚪ A, ⚫ B, ⚪ C | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | When autoselect\_single\_option=True, expect the following behavior: Warning Keep in mind that in case of dynamic options and the possibility of having a single option, the (automatically) selected option might be changed without the user being aware of this! | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚫ A | | options dynamically change to multiple options | ⚫ A, ⚪ B, ⚪ C | | options dynamically change to single option B (user might not be aware!) | ⚫ B | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | Data: * type of selected option: integer, float or string * None when nothing is selected ## OptionListElement[​](/sdk/api/parametrization/.md#_OptionListElement "Direct link to OptionListElement") * *class *viktor.parametrization.OptionListElement(*value*, *label=None*, *visible=True*)[](#OptionListElement "Link to this definition") Create an option which can be used inside an OptionField. Example: value only with type str ``` >>> option = OptionListElement('apple') >>> option.value 'apple' >>> option.label 'apple' ``` Example: value only with type int ``` >>> option = OptionListElement(33) >>> option.value 33 >>> option.label '33' ``` Example: value and label ``` >>> option = OptionListElement('apple', 'Delicious apple') >>> option.value 'apple' >>> option.label 'Delicious apple' ``` * Parameters: * **value** (`Union`\[`float`, `str`]) – The identifier which is used to store and retrieve chosen option. * **label** (`str`) – The identifier which is shown to the user. If no label is specified, the value identifier is used, cast to a string. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup")]) – Determines whether option is visible. Will mostly be used with Constraint. - *property *label*: str*[](#OptionListElement.label "Link to this definition") * *property *value*: float | str*[](#OptionListElement.value "Link to this definition") ## Or[​](/sdk/api/parametrization/.md#_Or "Direct link to Or") * *class *viktor.parametrization.Or(*\*operands*)[](#Or "Link to this definition") Bases: [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator") Can be used to evaluate if at least one operand is True. ``` field_1 = NumberField('Field 1') field_2 = BooleanField('Field 2') field_3 = NumberField('Field 3', visible=Or(IsEqual(Lookup('field_1'), 5), Lookup('field_2'))) ``` * Parameters: **operands** (`Union`\[[`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), `bool`]) – Operands to be evaluated. ## OutputField[​](/sdk/api/parametrization/.md#_OutputField "Direct link to OutputField") * *class *viktor.parametrization.OutputField(*ui\_name*, *\**, *value=None*, *prefix=None*, *suffix=None*, *visible=True*, *flex=None*, *description=None*)[](#OutputField "Link to this definition") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **value** (`Union`\[`float`, `str`, `bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Value to be presented in the interface (can be hard-coded or calculated). Example: Point to another parameter ``` field_1 = NumberField() field_2 = OutputField(ui_name, value=Lookup("field_1")) ``` Example: Compute output value using callback function ``` def get_value(params, entity_id, **kwargs): # app specific logic value = ... return value field = OutputField(ui_name, value=get_value) ``` Data: * OutputFields are not present in the params ## Page[​](/sdk/api/parametrization/.md#_Page "Direct link to Page") * *class *viktor.parametrization.Page(*title*, *\**, *views=None*, *description=None*, *visible=True*, *width=None*)[](#Page "Link to this definition") Bases: `_Group` A Page can be used to group certain inputs (e.g. fields) with certain outputs (views). For example: ``` class Parametrization(ViktorParametrization): page_1 = Page('Page 1') # no views page_1.field_1 = NumberField(...) ... page_2 = Page('Page 2', views='view_data') # single view page_2.field_1 = NumberField(...) ... page_3 = Page('Page 3', views=['view_map', 'view_data']) # multiple views page_3.field_1 = NumberField(...) ... class Controller(ViktorController): ... @DataView(...) # visible on "Page 2" and "Page 3" def view_data(self, params, **kwargs): ... @MapView(...) # only visible on "Page 3" def view_map(self, params, **kwargs): ... ``` **(new in v14.7.0)** Adjust the width of a specific page: ``` class Parametrization(ViktorParametrization): page_1 = Page('Page 1', width=30) ... page_2 = Page('Page 2', width=70) ... ``` * Parameters: * **title** (`str`) – Title which is shown in the interface. * **views** (`Union`\[`str`, `Sequence`\[`str`]]) – View method(s) that should be visible in this page, e.g. ‘my\_view’ for a single view, or \[‘my\_data\_view’, ‘my\_geometry\_view’, …] for multiple views (default: None). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. New in v14.7.0 * **width** (`int`) – Sets the width of the parametrization side of this page as percentage of the complete width of the editor (input + output). The value should be an integer between 20 and 80. If a width is defined both on the Parametrization and the Page, the Page takes precedence. New in v14.7.0 ## Parametrization[​](/sdk/api/parametrization/.md#_Parametrization "Direct link to Parametrization") * *class *viktor.parametrization.Parametrization(*\**, *width=None*)[](#Parametrization "Link to this definition") The Parametrization class functions as the basis of the parameter set of an entity. A simple parametrization looks as follows: ``` from viktor.parametrization import Parametrization, TextField, NumberField class ExampleParametrization(Parametrization): input_1 = TextField('This is a text field') input_2 = NumberField('This is a number field') ``` In the VIKTOR user interface, this will be visualized as: [![/\_images/editor-single-layered.png](/_images/editor-single-layered.png)](/_images/editor-single-layered.png) In some cases, the parametrization becomes quite big which requires a more structured layout. This can be achieved by making use of a [`Tab`](#Tab "viktor.parametrization.Tab") and [`Section`](#Section "viktor.parametrization.Section") object, which represent a tab and collapsible section in the interface respectively. A 2-layered structure using Tab objects looks like this: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Tab class ExampleParametrization(Parametrization): tab_1 = Tab('Tab 1') tab_1.input_1 = TextField('This is a text field') tab_1.input_2 = NumberField('This is a number field') tab_2 = Tab('Tab 2') tab_2.input_1 = TextField('Text field in Tab 2') tab_2.input_2 = NumberField('Number field in Tab 2') ``` [![/\_images/editor-two-layered-tabs.png](/_images/editor-two-layered-tabs.png)](/_images/editor-two-layered-tabs.png) Using Section objects results in the following: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Section class ExampleParametrization(Parametrization): section_1 = Section('Section 1') section_1.input_1 = TextField('This is a text field') section_1.input_2 = NumberField('This is a number field') section_2 = Section('Section 2') section_2.input_1 = TextField('Text field in Section 2') section_2.input_2 = NumberField('Number field in Section 2') ``` [![/\_images/editor-two-layered-sections.png](/_images/editor-two-layered-sections.png)](/_images/editor-two-layered-sections.png) A parametrization with a maximum depth of 3 layers consists of Tab, Section, and Field objects: ``` from viktor.parametrization import Parametrization, TextField, NumberField, Tab, Section class ExampleParametrization(Parametrization): tab_1 = Tab('Tab 1') tab_1.section_1 = Section('Section 1') tab_1.section_1.input_1 = TextField('This is a text field') tab_1.section_1.input_2 = NumberField('This is a number field') tab_1.section_2 = Section('Section 2') ... tab_2 = Tab('Tab 2') ... ``` [![/\_images/editor-three-layered.png](/_images/editor-three-layered.png)](/_images/editor-three-layered.png) Every class attribute is treated as a tab, section, or field. If you want to use a variable inside a field, you can either define it outside of the class or as class attribute starting with an underscore: ``` OPTIONS = ['Option 1', 'Option 2'] class ExampleParametrization(Parametrization): _options = ['Option 3', 'Option 4'] field_1 = OptionField('Choose option', options=OPTIONS) field_2 = OptionField('Choose option', options=_options) ``` * Parameters: **width** (`int`) – Sets the width of the parametrization side as percentage of the complete width of the editor (input + output). The value should be an integer between 20 and 80 (default: 40). If a width is defined both on the Parametrization and a Page / Step, the Page / Step takes precedence. ## RowLookup[​](/sdk/api/parametrization/.md#_RowLookup "Direct link to RowLookup") * *class *viktor.parametrization.RowLookup(*target*)[](#RowLookup "Link to this definition") Can be used to lookup the value of an input field within the same row of the dynamic array. This can be used to set the visibility of a field and a minimum and / or maximum boundary on a number field. Example usage: ``` array = DynamicArray('Array') array.field_1 = NumberField('Field 1') array.field_2 = NumberField('Field 2', min=RowLookup('field_1')) ``` For more complex constructions, it is advised to use a callback function. * Parameters: **target** (`str`) – Name of input field within the dynamic array. ## Section[​](/sdk/api/parametrization/.md#_Section "Direct link to Section") * *class *viktor.parametrization.Section(*title*, *\**, *description=None*, *initially\_expanded=None*, *visible=True*)[](#Section "Link to this definition") Bases: `_Group` * Parameters: * **title** (`str`) – Title which is shown in the interface. * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **initially\_expanded** (`Optional`\[`bool`]) – Whether the section should be expanded on editor entry New in v14.21.0 * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. New in v14.7.0 ## SetParamsButton[​](/sdk/api/parametrization/.md#_SetParamsButton "Direct link to SetParamsButton") * *class *viktor.parametrization.SetParamsButton(*ui\_name*, *method*, *longpoll=True*, *\**, *visible=True*, *always\_available=False*, *flex=None*, *description=None*, *interaction=None*)[](#SetParamsButton "Link to this definition") Bases: `_ActionButton` Action button which can be pressed to perform an analysis and override current input fields. Example usage: ``` # in parametrization: set_params_btn = SetParamsButton("Set params", "set_param_a", longpoll=True) # in controller: def set_param_a(self, params, **kwargs): # get updated input parameters ... return SetParamsResult(updated_parameter_set) ``` * Parameters: * **ui\_name** (`str`) – Name which is visible in the VIKTOR user interface. * **method** (`str`) – Name of the download method that is defined in the controller * **longpoll** (`bool`) – Set this option to True if the process that is invoked by the action button cannot be completed within the timeout limit. * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), [`DynamicArrayConstraint`](#DynamicArrayConstraint "viktor.parametrization.DynamicArrayConstraint"), [`RowLookup`](#RowLookup "viktor.parametrization.RowLookup"), `Callable`]) – Visibility of the button. A Constraint can be used when the visibility depends on other input fields. * **always\_available** (`bool`) – deprecated * **flex** (`int`) – The width of the field can be altered via this argument. value between 0 and 100 (default=33). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **interaction** ([`Interaction`](#Interaction "viktor.parametrization.Interaction")) – Enable view interaction through this button New in v13.2.0 ## SiblingEntityMultiSelectField[​](/sdk/api/parametrization/.md#_SiblingEntityMultiSelectField "Direct link to SiblingEntityMultiSelectField") * *class *viktor.parametrization.SiblingEntityMultiSelectField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[](#SiblingEntityMultiSelectField "Link to this definition") Bases: `_EntityMultiSelectField` Field to select zero or more sibling entities of given type(s). Up to 5000 entities may be visualized in the dropdown in the interface. Data: * List\[[`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity")] * Empty list when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. None = all entities. ## SiblingEntityOptionField[​](/sdk/api/parametrization/.md#_SiblingEntityOptionField "Direct link to SiblingEntityOptionField") * *class *viktor.parametrization.SiblingEntityOptionField(*ui\_name*, *name=None*, *visible=True*, *flex=None*, *\**, *entity\_type\_names=None*, *description=None*)[](#SiblingEntityOptionField "Link to this definition") Bases: `_EntityOptionField` Field to select a sibling entity of given type(s). Single option is not automatically pre-selected. Data: * [`Entity`](/sdk/api/api-v1/.md#Entity "viktor.api_v1.Entity") * None when nothing is selected See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **entity\_type\_names** (`List`\[`str`]) – User will only be able to select entities of types within this list. None = all entities. ## Step[​](/sdk/api/parametrization/.md#_Step "Direct link to Step") * *class *viktor.parametrization.Step(*title*, *\**, *views=None*, *description=None*, *enabled=True*, *previous\_label=None*, *next\_label=None*, *on\_next=None*, *width=None*)[](#Step "Link to this definition") Bases: [`Page`](#Page "viktor.parametrization.Page") A Step can be used to group certain inputs (e.g. fields) with certain outputs (views) within a predefined order, browsable through a previous and next button. For example: ``` class Parametrization(ViktorParametrization): step_1 = Step('Step 1') # no views step_1.field_1 = NumberField(...) ... step_2 = Step('Step 2', views='view_data') # single view step_2.field_1 = NumberField(...) ... step_3 = Step('Step 3', views=['view_map', 'view_data']) # multiple views step_3.field_1 = NumberField(...) ... class Controller(ViktorController): ... @DataView(...) # visible on "Step 2" and "Step 3" def view_data(self, params, **kwargs): ... @MapView(...) # only visible on "Step 3" def view_map(self, params, **kwargs): ... ``` **(new in v13.7.0)** When implementing the on\_next argument, the corresponding function is called when a user clicks the ‘next’ button to move to the next step. This can be used to, for example, validate the input of the current active step: ``` def validate_step_1(params, **kwargs): if params.step_1.field_z <= params.step_1.field_x + params.step_1.field_y: raise UserError(...) class Parametrization(ViktorParametrization): step_1 = Step('Step 1', on_next=validate_step_1) ... ``` **(new in v14.7.0)** Adjust the width of a specific step: ``` class Parametrization(ViktorParametrization): step_1 = Step('Step 1', width=30) ... step_2 = Step('Step 2', width=70) ... ``` **(new in v14.11.0)** Disable steps: Disabled steps are skipped, you will go straight from Step 1 to Step 3 if Step 2 is disabled. ``` def is_step_enabled(params, **kwargs): return params.step_1.field_z <= params.step_1.field_x + params.step_1.field_y class Parametrization(ViktorParametrization): step_1 = Step('Step 1', enabled=True) ... step_2 = Step('Step 2', enabled=is_step_enabled) ... step_3 = Step('Step 3') # enabled=True by default ... ``` * Parameters: * **title** (`str`) – Title which is shown in the interface. * **views** (`Union`\[`str`, `Sequence`\[`str`]]) – View method(s) that should be visible in this step, e.g. ‘my\_view’ for a single view, or \[‘my\_data\_view’, ‘my\_geometry\_view’, …] for multiple views (default: None). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **enabled** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used to disable (skip) steps, may depend on other input fields. New in v14.11.0 * **previous\_label** (`str`) – Text to be shown on the previous button (ignored for first step, max. 30 characters). * **next\_label** (`str`) – Text to be shown on the next button (ignored for last step, max. 30 characters). * **on\_next** (`Callable`) – Callback function which is triggered when the user moves to the next step. New in v13.7.0 * **width** (`int`) – Sets the width of the parametrization side of this step as percentage of the complete width of the editor (input + output). The value should be an integer between 20 and 80. If a width is defined both on the Parametrization and the Step, the Step takes precedence. New in v14.7.0 ## Tab[​](/sdk/api/parametrization/.md#_Tab "Direct link to Tab") * *class *viktor.parametrization.Tab(*title*, *\**, *description=None*, *visible=True*)[](#Tab "Link to this definition") Bases: `_Group` * Parameters: * **title** (`str`) – Title which is shown in the interface. * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **visible** (`Union`\[`bool`, [`BoolOperator`](#BoolOperator "viktor.parametrization.BoolOperator"), [`Lookup`](#Lookup "viktor.parametrization.Lookup"), [`FunctionLookup`](#FunctionLookup "viktor.parametrization.FunctionLookup"), `Callable`]) – Can be used when the visibility depends on other input fields. New in v14.7.0 ## Table[​](/sdk/api/parametrization/.md#_Table "Direct link to Table") * *class *viktor.parametrization.Table(*ui\_name*, *name=None*, *\**, *default=None*, *visible=True*, *description=None*)[](#Table "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field"), `_AttrGroup` Example usage: ``` table = Table('Input table') table.name = TextField('Planet') table.period = NumberField('Orbital period', suffix='years') table.eccentricity = NumberField('Orbital eccentricity', num_decimals=3) ``` A table can also be created with default content. Assume the columns as defined above: ``` _default_content = [ {'name': 'Earth', 'period': 1, 'eccentricity': 0.017}, {'name': 'Mars', 'period': 1.88, 'eccentricity': 0.093}, {'name': 'Saturn', 'period': 29.42, 'eccentricity': 0.054}, ] table = Table('Input table', default=_default_content) ... ``` Supported fields are: > * [`TextField`](#TextField "viktor.parametrization.TextField") > > * [`NumberField`](#NumberField "viktor.parametrization.NumberField") > > * [`IntegerField`](#IntegerField "viktor.parametrization.IntegerField") > > * [`BooleanField`](#BooleanField "viktor.parametrization.BooleanField") > > * [`OptionField`](#OptionField "viktor.parametrization.OptionField") > > * [`AutocompleteField`](#AutocompleteField "viktor.parametrization.AutocompleteField") Note, specifying a default and / or constraints on a field within a table is not supported. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: * list of dictionaries * empty list if there are no rows * when fields are empty, the corresponding empty values are used (see documentation of specific field) ## TableInput[​](/sdk/api/parametrization/.md#_TableInput "Direct link to TableInput") * viktor.parametrization.TableInput[](#TableInput "Link to this definition") alias of [`Table`](#Table "viktor.parametrization.Table") ## Text[​](/sdk/api/parametrization/.md#_Text "Direct link to Text") * *class *viktor.parametrization.Text(*value*, *\**, *visible=True*, *flex=100*)[](#Text "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") Field that can be used to display a static text (max. 1800 characters). It is not included in the params. Changed in v13.3.0: character limit has been increased from 500 to 1800. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: * Parameters: **value** (`str`) – Text to be shown ## TextAreaField[​](/sdk/api/parametrization/.md#_TextAreaField "Direct link to TextAreaField") * *class *viktor.parametrization.TextAreaField(*ui\_name*, *name=None*, *default=None*, *visible=True*, *flex=100*, *\**, *description=None*)[](#TextAreaField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") Multiple lines textual input. For one line use TextField. See [`Field`](#Field "viktor.parametrization.Field") for parameters. Data: * string * empty string, when empty ## TextAreaInput[​](/sdk/api/parametrization/.md#_TextAreaInput "Direct link to TextAreaInput") * viktor.parametrization.TextAreaInput[](#TextAreaInput "Link to this definition") alias of [`TextAreaField`](#TextAreaField "viktor.parametrization.TextAreaField") ## TextField[​](/sdk/api/parametrization/.md#_TextField "Direct link to TextField") * *class *viktor.parametrization.TextField(*ui\_name*, *name=None*, *prefix=None*, *\**, *suffix=None*, *default=None*, *visible=True*, *flex=None*, *description=None*)[](#TextField "Link to this definition") Bases: [`Field`](#Field "viktor.parametrization.Field") See [`Field`](#Field "viktor.parametrization.Field") for parameters. Additional parameters: - Data: * string * empty string, when empty ## ToggleButton[​](/sdk/api/parametrization/.md#_ToggleButton "Direct link to ToggleButton") * viktor.parametrization.ToggleButton[](#ToggleButton "Link to this definition") alias of [`BooleanField`](#BooleanField "viktor.parametrization.BooleanField") ## ViktorParametrization[​](/sdk/api/parametrization/.md#_ViktorParametrization "Direct link to ViktorParametrization") * viktor.parametrization.ViktorParametrization[](#ViktorParametrization "Link to this definition") alias of [`Parametrization`](#Parametrization "viktor.parametrization.Parametrization") --- # viktor.result ## ChatResult[​](/sdk/api/result/.md#_ChatResult "Direct link to ChatResult") * *class *viktor.result.ChatResult(*conversation*, *response*)[](#ChatResult "Link to this definition") Bases: `_ButtonResult` Container for the output of a [`Chat`](/sdk/api/parametrization/.md#Chat "viktor.parametrization.Chat"). ``` ChatResult(conversation=my_conversation, response="The LLM response") ``` * Parameters: * **conversation** ([`ChatConversation`](/sdk/api/api-v1/.md#ChatConversation "viktor.api_v1.ChatConversation")) – The conversation that has to be updated. * **response** (`Union`\[`str`, `Iterable`\[`str`]]) – The response that the conversation has to be updated with. ## DownloadResult[​](/sdk/api/result/.md#_DownloadResult "Direct link to DownloadResult") * *class *viktor.result.DownloadResult(*file\_content=None*, *file\_name=None*, *encoding='utf-8'*, *\**, *zipped\_files=None*)[](#DownloadResult "Link to this definition") Bases: `_ButtonResult` Container for the output of a [`DownloadButton`](/sdk/api/parametrization/.md#DownloadButton "viktor.parametrization.DownloadButton"). Download of single file: ``` DownloadResult(file_content=my_file, file_name="my_file.txt") ``` Download of multiple files bundled in a zip-file: ``` DownloadResult(zipped_files={'my_file_1.txt': my_file_1, 'my_file_2.txt': my_file_2}, file_name="my_file.zip") ``` * Parameters: * **file\_content** (`Union`\[`str`, `bytes`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `StringIO`, `BytesIO`]) – if type str and encoding is not utf-8, specify in additional argument. Mutual exclusive with ‘zipped\_files’. * **file\_name** (`str`) – name (including extension) to be used for download. In case of ‘zipped\_files’, this is the name of the zip-file. May only consist of alphanumeric characters, underscores and dots (any other characters are converted to an underscore). * **encoding** (`str`) – optional argument to specify file encoding when file\_content is provided with type str * **zipped\_files** (`dict`\[`str`, `Union`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), `StringIO`, `BytesIO`]]) – a dict of {file name: content} to be bundled in a zip-file with file-name ‘file\_name’. Mutual exclusive with ‘file\_content’. ## OptimisationResult[​](/sdk/api/result/.md#_OptimisationResult "Direct link to OptimisationResult") * viktor.result.OptimisationResult[](#OptimisationResult "Link to this definition") alias of [`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult") ## OptimisationResultElement[​](/sdk/api/result/.md#_OptimisationResultElement "Direct link to OptimisationResultElement") * viktor.result.OptimisationResultElement[](#OptimisationResultElement "Link to this definition") alias of [`OptimizationResultElement`](#OptimizationResultElement "viktor.result.OptimizationResultElement") ## OptimizationResult[​](/sdk/api/result/.md#_OptimizationResult "Direct link to OptimizationResult") * *class *viktor.result.OptimizationResult(*results*, *result\_column\_names\_input=None*, *output\_headers=None*, *image=None*)[](#OptimizationResult "Link to this definition") Bases: `_ButtonResult` Container for the output of an [`OptimizationButton`](/sdk/api/parametrization/.md#OptimizationButton "viktor.parametrization.OptimizationButton"). * Parameters: * **results** (`list`\[[`OptimizationResultElement`](#OptimizationResultElement "viktor.result.OptimizationResultElement")]) – list of results, order is kept in user interface. * **result\_column\_names\_input** (`list`\[`str`]) – specifies which input parameters should be shown the table. The parametrization class defined the label which is shown * **output\_headers** (`dict`) – specifies which results should be shown in the results table. Key should match the key of the analysis\_result inside each result. Value is the corresponding label which the end user sees. * **image** ([`ImageResult`](/sdk/api/views/.md#ImageResult "viktor.views.ImageResult")) – image which is shown next to the results. Could be JPG, PNG or SVG. Example: ``` params1 = {'tab': {'section': {'field1': 'a', 'field2': 5}}} params2 = {'tab': {'section': {'field1': 'b', 'field2': 8}}} analysis1 = {'result1': 10, 'result2': 20} analysis2 = {'result1': 100, 'result2': 150} results = [ OptimizationResultElement(params1, analysis1), OptimizationResultElement(params2, analysis2), ] OptimizationResult( results, result_column_names_input=['tab.section.field1'], output_headers={'result1': 'Result 1'} ) ``` This renders as the following table for the end-user: | # | Field 1 | Result 1 | | - | ------- | -------- | | 1 | a | 10 | | 2 | b | 100 | ## OptimizationResultElement[​](/sdk/api/result/.md#_OptimizationResultElement "Direct link to OptimizationResultElement") * *class *viktor.result.OptimizationResultElement(*params*, *analysis\_result=None*)[](#OptimizationResultElement "Link to this definition") * Parameters: * **params** (`Union`\[`dict`, `Munch`]) – a complete parameter set * **analysis\_result** (`dict`) – the accompanying results. For an example, see [`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult") ## SetParametersResult[​](/sdk/api/result/.md#_SetParametersResult "Direct link to SetParametersResult") * viktor.result.SetParametersResult[](#SetParametersResult "Link to this definition") alias of [`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult") ## SetParamsResult[​](/sdk/api/result/.md#_SetParamsResult "Direct link to SetParamsResult") * *class *viktor.result.SetParamsResult(*params*)[](#SetParamsResult "Link to this definition") Bases: `_ButtonResult` Container for the output of a [`SetParamsButton`](/sdk/api/parametrization/.md#SetParamsButton "viktor.parametrization.SetParamsButton"). In order to set the content of the field Tab 1 > Section 1 > NumberField 1 to 1234 use the format: ``` SetParamsResult({ "tab_1": { "section_1": { "numberfield_1": 1234 } } }) ``` To clear one or more fields one has to explicitly set the params to the empty state. Note that the empty value is different for each field and can be found in their docs: ``` SetParamsResult({ "tab_1": { "section_1": { "numberfield_1": None, } } }) ``` * Parameters: **params** (`Union`\[`dict`, `Munch`]) – the params you want to set. If a param is not specified, the value will be kept as is. - get(*key*)[](#SetParamsResult.get "Link to this definition") * Return type: `Any` ## ViktorResult[​](/sdk/api/result/.md#_ViktorResult "Direct link to ViktorResult") * *class *viktor.result.ViktorResult(*optimisation\_result=None*, *set\_parameters\_result=None*, *download\_result=None*, *\**, *optimization\_result=None*, *set\_params\_result=None*)[](#ViktorResult "Link to this definition") Bases: `_SerializableObject` Standard output object of a ViktorController method, which serialises and combines several individual results into the standard automation output. All inputs are optional to facilitate many combinations of results where needed in the future. Currently, the serialisation only accounts for the following (backward compatible) combinations: * a single optimization result * a single set\_params result * a single download result - Parameters: * **optimisation\_result** ([`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult")) – alias for optimization\_result * **set\_parameters\_result** ([`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult")) – alias for set\_params\_result * **download\_result** ([`DownloadResult`](#DownloadResult "viktor.result.DownloadResult")) – DownloadResult object * **optimization\_result** ([`OptimizationResult`](#OptimizationResult "viktor.result.OptimizationResult")) – OptimizationResult object * **set\_params\_result** ([`SetParamsResult`](#SetParamsResult "viktor.result.SetParamsResult")) – SetParamsResult object --- # viktor.testing ## MockedEntity[​](/sdk/api/testing/.md#_MockedEntity "Direct link to MockedEntity") * *class *viktor.testing.MockedEntity(*\**, *entity\_id=1*, *name='Mocked Entity'*, *entity\_type=None*, *last\_saved\_params=None*, *last\_saved\_summary=None*, *get\_file=None*, *parent=None*, *children=None*, *siblings=None*, *revisions=None*, *invalid=False*, *workspace\_id=1*)[](#MockedEntity "Link to this definition") New in v13.3.0 To mock an Entity. All arguments are optional: instantiating MockedEntity without parameters returns a default MockedEntity. Example: ``` from viktor.testing import MockedEntity, MockedEntityRevision mocked_entity = MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ``` last\_saved\_params can be passed from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` import viktor as vkt from viktor.testing import MockedEntity, MockedEntityRevision, MockedFileResource, mock_params from app.my_entity.controller import MyEntityController json_file = vkt.File.from_path("path to JSON file") params = mock_params(json_file, MyEntityController.parametrization) mocked_entity = MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ``` * Parameters: * **entity\_id** (`int`) – Return value of Entity.id. * **name** (`str`) – Return value of Entity.name. * **entity\_type** ([`MockedEntityType`](#MockedEntityType "viktor.testing.MockedEntityType")) – Return value of Entity.entity\_type. None for default MockedEntityType. * **last\_saved\_params** (`Union`\[`dict`, `Munch`]) – Return value of Entity.last\_saved\_params(). Must be the deserialized params (see [`mock_params()`](#mock_params "viktor.testing.mock_params")). None to simulate an entity without params. * **last\_saved\_summary** (`dict`) – Return value of Entity.last\_saved\_summary(). None to simulate an entity without summary. * **get\_file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Return value of Entity.get\_file. None to simulate an entity without file. * **parent** ([`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")) – Return value of Entity.parent. None to simulate an entity without parent. * **children** (`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of Entity.children. None to simulate an entity without children. * **siblings** (`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of Entity.siblings. None to simulate an entity without siblings. * **revisions** (`Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")]) – Return value of Entity.revisions. None to simulate an entity without revisions. * **invalid** (`bool`) – Set to True to simulate failing API calls on this Entity. - children(*\*args*, *entity\_type\_names=None*, *\*\*kwargs*)[](#MockedEntity.children "Link to this definition") * Return type: [`MockedEntityList`](#MockedEntityList "viktor.testing.MockedEntityList") * create\_child(*entity\_type\_name*, *name*, *\*args*, *params=None*, *\*\*kwargs*)[](#MockedEntity.create_child "Link to this definition") * Return type: [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") - delete(*\*args*, *\*\*kwargs*)[](#MockedEntity.delete "Link to this definition") * Return type: `None` * *property *entity\_type*: [MockedEntityType](#MockedEntityType "viktor.testing.MockedEntityType")*[](#MockedEntity.entity_type "Link to this definition") - get\_file(*\*args*, *\*\*kwargs*)[](#MockedEntity.get_file "Link to this definition") * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * *property *id*: int*[](#MockedEntity.id "Link to this definition") - *property *last\_saved\_params*: munch.Munch*[](#MockedEntity.last_saved_params "Link to this definition") * *property *last\_saved\_summary*: munch.Munch*[](#MockedEntity.last_saved_summary "Link to this definition") - *property *name*: str*[](#MockedEntity.name "Link to this definition") * parent(*\*args*, *\*\*kwargs*)[](#MockedEntity.parent "Link to this definition") * Return type: [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") - rename(*name*, *\*args*, *\*\*kwargs*)[](#MockedEntity.rename "Link to this definition") * Return type: [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") * revisions(*\*args*, *\*\*kwargs*)[](#MockedEntity.revisions "Link to this definition") * Return type: `List`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")] - set\_params(*params*, *\*args*, *\*\*kwargs*)[](#MockedEntity.set_params "Link to this definition") * Return type: [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity") * siblings(*\*args*, *entity\_type\_names=None*, *\*\*kwargs*)[](#MockedEntity.siblings "Link to this definition") * Return type: [`MockedEntityList`](#MockedEntityList "viktor.testing.MockedEntityList") ## MockedEntityList[​](/sdk/api/testing/.md#_MockedEntityList "Direct link to MockedEntityList") * *class *viktor.testing.MockedEntityList(*entities*, *\**, *error=None*)[](#MockedEntityList "Link to this definition") ## MockedEntityRevision[​](/sdk/api/testing/.md#_MockedEntityRevision "Direct link to MockedEntityRevision") * *class *viktor.testing.MockedEntityRevision(*params=None*, *created\_date=None*, *entity\_revision\_id=1*)[](#MockedEntityRevision "Link to this definition") Bases: [`EntityRevision`](/sdk/api/api-v1/.md#EntityRevision "viktor.api_v1.EntityRevision") New in v13.3.0 To mock an EntityRevision. Example: ``` from viktor.testing import MockedEntityRevision, MockedEntity, MockedFileResource params = { 'number': 1, 'entity': MockedEntity(name="MyEntity"), 'file': MockedFileResource(vkt.File.from_data("content"), "file.txt") } mocked_entity_revision = MockedEntityRevision(params) ``` params can be passed from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` import viktor as vkt from viktor.testing import MockedEntityRevision, MockedEntity, MockedFileResource, mock_params from app.my_entity.controller import MyEntityController json_file = vkt.File.from_path("path to JSON file") params = mock_params( json_file, MyEntityController.parametrization, entities={1: MockedEntity(name="MyEntity")}, file_resources={1: MockedFileResource(vkt.File.from_data("content"), "file")} ) mocked_entity_revision = MockedEntityRevision(params) ``` * Parameters: * **params** (`Union`\[`dict`, `Munch`]) – Return value of EntityRevision.params. Must be the deserialized params (see [`mock_params()`](#mock_params "viktor.testing.mock_params")). None to set default (empty) params. * **created\_date** (`datetime`) – Return value of EntityRevision.created\_date. None to set default date (2000, 1, 1). * **entity\_revision\_id** (`int`) – Return value of EntityRevision.id. ## MockedEntityType[​](/sdk/api/testing/.md#_MockedEntityType "Direct link to MockedEntityType") * *class *viktor.testing.MockedEntityType(*name='MockedEntityType'*, *entity\_type\_id=1*)[](#MockedEntityType "Link to this definition") Bases: [`EntityType`](/sdk/api/api-v1/.md#EntityType "viktor.api_v1.EntityType") New in v13.3.0 To mock a EntityType. ## MockedFileResource[​](/sdk/api/testing/.md#_MockedFileResource "Direct link to MockedFileResource") * *class *viktor.testing.MockedFileResource(*file=None*, *filename='mocked\_file.txt'*)[](#MockedFileResource "Link to this definition") New in v13.3.0 To mock a FileResource. * Parameters: * **file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – Return value of FileResource.file. None to set default file with content = “mocked content”. * **filename** (`str`) – Return value of FileResource.filename. ## MockedUser[​](/sdk/api/testing/.md#_MockedUser "Direct link to MockedUser") * *class *viktor.testing.MockedUser(*\**, *first\_name='John'*, *last\_name='Doe'*, *email='john.doe\@email.com'*, *job\_title='Employee'*, *user\_id=1*)[](#MockedUser "Link to this definition") Bases: [`User`](/sdk/api/api-v1/.md#User "viktor.api_v1.User") New in v13.3.0 To mock a User. ## mock\_API[​](/sdk/api/testing/.md#_mock_API "Direct link to mock_API") * viktor.testing.mock\_API(*\**, *get\_entity=None*, *create\_child\_entity=None*, *generate\_upload\_url=None*, *get\_current\_user=None*, *get\_entities\_by\_type=None*, *get\_entity\_children=None*, *get\_entity\_siblings=None*, *get\_root\_entities=None*, *get\_entity\_parent=None*, *get\_entity\_revisions=None*, *get\_entity\_file=None*, *rename\_entity=None*, *set\_entity\_params=None*)[](#mock_API "Link to this definition") New in v13.3.0 Decorator that can be used to mock API() method calls, to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_API, MockedEntity from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_API( get_entity=[MockedEntity(entity_id=98), MockedEntity(entity_id=99)], get_entity_file=vkt.File.from_data("fake content") ) def test_api_calls(self): MyEntityController().api_calls() ``` Note that last\_saved\_params can be passed to MockedEntity from a JSON file by making use of [`mock_params()`](#mock_params "viktor.testing.mock_params"): ``` import unittest import viktor as vkt from viktor.testing import mock_API, MockedEntity, mock_params, MockedFileResource from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): json_file = vkt.File.from_path("path to JSON file") params = mock_params( json_file, MyEntityController.parametrization, entities={1: MockedEntity(name="MyEntity")}, file_resources={1: MockedFileResource(vkt.File.from_data("content"), "file")} ) @mock_API( get_entity=MockedEntity(last_saved_params=params, revisions=[MockedEntityRevision(params)]) ) def test_api_calls(self): MyEntityController().api_calls() ``` * For all parameters the following holds: * If a Sequence type is provided, the next entry is returned for each corresponding API method call. When an API method is called on a depleted iterable, an Exception is raised. * If a single object is provided, the object is returned each time the corresponding API method is called (endlessly). * If None is provided (default), a default object is returned each time the corresponding API method is called (endlessly). - Parameters: * **get\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of API.get\_entity. * **create\_child\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of API.create\_child\_entity. * **generate\_upload\_url** (`Union`\[`Sequence`\[`dict`], `dict`]) – Return value of API.generate\_upload\_url. * **get\_current\_user** (`Union`\[`Sequence`\[[`MockedUser`](#MockedUser "viktor.testing.MockedUser")], [`MockedUser`](#MockedUser "viktor.testing.MockedUser")]) – Return value of API.get\_current\_user. * **get\_entities\_by\_type** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of API.get\_entities\_by\_type. * **get\_entity\_children** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of API.get\_entity\_children. * **get\_entity\_siblings** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of API.get\_entity\_siblings. * **get\_root\_entities** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]], `Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]]) – Return value of API.get\_root\_entities. * **get\_entity\_parent** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of API.get\_entity\_parent. * **get\_entity\_revisions** (`Union`\[`Sequence`\[`Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")]], `Sequence`\[[`MockedEntityRevision`](#MockedEntityRevision "viktor.testing.MockedEntityRevision")]]) – Return value of API.get\_entity\_revisions. * **get\_entity\_file** (`Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of API.get\_entity\_file. * **rename\_entity** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of API.rename\_entity. * **set\_entity\_params** (`Union`\[`Sequence`\[[`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")], [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Return value of API.set\_entity\_params. - Return type: `Callable` ## mock\_AxisVMAnalysis[​](/sdk/api/testing/.md#_mock_AxisVMAnalysis "Direct link to mock_AxisVMAnalysis") * viktor.testing.mock\_AxisVMAnalysis(*get\_model\_file=None*, *get\_result\_file=None*, *get\_results=None*)[](#mock_AxisVMAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.axisvm.AxisVMAnalysis`](/sdk/api/external/axisvm/.md#AxisVMAnalysis "viktor.external.axisvm.AxisVMAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_AxisVMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_AxisVMAnalysis( get_model_file=vkt.File.from_path(Path(__file__).parent / 'test_model.axs'), get_result_file=vkt.File.from_path(Path(__file__).parent / 'test_model.axe'), get_results={'Forces': ...} ) def test_axisvm_analysis(self): MyEntityTypeController().axisvm_analysis() ``` * For all 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/dict object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: * **get\_model\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of AxisVMAnalysis.get\_model\_file. * **get\_result\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of AxisVMAnalysis.get\_result\_file. * **get\_results** (`Union`\[`Sequence`\[`dict`], `dict`]) – Return value of AxisVMAnalysis.get\_results. - Return type: `Callable` ## mock\_DFoundationsAnalysis[​](/sdk/api/testing/.md#_mock_DFoundationsAnalysis "Direct link to mock_DFoundationsAnalysis") * viktor.testing.mock\_DFoundationsAnalysis(*get\_output\_file=None*)[](#mock_DFoundationsAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dfoundations.DFoundationsAnalysis`](/sdk/api/external/dfoundations/.md#DFoundationsAnalysis "viktor.external.dfoundations.DFoundationsAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DFoundationsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DFoundationsAnalysis(get_output_file={ '.fod': vkt.File.from_path(Path(__file__).parent / 'test_output.fod'), '.fos': vkt.File.from_path(Path(__file__).parent / 'test_output.fos') }) def test_dfoundations_analysis(self): MyEntityTypeController().dfoundations_analysis() ``` * For all 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). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DFoundationsAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_DGeoStabilityAnalysis[​](/sdk/api/testing/.md#_mock_DGeoStabilityAnalysis "Direct link to mock_DGeoStabilityAnalysis") * viktor.testing.mock\_DGeoStabilityAnalysis(*get\_output\_file=None*)[](#mock_DGeoStabilityAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dgeostability.DGeoStabilityAnalysis`](/sdk/api/external/dgeostability/.md#DGeoStabilityAnalysis "viktor.external.dgeostability.DGeoStabilityAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DGeoStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DGeoStabilityAnalysis(get_output_file={ '.sto': vkt.File.from_path(Path(__file__).parent / 'test_output.sto') }) def test_dgeostability_analysis(self): MyEntityTypeController().dgeostability_analysis() ``` * For all 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). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DGeoStabilityAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_DSettlementAnalysis[​](/sdk/api/testing/.md#_mock_DSettlementAnalysis "Direct link to mock_DSettlementAnalysis") * viktor.testing.mock\_DSettlementAnalysis(*get\_output\_file=None*, *get\_sld\_file=None*)[](#mock_DSettlementAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dsettlement.DSettlementAnalysis`](/sdk/api/external/dsettlement/.md#DSettlementAnalysis "viktor.external.dsettlement.DSettlementAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DSettlementAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSettlementAnalysis(get_output_file={ '.sld': vkt.File.from_path(Path(__file__).parent / 'test_output.sld'), '.slo': vkt.File.from_path(Path(__file__).parent / 'test_output.slo') }) def test_dsettlement_analysis(self): MyEntityTypeController().dsettlement_analysis() ``` * For all 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 or StringIO/BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: * **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DSettlementAnalysis.get\_output\_file. * **get\_sld\_file** (`Union`\[`Sequence`\[`Union`\[`StringIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `StringIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of DSettlementAnalysis.get\_sld\_file. - Return type: `Callable` ## mock\_DSheetPilingAnalysis[​](/sdk/api/testing/.md#_mock_DSheetPilingAnalysis "Direct link to mock_DSheetPilingAnalysis") * viktor.testing.mock\_DSheetPilingAnalysis(*get\_output\_file=None*)[](#mock_DSheetPilingAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dsheetpiling.DSheetPilingAnalysis`](/sdk/api/external/dsheetpiling/.md#DSheetPilingAnalysis "viktor.external.dsheetpiling.DSheetPilingAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DSheetPilingAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DSheetPilingAnalysis(get_output_file={ '.shd': vkt.File.from_path(Path(__file__).parent / 'test_output.shd'), '.shl': vkt.File.from_path(Path(__file__).parent / 'test_output.shl'), '.shs': vkt.File.from_path(Path(__file__).parent / 'test_output.shs'), '.sho': vkt.File.from_path(Path(__file__).parent / 'test_output.sho') }) def test_dsheetpiling_analysis(self): MyEntityTypeController().dsheetpiling_analysis() ``` * For all 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). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DSheetPilingAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_DStabilityAnalysis[​](/sdk/api/testing/.md#_mock_DStabilityAnalysis "Direct link to mock_DStabilityAnalysis") * viktor.testing.mock\_DStabilityAnalysis(*get\_output\_file=None*)[](#mock_DStabilityAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.dstability.DStabilityAnalysis`](/sdk/api/external/dstability/.md#DStabilityAnalysis "viktor.external.dstability.DStabilityAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DStabilityAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DStabilityAnalysis(get_output_file={ '.stix': vkt.File.from_path(Path(__file__).parent / 'test_output.stix') }) def test_dstability_analysis(self): MyEntityTypeController().dstability_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DStabilityAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_DynamoAnalysis[​](/sdk/api/testing/.md#_mock_DynamoAnalysis "Direct link to mock_DynamoAnalysis") * viktor.testing.mock\_DynamoAnalysis(*get\_output\_file=None*)[](#mock_DynamoAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.dynamo.DynamoAnalysis`](/sdk/api/external/dynamo/.md#DynamoAnalysis "viktor.external.dynamo.DynamoAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_DynamoAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_DynamoAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_dynamo_analysis(self): MyEntityTypeController().dynamo_analysis() ``` * For all 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 or BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of DynamoAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_ETABSAnalysis[​](/sdk/api/testing/.md#_mock_ETABSAnalysis "Direct link to mock_ETABSAnalysis") * viktor.testing.mock\_ETABSAnalysis(*get\_output\_file=None*)[](#mock_ETABSAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.etabs.ETABSAnalysis`](/sdk/api/external/etabs/.md#ETABSAnalysis "viktor.external.etabs.ETABSAnalysis"), to facilitate easier testing. Example: ``` 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={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_etabs_analysis(self): MyEntityTypeController().etabs_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of ETABSAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_Excel[​](/sdk/api/testing/.md#_mock_Excel "Direct link to mock_Excel") * viktor.testing.mock\_Excel(*get\_named\_cell\_result=None*, *get\_direct\_cell\_result=None*, *get\_filled\_template=None*)[](#mock_Excel "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.excel.Excel`](/sdk/api/external/excel/.md#Excel "viktor.external.excel.Excel"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_Excel from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_Excel( get_filled_template=vkt.File.from_path(Path(__file__).parent / 'test_model.xlsx'), get_named_cell_result={"cell name": 5.5}, get_direct_cell_result={ ("Sheet1", "A", 5): "cell value", ("Sheet2", "B", 1): 1.4, } ) def test_excel_analysis(self): MyEntityTypeController().excel_analysis() ``` * For all 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 object (with empty content) is returned for the template, whereas None is returned for the cell values, each time the corresponding method is called (endlessly). - Parameters: * **get\_named\_cell\_result** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`str`, `int`, `float`, `bool`]], `str`, `int`, `float`, `bool`]]) – Return value of Excel.get\_named\_cell\_result. * **get\_direct\_cell\_result** (`Dict`\[`Tuple`\[`str`, `str`, `int`], `Union`\[`Sequence`\[`Union`\[`str`, `int`, `float`, `bool`]], `str`, `int`, `float`, `bool`]]) – Return value of Excel.get\_direct\_cell\_result. * **get\_filled\_template** (`Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of Excel.get\_filled\_template. - Return type: `Callable` ## mock\_GRLWeapAnalysis[​](/sdk/api/testing/.md#_mock_GRLWeapAnalysis "Direct link to mock_GRLWeapAnalysis") * viktor.testing.mock\_GRLWeapAnalysis(*get\_output\_file=None*)[](#mock_GRLWeapAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.grlweap.GRLWeapAnalysis`](/sdk/api/external/grlweap/.md#GRLWeapAnalysis "viktor.external.grlweap.GRLWeapAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_GRLWeapAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GRLWeapAnalysis( get_output_file=vkt.File.from_path(Path(__file__).parent / 'test_output.GWO') ) def test_grlweap_analysis(self): MyEntityTypeController().grlweap_analysis() ``` * For all 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). - Parameters: **get\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of GRLWeapAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_GenericAnalysis[​](/sdk/api/testing/.md#_mock_GenericAnalysis "Direct link to mock_GenericAnalysis") * viktor.testing.mock\_GenericAnalysis(*get\_output\_file=None*)[](#mock_GenericAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.generic.GenericAnalysis`](/sdk/api/external/generic/.md#GenericAnalysis "viktor.external.generic.GenericAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_GenericAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_GenericAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_generic_analysis(self): MyEntityTypeController().generic_analysis() ``` * For all 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 or BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of GenericAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_IdeaRcsAnalysis[​](/sdk/api/testing/.md#_mock_IdeaRcsAnalysis "Direct link to mock_IdeaRcsAnalysis") * viktor.testing.mock\_IdeaRcsAnalysis(*get\_output\_file=None*, *get\_idea\_rcs\_file=None*)[](#mock_IdeaRcsAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock `viktor.external.idea_rcs.IdeaRcsAnalysis`, to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_IdeaRcsAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_IdeaRcsAnalysis( get_output_file=vkt.File.from_path(Path(__file__).parent / 'test_output.xml'), get_idea_rcs_file=vkt.File.from_path(Path(__file__).parent / 'test_rcs.ideaRcs') ) def test_idea_rcs_analysis(self): MyEntityTypeController().idea_rcs_analysis() ``` * For all 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). - Parameters: * **get\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of IdeaRcsAnalysis.get\_output\_file. * **get\_idea\_rcs\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of IdeaRcsAnalysis.get\_idea\_rcs\_file. - Return type: `Callable` ## mock\_MatlabAnalysis[​](/sdk/api/testing/.md#_mock_MatlabAnalysis "Direct link to mock_MatlabAnalysis") * viktor.testing.mock\_MatlabAnalysis(*get\_output\_file=None*)[](#mock_MatlabAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.matlab.MatlabAnalysis`](/sdk/api/external/matlab/.md#MatlabAnalysis "viktor.external.matlab.MatlabAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_MatlabAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_MatlabAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_matlab_analysis(self): MyEntityTypeController().matlab_analysis() ``` * For all 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 or BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of MatlabAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_ParamsFromFile[​](/sdk/api/testing/.md#_mock_ParamsFromFile "Direct link to mock_ParamsFromFile") * viktor.testing.mock\_ParamsFromFile(*controller*)[](#mock_ParamsFromFile "Link to this definition") Decorator that can be used for testing methods decorated with [`viktor.core.ParamsFromFile`](/sdk/api/core/.md#ParamsFromFile "viktor.core.ParamsFromFile"). Example: ``` import unittest import viktor as vkt from viktor.testing import mock_ParamsFromFile from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_ParamsFromFile(MyEntityController) def test_process_file(self): file = vkt.File.from_data("abc") returned_dict = MyEntityController().process_file(file) self.assertDictEqual(returned_dict, {...}) ``` * Parameters: **controller** (`Type`\[[`Controller`](/sdk/api/core/.md#Controller "viktor.core.Controller")]) – Controller class on which the ParamsFromFile should be mocked * Return type: `Callable` ## mock\_PlaxisAnalysis[​](/sdk/api/testing/.md#_mock_PlaxisAnalysis "Direct link to mock_PlaxisAnalysis") * viktor.testing.mock\_PlaxisAnalysis(*get\_output\_file=None*)[](#mock_PlaxisAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.plaxis.PlaxisAnalysis`](/sdk/api/external/plaxis/.md#PlaxisAnalysis "viktor.external.plaxis.PlaxisAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_PlaxisAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_PlaxisAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_plaxis_analysis(self): MyEntityTypeController().plaxis_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of PlaxisAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_PythonAnalysis[​](/sdk/api/testing/.md#_mock_PythonAnalysis "Direct link to mock_PythonAnalysis") * viktor.testing.mock\_PythonAnalysis(*get\_output\_file=None*)[](#mock_PythonAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.python.PythonAnalysis`](/sdk/api/external/python/.md#PythonAnalysis "viktor.external.python.PythonAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_PythonAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_PythonAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_python_analysis(self): MyEntityTypeController().python_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of PythonAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_RFEMAnalysis[​](/sdk/api/testing/.md#_mock_RFEMAnalysis "Direct link to mock_RFEMAnalysis") * viktor.testing.mock\_RFEMAnalysis(*get\_model=None*, *get\_result=None*)[](#mock_RFEMAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.rfem.RFEMAnalysis`](/sdk/api/external/rfem/.md#RFEMAnalysis "viktor.external.rfem.RFEMAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_RFEMAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RFEMAnalysis( get_model=vkt.File.from_path(Path(__file__).parent / 'test_model.rfx') get_result={ 3: vkt.File.from_path(Path(__file__).parent / 'load_case_3.json'), 5: vkt.File.from_path(Path(__file__).parent / 'load_case_5.json') } ) def test_rfem_analysis(self): MyEntityTypeController().rfem_analysis() }) def test_rfem_analysis(self): MyEntityTypeController().rfem_analysis() ``` * For all parameters the following can be provided: * 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 BytesIO/File object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: * **get\_model** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], [`File`](/sdk/api/core/.md#File "viktor.core.File"), `BytesIO`]) – Return value of RFEMAnalysis.get\_model. * **get\_result** (`Dict`\[`int`, `Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], [`File`](/sdk/api/core/.md#File "viktor.core.File"), `BytesIO`]]) – Return value of RFEMAnalysis.get\_result. - Return type: `Callable` ## mock\_RevitAnalysis[​](/sdk/api/testing/.md#_mock_RevitAnalysis "Direct link to mock_RevitAnalysis") * viktor.testing.mock\_RevitAnalysis(*get\_output\_file=None*)[](#mock_RevitAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.revit.RevitAnalysis`](/sdk/api/external/revit/.md#RevitAnalysis "viktor.external.revit.RevitAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_RevitAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RevitAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_revit_analysis(self): MyEntityTypeController().revit_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of RevitAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_RobotAnalysis[​](/sdk/api/testing/.md#_mock_RobotAnalysis "Direct link to mock_RobotAnalysis") * viktor.testing.mock\_RobotAnalysis(*get\_model\_file=None*, *get\_results=None*)[](#mock_RobotAnalysis "Link to this definition") New in v13.5.0 Decorator that can be used to mock [`viktor.external.robot.RobotAnalysis`](/sdk/api/external/robot/.md#RobotAnalysis "viktor.external.robot.RobotAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_RobotAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_RobotAnalysis( get_model_file=vkt.File.from_path(Path(__file__).parent / 'test_model.rtd'), get_results={'bar_forces': {...}, ...} ) def test_robot_analysis(self): MyEntityTypeController().robot_analysis() ``` * For all 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/dict object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: * **get\_model\_file** (`Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of RobotAnalysis.get\_model\_file. * **get\_results** (`Union`\[`Sequence`\[`dict`], `dict`]) – Return value of RobotAnalysis.get\_results. - Return type: `Callable` ## mock\_SAP2000Analysis[​](/sdk/api/testing/.md#_mock_SAP2000Analysis "Direct link to mock_SAP2000Analysis") * viktor.testing.mock\_SAP2000Analysis(*get\_output\_file=None*)[](#mock_SAP2000Analysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.sap2000.SAP2000Analysis`](/sdk/api/external/sap2000/.md#SAP2000Analysis "viktor.external.sap2000.SAP2000Analysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_SAP2000Analysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_SAP2000Analysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_sap2000_analysis(self): MyEntityTypeController().sap2000_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of SAP2000Analysis.get\_output\_file. - Return type: `Callable` ## mock\_SciaAnalysis[​](/sdk/api/testing/.md#_mock_SciaAnalysis "Direct link to mock_SciaAnalysis") * viktor.testing.mock\_SciaAnalysis(*get\_engineering\_report=None*, *get\_updated\_esa\_model=None*, *get\_xml\_output\_file=None*)[](#mock_SciaAnalysis "Link to this definition") New in v13.3.0 Decorator that can be used to mock `viktor.external.scia.SciaAnalysis`, to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_SciaAnalysis from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_SciaAnalysis( get_engineering_report=vkt.File.from_path(Path(__file__).parent / 'test_file.pdf'), get_updated_esa_model=vkt.File.from_path(Path(__file__).parent / 'test_file.esa'), get_xml_output_file=vkt.File.from_path(Path(__file__).parent / 'test_output.xml') ) def test_scia_analysis(self): MyEntityController().scia_analysis() ``` * For all 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). - Parameters: * **get\_engineering\_report** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of SciaAnalysis.get\_engineering\_report. * **get\_updated\_esa\_model** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of SciaAnalysis.get\_updated\_esa\_model. * **get\_xml\_output\_file** (`Union`\[`Sequence`\[`Union`\[`BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]], `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Return value of SciaAnalysis.get\_xml\_output\_file. - Return type: `Callable` ## mock\_Storage[​](/sdk/api/testing/.md#_mock_Storage "Direct link to mock_Storage") * viktor.testing.mock\_Storage(*\**, *get=None*, *list=None*)[](#mock_Storage "Link to this definition") Decorator that can be used for testing methods which invoke the [`viktor.core.Storage`](/sdk/api/core/.md#Storage "viktor.core.Storage"). Use the get and list arguments to instruct which file(s) the respective Storage().get(…) and Storage().list(…) methods should return. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_Storage from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_Storage( get=[vkt.File.from_data("abc"), vkt.File.from_data("def")], list=[{'data_key_3': vkt.File.from_data("ghi")}] ) def test_process_analysis_result(self): # Storage().get(...) invoked twice, Storage().list(...) invoked once result = MyEntityController().process_analysis_result() ... ``` * Parameters: * **get** (`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Files to be returned by Storage().get(…). The files are returned in order of the input list. * **list** (`Sequence`\[`Dict`\[`str`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – File dicts to be returned by Storage().list(…). The dicts are returned in order of the input list. * Return type: `Callable` ## mock\_TeklaAnalysis[​](/sdk/api/testing/.md#_mock_TeklaAnalysis "Direct link to mock_TeklaAnalysis") * viktor.testing.mock\_TeklaAnalysis(*get\_output\_file=None*)[](#mock_TeklaAnalysis "Link to this definition") New in 14.17.0 Decorator that can be used to mock [`viktor.external.tekla.TeklaAnalysis`](/sdk/api/external/tekla/.md#TeklaAnalysis "viktor.external.tekla.TeklaAnalysis"), to facilitate easier testing. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_TeklaAnalysis from app.my_entity_type.controller import MyEntityTypeController class TestMyEntityTypeController(unittest.TestCase): @mock_TeklaAnalysis(get_output_file={ 'data.out': vkt.File.from_path(Path(__file__).parent / 'data.out'), 'info.log': vkt.File.from_path(Path(__file__).parent / 'info.log') }) def test_tekla_analysis(self): MyEntityTypeController().tekla_analysis() ``` * For all 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 object (with empty content) is returned each time the corresponding method is called (endlessly). - Parameters: **get\_output\_file** (`Dict`\[`str`, `Union`\[`Sequence`\[[`File`](/sdk/api/core/.md#File "viktor.core.File")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]]) – Return value of TeklaAnalysis.get\_output\_file. - Return type: `Callable` ## mock\_View[​](/sdk/api/testing/.md#_mock_View "Direct link to mock_View") * viktor.testing.mock\_View(*controller*)[](#mock_View "Link to this definition") New in v13.3.0 Decorator that can be used to mock @View decorators (any subclass of [`viktor.views.View`](/sdk/api/views/.md#View "viktor.views.View")), to facilitate easier testing of view methods. Example: ``` import unittest import viktor as vkt from viktor.testing import mock_View from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): @mock_View(MyEntityController) def test_geometry_view(self): params = ... geometry_result = MyEntityController().geometry_view(params=params) self.assertIsInstance(geometry_result.geometry, TransformableObject) self.assertEqual(geometry_result.labels, ...) ``` * Parameters: **controller** (`Type`\[[`Controller`](/sdk/api/core/.md#Controller "viktor.core.Controller")]) – Controller class on which the @View decorator should be mocked * Return type: `Callable` ## mock\_params[​](/sdk/api/testing/.md#_mock_params "Direct link to mock_params") * viktor.testing.mock\_params(*params*, *parametrization*, *file\_resources=None*, *entities=None*)[](#mock_params "Link to this definition") Convert a plain dict to the (deserialized) params, replacing FileResource and Entity objects with their mocked counterpart (MockedFileResource, MockedEntity). Can be used to test methods with params in their signature that are called by the VIKTOR platform (e.g. view methods, button methods). Example: ``` import unittest import viktor as vkt from viktor.testing import mock_params, MockedEntity, MockedFileResource from app.my_entity.controller import MyEntityController class TestMyEntityController(unittest.TestCase): def test_button_method(self): // provide the params manually... params_dict = {'number': 1, 'entity': 2, 'file': 3} // or from a JSON file... params_dict = vkt.File.from_path("path to my JSON file") mocked_params = mock_params( params, MyEntityController.parametrization, entities={2: MockedEntity(entity_id=2, name="My Entity")} file_resources={3: MockedFileResource(vkt.File.from_data("content"), "file.txt")}, ) MyEntityController().button_method(mocked_params) ``` Deserialization only affects the raw values associated with the following fields: > * DateField > > * EntityOptionField > > * ChildEntityOptionField > > * SiblingEntityOptionField > > * EntityMultiSelectField > > * ChildEntityMultiSelectField > > * SiblingEntityMultiSelectField > > * GeoPointField > > * GeoPolylineField > > * GeoPolygonField > > * FileField > > * MultiFileField * Parameters: * **params** (`Union`\[`dict`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – Plain dict or JSON file (with serialized params) to be converted to the (deserialized) params. * **parametrization** (`Union`\[[`Parametrization`](/sdk/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization"), `Type`\[[`Parametrization`](/sdk/api/parametrization/.md#Parametrization "viktor.parametrization.Parametrization")]]) – Parametrization corresponding to the params. * **file\_resources** (`Dict`\[`int`, [`MockedFileResource`](#MockedFileResource "viktor.testing.MockedFileResource")]) – Maps FileResource source id in params to mocked file resource. If source id is not in file\_resources, a default MockedFileResource (with default filename and File) is returned. * **entities** (`Dict`\[`int`, [`MockedEntity`](#MockedEntity "viktor.testing.MockedEntity")]) – Maps entity id in params to mocked entity. If entity id is not in entities, a default MockedEntity is returned. * Return type: `Munch` --- # viktor.utils ## convert\_excel\_to\_pdf[​](/sdk/api/utils/.md#_convert_excel_to_pdf "Direct link to convert_excel_to_pdf") * viktor.utils.convert\_excel\_to\_pdf(*file*)[](#convert_excel_to_pdf "Link to this definition") Convert an Excel document to PDF. Example usages: ``` import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.xlsx") with file1.open_binary() as f1: pdf = convert_excel_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.xlsx", "rb") as f1: pdf = convert_excel_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **file** (`BinaryIO`) – Document to be converted. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing converted document. ## convert\_svg\_to\_pdf[​](/sdk/api/utils/.md#_convert_svg_to_pdf "Direct link to convert_svg_to_pdf") * viktor.utils.convert\_svg\_to\_pdf(*file*)[](#convert_svg_to_pdf "Link to this definition") Convert a SVG document to PDF. Example usages: ``` import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.svg") with file1.open_binary() as f1: pdf = convert_svg_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.svg", "rb") as f1: pdf = convert_svg_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **file** (`BinaryIO`) – Document to be converted. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing converted document. ## convert\_word\_to\_pdf[​](/sdk/api/utils/.md#_convert_word_to_pdf "Direct link to convert_word_to_pdf") * viktor.utils.convert\_word\_to\_pdf(*file*)[](#convert_word_to_pdf "Link to this definition") Convert a Word document to PDF. Example usages: ``` import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "mydocument.docx") with file1.open_binary() as f1: pdf = convert_word_to_pdf(f1) # using built-in `open()` with open(Path(__file__).parent / "mydocument.docx", "rb") as f1: pdf = convert_word_to_pdf(f1) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: **file** (`BinaryIO`) – Document to be converted. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing converted document. ## memoize[​](/sdk/api/utils/.md#_memoize "Direct link to memoize") * viktor.utils.memoize(*fun*)[](#memoize "Link to this definition") Decorator that applies memoization to a function. This can increase performance when the function is called multiple times with identical input. When using multiple decorators, this should be the last decorator. Warning memoized keys will differ depending on parameters being passed as args or kwargs, which can cause a (unexpected) cache miss! For example, f(1, y=2) and f(x=1, y=2) will be treated as two different entries. Prefer to use functions with kwargs only to prevent this. Example: ``` # In this example, a DataView performs a long-running calculation when # calling `func`. When the user changes input in the editor and updates # the view again, `func` will only be evaluated again if either one of # `param_a`, `param_b`, or `param_c` is changed in-between jobs. import viktor as vkt @vkt.memoize def func(*, param_a, param_b, param_c): # perform lengthy calculation return result class Controller(vkt.Controller): ... @vkt.DataView("Results", duration_guess=30) def get_data_view(self, params, **kwargs): ... result = func(param_a=..., param_b=..., param_c=...) ... return vkt.DataResult(...) ``` CAUTION: Only use this function when you are 100% sure of the following: > * The function is a pure function (e.g. @staticmethod) meaning: > > > * It always returns the same result for a given input. [\[1\]](#id5) > > > > * It does not depend on other data and does not have side effects such as API calls or calls to others objects that persist state. [\[2\]](#id6) > > * If part of the returning data contains a modified input, it must not be a problem that the memory reference is lost and a new object is returned. > > * The input of the function is serializable. [\[3\]](#id7) > > * The output of the function is serializable. [\[3\]](#id7) > > * During memoization, tuples in the input are casted to lists before determining uniqueness. > > * During memoization, tuples in the output are casted to lists before returning. > > * In the design of your application you should take into account that the application should not fail in timeouts/unresponsiveness if the memoization does not work. It should be a bonus if it works. > > * The function name is unique within the Python file. \[[1](#id1)] Variables/objects/functions defined outside of the memoized function are not used in the memoized function. \[[2](#id2)] The function should only return results. Any other actions defined in the function are not performed if the function call is memoized. \[3] ([1](#id3),[2](#id4)) ‘Serializable’ in this context means the data is any of the following types: boolean, dictionary, float, int, list, none, string, tuple. Types as returned in the ‘params’ are also allowed (e.g. GeoPoint, FileResource, Color, datetime.date, etc.) with the exception of Entity. When data is nested, the nesting can only contain any of the aforementioned types. Practical uses of this are, but not limited to, function calls with input and output that is relatively small compared to the amount of time required for the evaluation. Cached results are kept for a maximum of 24 hours. Note When using the memoization decorator on your development environment the cache is stored locally. The local storage is limited to 50 function calls. If the limit is exceeded, cached results are cleared based on a first in, first out approach. In production the storage is unlimited. * Parameters: **fun** (`Callable`) – original function * Return type: `Callable` ## merge\_pdf\_files[​](/sdk/api/utils/.md#_merge_pdf_files "Direct link to merge_pdf_files") * viktor.utils.merge\_pdf\_files(*\*files*)[](#merge_pdf_files "Link to this definition") This method can be used to merge several PDFs into one document. BinaryIO objects can be directly used as arguments in the method. The merged document is returned as a File object. The order of the input files is preserved in the resulting document. Example usages: ``` import viktor as vkt # using File object file1 = vkt.File.from_path(Path(__file__).parent / "pdf1.pdf") file2 = vkt.File.from_path(Path(__file__).parent / "pdf2.pdf") with file1.open_binary() as f1, file2.open_binary() as f2: merged_pdf = merge_pdf_files(f1, f2) # using built-in `open()` with open(Path(__file__).parent / "pdf1.pdf", "rb") as f1, open(Path(__file__).parent / "pdf2.pdf", "rb") as f2: merged_pdf = merge_pdf_files(f1, f2) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing merged document. ## render\_jinja\_template[​](/sdk/api/utils/.md#_render_jinja_template "Direct link to render_jinja_template") * viktor.utils.render\_jinja\_template(*template*, *variables*)[](#render_jinja_template "Link to this definition") Render a template using Jinja. Example usage: ``` with open("path/to/template.jinja", 'rb') as template: result = render_jinja_template(template, {'name': 'John Doe'}) ``` Note This method needs to be mocked in (automated) unit and integration tests. * Parameters: * **template** (`BinaryIO`) – Jinja template file. * **variables** (`dict`) – set of variables to fill the template with. * Return type: [`File`](/sdk/api/core/.md#File "viktor.core.File") * Returns: File object containing the rendered template --- # viktor.views ## DataGroup[​](/sdk/api/views/.md#_DataGroup "Direct link to DataGroup") * *class *viktor.views.DataGroup(*\*args*, *\*\*kwargs*)[](#DataGroup "Link to this definition") Bases: `dict` Container for DataItems (max. 100). DataItems can be added with or without a keyword argument. Keywords are required when you want to use a DataItem in the summary (for lookup). Example: ``` DataGroup( DataItem('a', 1), DataItem('b', 2), output_c=DataItem('c', 3), # 'output_c' can be used in the entity summary output_d=DataItem('d', 4), # 'output_d' can be used in the entity summary ) ``` **(new in v14.22.0)** Append items to an existing data group using DataGroup.add(): ``` d = DataGroup( DataItem('a', 1), ) d.add(DataItem('b', 2)) d.add(DataItem('c', 3), DataItem('d', 4)) ``` * Parameters: * **args** ([`DataItem`](#DataItem "viktor.views.DataItem")) – DataItem entries. * **kwargs** ([`DataItem`](#DataItem "viktor.views.DataItem")) – Keyworded DataItem entries. * Raises: * AttributeError when more than 100 DataItems are used - add(*\*items*)[](#DataGroup.add "Link to this definition") New in v14.22.0 Add one or more DataItems to an existing DataGroup. * Return type: `None` * *classmethod *from\_data\_groups(*groups*)[](#DataGroup.from_data_groups "Link to this definition") Constructs a combined DataGroup object from a list of individual DataGroup entries. Note that is not possible to have multiple DataGroups that share a specific key for a DataItem, e.g. the following will result in an error: ``` d1 = DataGroup(output_a=DataItem(...)) d2 = DataGroup(output_a=DataItem(...)) d3 = DataGroup.from_data_groups([d1, d2]) # raises KeyError ``` * Return type: [`DataGroup`](#DataGroup "viktor.views.DataGroup") ## DataItem[​](/sdk/api/views/.md#_DataItem "Direct link to DataItem") * *class *viktor.views.DataItem(*label*, *value=None*, *subgroup=None*, *\**, *prefix=''*, *suffix=''*, *number\_of\_decimals=None*, *status=DataStatus.INFO*, *status\_message=''*, *explanation\_label=''*)[](#DataItem "Link to this definition") Constructs an entry that can be used as input of a DataGroup, to fill the data view with results. The data view is dynamic, which means that a DataItem itself can consist of another DataGroup as subgroup. Both examples are demonstrated below. Example single entry: ``` result = "I am a great result" item = DataItem('output 1', result) ``` Example subgroup: ``` result = "I am a great result" item = DataItem('output 1', result, subgroup=DataGroup( output11=DataItem('output 1.1', "I can also be a numeric result"), output12=DataItem('output 1.2', 123) )) ``` The prefix / suffix can potentially change with every call. However, when the result is used in the Summary, the prefix / suffix of the DataItem should be equal to the prefix / suffix of the SummaryItem to maintain a consistent database. * Parameters: * **label** (`str`) – Description of the value which is shown. e.g: ‘Uc bending’ * **value** (`Union`\[`str`, `float`]) – Value of the data. e.g: 0.9 * **subgroup** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Optional DataItems grouped together in a DataGroup underneath this DataItem. Maximum depth = 3 * **prefix** (`str`) – E.g: €. Should be equal to the prefix of the SummaryItem if linked. * **suffix** (`str`) – E.g: N. Should be equal to the suffix of the SummaryItem if linked. * **number\_of\_decimals** (`int`) – Number of decimals with which the value is rounded for display. * **status** ([`DataStatus`](#DataStatus "viktor.views.DataStatus")) – Status of value. This controls the formatting of the status\_message: * status=DataStatus.INFO: black text * status=DataStatus.SUCCESS: green text * status=DataStatus.WARNING: orange text * status=DataStatus.ERROR: red text * **status\_message** (`str`) – Message which will be shown underneath the value. Color can be formatted with status. * **explanation\_label** (`str`) – Optional text which is placed between the label and the value. Could for instance be used for a calculation. * Raises: **TypeError** – if number\_of\_decimals is used on a non-numeric value. - *property *subgroup*: [DataGroup](#DataGroup "viktor.views.DataGroup")*[](#DataItem.subgroup "Link to this definition") ## DataResult[​](/sdk/api/views/.md#_DataResult "Direct link to DataResult") * *class *viktor.views.DataResult(*data*)[](#DataResult "Link to this definition") Bases: `_ViewResult` Container with the data that should be shown in a DataView. This data can be nested up to three levels deep. * Parameters: **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## DataStatus[​](/sdk/api/views/.md#_DataStatus "Direct link to DataStatus") * *class *viktor.views.DataStatus(*value*, *names=\*, *\*values*, *module=None*, *qualname=None*, *type=None*, *start=1*, *boundary=None*)[](#DataStatus "Link to this definition") Bases: `Enum` Enumeration of statuses to annotate a DataItem. * ERROR*: [`DataStatus`](#DataStatus "viktor.views.DataStatus")** = 'error'*[](#DataStatus.ERROR "Link to this definition") - INFO*: [`DataStatus`](#DataStatus "viktor.views.DataStatus")** = 'info'*[](#DataStatus.INFO "Link to this definition") * SUCCESS*: [`DataStatus`](#DataStatus "viktor.views.DataStatus")** = 'success'*[](#DataStatus.SUCCESS "Link to this definition") - WARNING*: [`DataStatus`](#DataStatus "viktor.views.DataStatus")** = 'warning'*[](#DataStatus.WARNING "Link to this definition") ## DataView[​](/sdk/api/views/.md#_DataView "Direct link to DataView") * *class *viktor.views.DataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#DataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a data view that contains calculation result. Example usage: ``` @DataView("Cost breakdown") def get_data_view(self, params, **kwargs): # calculate data ... return DataResult(data_group) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## GeoJSONAndDataResult[​](/sdk/api/views/.md#_GeoJSONAndDataResult "Direct link to GeoJSONAndDataResult") * *class *viktor.views.GeoJSONAndDataResult(*geojson*, *data*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[](#GeoJSONAndDataResult "Link to this definition") Bases: `_ViewResult` Container with the GeoJSON data and result data that should be visualized in a GeoJSONAndDataView. Optionally a legend and map labels can be included. * Parameters: * **geojson** (`dict`) – GeoJSON dictionary. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]) – Labels that should be placed on the map. * **legend** ([`MapLegend`](#MapLegend "viktor.views.MapLegend")) – Map legend. * **interaction\_groups** (`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *geojson*: dict*[](#GeoJSONAndDataResult.geojson "Link to this definition") ## GeoJSONAndDataView[​](/sdk/api/views/.md#_GeoJSONAndDataView "Direct link to GeoJSONAndDataView") * *class *viktor.views.GeoJSONAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#GeoJSONAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a GeoJSON and data. Example usage: ``` @GeoJSONAndDataView("Map / Data") def get_geojson_data_view(self, params, **kwargs): ... return GeoJSONAndDataResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## GeoJSONResult[​](/sdk/api/views/.md#_GeoJSONResult "Direct link to GeoJSONResult") * *class *viktor.views.GeoJSONResult(*geojson*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[](#GeoJSONResult "Link to this definition") Bases: `_ViewResult` Container with the GeoJSON data that should be visualized in a GeoJSONView. Optionally a legend and map labels can be included. The following geojson properties are supported that can be used for styling of the map elements: > * icon (geometry type ‘Point’ only): icon to be shown (default: “pin”). For a complete list of all available markers, see [`MapPoint`](#MapPoint "viktor.views.MapPoint") > > * marker-color: the color of a marker [\[\*\]](#id2) > > * description: text to show when this item is clicked > > * stroke: the color of a line as part of a polygon, polyline, or multigeometry \* > > * fill: the color of the interior of a polygon \* \[[\*](#id1)] color rules: Colors can be in short form “#ace” or long form “#aaccee”, and should contain the # prefix. Colors are interpreted the same as in CSS, in #RRGGBB and #RGB order. To enable interaction, the map feature identifiers can be defined within the geojson dict by adding an “id” attribute to a feature as follows: ``` { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": ..., "geometry": ... "id": "my identifier", ... ``` * Parameters: * **geojson** (`dict`) – GeoJSON dictionary. * **labels** (`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]) – Labels that should be placed on the map. * **legend** ([`MapLegend`](#MapLegend "viktor.views.MapLegend")) – Map legend. * **interaction\_groups** (`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *geojson*: dict*[](#GeoJSONResult.geojson "Link to this definition") ## GeoJSONView[​](/sdk/api/views/.md#_GeoJSONView "Direct link to GeoJSONView") * *class *viktor.views.GeoJSONView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#GeoJSONView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a GeoJSON (geographic data) view. Example usage: ``` @GeoJSONView("Map") def get_geojson_view(self, params, **kwargs): ... return GeoJSONResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## GeometryAndDataResult[​](/sdk/api/views/.md#_GeometryAndDataResult "Direct link to GeometryAndDataResult") * *class *viktor.views.GeometryAndDataResult(*geometry*, *data*, *labels=None*, *\**, *geometry\_type='gltf'*)[](#GeometryAndDataResult "Link to this definition") Bases: `_ViewResult` Container with the results that should be visualized in a GeometryAndDataView. This consists of three-dimensional geometry object(s) with optional text labels and data. Please have a look at GeometryResult for examples. * Parameters: * **geometry** (`Union`\[[`TransformableObject`](/sdk/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject"), `Sequence`\[[`TransformableObject`](/sdk/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – TransformableObject(s) that contain the geometric objects, or a geometry file such as glTF/GLB (v2.0) (). * **geometry\_type** (`str`) – Type of loader that should be used to render the geometry (“gltf”, “3dm”) New in v14.4.0 . * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`List`\[[`Label`](#Label "viktor.views.Label")]) – Text labels that can be used to provide additional information. ## GeometryAndDataView[​](/sdk/api/views/.md#_GeometryAndDataView "Direct link to GeometryAndDataView") * *class *viktor.views.GeometryAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *view\_mode='3D'*, *default\_shadow=False*, *up\_axis='Z'*, *x\_axis\_to\_right=None*, *visible=True*)[](#GeometryAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of geometries and data. Example usage: ``` @GeometryAndDataView("Model / Cost") def get_geometry_data_view(self, params, **kwargs): ... return GeometryAndDataResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – See [`View`](#View "viktor.views.View"). * **duration\_guess** (`int`) – See [`View`](#View "viktor.views.View"). * **description** (`str`) – See [`View`](#View "viktor.views.View"). * **update\_label** (`str`) – See [`View`](#View "viktor.views.View"). * **view\_mode** (`Literal`\[`'2D'`, `'3D'`]) – Sets the view mode: * ’3D’: Camera is free to move and user can choose between orthographic and perspective view. * ’2D’: Camera is fixed on the xy-plane and view is orthographic. * **default\_shadow** (`bool`) – Show shadow when editor is opened. User can still switch it off. * **up\_axis** (`Literal`\[`'Y'`, `'Z'`]) – (view\_mode=’3D’ only) Upwards pointing axis. Possible options: ‘Y’, ‘Z’ (default: ‘Z’) * **x\_axis\_to\_right** (`bool`) – (view\_mode=’3D’ and up\_axis=’Y’ only) X-axis pointing to the right in the initial view New in v14.8.0 * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## GeometryResult[​](/sdk/api/views/.md#_GeometryResult "Direct link to GeometryResult") * *class *viktor.views.GeometryResult(*geometry*, *labels=None*, *\**, *geometry\_type='gltf'*)[](#GeometryResult "Link to this definition") Bases: `_ViewResult` Container with the results that should be visualized in a GeometryView. This consists of three-dimensional geometry object(s) and optional text labels. To enable a geometric object for interaction, the object must be named using the ‘identifier’ argument. In case of a glTF/GLB-file, the objects name can be provided on the “name” key within a node. If none of the objects in the GeometryResult have a name assigned, default names are assigned to all of them (enabling them for interaction). Note: if there are multiple objects with the same name, a number will automatically be appended to enforce uniqueness. Example viktor.geometry TransformableObject(s): ``` geometry = Sphere(Point(0, 0), 10, identifier="MySphere") GeometryResult(geometry) # or [obj1, obj2, ...] in case of multiple objects ``` By specifying the geometry\_type you can render 3D geometry files either by providing a path, URL, or dynamically created (e.g. using trimesh). Currently supported geometry types are: “gltf”, “3dm”. Example static geometry file from path: ``` geometry = File.from_path(Path(__file__).parent / "my_model.gltf") GeometryResult(geometry, geometry_type="gltf") ``` Example static geometry file from a URL: ``` geometry = File.from_url("https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb") GeometryResult(geometry, geometry_type="gltf") ``` Example dynamic geometry file (e.g. using trimesh): ``` sphere = trimesh.creation.uv_sphere(10) scene = trimesh.Scene(geometry={'sphere': sphere}) geometry = File() with geometry.open_binary() as w: w.write(trimesh.exchange.gltf.export_glb(scene)) GeometryResult(geometry, geometry_type="gltf") ``` * Parameters: * **geometry** (`Union`\[[`TransformableObject`](/sdk/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject"), `Sequence`\[[`TransformableObject`](/sdk/api/geometry/.md#TransformableObject "viktor.geometry.TransformableObject")], [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – TransformableObject(s) that contain the geometric objects, or a geometry file such as glTF/GLB (v2.0) (). * **geometry\_type** (`str`) – Type of loader that should be used to render the geometry (“gltf”, “3dm”) New in v14.4.0 . * **labels** (`List`\[[`Label`](#Label "viktor.views.Label")]) – Text labels that can be used to provide additional information. ## GeometryView[​](/sdk/api/views/.md#_GeometryView "Direct link to GeometryView") * *class *viktor.views.GeometryView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *view\_mode='3D'*, *default\_shadow=False*, *up\_axis='Z'*, *x\_axis\_to\_right=None*, *visible=True*)[](#GeometryView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a geometry view (2D / 3D). Example usage: ``` @GeometryView("3D model") def get_geometry_view(self, params, **kwargs): ... return GeometryResult(...) @GeometryView("2D model", view_mode='2D') def get_geometry_view_2d(self, params, **kwargs): ... return GeometryResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. See [`GeometryResult`](#GeometryResult "viktor.views.GeometryResult") for example implementations. * Parameters: * **label** (`str`) – See [`View`](#View "viktor.views.View"). * **duration\_guess** (`int`) – See [`View`](#View "viktor.views.View"). * **description** (`str`) – See [`View`](#View "viktor.views.View"). * **update\_label** (`str`) – See [`View`](#View "viktor.views.View"). * **view\_mode** (`Literal`\[`'2D'`, `'3D'`]) – Sets the view mode: * ’3D’: Camera is free to move and user can choose between orthographic and perspective view. * ’2D’: Camera is fixed on the xy-plane and view is orthographic. * **default\_shadow** (`bool`) – Show shadow when editor is opened. User can still switch it off. * **up\_axis** (`Literal`\[`'Y'`, `'Z'`]) – (view\_mode=’3D’ only) Upwards pointing axis. Possible options: ‘Y’, ‘Z’ (default: ‘Z’) * **x\_axis\_to\_right** (`bool`) – (view\_mode=’3D’ and up\_axis=’Y’ only) X-axis pointing to the right in the initial view New in v14.8.0 * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## IFCAndDataResult[​](/sdk/api/views/.md#_IFCAndDataResult "Direct link to IFCAndDataResult") * *class *viktor.views.IFCAndDataResult(*ifc*, *data*)[](#IFCAndDataResult "Link to this definition") Bases: `_ViewResult` New in v14.6.0 Container with the results that should be visualized in an IFCAndDataView. Please have a look at IFCResult for examples. * Parameters: * **ifc** (`Union`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), [`FileResource`](/sdk/api/api-v1/.md#FileResource "viktor.api_v1.FileResource")]) – IFC geometry file. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## IFCAndDataView[​](/sdk/api/views/.md#_IFCAndDataView "Direct link to IFCAndDataView") * *class *viktor.views.IFCAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#IFCAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") New in v14.6.0 Function decorator to instruct the controller method to return a combined view consisting of an IFCView and a DataView. Example usage: ``` @IFCAndDataView("IFC and data view") def get_ifc_and_data_view(self, params, **kwargs): ifc = File.from_path(Path(__file__).parent / 'sample.ifc') data = ... return IFCAndDataResult(ifc, data) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## IFCResult[​](/sdk/api/views/.md#_IFCResult "Direct link to IFCResult") * *class *viktor.views.IFCResult(*ifc*)[](#IFCResult "Link to this definition") Bases: `_ViewResult` New in v14.6.0 IFC to be visualized in an IFCView. Example static geometry file from path: ``` ifc = File.from_path(Path(__file__).parent / 'sample.ifc') IFCResult(ifc) ``` Example static geometry file from a URL: ``` ifc = File.from_url("https://github.com/IFCjs/test-ifc-files/raw/main/Others/haus.ifc") IFCResult(ifc) ``` **(new in v14.6.1)** In order to improve performance it is possible to use the value of a FileField (i.e. FileResource) directly: ``` IFCResult(params.file_field) ``` * Parameters: **ifc** (`Union`\[[`File`](/sdk/api/core/.md#File "viktor.core.File"), [`FileResource`](/sdk/api/api-v1/.md#FileResource "viktor.api_v1.FileResource")]) – IFC geometry file. ## IFCView[​](/sdk/api/views/.md#_IFCView "Direct link to IFCView") * *class *viktor.views.IFCView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#IFCView "Link to this definition") Bases: [`View`](#View "viktor.views.View") New in v14.6.0 Function decorator to instruct the controller method to return an IFCView. Example usage: ``` @IFCView("IFC view") def get_ifc_view(self, params, **kwargs): ifc = File.from_path(Path(__file__).parent / 'sample.ifc') return IFCResult(ifc) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## ImageAndDataResult[​](/sdk/api/views/.md#_ImageAndDataResult "Direct link to ImageAndDataResult") * *class *viktor.views.ImageAndDataResult(*image*, *data*)[](#ImageAndDataResult "Link to this definition") Bases: `_ViewResult` New in v13.7.0 Container with the image and result data that should be visualized in a ImageAndDataView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. * Parameters: * **image** (`Union`\[`StringIO`, `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – image file. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## ImageAndDataView[​](/sdk/api/views/.md#_ImageAndDataView "Direct link to ImageAndDataView") * *class *viktor.views.ImageAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#ImageAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") New in v13.7.0 Function decorator to instruct the controller method to return a combined view consisting of an image and data. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. Example usage: ``` @ImageAndDataView("Image View") def get_image_data_view(self, params, **kwargs): ... return ImageAndDataResult(image, data_group) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## ImageResult[​](/sdk/api/views/.md#_ImageResult "Direct link to ImageResult") * *class *viktor.views.ImageResult(*image*)[](#ImageResult "Link to this definition") Bases: `_ViewResult` New in v13.7.0 Image to be visualized in an ImageView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. * Parameters: **image** (`Union`\[`StringIO`, `BytesIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File")]) – image file. - *classmethod *from\_path(*file\_path*)[](#ImageResult.from_path "Link to this definition") Use file path to construct the image result. * Parameters: **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – Path to the image. * Return type: [`ImageResult`](#ImageResult "viktor.views.ImageResult") ## ImageView[​](/sdk/api/views/.md#_ImageView "Direct link to ImageView") * *class *viktor.views.ImageView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#ImageView "Link to this definition") Bases: [`View`](#View "viktor.views.View") New in v13.7.0 Function decorator to instruct the controller method to return an ImageView. Supported image types are ‘svg’, ‘jpeg’, ‘png’, ‘gif’. Example usage: ``` @ImageView("Image View") def get_image_view(self, params, **kwargs): file_path = Path(__file__).parent / 'sample.png' return ImageResult(File.from_path(file_path)) # or `ImageResult.from_path(file_path)` ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## InteractionEvent[​](/sdk/api/views/.md#_InteractionEvent "Direct link to InteractionEvent") * *class *viktor.views.InteractionEvent(*event\_type*, *value*)[](#InteractionEvent "Link to this definition") Event triggered by the user as a consequence of an [`viktor.parametrization.Interaction`](/sdk/api/parametrization/.md#Interaction "viktor.parametrization.Interaction"). Warning Do not instantiate this class directly, it is returned as ‘event’ in the method of the button with the corresponding interaction. * Parameters: * **event\_type** (`str`) – type of the event (‘map\_select’) * **value** (`Any`) – value of the user performed interaction. Type depends on event\_type: * map\_select: List\[Union\[str, int]] = identifier of selected features ## Label[​](/sdk/api/views/.md#_Label "Direct link to Label") * *class *viktor.views.Label(*point*, *\*text*, *size\_factor=1*, *color=(0, 0, 0)*)[](#Label "Link to this definition") Text label * Parameters: * **point** ([`Point`](/sdk/api/geometry/.md#Point "viktor.geometry.Point")) – Position of the label. * **text** (`str`) – Text to show; multiple text arguments will each be shown on a new line. * **size\_factor** (`float`) – Factor to be applied to the font size (0 < size\_factor <= 10). * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – Color of the text. - *property *point*: [Point](/sdk/api/geometry/.md#Point "viktor.geometry.Point")*[](#Label.point "Link to this definition") * serialize()[](#Label.serialize "Link to this definition") * Return type: `dict` - *property *text*: str | Tuple\[str, ...]*[](#Label.text "Link to this definition") ## MapAndDataResult[​](/sdk/api/views/.md#_MapAndDataResult "Direct link to MapAndDataResult") * *class *viktor.views.MapAndDataResult(*features*, *data*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[](#MapAndDataResult "Link to this definition") Bases: [`GeoJSONAndDataResult`](#GeoJSONAndDataResult "viktor.views.GeoJSONAndDataResult") Container with the Map data and result data that should be visualized in a MapAndDataView. Optionally a legend and map labels can be included. * Parameters: * **features** (`List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")]) – List that contains the map objects. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. * **labels** (`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]) – Labels that should be placed on the map. * **legend** ([`MapLegend`](#MapLegend "viktor.views.MapLegend")) – Map legend. * **interaction\_groups** (`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *features*: List\[[MapFeature](#MapFeature "viktor.views.MapFeature")]*[](#MapAndDataResult.features "Link to this definition") * *property *geojson*: dict*[](#MapAndDataResult.geojson "Link to this definition") ## MapAndDataView[​](/sdk/api/views/.md#_MapAndDataView "Direct link to MapAndDataView") * *class *viktor.views.MapAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#MapAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a Map and data. Example usage: ``` @MapAndDataView("Map / Data") def get_map_data_view(self, params, **kwargs): ... return MapAndDataResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## MapCircle[​](/sdk/api/views/.md#_MapCircle "Direct link to MapCircle") * *class *viktor.views.MapCircle(*center*, *radius*, *\**, *num\_edges=64*, *\*\*kwargs*)[](#MapCircle "Link to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") New in v14.22.0 Represents a circular polygon on the Earth’s surface formed by a latitude/longitude coordinate and radius \[m]. Example usage: ``` circle = MapCircle( center=MapPoint(52.373922404495474, 5.2459716796875), radius=500 ) ``` * Parameters: * **center** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – Center point of the circle. * **radius** (`float`) – Radius in \[m]. * **num\_edges** (`int`) – Number of polygon edges. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. ## MapEntityLink[​](/sdk/api/views/.md#_MapEntityLink "Direct link to MapEntityLink") * *class *viktor.views.MapEntityLink(*label*, *entity\_id*)[](#MapEntityLink "Link to this definition") Represents a link between a feature in a MapView and a specific entity. Example usage: ``` gef_link = MapEntityLink('GEF x', gef_entity_id) gef_marker = MapPoint(51.99311570849245, 4.385752379894256, entity_links=[gef_link]) ``` * Parameters: * **label** (`str`) – text which is shown to the user. * **entity\_id** (`int`) – id of the linked entity. ## MapFeature[​](/sdk/api/views/.md#_MapFeature "Direct link to MapFeature") * *class *viktor.views.MapFeature(*\**, *title=None*, *description=None*, *color=(39, 45, 51)*, *entity\_links=None*, *identifier=None*)[](#MapFeature "Link to this definition") Bases: `ABC` Base class for features that can be shown in a MapView. See the documentation of the subclasses for example implementations. * Parameters: * **title** (`str`) – Title of a clickable map feature. * **description** (`str`) – Description of a clickable map feature. * **color** ([`Color`](/sdk/api/core/.md#Color "viktor.core.Color")) – Specifies the color of the map feature. * **entity\_links** (`List`\[[`MapEntityLink`](#MapEntityLink "viktor.views.MapEntityLink")]) – When clicking on the map feature, links towards multiple entities can be shown. * **identifier** (`Union`\[`int`, `str`]) – feature identifier New in v13.2.0 ## MapLabel[​](/sdk/api/views/.md#_MapLabel "Direct link to MapLabel") * *class *viktor.views.MapLabel(*lat*, *lon*, *text*, *scale*, *\**, *fixed\_size=False*)[](#MapLabel "Link to this definition") Text which is placed as an overlay on the map. Scale 0-5 is approximately the scale for countries: [![/\_images/map\_label\_scale\_0\_5.png](/_images/map_label_scale_0_5.png)](/_images/map_label_scale_0_5.png) Scale 6-10 is approximately the scale for cities: [![/\_images/map\_label\_scale\_6\_11.png](/_images/map_label_scale_6_11.png)](/_images/map_label_scale_6_11.png) Scale 11-15 is approximately the scale for neighborhoods and streets [![/\_images/map\_label\_scale\_11\_15.png](/_images/map_label_scale_11_15.png)](/_images/map_label_scale_11_15.png) Scale 16-18 is approximately for individual houses. [![/\_images/map\_label\_scale\_14\_19.png](/_images/map_label_scale_14_19.png)](/_images/map_label_scale_14_19.png) * Parameters: * **lat** (`float`) – Latitude of text in degrees. * **lon** (`float`) – Longitude of text in degrees. * **text** (`str`) – Text with is displayed on the map. * **scale** (`float`) – Size of the text on an exponential scale. See example in class docstring for estimate. * **fixed\_size** (`bool`) – When True, the size of the text is fixed regardless of zoom level (default: False). ## MapLegend[​](/sdk/api/views/.md#_MapLegend "Direct link to MapLegend") * *class *viktor.views.MapLegend(*entries*)[](#MapLegend "Link to this definition") A legend which is placed as an overlay on a map view. Example usage: ``` legend = MapLegend([ (Color.from_hex('#0016FF'), "I'm blue"), (Color.from_hex('#FF0000'), "I'm red"), ... ]) ``` * Parameters: **entries** (`List`\[`Tuple`\[[`Color`](/sdk/api/core/.md#Color "viktor.core.Color"), `str`]]) – Items in the legend, defined by color and label. ## MapLine[​](/sdk/api/views/.md#_MapLine "Direct link to MapLine") * *class *viktor.views.MapLine(*start\_point*, *end\_point*, *\*\*kwargs*)[](#MapLine "Link to this definition") Bases: [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") Represents a line on the earth’s surface between two latitude/longitude pairs. In case multiple line segments are to be created, a [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") may be preferred. Example usage: ``` line = MapLine( MapPoint(51.99311570849245, 4.385752379894256), MapPoint(52.40912125231122, 5.031738281255681) ) ``` * Parameters: * **start\_point** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – Map point with latitude and longitude pair. * **end\_point** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – Map point with latitude and longitude pair. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *property *end\_point*: [MapPoint](#MapPoint "viktor.views.MapPoint")*[](#MapLine.end_point "Link to this definition") * *property *start\_point*: [MapPoint](#MapPoint "viktor.views.MapPoint")*[](#MapLine.start_point "Link to this definition") ## MapPoint[​](/sdk/api/views/.md#_MapPoint "Direct link to MapPoint") * *class *viktor.views.MapPoint(*lat*, *lon*, *alt=0*, *\**, *icon=None*, *size='medium'*, *\*\*kwargs*)[](#MapPoint "Link to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a point on the Earth’s surface described by a latitude/longitude coordinate pair. Example usage: ``` marker = MapPoint(51.99311570849245, 4.385752379894256) ``` * Parameters: * **lat** (`float`) – Latitude. * **lon** (`float`) – Longitude. * **alt** (`float`) – Altitude. * **icon** (`str`) – icon to be shown (default: “pin”). See below for all possible icons. * **size** (`Literal`\[`'small'`, `'medium'`, `'large'`]) – size of the marker (“small” | “medium” | “large”) New in v14.5.0 . * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. List of icons: > * arrow-down: [![arrow-down](/_images/arrow-down.svg)](/_images/arrow-down.svg) > > * arrow-left: [![arrow-left](/_images/arrow-left.svg)](/_images/arrow-left.svg) > > * arrow-right: [![arrow-right](/_images/arrow-right.svg)](/_images/arrow-right.svg) > > * arrow-up: [![arrow-up](/_images/arrow-up.svg)](/_images/arrow-up.svg) > > * chevron-down: [![chevron-down](/_images/chevron-down.svg)](/_images/chevron-down.svg) > > * chevron-left: [![chevron-left](/_images/chevron-left.svg)](/_images/chevron-left.svg) > > * chevron-right: [![chevron-right](/_images/chevron-right.svg)](/_images/chevron-right.svg) > > * chevron-up: [![chevron-up](/_images/chevron-up.svg)](/_images/chevron-up.svg) > > * circle: [![circle](/_images/circle.svg)](/_images/circle.svg) > > * circle-filled: [![circle-filled](/_images/circle-filled.svg)](/_images/circle-filled.svg) > > * cross: [![cross](/_images/cross.svg)](/_images/cross.svg) > > * diamond: [![diamond](/_images/diamond.svg)](/_images/diamond.svg) > > * diamond-horizontal: [![diamond-horizontal](/_images/diamond-horizontal.svg)](/_images/diamond-horizontal.svg) > > * drop: [![drop](/_images/drop.svg)](/_images/drop.svg) > > * exclamation-circle: [![exclamation-circle](/_images/exclamation-circle.svg)](/_images/exclamation-circle.svg) > > * exclamation-circle-filled: [![exclamation-circle-filled](/_images/exclamation-circle-filled.svg)](/_images/exclamation-circle-filled.svg) > > * message: [![message](/_images/message.svg)](/_images/message.svg) > > * minus: [![minus](/_images/minus.svg)](/_images/minus.svg) > > * minus-circle: [![minus-circle](/_images/minus-circle.svg)](/_images/minus-circle.svg) > > * minus-circle-filled: [![minus-circle-filled](/_images/minus-circle-filled.svg)](/_images/minus-circle-filled.svg) > > * pin: [![pin](/_images/pin.svg)](/_images/pin.svg) > > * pin-add: [![pin-add](/_images/pin-add.svg)](/_images/pin-add.svg) > > * pin-edit: [![pin-edit](/_images/pin-edit.svg)](/_images/pin-edit.svg) > > * plus: [![plus](/_images/plus.svg)](/_images/plus.svg) > > * plus-circle: [![plus-circle](/_images/plus-circle.svg)](/_images/plus-circle.svg) > > * plus-circle-filled: [![plus-circle-filled](/_images/plus-circle-filled.svg)](/_images/plus-circle-filled.svg) > > * plus-thick: [![plus-thick](/_images/plus-thick.svg)](/_images/plus-thick.svg) > > * question-circle: [![question-circle](/_images/question-circle.svg)](/_images/question-circle.svg) > > * question-circle-filled: [![question-circle-filled](/_images/question-circle-filled.svg)](/_images/question-circle-filled.svg) > > * square: [![square](/_images/square.svg)](/_images/square.svg) > > * square-filled: [![square-filled](/_images/square-filled.svg)](/_images/square-filled.svg) > > * star: [![star](/_images/star.svg)](/_images/star.svg) > > * triangle: [![triangle](/_images/triangle.svg)](/_images/triangle.svg) > > * triangle-down: [![triangle-down](/_images/triangle-down.svg)](/_images/triangle-down.svg) > > * triangle-down-filled: [![triangle-down-filled](/_images/triangle-down-filled.svg)](/_images/triangle-down-filled.svg) > > * triangle-filled: [![triangle-filled](/_images/triangle-filled.svg)](/_images/triangle-filled.svg) > > * triangle-left: [![triangle-left](/_images/triangle-left.svg)](/_images/triangle-left.svg) > > * triangle-left-filled: [![triangle-left-filled](/_images/triangle-left-filled.svg)](/_images/triangle-left-filled.svg) > > * triangle-right: [![triangle-right](/_images/triangle-right.svg)](/_images/triangle-right.svg) > > * triangle-right-filled: [![triangle-right-filled](/_images/triangle-right-filled.svg)](/_images/triangle-right-filled.svg) > > * viktor: [![viktor](/_images/viktor.svg)](/_images/viktor.svg) > > * warning: [![warning](/_images/warning.svg)](/_images/warning.svg) > > * warning-filled: [![warning-filled](/_images/warning-filled.svg)](/_images/warning-filled.svg) > > * wye: [![wye](/_images/wye.svg)](/_images/wye.svg) * *property *alt*: float*[](#MapPoint.alt "Link to this definition") - *classmethod *from\_geo\_point(*point*, *\**, *icon=None*, *size='medium'*, *\*\*kwargs*)[](#MapPoint.from_geo_point "Link to this definition") Instantiates a MapPoint from the provided GeoPoint. * Parameters: * **point** ([`GeoPoint`](/sdk/api/geometry/.md#GeoPoint "viktor.geometry.GeoPoint")) – GeoPoint. * **icon** (`str`) – icon to be shown (default: “pin”). For a complete list of all available markers, see `__init__()` * **size** (`Literal`\[`'small'`, `'medium'`, `'large'`]) – size of the marker (“small” | “medium” | “large”) New in v14.5.0 . * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type: [`MapPoint`](#MapPoint "viktor.views.MapPoint") * *property *lat*: float*[](#MapPoint.lat "Link to this definition") - *property *lon*: float*[](#MapPoint.lon "Link to this definition") ## MapPolygon[​](/sdk/api/views/.md#_MapPolygon "Direct link to MapPolygon") * *class *viktor.views.MapPolygon(*points*, *\**, *holes=None*, *\*\*kwargs*)[](#MapPolygon "Link to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a polygon on the earth’s surface formed by a set of latitude/longitude pairs. Example usage: ``` polygon = MapPolygon([ MapPoint(52.373922404495474, 5.2459716796875), MapPoint(52.10313118589299, 5.3997802734375), MapPoint(52.373922404495474, 5.57281494140625), ]) ``` * Parameters: * **points** (`List`\[[`MapPoint`](#MapPoint "viktor.views.MapPoint")]) – Map points with latitude and longitude pair. The profile is automatically closed, so it is not necessary to add the start point at the end. * **holes** (`List`\[[`MapPolygon`](#MapPolygon "viktor.views.MapPolygon")]) – List of interior polygons which form holes in the exterior polygon. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *classmethod *from\_geo\_polygon(*polygon*, *\*\*kwargs*)[](#MapPolygon.from_geo_polygon "Link to this definition") Instantiates a MapPolygon from the provided GeoPolygon. * Parameters: * **polygon** ([`GeoPolygon`](/sdk/api/geometry/.md#GeoPolygon "viktor.geometry.GeoPolygon")) – GeoPolygon. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type: [`MapPolygon`](#MapPolygon "viktor.views.MapPolygon") * *property *holes*: List\[[MapPolygon](#MapPolygon "viktor.views.MapPolygon")]*[](#MapPolygon.holes "Link to this definition") - *property *points*: List\[[MapPoint](#MapPoint "viktor.views.MapPoint")]*[](#MapPolygon.points "Link to this definition") ## MapPolyline[​](/sdk/api/views/.md#_MapPolyline "Direct link to MapPolyline") * *class *viktor.views.MapPolyline(*\*points*, *\*\*kwargs*)[](#MapPolyline "Link to this definition") Bases: [`MapFeature`](#MapFeature "viktor.views.MapFeature") Represents a polyline on the earth’s surface between several latitude/longitude pairs. Example usage: ``` line = MapPolyline( MapPoint(51.99311570849245, 4.385752379894256), MapPoint(52.40912125231122, 5.031738281255681), ... ) ``` * Parameters: * **points** ([`MapPoint`](#MapPoint "viktor.views.MapPoint")) – MapPoints with latitude and longitude pair. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. - *classmethod *from\_geo\_polyline(*polyline*, *\*\*kwargs*)[](#MapPolyline.from_geo_polyline "Link to this definition") Instantiates a MapPolyline from the provided GeoPolyline. * Parameters: * **polyline** ([`GeoPolyline`](/sdk/api/geometry/.md#GeoPolyline "viktor.geometry.GeoPolyline")) – GeoPolyline. * **kwargs** (`Any`) – See [`MapFeature`](#MapFeature "viktor.views.MapFeature") for possible kwargs. * Return type: [`MapPolyline`](#MapPolyline "viktor.views.MapPolyline") * *property *points*: List\[[MapPoint](#MapPoint "viktor.views.MapPoint")]*[](#MapPolyline.points "Link to this definition") ## MapResult[​](/sdk/api/views/.md#_MapResult "Direct link to MapResult") * *class *viktor.views.MapResult(*features*, *labels=None*, *legend=None*, *\**, *interaction\_groups=None*)[](#MapResult "Link to this definition") Bases: [`GeoJSONResult`](#GeoJSONResult "viktor.views.GeoJSONResult") Container with the Map data that should be visualized in a MapView. Optionally a legend and map labels can be included. * Parameters: * **features** (`List`\[[`MapFeature`](#MapFeature "viktor.views.MapFeature")]) – List that contains the map objects. * **labels** (`List`\[[`MapLabel`](#MapLabel "viktor.views.MapLabel")]) – Labels that should be placed on the map. * **legend** ([`MapLegend`](#MapLegend "viktor.views.MapLegend")) – Map legend. * **interaction\_groups** (`Dict`\[`str`, `Sequence`\[`Union`\[`int`, `str`, [`MapFeature`](#MapFeature "viktor.views.MapFeature")]]]) – create named groups that can be referred to in a map interaction New in v13.2.0 - *property *features*: List\[[MapFeature](#MapFeature "viktor.views.MapFeature")]*[](#MapResult.features "Link to this definition") * *property *geojson*: dict*[](#MapResult.geojson "Link to this definition") ## MapView[​](/sdk/api/views/.md#_MapView "Direct link to MapView") * *class *viktor.views.MapView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#MapView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a Map (geographic data) view. Example usage: ``` @MapView("Map") def get_map_view(self, params, **kwargs): ... return MapResult(...) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## PDFResult[​](/sdk/api/views/.md#_PDFResult "Direct link to PDFResult") * *class *viktor.views.PDFResult(*\**, *file=None*, *url=None*)[](#PDFResult "Link to this definition") Bases: `_ViewResult` PDF document to be visualized in a PDFView. Can be defined from a File object or from a URL (direct-sharing). If both file and url are defined, url takes precedence. In case of URL: the hosting website must allow for direct accessing for the document to be shown. If this is forbidden (undefined CORS-headers), the document can alternatively be shown via the file argument with a File.from\_url(…), in which it is downloaded first and viewed subsequently (indirect-sharing). Example usages: From URL (direct-sharing): ``` PDFResult(url="https://www...") ``` From URL (indirect-sharing): ``` f = File.from_url("https://www...") PDFResult(file=f) ``` From path: ``` file_path = Path(__file__).parent / 'sample.pdf' PDFResult.from_path(file_path) # or ... PDFResult(File.from_path(file_path)) ``` * Parameters: * **file** ([`File`](/sdk/api/core/.md#File "viktor.core.File")) – PDF document to view * **url** (`str`) – URL of PDF document to view. If accessing the PDF directly from the URL is not allowed by the host website (undefined CORS-headers), this will result in the document not showing up in the view (as an alternative one can use File.from\_url). - *classmethod *from\_path(*file\_path*)[](#PDFResult.from_path "Link to this definition") Create the PDFResult from a path to the PDF file. * Parameters: **file\_path** (`Union`\[`str`, `bytes`, `PathLike`]) – file path to a PDF file * Return type: [`PDFResult`](#PDFResult "viktor.views.PDFResult") ## PDFView[​](/sdk/api/views/.md#_PDFView "Direct link to PDFView") * *class *viktor.views.PDFView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#PDFView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a PDFView. Example usage: ``` @PDFView("PDF View") def get_pdf_view(self, params, **kwargs): file_path = Path(__file__).parent / 'sample.pdf' return PDFResult(File.from_path(file_path)) # or `PDFResult.from_path(file_path)` ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## PlotlyAndDataResult[​](/sdk/api/views/.md#_PlotlyAndDataResult "Direct link to PlotlyAndDataResult") * *class *viktor.views.PlotlyAndDataResult(*figure*, *data*)[](#PlotlyAndDataResult "Link to this definition") Bases: `_ViewResult` Plotly figure to be visualized in a PlotlyAndDataView. The figure can be provided in json-string or dict format. **(new in v14.22.0)** Support a plotly ‘Figure’ object. Example usage: ``` @PlotlyAndDataView("Plotly and data view") def get_plotly_and_data_view(self, params, **kwargs): data_group = ... fig = go.Figure( data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])], layout=go.Layout(title=go.layout.Title(text="A Figure Specified By A Graph Object")) ) return PlotlyAndDataResult(fig, data_group) ``` * Parameters: * **figure** (`Union`\[`str`, `dict`, `Figure`]) – Plotly figure * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – result data ## PlotlyAndDataView[​](/sdk/api/views/.md#_PlotlyAndDataView "Direct link to PlotlyAndDataView") * *class *viktor.views.PlotlyAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#PlotlyAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of a PlotlyView and a DataView. Example usage: ``` @PlotlyAndDataView("Plotly and data view") def get_plotly_and_data_view(self, params, **kwargs): ... return PlotlyAndDataResult(figure, data_group) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## PlotlyResult[​](/sdk/api/views/.md#_PlotlyResult "Direct link to PlotlyResult") * *class *viktor.views.PlotlyResult(*figure*)[](#PlotlyResult "Link to this definition") Bases: `_ViewResult` Plotly figure to be visualized in a PlotlyView. The figure can be provided in json-string or dict format. **(new in v14.22.0)** Support a plotly ‘Figure’ object. Example usages: ``` @PlotlyView("Plotly view") def get_plotly_view(self, params, **kwargs): fig = go.Figure( data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])], layout=go.Layout(title=go.layout.Title(text="A Figure Specified By A Graph Object")) ) return PlotlyResult(fig) ``` ``` @PlotlyView("Plotly view") def get_plotly_view(self, params, **kwargs): fig = { "data": [{"type": "bar", "x": [1, 2, 3], "y": [1, 3, 2]}], "layout": {"title": {"text": "A Figure Specified By Python Dictionary"}} } return PlotlyResult(fig) ``` * Parameters: **figure** (`Union`\[`str`, `dict`, `Figure`]) – Plotly figure ## PlotlyView[​](/sdk/api/views/.md#_PlotlyView "Direct link to PlotlyView") * *class *viktor.views.PlotlyView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#PlotlyView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a PlotlyView. Example usage: ``` @PlotlyView("Plotly view") def get_plotly_view(self, params, **kwargs): ... return PlotlyResult(figure) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## Summary[​](/sdk/api/views/.md#_Summary "Direct link to Summary") * *class *viktor.views.Summary(*\*\*items*)[](#Summary "Link to this definition") Bases: `OrderedDict` Summary of resulting data items, which can be used in the summary view of an entity. Example usage: ``` class Controller: ... summary = Summary( item_1=SummaryItem(...), item_2=SummaryItem(...), item_3=SummaryItem(...) ) ``` * Parameters: **items** ([`SummaryItem`](#SummaryItem "viktor.views.SummaryItem")) – Items that are shown in the summary, with a maximum of 6 items per summary. ## SummaryItem[​](/sdk/api/views/.md#_SummaryItem "Direct link to SummaryItem") * *class *viktor.views.SummaryItem(*label*, *item\_type*, *source*, *value\_path*, *\**, *suffix=''*, *prefix=''*)[](#SummaryItem "Link to this definition") A summary consists of SummaryItem objects, that define which input / result values should be displayed. Suppose we have a data view with a controller method ‘data\_view’, which returns a DataItem with key ‘output\_item\_1’. The following summary item can be constructed to refer to this result: ``` item_1 = SummaryItem('Label', float, 'data_view', 'output_item_1', suffix='N') ``` Suppose we have a parametrization with a certain parameter defined as geometry.input.length, this can be converted to a summary item by doing: ``` item_2 = SummaryItem('Length', float, 'parametrization', 'geometry.input.length', suffix='m') ``` * Parameters: * **label** (`str`) – Text label of the item. * **item\_type** (`Type`\[`Union`\[`str`, `float`]]) – Type of value, options are ‘str’ | ‘float’. * **source** (`str`) – Source from which the input / output should be extracted. * **value\_path** (`str`) – Dotted path of value in parametrization / data structure of view. e.g: level1.level2.value * **suffix** (`str`) – A suffix will be put behind the value to provide additional information such as units. * **prefix** (`str`) – A prefix will be put in front of the value to provide info such as a dollar sign. ## TableCell[​](/sdk/api/views/.md#_TableCell "Direct link to TableCell") * *class *viktor.views.TableCell(*value*, *\**, *text\_color=None*, *background\_color=None*, *text\_style=None*)[](#TableCell "Link to this definition") ## TableHeader[​](/sdk/api/views/.md#_TableHeader "Direct link to TableHeader") * *class *viktor.views.TableHeader(*title*, *\**, *align=None*, *num\_decimals=None*)[](#TableHeader "Link to this definition") Header object that can be used in [`TableResult`](#TableResult "viktor.views.TableResult") to set styling. * Parameters: * **title** (`str`) – Title that will be shown in the header. * **align** (`Optional`\[`Literal`\[`'center'`, `'left'`, `'right'`]]) – Visual alignment of the corresponding row/column values within the table * **num\_decimals** (`Optional`\[`int`]) – Number of decimals that is shown for the row/column values (requires corresponding row/column to contain only numbers). ## TableResult[​](/sdk/api/views/.md#_TableResult "Direct link to TableResult") * *class *viktor.views.TableResult(*data*, *\**, *column\_headers=None*, *row\_headers=None*, *enable\_sorting\_and\_filtering=None*)[](#TableResult "Link to this definition") Bases: `_ViewResult` New in v14.13.0 Data to be visualized in an TableView. Example of a simple TableResult: ``` data = [ [1.5, "Square"], [3.1, "Circle"], ] TableResult(data) ``` Example of a simple TableResult with column header titles: ``` data = [ [1.5, "Square"], [3.1, "Circle"], ] TableResult(data, column_headers=["Area [m²]", "Shape"]) ``` Example of a more complex TableResult with column and cell styling: ``` data = [ [1.5, "Square"], [ TableCell(3.1, text_color=Color.green()), TableCell("Circle", background_color=Color(211, 211, 211), text_style='italic') ], ] TableResult(data, column_headers=[ TableHeader("Area [m²]", num_decimals=2), TableHeader("Shape", align='center') ])) ``` Example of a transposed table: ``` data = [ [1.5, "Square"], [3.1, "Circle"], ] transposed_data = [list(i) for i in zip(*data)] TableResult( transposed_data, row_headers=[ TableHeader("Area [m²]", num_decimals=2), TableHeader("Shape", align='center') ], column_headers=["Object 1", "Object 2"] )) ``` Example of a pandas Dataframe object: ``` df = pd.DataFrame([[1, 4], [2, 3]]) TableResult(df) ``` Example of a pandas Styler object: ``` df = pd.DataFrame([[1, 4], [2, 3]]) styler = df.style.highlight_min(color="red") TableResult(styler) ``` Result to be shown in a TableView. In case the data is a pandas Styler object, the following properties will be inherited: * background\_color (per cell) * text\_color (per cell) * text\_style (per cell, bold or italic) * align (per column/row, only if all cells in a row/column have the same alignment) - Parameters: * **data** (`Union`\[`Sequence`\[`Sequence`\[`Union`\[`str`, `float`, `int`, `bool`, `datetime`, `date`, `None`, [`TableCell`](#TableCell "viktor.views.TableCell")]]], `DataFrame`, `Styler`]) – Table content. Can also be a pandas DataFrame or Styler object. * **column\_headers** (`Optional`\[`Sequence`\[`Union`\[`str`, [`TableHeader`](#TableHeader "viktor.views.TableHeader")]]]) – Headers shown above the columns. Can be used for custom titles and styling. In case the data is a pandas Styler object, this can be set explicitly to overwrite the generated titles and styling. * **row\_headers** (`Optional`\[`Sequence`\[`Union`\[`str`, [`TableHeader`](#TableHeader "viktor.views.TableHeader")]]]) – Headers shown next to the rows. Can be used for custom titles and styling. In case the data is a pandas Styler object, this can be set explicitly to overwrite the generated titles and styling. * **enable\_sorting\_and\_filtering** (`Optional`\[`bool`]) – Enable sorting and filtering on columns. If set to None (default), sorting and filtering will be enabled if each of the columns in data is of homogeneous type, and disabled otherwise. If sorting and filtering is enabled explicitly, each column must be of homogeneous type. ## TableView[​](/sdk/api/views/.md#_TableView "Direct link to TableView") * *class *viktor.views.TableView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#TableView "Link to this definition") Bases: [`View`](#View "viktor.views.View") New in v14.13.0 Function decorator to instruct the controller method to return an TableView. Example usage: ``` @TableView("Table view") def get_table_view(self, params, **kwargs): data = [ [2.5, 7, "Square"], [1.5, 8, "Circle"], ] return TableResult(data, column_headers=["Width", "Height", "Shape"]) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## View[​](/sdk/api/views/.md#_View "Direct link to View") * *class *viktor.views.View(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#View "Link to this definition") Bases: `ABC` Warning Do not use this class directly in an application. Base-class of a function decorator that can be used to specify the desired view to be returned. See the subclasses for specific examples of each type of view. **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## WebAndDataResult[​](/sdk/api/views/.md#_WebAndDataResult "Direct link to WebAndDataResult") * *class *viktor.views.WebAndDataResult(*\**, *html=None*, *url=None*, *data=None*)[](#WebAndDataResult "Link to this definition") Bases: `_ViewResult` Container with the web data and result data that should be visualized in a WebAndDataView. The Web part can be constructed in two ways, which should not be used together: * url: to serve a URL (takes precedence if both are defined) * html: for serving a single html page - Parameters: * **html** (`Union`\[`StringIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `str`]) – HTML formatted content. * **url** (`str`) – Direct URL. * **data** ([`DataGroup`](#DataGroup "viktor.views.DataGroup")) – Result data. ## WebAndDataView[​](/sdk/api/views/.md#_WebAndDataView "Direct link to WebAndDataView") * *class *viktor.views.WebAndDataView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#WebAndDataView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a combined view consisting of web-content and data. Example usage: ``` @WebAndDataView("Web / Data") def get_web_data_view(self, params, **kwargs): # calculate data ... return WebAndDataResult(html="Hello world", data=data_group) ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 ## WebResult[​](/sdk/api/views/.md#_WebResult "Direct link to WebResult") * *class *viktor.views.WebResult(*\**, *html=None*, *url=None*)[](#WebResult "Link to this definition") Bases: `_ViewResult` Container with the data that should be visualized in a WebView. There are two options, which should not be used together: * url: to serve a URL (takes precedence if both are defined) * html: for serving a single html page - Parameters: * **html** (`Union`\[`StringIO`, [`File`](/sdk/api/core/.md#File "viktor.core.File"), `str`]) – HTML formatted content. * **url** (`str`) – Direct URL. * *classmethod *from\_path(*file\_path*)[](#WebResult.from_path "Link to this definition") * Return type: [`WebResult`](#WebResult "viktor.views.WebResult") ## WebView[​](/sdk/api/views/.md#_WebView "Direct link to WebView") * *class *viktor.views.WebView(*label*, *duration\_guess=None*, *\**, *description=None*, *update\_label=None*, *visible=True*, *\*\*kwargs*)[](#WebView "Link to this definition") Bases: [`View`](#View "viktor.views.View") Function decorator to instruct the controller method to return a web-content view. Example usage: ``` @WebView("Hello world") def get_web_view(self, params, **kwargs): return WebResult(html="Hello world") ``` **(new in v14.15.0)** The ‘duration\_guess’ argument is now optional. * Parameters: * **label** (`str`) – Name which is shown on tab in interface. e.g: ‘3D Representation’ * **duration\_guess** (`int`) – Estimation of view calculation in seconds. This will be used to add a manual refresh button for long-running tasks (larger than 3s). This estimation does not need to be very precise, but the performance will be better if this is close to the real maximum computation time (defaults to 1). * **description** (`str`) – Show more information to the user through a tooltip on hover (max. 200 characters). * **update\_label** (`str`) – Name which is shown on the update button in case of a slow view (max. 30 characters). * **visible** (`Union`\[`bool`, `Callable`]) – Visibility of the view. Can depend on params by using a callback function New in v14.22.0 --- # Changelog All notable changes to the viktor SDK will be documented in this file, categorized by version number. The changes can be categorized further in the following headers: * **Action Required**: when a backwards incompatible change is made, which requires actions in the application code. This header will only be present in major releases, on Beta features, or when a Python version is dropped. * **Added**: when a functionality is added, without breaking compatibility with older versions. * **Deprecated**: when an existing functionality will be removed in upcoming releases. You will find a reference to the upgrade instructions in this change. * **Docs**: when the change involves SDK documentation, docstring, and/or type hinting. * **Fixed**: when the change fixes a bug/error. * **Security**: when a vulnerability is fixed. Each change consists of a tag to annotate which VIKTOR module is involved. If the change encompasses multiple modules, the `viktor` tag is used. ## v14[​](/sdk/changelog/.md#v14 "Direct link to v14") *** ### v14.24.0 - 29/07/2025[​](/sdk/changelog/.md#v14240---29072025 "Direct link to v14.24.0 - 29/07/2025") #### Added[​](/sdk/changelog/.md#added "Direct link to Added") * `core` Added allow\_saving to Controller. *** ### v14.23.0 - 22/07/2025[​](/sdk/changelog/.md#v14230---22072025 "Direct link to v14.23.0 - 22/07/2025") #### Added[​](/sdk/changelog/.md#added-1 "Direct link to Added") * `external` `OAuth2Integration` to support third-party OAuth 2.0 integrations *** ### v14.22.0 - 22/05/2025[​](/sdk/changelog/.md#v14220---22052025 "Direct link to v14.22.0 - 22/05/2025") #### Added[​](/sdk/changelog/.md#added-2 "Direct link to Added") * `geometry` Support counter-clockwise profile for `Polygon` extrusion * `views` Added `MapCircle` object * `views` Make private properties of `DataItem` public and make 'value' argument optional * `views` Directly use a plotly Figure object in `PlotlyResult` / `PlotlyAndDataResult` * `views` Append items to an existing data group using `DataGroup.add()` * `views` Added properties `GeoPoint.latitude` and `GeoPoint.longitude` * `geometry` Support hex value and RGB tuple as 'color' input on a `Material` * `views` `visible` argument on views to enable view visibility based on params *** ### v14.21.0 - 29/04/2025[​](/sdk/changelog/.md#v14210---29042025 "Direct link to v14.21.0 - 29/04/2025") #### Added[​](/sdk/changelog/.md#added-3 "Direct link to Added") * `parametrization` `initially_expanded` argument on `Section` to expand or collapse individual sections on editor entry * `parametrization` **\[BETA]** `Chat` field *** ### v14.20.1 - 24/03/2025[​](/sdk/changelog/.md#v14201---24032025 "Direct link to v14.20.1 - 24/03/2025") #### Added[​](/sdk/changelog/.md#added-4 "Direct link to Added") * `viktor` Support numpy v2 *** ### v14.20.0 - 05/03/2025[​](/sdk/changelog/.md#v14200---05032025 "Direct link to v14.20.0 - 05/03/2025") #### Added[​](/sdk/changelog/.md#added-5 "Direct link to Added") * `result` DownloadResult allows file names consisting of non-ASCII characters and whitespaces * `parametrization` Support OutputField in DynamicArray #### Docs[​](/sdk/changelog/.md#docs "Direct link to Docs") * `api_v1` Updated docstring reference `uses_privileged_api` to `enable_privileged_api` #### Fixed[​](/sdk/changelog/.md#fixed "Direct link to Fixed") * `external` RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements * `parametrization` Error in FunctionLookup during generation of OutputField causes broken editor *** ### v14.19.0 - 08/01/2025[​](/sdk/changelog/.md#v14190---08012025 "Direct link to v14.19.0 - 08/01/2025") #### Known Issues[​](/sdk/changelog/.md#known-issues "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/sdk/changelog/.md#added-6 "Direct link to Added") * `core` Appoint top-level entity as starting page with `InitialEntity` `use_as_start_page` argument *** ### v14.18.0 - 03/01/2025[​](/sdk/changelog/.md#v14180---03012025 "Direct link to v14.18.0 - 03/01/2025") #### Known Issues[​](/sdk/changelog/.md#known-issues-1 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/sdk/changelog/.md#added-7 "Direct link to Added") * `parametrization` Support 'name' on DynamicArray * `parametrization` Removed **\[BETA]** status from GeometrySelectField and GeometryMultiSelectField * `utils` Increased expiration of memoization results from 1 hour to 24 hours * `utils` Increased amount of locally stored memoization results from 10 to 50 items #### Fixed[​](/sdk/changelog/.md#fixed-1 "Direct link to Fixed") * `core` Remove newly created file key from storage in case subsequent Storage.set fails * `parametrization` Warning regarding numeric option value within a table is not triggered for AutocompleteField and MultiSelectField * `parametrization` Fixed typehint of default argument in GeometryMultiSelectField *** ### v14.17.0 - 03/12/2024[​](/sdk/changelog/.md#v14170---03122024 "Direct link to v14.17.0 - 03/12/2024") #### Known Issues[​](/sdk/changelog/.md#known-issues-2 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/sdk/changelog/.md#added-8 "Direct link to Added") * `external` DynamoAnalysis * `external` ETABSAnalysis * `external` MatlabAnalysis * `external` PlaxisAnalysis * `external` PythonAnalysis * `external` RevitAnalysis * `external` SAP2000Analysis * `external` TeklaAnalysis *** ### v14.16.2 - 30/10/2024[​](/sdk/changelog/.md#v14162---30102024 "Direct link to v14.16.2 - 30/10/2024") #### Known Issues[​](/sdk/changelog/.md#known-issues-3 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Added[​](/sdk/changelog/.md#added-9 "Direct link to Added") * `external` Serialized SCIA model is compressed to allow for large input models *** ### v14.16.1 - 15/10/2024[​](/sdk/changelog/.md#v14161---15102024 "Direct link to v14.16.1 - 15/10/2024") #### Known Issues[​](/sdk/changelog/.md#known-issues-4 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Fixed[​](/sdk/changelog/.md#fixed-2 "Direct link to Fixed") * `api_v1` Fixed several Entity methods that did not work when using a Personal Access Token *** ### v14.16.0 - 08/10/2024[​](/sdk/changelog/.md#v14160---08102024 "Direct link to v14.16.0 - 08/10/2024") #### Known Issues[​](/sdk/changelog/.md#known-issues-5 "Direct link to Known Issues") * `external` **\[fixed in v14.20.0]** RcsOutputFileParser return format breaks backward compatibility in case of empty XML elements #### Action Required[​](/sdk/changelog/.md#action-required "Direct link to Action Required") * `viktor` Removed support for Python 3.8 #### Added[​](/sdk/changelog/.md#added-10 "Direct link to Added") * `viktor` Support for Python 3.13 #### Deprecated[​](/sdk/changelog/.md#deprecated "Direct link to Deprecated") * `viktor` Support for Python 3.9 will be removed [(U91)](/sdk/upgrades/.md#U91) #### Docs[​](/sdk/changelog/.md#docs-1 "Direct link to Docs") * `viktor` Fixed that public classes/functions not in **all** were excluded from the docs *** ### v14.15.2 - 04/09/2024[​](/sdk/changelog/.md#v14152---04092024 "Direct link to v14.15.2 - 04/09/2024") #### Fixed[​](/sdk/changelog/.md#fixed-3 "Direct link to Fixed") * `views` Fixed TableView from pandas Styler object crashing on unsupported format * `viktor` Requests now use the user's system certificates to solve SSL cert verification errors *** ### v14.15.1 - 26/08/2024[​](/sdk/changelog/.md#v14151---26082024 "Direct link to v14.15.1 - 26/08/2024") #### Fixed[​](/sdk/changelog/.md#fixed-4 "Direct link to Fixed") * `viktor` Lazy import of the `external` modules which fixes a potential ImportError and improves import speed * `views` Lazy import of pandas to improve import speed of the `views` module *** ### v14.15.0 - 22/08/2024[​](/sdk/changelog/.md#v14150---22082024 "Direct link to v14.15.0 - 22/08/2024") #### Added[​](/sdk/changelog/.md#added-11 "Direct link to Added") * `viktor` Support for single import (e.g. `import viktor as vkt; vkt.NumberField(...)`) * `core` Make 'label' on ViktorController optional * `views` Make 'duration\_guess' on all Views optional #### Fixed[​](/sdk/changelog/.md#fixed-5 "Direct link to Fixed") * `views` Fix bug with using `TableView` with `pandas` showing data incorrectly in certain cases * `views` Fix small typo in `SummaryItem` suffix docstring * `external` Fix error mapping for spreadsheet calculation (SpreadsheetCalculation) so more error information is shown * `external` Fix error mapping for spreadsheet renderer (SpreadsheetTemplate / render\_spreadsheet) so more error information is shown * `core` External services (e.g. `convert_word_to_pdf`, `render_jinja_template`, etc.) now show more error information *** ### v14.14.0 - 07/08/2024[​](/sdk/changelog/.md#v14140---07082024 "Direct link to v14.14.0 - 07/08/2024") #### Added[​](/sdk/changelog/.md#added-12 "Direct link to Added") * `utils` `render_jinja_template` now validates identifiers before filling template * `external` `render_word_file` and `WordFileTemplate.render()` now validate identifiers before filling template * `external` Added `file` property to `SpreadsheetCalculation` and `SpreadsheetResult` #### Fixed[​](/sdk/changelog/.md#fixed-6 "Direct link to Fixed") * `parametrization` Removed distracting warning when Controller contains an empty parametrization * `core` Delete temp file from disk after closing a `File.from_url` *** ### v14.13.0 - 10/07/2024[​](/sdk/changelog/.md#v14130---10072024 "Direct link to v14.13.0 - 10/07/2024") #### Added[​](/sdk/changelog/.md#added-13 "Direct link to Added") * `views` Added `TableView` for easy creation of output tables *** ### v14.12.0 - 01/07/2024[​](/sdk/changelog/.md#v14120---01072024 "Direct link to v14.12.0 - 01/07/2024") #### Added[​](/sdk/changelog/.md#added-14 "Direct link to Added") * `api_v1` Added `entity_compute` method for doing computations via the API #### Fixed[​](/sdk/changelog/.md#fixed-7 "Direct link to Fixed") * `external` Updated polling interval of external integrations to make short duration external computations more responsive *** ### v14.11.0 - 18/06/2024[​](/sdk/changelog/.md#v14110---18062024 "Direct link to v14.11.0 - 18/06/2024") #### Added[​](/sdk/changelog/.md#added-15 "Direct link to Added") * `api_v1` Added retries in relevant API calls * `parametrization` Added support for disabling a `Step` *** ### v14.10.1 - 17/06/2024[​](/sdk/changelog/.md#v14101---17062024 "Direct link to v14.10.1 - 17/06/2024") #### Fixed[​](/sdk/changelog/.md#fixed-8 "Direct link to Fixed") * `viktor` Mark numpy v2 as incompatible with viktor *** ### v14.10.0 - 15/05/2024[​](/sdk/changelog/.md#v14100---15052024 "Direct link to v14.10.0 - 15/05/2024") #### Added[​](/sdk/changelog/.md#added-16 "Direct link to Added") * `parametrization` Added GeometrySelectField and GeometryMultiSelectField * `geometry` Added `identifier` to geometrical objects #### Fixed[​](/sdk/changelog/.md#fixed-9 "Direct link to Fixed") * `viktor` Fix command to also function for `app.py` *** ### v14.9.0 - 04/04/2024[​](/sdk/changelog/.md#v1490---04042024 "Direct link to v14.9.0 - 04/04/2024") #### Added[​](/sdk/changelog/.md#added-17 "Direct link to Added") * `api_v1` Added `API().get_workspace` and `API().get_workspaces` * `api_v1` Support to use the API module from outside of a VIKTOR app *** ### v14.8.0 - 28/02/2024[​](/sdk/changelog/.md#v1480---28022024 "Direct link to v14.8.0 - 28/02/2024") #### Added[​](/sdk/changelog/.md#added-18 "Direct link to Added") * `parametrization` Define dynamic option lists per dynamic array row * `views` `GeometryView` `x_axis_to_right` setting to set the initial x-axis orientation * `external` GrasshopperAnalysis #### Deprecated[​](/sdk/changelog/.md#deprecated-1 "Direct link to Deprecated") * `views` `GeometryView` initial x-axis orientation will be to the right by default [(U90)](/sdk/upgrades/.md#U90) #### Fixed[​](/sdk/changelog/.md#fixed-10 "Direct link to Fixed") * `parametrization` Fix incorrect or failing serialization when using non-native objects (e.g. Color, GeoPoint, etc.) in DynamicArray default *** ### v14.7.1 - 06/02/2024[​](/sdk/changelog/.md#v1471---06022024 "Direct link to v14.7.1 - 06/02/2024") #### Added[​](/sdk/changelog/.md#added-19 "Direct link to Added") * `parametrization` Added `workspace_id` in signature of controller methods and callback functions *** ### v14.7.0 - 10/01/2024[​](/sdk/changelog/.md#v1470---10012024 "Direct link to v14.7.0 - 10/01/2024") #### Added[​](/sdk/changelog/.md#added-20 "Direct link to Added") * `viktor` Support for Python 3.12 * `parametrization` Support for (dynamic) visibility on `Page`, `Tab`, and `Section` * `parametrization` Support to specify `width` on a Page and Step to adjust the width-ratio between input and output of an editor * `external` SCIA binding: general cross-sections (polygon + openings only) #### Deprecated[​](/sdk/changelog/.md#deprecated-2 "Direct link to Deprecated") * `parametrization` Removed `always_available` from buttons [(U88)](/sdk/upgrades/.md#U88) * `viktor` Support for Python 3.8 will be removed [(U89)](/sdk/upgrades/.md#U89) #### Fixed[​](/sdk/changelog/.md#fixed-11 "Direct link to Fixed") * `viktor` Upgrade vendored trimesh to resolve numpy deprecation *** ### v14.6.1 - 16/10/2023[​](/sdk/changelog/.md#v1461---16102023 "Direct link to v14.6.1 - 16/10/2023") #### Added[​](/sdk/changelog/.md#added-21 "Direct link to Added") * `views` Added the possibility to use a FileResource as input for the IFCResult and IFCAndDAtaResult #### Fixed[​](/sdk/changelog/.md#fixed-12 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` crashes due to incorrect parsing of line strips *** ### v14.6.0 - 03/10/2023[​](/sdk/changelog/.md#v1460---03102023 "Direct link to v14.6.0 - 03/10/2023") #### Added[​](/sdk/changelog/.md#added-22 "Direct link to Added") * `external` IDEA binding: added support to set name of design member * `external` IDEA binding: added support to set description of extreme * `external` IDEA binding: added support to set project data properties * `views` IFCView and IFCAndDataView #### Fixed[​](/sdk/changelog/.md#fixed-13 "Direct link to Fixed") * `geo` Fixed error caused by deprecated matplotlib style 'seaborn-whitegrid' * `viktor` Removed upper bounds of VIKTOR dependencies ('pandas' and 'munch') *** ### v14.5.0 - 05/09/2023[​](/sdk/changelog/.md#v1450---05092023 "Direct link to v14.5.0 - 05/09/2023") #### Added[​](/sdk/changelog/.md#added-23 "Direct link to Added") * `geometry` Metalness and roughness of default `Material` updated to 0.5 and 1.0 respectively * `geometry` `Material` properties can now be set on the instance (e.g. `mat.opacity = 0.3`) * `views` Support marker size of a `MapPoint` by specifying the `size` argument #### Deprecated[​](/sdk/changelog/.md#deprecated-3 "Direct link to Deprecated") * `geometry` Threejs properties renamed / removed from `Material` [(U87)](/sdk/upgrades/.md#U87) *** ### v14.4.0 - 25/07/2023[​](/sdk/changelog/.md#v1440---25072023 "Direct link to v14.4.0 - 25/07/2023") #### Added[​](/sdk/changelog/.md#added-24 "Direct link to Added") * `views` Add `geometry_type` to `GeometryResult` and `GeometryAndDataResult` to support alternative geometry file formats (e.g. 3DM) *** ### v14.3.0 - 11/07/2023[​](/sdk/changelog/.md#v1430---11072023 "Direct link to v14.3.0 - 11/07/2023") #### Added[​](/sdk/changelog/.md#added-25 "Direct link to Added") * `external` SCIA binding: create averaging strips (POINT type only) * `parametrization` `Image` field that can be used to display a static image *** ### v14.2.1 - 15/06/2023[​](/sdk/changelog/.md#v1421---15062023 "Direct link to v14.2.1 - 15/06/2023") #### Fixed[​](/sdk/changelog/.md#fixed-14 "Direct link to Fixed") * `api_v1` Regression in `len(entity.revisions())` causing an error *** ### v14.2.0 - 13/06/2023[​](/sdk/changelog/.md#v1420---13062023 "Direct link to v14.2.0 - 13/06/2023") #### Added[​](/sdk/changelog/.md#added-26 "Direct link to Added") * `parametrization` `ChildEntityManager` field that can be used to manage child entities *** ### v14.1.0 - 23/05/2023[​](/sdk/changelog/.md#v1410---23052023 "Direct link to v14.1.0 - 23/05/2023") #### Added[​](/sdk/changelog/.md#added-27 "Direct link to Added") * `external` SCIA binding: create selections *** ### v14.0.0 - 12/04/2023[​](/sdk/changelog/.md#v1400---12042023 "Direct link to v14.0.0 - 12/04/2023") #### Action Required[​](/sdk/changelog/.md#action-required-1 "Direct link to Action Required") * `viktor` Upgrade instructions U76 - U86 have been applied #### Added[​](/sdk/changelog/.md#added-28 "Direct link to Added") * `parametrization` `ColorField` which allow users to select from a color palette * `core` Non-breaking user messages using `UserMessage` * `testing` Allow for `Parametrization` class in `mock_params` #### Docs[​](/sdk/changelog/.md#docs-2 "Direct link to Docs") * `testing` Simplified `MockedEntity` example #### Fixed[​](/sdk/changelog/.md#fixed-15 "Direct link to Fixed") * `viktor` Fixed `matplotlib` dependency range set too strict *** ## v13[​](/sdk/changelog/.md#v13 "Direct link to v13") ### v13.8.0 - 16/02/2023[​](/sdk/changelog/.md#v1380---16022023 "Direct link to v13.8.0 - 16/02/2023") #### Added[​](/sdk/changelog/.md#added-29 "Direct link to Added") * `viktor` Support for Python 3.11 *** ### v13.7.2 - 08/02/2023[​](/sdk/changelog/.md#v1372---08022023 "Direct link to v13.7.2 - 08/02/2023") #### Docs[​](/sdk/changelog/.md#docs-3 "Direct link to Docs") * `views` Added info about "id" attribute for interaction to docstring of GeoJSONResult * `result` Fixed example in `OptimizationResult` docstring #### Fixed[​](/sdk/changelog/.md#fixed-16 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` now correctly implements transparency * `geometry` Fixed rotation bug in Cone geometry when oriented in (0, -1, 0) direction *** ### v13.7.1 - 16/01/2023[​](/sdk/changelog/.md#v1371---16012023 "Direct link to v13.7.1 - 16/01/2023") #### Fixed[​](/sdk/changelog/.md#fixed-17 "Direct link to Fixed") * `errors` Fixed `UserError` to accept multiple messages of any type, in line with `UserException` *** ### v13.7.0 - 16/12/2022[​](/sdk/changelog/.md#v1370---16122022 "Direct link to v13.7.0 - 16/12/2022") #### Added[​](/sdk/changelog/.md#added-30 "Direct link to Added") * `result` Support 'Munch' type in a `SetParamsResult` * `views` New `ImageView` and `ImageAndDataView` that accept 'svg', 'jpeg', 'png', 'gif' files * `parametrization` Validation of a `Step` using the `on_next` callback function * `errors` `UserError` to show an error to the user and mark fields invalid in the interface * `core` Show/hide top-level entities on the dashboard with `InitialEntity` `show_on_dashboard` argument #### Deprecated[​](/sdk/changelog/.md#deprecated-4 "Direct link to Deprecated") * `views` `SVGView`, `JPGView`, `PNGView` are replaced by `ImageView` [(U82)](/sdk/upgrades/.md#U82) * `views` `SVGResult`, `JPGResult`, `PNGResult` are replaced by `ImageResult` [(U82)](/sdk/upgrades/.md#U82) * `views` `SVGAndDataView`, `JPGAndDataView`, `PNGAndDataView` are replaced by `ImageAndDataView` [(U82)](/sdk/upgrades/.md#U82) * `views` `SVGAndDataResult`, `JPGAndDataResult`, `PNGAndDataResult` are replaced by `ImageAndDataResult` [(U82)](/sdk/upgrades/.md#U82) * `parametrization` Violated field constraints will block actions [(U83)](/sdk/upgrades/.md#U83) * `viktor` `UserException` will be replaced by `UserError` [(U84)](/sdk/upgrades/.md#U84) *** ### v13.6.2 - 05/12/2022[​](/sdk/changelog/.md#v1362---05122022 "Direct link to v13.6.2 - 05/12/2022") #### Fixed[​](/sdk/changelog/.md#fixed-18 "Direct link to Fixed") * `geometry` Regression in `CircularExtrusion` causing incorrect positioning *** ### v13.6.1 - 17/11/2022[​](/sdk/changelog/.md#v1361---17112022 "Direct link to v13.6.1 - 17/11/2022") #### Fixed[​](/sdk/changelog/.md#fixed-19 "Direct link to Fixed") * `views` Regression in SVGAndDataResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) *** ### v13.6.0 - 7/11/2022[​](/sdk/changelog/.md#v1360---7112022 "Direct link to v13.6.0 - 7/11/2022") #### Added[​](/sdk/changelog/.md#added-31 "Direct link to Added") * `viktor` Show progress messages in terminal * `geometry` Specify `shell_thickness` on a `CircularExtrusion` to create a hollow extrusion #### Deprecated[​](/sdk/changelog/.md#deprecated-5 "Direct link to Deprecated") * `geometry` Remove `open_ends` from `CircularExtrusion` [(U81)](/sdk/upgrades/.md#U81) #### Fixed[​](/sdk/changelog/.md#fixed-20 "Direct link to Fixed") * `codemod` Fixed codemods failing on f-string with unparenthesized tuples * `viktor` Ignore errors in sending progress messages * `views` Regression in SVGResult causing StringIO image to crash with UnicodeEncodeError in certain cases (e.g. matplotlib) *** ### v13.5.1 - 18/10/2022[​](/sdk/changelog/.md#v1351---18102022 "Direct link to v13.5.1 - 18/10/2022") #### Fixed[​](/sdk/changelog/.md#fixed-21 "Direct link to Fixed") * `external` Dynamo `convert_geometry_to_glb` fix colors *** ### v13.5.0 - 11/10/2022[​](/sdk/changelog/.md#v1350---11102022 "Direct link to v13.5.0 - 11/10/2022") #### Added[​](/sdk/changelog/.md#added-32 "Direct link to Added") * `external` Added repr function to spreadsheet input classes * `external` Various analysis classes and functions now accept a `File` object, or return a `File` object if as\_file=True * `views` All image results (`PNGResult`, etc...) allow for image of type `File` * `geo` `gef_visualization` returns `File` object if as\_file=True * `views` `WebResult` allows for `html` of type `File` and `str` * `geometry` Support visualization of `Arc`, `Line`, and `Polyline` in a `GeometryView` * `testing` Various `mock_*Analysis` classes to facilitate easier testing of analysis classes #### Deprecated[​](/sdk/changelog/.md#deprecated-6 "Direct link to Deprecated") * `geometry` Remove `hex_to_rgb` and `rgb_to_hex` from geometry module [(U79)](/sdk/upgrades/.md#U79) * `parametrization` Remove `min_message` and `max_message` from `NumberField`/`IntegerField` [(U80)](/sdk/upgrades/.md#U80) *** ### v13.4.0 - 12/09/2022[​](/sdk/changelog/.md#v1340---12092022 "Direct link to v13.4.0 - 12/09/2022") #### Added[​](/sdk/changelog/.md#added-33 "Direct link to Added") * `external` Upload inputs of `render_word_file` and `WordFileTemplate.render` to s3 to prevent payload errors * `external` Added torsion and interaction results to `RcsOutputFileParser` #### Fixed[​](/sdk/changelog/.md#fixed-22 "Direct link to Fixed") * `codemod` U77 incorrectly includes yaml-comments in welcome\_text * `external` Dynamo `convert_geometry_to_glb` now generates double-sided faces * `codemod` U78 unintentionally removes comments from viktor.config.toml *** ### v13.3.1 - 24/08/2022[​](/sdk/changelog/.md#v1331---24082022 "Direct link to v13.3.1 - 24/08/2022") #### Fixed[​](/sdk/changelog/.md#fixed-23 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions * `external` Fix type-error in fill-spreadsheet helper * `geometry` `get_lowest_or_highest_profile_x` sometimes returns the incorrect profile * `parametrization` Raise a warning when using an `OptionField` with an `int` value in a `Table` *** ### v13.3.0 - 10/08/2022[​](/sdk/changelog/.md#v1330---10082022 "Direct link to v13.3.0 - 10/08/2022") #### Added[​](/sdk/changelog/.md#added-34 "Direct link to Added") * `parametrization` Increased character limit on `Text` element from 500 to 1800 * `testing` `mock_API` decorator to mock the `API` class in tests * `testing` `mock_params` function to convert a JSON/dict to the (deserialized) params * `testing` `mock_View` decorator to mock `View` decorators in tests * `testing` `mock_SciaAnalysis` to mock `SciaAnalysis.execute` and analysis returns in tests * `api_v1` Compare `EntityType`s or `User`s with "==" * `geometry` Compare `GeoPoint`s, `GeoPolyline`s, or `GeoPolygon`s with "==" #### Deprecated[​](/sdk/changelog/.md#deprecated-7 "Direct link to Deprecated") * `viktor` `app_type` entry should be defined in viktor.config.toml [(U78)](/sdk/upgrades/.md#U78) *** ### v13.2.1 - 27/06/2022[​](/sdk/changelog/.md#v1321---27062022 "Direct link to v13.2.1 - 27/06/2022") #### Fixed[​](/sdk/changelog/.md#fixed-24 "Direct link to Fixed") * `codemod` U77 incorrectly fixing the `welcome_text` path *** ### v13.2.0 - 15/06/2022[​](/sdk/changelog/.md#v1320---15062022 "Direct link to v13.2.0 - 15/06/2022") #### Added[​](/sdk/changelog/.md#added-35 "Direct link to Added") * `geometry` Construct an extruded polygon using `Polygon.extrude()` * `geometry` Compare `Point`s and `Line`s with "==" (e.g. `Point(1, 1) == Point(1, 1)` -> True) * `geometry` Allow for indexing/iterating of `Vector`, `Point` and `Line` objects * `geometry` `Line` methods `project_point` and `distance_to_point` * `codemod` Apply all fixes of current major when using the `viktor-cli fix` command without --upgrade flag * `parametrization` Select interaction on Map/GeoJSONView #### Deprecated[​](/sdk/changelog/.md#deprecated-8 "Direct link to Deprecated") * `viktor` Removal of manifest [(U77)](/sdk/upgrades/.md#U77) #### Fixed[​](/sdk/changelog/.md#fixed-25 "Direct link to Fixed") * `geometry` bug in `points_are_coplanar` * `geometry` `point_is_on_bounded_line` now correctly calculates for 3D *** ### v13.1.0 - 06/05/2022[​](/sdk/changelog/.md#v1310---06052022 "Direct link to v13.1.0 - 06/05/2022") #### Added[​](/sdk/changelog/.md#added-36 "Direct link to Added") * `external` SCIA binding: `description` on (nonlinear) load combination * `external` SCIA binding: (general) solver settings * `external` SCIA binding: library cross-sections * `external` SCIA binding: basic project data * `external` SCIA binding: cross-links #### Fixed[​](/sdk/changelog/.md#fixed-26 "Direct link to Fixed") * `viktor` Set timeouts on addons requests to 60 seconds to prevent timeout errors * `external` SCIA binding: applying a line load on a circular plane edge no longer raises an error *** ### v13.0.0 - 13/04/2022[​](/sdk/changelog/.md#v1300---13042022 "Direct link to v13.0.0 - 13/04/2022") #### Action Required[​](/sdk/changelog/.md#action-required-2 "Direct link to Action Required") * `viktor` Upgrade instructions U61 - U75 have been applied #### Added[​](/sdk/changelog/.md#added-37 "Direct link to Added") * `core` `Storage` class to permanently store files which can be retrieved at any time * `parametrization` `FileField` and `MultiFileField` which allow users to upload one or multiple files * `parametrization` `EntityOptionField` and `EntityMultiSelectField` for generic selection of entities * `parametrization` `ViktorParametrization` as alias of `Parametrization` #### Deprecated[​](/sdk/changelog/.md#deprecated-9 "Direct link to Deprecated") * `codemod` Cleanup previously set flags which were necessary to migrate to v13 [(U76)](/sdk/upgrades/.md#U76) *** ## v12[​](/sdk/changelog/.md#v12 "Direct link to v12") ### v12.12.2 - 23/08/2022[​](/sdk/changelog/.md#v12122---23082022 "Direct link to v12.12.2 - 23/08/2022") #### Fixed[​](/sdk/changelog/.md#fixed-27 "Direct link to Fixed") * `api_v1` Incorrectly setting `last_saved_params` equal to None for old entity revisions *** ### v12.12.1 - 11/04/2022[​](/sdk/changelog/.md#v12121---11042022 "Direct link to v12.12.1 - 11/04/2022") #### Docs[​](/sdk/changelog/.md#docs-4 "Direct link to Docs") * `external` Fixed example in Dynamo docstring #### Fixed[​](/sdk/changelog/.md#fixed-28 "Direct link to Fixed") * `parametrization` Fixed U74 warning not being logged in case of dynamic options *** ### v12.12.0 - 06/04/2022[​](/sdk/changelog/.md#v12120---06042022 "Direct link to v12.12.0 - 06/04/2022") #### Added[​](/sdk/changelog/.md#added-38 "Direct link to Added") * `views` `up_axis` setting to GeometryView and GeometryAndDataView * `views` `GeometryResult` accepts a GLB `File` * `views` Fix the font size of a `MapLabel` regardless of zoom level by setting the `fixed_size` flag * `external` Helper functions for updating Dynamo input files and processing output files (results + geometry) * `external` `GenericAnalysis.get_output_file` returns File object if as\_file=True * `parametrization` Support setting a `value` and a `label` of an `OptionField` option within a table * `parametrization` Added `entity_name` in signature of controller methods and callback functions #### Deprecated[​](/sdk/changelog/.md#deprecated-10 "Direct link to Deprecated") * `views` `GeometryResult` argument `visualization_group` renamed to `geometry` [(U73)](/sdk/upgrades/.md#U73) * `parametrization` Setting both a `value` and a `label` of an `OptionField` option within a table will no longer be ignored [(U74)](/sdk/upgrades/.md#U74) * `viktor` Removed `name` and `filename` from the params [(U75)](/sdk/upgrades/.md#U75) #### Fixed[​](/sdk/changelog/.md#fixed-29 "Direct link to Fixed") * `codemod` U68 fixed for the case of having multiple 'import as' aliases * `geometry` `Torus` and `ArcRevolve` showing wrong face normals and ignoring rotation angle *** ### v12.11.0 - 09/03/2022[​](/sdk/changelog/.md#v12110---09032022 "Direct link to v12.11.0 - 09/03/2022") #### Added[​](/sdk/changelog/.md#added-39 "Direct link to Added") * `viktor` Create a views-only entity type by omitting the `parametrization` attribute on the corresponding `Controller` class * `views` Select a custom map marker using the `icon` attribute on `MapPoint` #### Deprecated[​](/sdk/changelog/.md#deprecated-11 "Direct link to Deprecated") * `viktor` The `background_image` of a workspace is customizable through the admin panel instead of the manifest [(U71)](/sdk/upgrades/.md#U71) * `api` The complete `viktor.api` module and all of its classes and functions [(U72)](/sdk/upgrades/.md#U72) #### Docs[​](/sdk/changelog/.md#docs-5 "Direct link to Docs") * `views` Fixed example in PlotlyView docstring *** ### v12.10.0 - 08/02/2022[​](/sdk/changelog/.md#v12100---08022022 "Direct link to v12.10.0 - 08/02/2022") #### Added[​](/sdk/changelog/.md#added-40 "Direct link to Added") * `views` PlotlyView and PlotlyAndDataView * `api_v1` Various missing functionalities (e.g. to create, delete and modify entities) * `views` `GeometryResult` accepts a (sequence of) `TransformableObject`(s) * `testing` `mock_ParamsFromFile` to mock the `ParamsFromFile` class in tests #### Deprecated[​](/sdk/changelog/.md#deprecated-12 "Direct link to Deprecated") * `parametrization` Automatic selection of a single option in an `OptionField` will no longer be the standard behavior [(U69)](/sdk/upgrades/.md#U69) * `geometry` Removed method `Polyline.from_dict` [(U70)](/sdk/upgrades/.md#U70) #### Fixed[​](/sdk/changelog/.md#fixed-30 "Direct link to Fixed") * `external` D-Foundations parser: `IsKsi3Used` incorrectly returns `True` *** ### v12.9.0 - 11/01/2022[​](/sdk/changelog/.md#v1290---11012022 "Direct link to v12.9.0 - 11/01/2022") #### Added[​](/sdk/changelog/.md#added-41 "Direct link to Added") * `parametrization` `Step` which can be used to have pages within a predefined order, browsable through a previous and next button * `parametrization` `row_label` attribute on `DynamicArray` which can be used to prefix the row index #### Deprecated[​](/sdk/changelog/.md#deprecated-13 "Direct link to Deprecated") * `viktor` GEOLIB is now publicly available; hosting by VIKTOR will be terminated [(U67)](/sdk/upgrades/.md#U67) * `parametrization` Input argument `require_all_fields` will be removed from buttons [(U68)](/sdk/upgrades/.md#U68) *** ### v12.8.0 - 1/12/2021[​](/sdk/changelog/.md#v1280---1122021 "Direct link to v12.8.0 - 1/12/2021") #### Added[​](/sdk/changelog/.md#added-42 "Direct link to Added") * `external` Removed **\[BETA]** status from the Robot integration * `parametrization` Radio variant of `OptionField` (vertical + horizontal) #### Deprecated[​](/sdk/changelog/.md#deprecated-14 "Direct link to Deprecated") * `parametrization` Entity selection fields return an `Entity` object in the params instead of an integer [(U65)](/sdk/upgrades/.md#U65) * `parametrization` NumberField variant attribute of type `str` ('slider') replaces type `Enum` (`NumberField.Variant.SLIDER`) [(U66)](/sdk/upgrades/.md#U66) #### Fixed[​](/sdk/changelog/.md#fixed-31 "Direct link to Fixed") * `external` D-Foundations and D-Settlement input file generation timeout increased to 30 seconds *** ### v12.7.0 - 3/11/2021[​](/sdk/changelog/.md#v1270---3112021 "Direct link to v12.7.0 - 3/11/2021") #### Added[​](/sdk/changelog/.md#added-43 "Direct link to Added") * `views` An `update_label` can be used to change the label of the update button of a View * `parametrization` A `description` can now be added on action buttons, to provide more information to the user through a tooltip * `external` IDEA-RCS RcsOutputFileParser: decision method added to fatigue results * `external` IDEA-RCS RcsOutputFileParser: obtain combined results per extreme using `section.extremes()` * `external` IDEA binding: `Member.create_bar_layer()` and `ReinforcedCrossSection.create_bar_layer()` to create multiple bars positioned on a line * `external` IDEA binding: `theta`, `theta_min`, `theta_max`, and `n_cycles_fatigue` can be set in the `CodeSettings` * `external` IDEA binding: `relative_humidity` can be set in the design member data * `external` IDEA binding: a general cross-section can be added to a model, defined by a set of coordinates * `parametrization` `Text` field that can be used to display a static text #### Docs[​](/sdk/changelog/.md#docs-6 "Direct link to Docs") * `parametrization` Parameter NumberField.step added to docstring * `parametrization` Fixed example in ParamsFromFile docstring #### Fixed[​](/sdk/changelog/.md#fixed-32 "Direct link to Fixed") * `external` Scia input file generation timeout increased to 30 seconds *** ### v12.6.0 - 29/09/2021[​](/sdk/changelog/.md#v1260---29092021 "Direct link to v12.6.0 - 29/09/2021") #### Action Required[​](/sdk/changelog/.md#action-required-3 "Direct link to Action Required") * `external` **\[BETA]** Robot binding: `requested_results` format has changed; specify per category which components are to be returned #### Added[​](/sdk/changelog/.md#added-44 "Direct link to Added") * `external` SCIA binding: Model.create\_numerical\_cross\_section * `external` SCIA binding: Model.create\_point\_load\_node * `external` SCIA binding: added `angle` argument to Model.create\_point\_load * `core` Controller attribute `summary` is no longer required to be defined * `core` Controller attributes (`label`, `summary`, `parametrization`, etc.) visible in stubs and docs #### Deprecated[​](/sdk/changelog/.md#deprecated-15 "Direct link to Deprecated") * `api_v1` `PrivilegedAPI` has been replaced by explicit `privileged` flag on the individual API calls [(U64)](/sdk/upgrades/.md#U64) #### Docs[​](/sdk/changelog/.md#docs-7 "Direct link to Docs") * `geometry` Fixed code-block in `RDWGSConverter.from_wgs_to_rd()` * `viktor` Link to upgrade instruction webpage in deprecation warnings #### Fixed[​](/sdk/changelog/.md#fixed-33 "Direct link to Fixed") * `external` Word file rendering timeout increased to 60 seconds * `parametrization` Naming a table column 'name' does no longer cause a warning in the IDE about not being able to set the 'name' property *** ### v12.5.0 - 24/08/2021[​](/sdk/changelog/.md#v1250---24082021 "Direct link to v12.5.0 - 24/08/2021") #### Added[​](/sdk/changelog/.md#added-45 "Direct link to Added") * `parametrization` Page which can be used to construct a combination of inputs (e.g. tabs / sections) and outputs (views) * `core` Improved upload performance when no data is returned during post processing * `api_v1` Multiple API requests within the same job are now faster due to session sharing * `core` Improved error messages when a Summary is wrongly defined (e.g. non-existing SummaryItem 'source') * `geo` SoilLayout.filter\_layers\_on\_thickness merges adjacent layers with equal property values of type 'str', and raises a more explicit error otherwise * `external` IDEA-RCS `RcsOutputFileParser` which is an improved version of `OutputFileParser` (allowing large files) * `geometry` Improved performance of TriangleAssembly and Polygon visualization. Additionally a `skip_duplicate_vertices_check` flag can be set to boost performance further. * `parametrization` The width-ratio between input and output of an editor can be adjusted through a `width` argument on Parametrization * `parametrization` A `description` can now be added on a Field / Tab / Section / Page, to provide more information to the user through a tooltip * `views` A `description` can now be added on a View, to provide more information to the user through a tooltip #### Deprecated[​](/sdk/changelog/.md#deprecated-16 "Direct link to Deprecated") * `geo` Renamed `SoilLayout2D.threejs_visualisation()` to `SoilLayout2D.visualize_geometry()` and `SoilLayer2D.threejs_visualisation()` to `SoilLayer2D.visualize_geometry()` [(U62)](/sdk/upgrades/.md#U62) * `parametrization` Input arguments `prefix` and `suffix` on a DateField will be removed [(U63)](/sdk/upgrades/.md#U63) #### Docs[​](/sdk/changelog/.md#docs-8 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/sdk/changelog/.md#fixed-34 "Direct link to Fixed") * `geometry` Small triangles return NaN when calling the area *** ### v12.4.0 - 14/07/2021[​](/sdk/changelog/.md#v1240---14072021 "Direct link to v12.4.0 - 14/07/2021") #### Added[​](/sdk/changelog/.md#added-46 "Direct link to Added") * `external` SCIA binding: NonLinearLoadCombination can be used in `Model.create_result_class()` #### Docs[​](/sdk/changelog/.md#docs-9 "Direct link to Docs") * `viktor` Added description of publish commands to cli guide #### Fixed[​](/sdk/changelog/.md#fixed-35 "Direct link to Fixed") * `external` Timeout issue when using large files in `render_spreadsheet()` and `SpreadsheetCalculation.evaluate()` *** ### v12.3.1 - 25/06/2021[​](/sdk/changelog/.md#v1231---25062021 "Direct link to v12.3.1 - 25/06/2021") #### Fixed[​](/sdk/changelog/.md#fixed-36 "Direct link to Fixed") * `parametrization` Issue where clicking "Add new row" on a Table does not work *** ### v12.3.0 - 25/06/2021[​](/sdk/changelog/.md#v1230---25062021 "Direct link to v12.3.0 - 25/06/2021") #### Added[​](/sdk/changelog/.md#added-47 "Direct link to Added") * `external` IDEA-RCS binding: fatigue loading can be applied on an extreme * `external` IDEA-RCS OutputFileParser: fatigue results can be parsed * `views` 'points' and 'holes' properties added on MapPolygon * `external` Log when external analysis job has been completed successfully * `parametrization` Simple options can be used in OptionField, AutocompleteField, MultiSelectField (e.g. `options=['A', 'B', 'C']`) #### Deprecated[​](/sdk/changelog/.md#deprecated-17 "Direct link to Deprecated") * `core` Entity-type information (`label`, `children`, and `show_children_as`) is moved from the manifest to the Controller [(U61)](/sdk/upgrades/.md#U61) #### Fixed[​](/sdk/changelog/.md#fixed-37 "Direct link to Fixed") * `utils` Memoized functions called on app-load breaks in production *** ### v12.2.0 - 26/05/2021[​](/sdk/changelog/.md#v1220---26052021 "Direct link to v12.2.0 - 26/05/2021") #### Added[​](/sdk/changelog/.md#added-48 "Direct link to Added") * `parametrization` GeoPointField, GeoPolylineField, and GeoPolygonField can now be used in a DynamicArray * `external` **\[BETA]** RobotAnalysis #### Docs[​](/sdk/changelog/.md#docs-10 "Direct link to Docs") * `viktor` Regular docs maintenance *** ### v12.1.0 - 18/05/2021[​](/sdk/changelog/.md#v1210---18052021 "Direct link to v12.1.0 - 18/05/2021") #### Added[​](/sdk/changelog/.md#added-49 "Direct link to Added") * `parametrization` Parametrization can consist of 1 layer (Field) or 2 layers (Tab + Field, Section + Field) * `external` Improved error handling in execution of RFEMAnalysis * `geometry` Cone object * `api_v1` Allow negative indexing on EntityList * `parametrization` More consistent naming for many fields (old names will be deprecated in future) * `result` Allow for multiple files to be downloaded (as zip-file) in DownloadResult #### Docs[​](/sdk/changelog/.md#docs-11 "Direct link to Docs") * `viktor` Regular docs maintenance #### Fixed[​](/sdk/changelog/.md#fixed-38 "Direct link to Fixed") * `parametrization` Setting field `name` argument using dot-notation within TableInput/DynamicArray was mistakenly allowed *** ### v12.0.0 - 20/04/2021[​](/sdk/changelog/.md#v1200---20042021 "Direct link to v12.0.0 - 20/04/2021") --- # Deprecations & Upgrades This document lists all current deprecations, with upgrade steps and planned removal. When the deprecation is removed with a major update, it will be moved under its corresponding header. All available upgrades of the current SDK major version can be performed at once by using: ``` viktor-cli fix ``` ## Current version[​](/sdk/upgrades/.md#current-version "Direct link to Current version") ### U91 - Remove support for Python 3.9[​](/sdk/upgrades/.md#U91 "Direct link to U91 - Remove support for Python 3.9")- planned removal: October 2025 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change "Direct link to Current behaviour + reason for change") VIKTOR currently supports Python 3.9 - 3.13, however version 3.9 will soon reach its [end-of-life](https://devguide.python.org/versions/). This means that the VIKTOR SDK will no longer be built for Python 3.9 in the future. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour "Direct link to New behaviour") The VIKTOR SDK will no longer be available in combination with Python 3.9. #### Conversion[​](/sdk/upgrades/.md#conversion "Direct link to Conversion") Update the `python_version` in the `viktor.config.toml` file: ``` python_version = '3.13' # '3.13' | '3.12' | '3.11' | '3.10' ``` caution Please make sure to update your code in case you are using Python features that are no longer available in the Python version you are upgrading to. ### U90 - GeometryView initial x-axis orientation will be to the right by default[​](/sdk/upgrades/.md#U90 "Direct link to U90 - GeometryView initial x-axis orientation will be to the right by default")- deprecated since: v14.8.0 - planned removal: v15 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-1 "Direct link to Current behaviour + reason for change") Currently, the 3D GeometryView has its initial x-axis orientation to the left by default. In most other software, the convention is to have the x-axis point to the right. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-1 "Direct link to New behaviour") In the new situation it is possible to set the initial x-axis orientation on the `GeometryView` by means of the `x_axis_to_right` setting (currently only supported for `view_mode='3D'` and `up_axis='Z'`). The default will be `x_axis_to_right=True`. #### Conversion[​](/sdk/upgrades/.md#conversion-1 "Direct link to Conversion") Update your `GeometryView` with `x_axis_to_right=False` to explicitly accept that the initial x-axis orientation is to the left. This can be done automatically by using the CLI command `viktor-cli fix -u 90`: ``` - @GeometryView(...) + @GeometryView(..., x_axis_to_right=False) ``` ``` - @GeometryAndDataView(...) + @GeometryAndDataView(..., x_axis_to_right=False) ``` Alternatively, to change the initial orientation of the x-axis to point to the right you can set `x_axis_to_right=True` (no automated code fix). If it is desired that the initial point of view of the geometry remains unchanged, rotate your geometry accordingly to compensate for the change in orientation: ``` - @GeometryView(...) + @GeometryView(..., x_axis_to_right=True) ... + geometry = geometry.rotate(angle=-0.5*math.pi, direction=(0, 0, 1)) GeometryResult(geometry) ``` ### U89 - Remove support for Python 3.8[​](/sdk/upgrades/.md#U89 "Direct link to U89 - Remove support for Python 3.8")- planned removal: October 2024 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-2 "Direct link to Current behaviour + reason for change") VIKTOR currently supports Python 3.8 - 3.12, however version 3.8 will soon reach its [end-of-life](https://devguide.python.org/versions/). This means that the VIKTOR SDK will no longer be built for Python 3.8 in the future. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-2 "Direct link to New behaviour") The VIKTOR SDK will no longer be available in combination with Python 3.8. #### Conversion[​](/sdk/upgrades/.md#conversion-2 "Direct link to Conversion") Update the `python_version` in the `viktor.config.toml` file: ``` python_version = '3.9' # '3.9' | '3.10' | '3.11' | '3.12' ``` caution Please make sure to update your code in case you are using Python features that will no longer be available in Python 3.9 or higher. ### U88 - Remove `always_available` from buttons[​](/sdk/upgrades/.md#U88 "Direct link to U88")- deprecated since: v14.7.0 - planned removal: v15 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-3 "Direct link to Current behaviour + reason for change") The `always_available` argument can be set on action buttons, but doesn't do anything. The argument could cause confusion and makes the SDK reference less readable. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-3 "Direct link to New behaviour") The `always_available` argument will be removed. The following fields are affected: * `DownloadButton` * `SetParamsButton` * `ActionButton` (`AnalyseButton`) * `OptimizationButton` (`OptimiseButton`) * `BooleanField` (`ToggleButton`) #### Conversion[​](/sdk/upgrades/.md#conversion-3 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 88`: ``` - download_button = DownloadButton("Download X", method="download_x", always_available=True) + download_button = DownloadButton("Download X", method="download_x") ``` ### U87 - Rename `Material` threejs properties[​](/sdk/upgrades/.md#U87 "Direct link to U87")- deprecated since: v14.5.0 - planned removal: v15 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-4 "Direct link to Current behaviour + reason for change") On a `Material` you can currently set the following properties that are prefixed with `threejs_`: * `threejs_metalness` * `threejs_opacity` * `threejs_roughness` * `threejs_type` Since material properties are not necessarily bound to ThreeJS, they will be renamed / removed. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-4 "Direct link to New behaviour") The following renames will be applied: * `threejs_metalness` -> `metalness` * `threejs_opacity` -> `opacity` * `threejs_roughness` -> `roughness` `threejs_type` is no longer used and will be removed completely. #### Conversion[​](/sdk/upgrades/.md#conversion-4 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 87`: ``` - concrete = Material("Concrete", threejs_metalness=1, threejs_opacity=1, threejs_roughness=1, threejs_type="X") + concrete = Material("Concrete", metalness=1, opacity=1, roughness=1) ``` ## Removed in v14[​](/sdk/upgrades/.md#removed-in-v14 "Direct link to Removed in v14") ### U86 - Remove support for Python 3.7[​](/sdk/upgrades/.md#U86 "Direct link to U86 - Remove support for Python 3.7")- deprecated since: CLI v0.29.2 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-5 "Direct link to Current behaviour + reason for change") VIKTOR currently supports Python 3.7 - 3.11, however version 3.7 will soon reach its [end-of-life](https://devguide.python.org/versions/). This means that the VIKTOR SDK will no longer be built for Python 3.7 in the future. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-5 "Direct link to New behaviour") The VIKTOR SDK will no longer be available in combination with Python 3.7. #### Conversion[​](/sdk/upgrades/.md#conversion-5 "Direct link to Conversion") Update the `python_version` in the `viktor.config.toml` file: ``` python_version = '3.11' # '3.8' | '3.9' | '3.10' | '3.11' ``` caution Please make sure to update your code in case you are using Python features that will no longer be available in Python 3.8 or higher. ### U85 - Remove leading hashtag for `viktor` dependency[​](/sdk/upgrades/.md#U85 "Direct link to U85")- deprecated since: CLI v0.29.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-6 "Direct link to Current behaviour + reason for change") Specifying `viktor` as dependency in the requirements.txt file requires a leading hashtag, which differs from other external dependencies. Since the `viktor` package is now publicly available on PyPI, the leading hashtag is no longer necessary. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-6 "Direct link to New behaviour") Specifying `# viktor` in the requirements.txt file will no longer be supported. #### Conversion[​](/sdk/upgrades/.md#conversion-6 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by submitting "yes" when the CLI asks to apply the diff: ``` - # viktor==X.X.X + viktor==X.X.X ``` ### U84 - UserException replaced by UserError[​](/sdk/upgrades/.md#U84 "Direct link to U84 - UserException replaced by UserError")- deprecated since: v13.7.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-7 "Direct link to Current behaviour + reason for change") A `UserException` can be raised by the app to inform the user of an error. Since the term `UserException` does not adhere to the naming [conventions](https://peps.python.org/pep-0008/#exception-names), we decided to replace it by `UserError`. In addition, `UserError` allows for marking of fields invalid in the interface, to improve user experience. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-7 "Direct link to New behaviour") `UserException` will no longer be available in the future, and will be replaced by `UserError`. #### Conversion[​](/sdk/upgrades/.md#conversion-7 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 84`: ``` - from viktor import UserException + from viktor import UserError - raise UserException("message") + raise UserError("message") ``` ### U83 - Violated field constraints block actions[​](/sdk/upgrades/.md#U83 "Direct link to U83 - Violated field constraints block actions")- deprecated since: v13.7.0 - automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-8 "Direct link to Current behaviour + reason for change") When a field constraint is violated by the user, he / she is still able to perform actions which potentially make use of the invalid value. This can lead to erroneous calculation results, which is undesired. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-8 "Direct link to New behaviour") In order to protect and guide the user in a better way, violation of field constraints will block actions in the future. The constraints that are automatically assessed by the platform are: * Numeric min/max boundary (`IntegerField` / `NumberField` / `DynamicArray`) * Non-existing option (`OptionField` / `MultiSelectField` / `AutocompleteField`) * Non-existing coordinate (`GeoPointField` / `GeoPolylineField` / `GeoPolygonField`) * Invalid date format (`DateField`) By defining `viktor_enforce_field_constraints = True` on the controller class, this behavior can be simulated: ``` class Controller(ViktorController): viktor_enforce_field_constraints = True ``` #### Conversion[​](/sdk/upgrades/.md#conversion-8 "Direct link to Conversion") Add a `viktor_enforce_field_constraints` class attribute on the `Controller` and set it to True. This can be done automatically by using the CLI command `viktor-cli fix -u 83`: ``` class Controller(ViktorController): + viktor_enforce_field_constraints = True ``` caution Unfortunately we cannot automatically fix your app logic because we do not know the intentions of your code. If, for example, exceeding of the `max` value of a `NumberField` is perfectly fine, you could log a warning to the user, instead of using the `max` constraint on the `NumberField` itself: ``` def my_view(self, params, **kwargs): if params.height > 5: progress_message('WARNING: height should be smaller than 5!') # optionally add a sleep to show the message for longer period of time ... ``` ### U82 - Specific image views replaced by `ImageView`[​](/sdk/upgrades/.md#U82 "Direct link to U82")- deprecated since: v13.7.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-9 "Direct link to Current behaviour + reason for change") We currently offer a specific view per image type ('png' / 'jpg' / 'svg'). This inseparable relation between view and image type makes implementation of these views limited and inflexible. For example, in case the type of a result image can be either 'png' or 'jpg', you are forced to implement 2 views instead of 1. The individual views will therefore be replaced by the generic `ImageView` (and `ImageAndDataView`). The corresponding results will be replaced by the generic `ImageResult` (and `ImageAndDataResult`). #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-9 "Direct link to New behaviour") * `PNGView`, `JPGView`, and `SVGView` will be replaced by `ImageView` in the future. * `PNGAndDataView`, `JPGAndDataView`, and `SVGAndDataView` will be replaced by `ImageAndDataView` in the future. * `PNGResult`, `JPGResult`, and `SVGResult` will be replaced by `ImageResult` in the future. * `PNGAndDataResult`, `JPGAndDataResult`, and `SVGAndDataResult` will be replaced by `ImageAndDataResult` in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-9 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 82`: ``` - from viktor.views import PNGView, PNGResult + from viktor.views import ImageView, ImageResult - @PNGView(...) + @ImageView(...) def my_view(self, params, **kwargs): ... - return PNGResult(...) + return ImageResult(...) ``` A similar conversion is required for all other views that are listed above. ### U81 - Remove `open_ends` from `CircularExtrusion`[​](/sdk/upgrades/.md#U81 "Direct link to U81")- deprecated since: v13.6.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-10 "Direct link to Current behaviour + reason for change") A `CircularExtrusion` can have open or closed ends depending on the `open_ends` argument: * `open_ends=False` (default): the extrusion is a solid * `open_ends=True`: the extrusion is a shell with zero thickness It is not possible to create a shell **with** a certain thickness. The additional `shell_thickness` can be used to achieve this, which makes the `open_ends` argument redundant. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-10 "Direct link to New behaviour") The `open_ends` argument will be removed in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-10 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 81`: ``` - CircularExtrusion(..., open_ends=True) + CircularExtrusion(..., shell_thickness=0) - CircularExtrusion(..., open_ends=False) + CircularExtrusion(..., shell_thickness=None) ``` ### U80 - Remove `min_message` and `max_message` from `NumberField`/`IntegerField`[​](/sdk/upgrades/.md#U80 "Direct link to U80")- deprecated since: v13.5.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-11 "Direct link to Current behaviour + reason for change") The `min_message` and `max_message` arguments on `NumberField`/`IntegerField` currently do not work as expected (they are ignored). We decided to not fix the problem, but remove the feature, since specific information can already be provided by means of the `description` argument. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-11 "Direct link to New behaviour") `min_message` and `max_message` will be removed from `NumberField`/`IntegerField` in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-11 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 80`: ``` - number = NumberField(..., min_message="...", max_message="...") + number = NumberField(...) - integer = IntegerField(..., min_message="...", max_message="...") + integer = IntegerField(...) ``` ### U79 - Remove `hex_to_rgb` and `rgb_to_hex` from geometry module[​](/sdk/upgrades/.md#U79 "Direct link to U79")- deprecated since: v13.5.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-12 "Direct link to Current behaviour + reason for change") `hex_to_rgb` and `rgb_to_hex` that are present in the geometry module can be used for color conversion. These are legacy functions and can be replaced by `Color.hex_to_rgb` and `Color.rgb_to_hex` respectively. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-12 "Direct link to New behaviour") `hex_to_rgb` and `rgb_to_hex` will be removed in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-12 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 79`: ``` - from viktor.geometry import hex_to_rgb, rgb_to_hex + from viktor.core import Color - rgb = hex_to_rgb("FFFFFF") + rgb = Color.hex_to_rgb("FFFFFF") - hex = rgb_to_hex(255, 255, 255) + hex = Color.rgb_to_hex(255, 255, 255) ``` ### U78 - viktor.config.toml requires `app_type` entry[​](/sdk/upgrades/.md#U78 "Direct link to U78")- deprecated since: v13.3.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-13 "Direct link to Current behaviour + reason for change") Currently, it is relatively complex to create a simple app with only 1 entity type, as there should always exist a second, top-level folder-like entity type. With the introduction of the `app_type` entry in the `viktor.config.toml` file, it becomes possible to define a 'simple' app-type, which allows for 1 (and only 1) entity type, instead of the current behaviour (from now on called 'tree'). This app-type entry also allows to introduce other types at a later stage. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-13 "Direct link to New behaviour") The `app_type` entry in `viktor.config.toml` is obligatory and defines the type of app you want to create. App layout, requirements and corresponding feedback errors might differ depending on the chosen app type. #### Conversion[​](/sdk/upgrades/.md#conversion-13 "Direct link to Conversion") Add the 'app\_type' key to `viktor.config.toml` ('tree' represents the current behaviour). This can be done automatically by using the CLI command `viktor-cli fix -u 78`: ``` + app_type = "tree" ``` ### U77 - Removal of manifest[​](/sdk/upgrades/.md#U77 "Direct link to U77 - Removal of manifest")- deprecated since: v13.2.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-14 "Direct link to Current behaviour + reason for change") The entity type information is currently partly described in the corresponding Controller, but some data is defined in the `manifest.yml`. This manifest is a concept which is often hard to grasp for a starting developer. In order to improve the onboarding of new developers, as well as consistency of where to define entity type information, we would like to get rid of the manifest completely. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-14 "Direct link to New behaviour") The manifest can be removed completely. This means that the following properties need to be removed / moved: ##### entity\_types[​](/sdk/upgrades/.md#entity_types "Direct link to entity_types") * `show_properties`: Legacy key which can be removed. * `has_designer`: Redundant in most cases. In specific cases it could happen that the entity type has a parametrization, but that `has_designer` has been set to False explicitly. For these cases, you may set `hide_editor` to True on the corresponding `Controller`. * naming of the entity type controller will no longer be in format `{entity_type}Controller`, but simply `{entity_type}` (e.g. `from .my_entity_type.controller import MyEntityTypeController` becomes `from .my_entity_type.controller import MyEntityTypeController as MyEntityType`, or rename the class and import with `from .my_entity_type.controller import MyEntityType`) ##### entities[​](/sdk/upgrades/.md#entities "Direct link to entities") Initial entities are created by setting the `initial_entities` variable in the `app.__init__.py` file, passing 1 or more `InitialEntity` objects. ``` from .my_entity_type.controller import MyEntityType from viktor import InitialEntity initial_entities = [ InitialEntity('MyEntityType', name='My Entity', params=...), ... ] ``` ##### metadata[​](/sdk/upgrades/.md#metadata "Direct link to metadata") * `welcome_text`: Moved to the `viktor.config.toml` file. * `uses_privileged_api`: Moved to the `viktor.config.toml` file. #### Conversion[​](/sdk/upgrades/.md#conversion-14 "Direct link to Conversion") The following conversion needs to be applied, which can be done automatically by using the CLI command `viktor-cli fix -u 77`: ##### entity\_types[​](/sdk/upgrades/.md#entity_types-1 "Direct link to entity_types") `manifest.yaml` ``` - entity_types: - EntityTypeA: - show_properties: false - has_designer: true ``` Import the controller in the `app.__init__.py` with the updated format: ``` - from .entity_type_a.controller import EntityTypeAController + from .entity_type_a.controller import EntityTypeAController as EntityTypeA ``` In case of explicit hiding the editor, set the `hide_editor` flag: ``` class EntityTypeController(ViktorController): + hide_editor = True ... ``` ##### entities[​](/sdk/upgrades/.md#entities-1 "Direct link to entities") `manifest.yaml` ``` - entities: - - entity_type: SettingsDatabase - properties: settings_database.json - - entity_type: ProjectFolder - properties: - name: Projects - children: - - entity_type: Project - properties: project_x.json ``` `app.__init__.py` ``` - from .settings_database.controller import SettingsDatabaseController - from .project_folder.controller import ProjectFolderController - from .project.controller import ProjectController + from .settings_database.controller import SettingsDatabaseController as SettingsDatabase + from .project_folder.controller import ProjectFolderController as ProjectFolder + from .project.controller import ProjectController as Project + + from viktor import InitialEntity + + initial_entities = [ + InitialEntity('SettingsDatabase', name='Settings', params='settings_database.json'), + InitialEntity('ProjectFolder', name='Projects', children=[ + InitialEntity('Project', name='Project X', params='project_x.json') + ]) + ] ``` ##### metadata[​](/sdk/upgrades/.md#metadata-1 "Direct link to metadata") `manifest.yaml` ``` - metadata: - welcome_text: file_path.md - uses_privileged_api: true ``` `viktor.config.toml` ``` + welcome_text = "manifest/file_path.md" + enable_privileged_api = true # true | false ``` Note that the `welcome_text` file is defined in the manifest with respect to the manifest folder (e.g. `my-app/manifest/`), while in the viktor.config.toml file it should be defined with respect to the root folder (e.g. `my-app/`). You are also free to move the `welcome_text` to any other location, for example directly in the root folder. This way, you could remove the manifest folder completely. ### U76 - v13 cleanup[​](/sdk/upgrades/.md#U76 "Direct link to U76 - v13 cleanup")- automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-15 "Direct link to Current behaviour + reason for change") Previous upgrades that were necessary to migrate to v13 instructed to add several flags on, for example, the `Controller` of the relevant entity type. Since v13 these flags became redundant. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-15 "Direct link to New behaviour") Previously set flags can be removed. #### Conversion[​](/sdk/upgrades/.md#conversion-15 "Direct link to Conversion") See the specific sections below for the required conversion. This can be done automatically by using the CLI command `viktor-cli fix -u 76`: ##### Cleanup U65[​](/sdk/upgrades/.md#cleanup-u65 "Direct link to Cleanup U65") ``` class Controller(ViktorController): - viktor_convert_entity_field = True ``` ##### Cleanup U69[​](/sdk/upgrades/.md#cleanup-u69 "Direct link to Cleanup U69") When `autoselect_single_option` is set to `False`, it can be removed (`autoselect_single_option=True` is still valid): ``` class Parametrization(ViktorParametrization): - options = OptionField("Options", options=dynamic_options, autoselect_single_option=False) + options = OptionField("Options", options=dynamic_options) ``` ##### Cleanup U74[​](/sdk/upgrades/.md#cleanup-u74 "Direct link to Cleanup U74") ``` class Controller(ViktorController): - viktor_store_table_option_field_value = True ``` ##### Cleanup U75[​](/sdk/upgrades/.md#cleanup-u75 "Direct link to Cleanup U75") ``` class Controller(ViktorController): - viktor_name_filename_in_params = False ``` ## Removed in v13[​](/sdk/upgrades/.md#removed-in-v13 "Direct link to Removed in v13") ### U75 - Remove `name` and `filename` from params[​](/sdk/upgrades/.md#U75 "Direct link to U75")- deprecated since: v12.12.0 - automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-16 "Direct link to Current behaviour + reason for change") Up to now you might have noticed a `name` property that was always present in the params of an entity, even though you had not specified a field referring to that position in the database. The entity name has been added to the signature of each controller method or can be obtained by using the API (e.g. `Entity.name`), which makes the `name` property redundant and will be removed. In case of file-upload entities, a `filename` property can be observed which will also be removed. Furthermore, the `name` and `filename` keys will become reserved for internal use and can no longer be used as `name` argument in parametrization fields. In order to simulate the removal of these params, you can use the `viktor_name_filename_in_params` controller flag: ``` class Controller(ViktorController): viktor_name_filename_in_params = False ``` This upgrade affects the following parts: * Parametrization + params * Entity mutations * `Entity.create_child()` / `API.create_child_entity()` * `Entity.set_params()` / `API.set_entity_params()` #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-16 "Direct link to New behaviour") Both `name` and `filename` will no longer be present in the params, and cannot be used as `name` argument of parametrization fields. #### Conversion[​](/sdk/upgrades/.md#conversion-16 "Direct link to Conversion") Add a `viktor_name_filename_in_params` class attribute on the `Controller` and set it to False. This can be done automatically by using the CLI command `viktor-cli fix -u 75`: ``` class Controller(ViktorController): + viktor_name_filename_in_params = False ``` caution Unfortunately we cannot automatically fix your app logic. The following sections will guide you through the manual conversion of the affected code. ##### Parametrization + params[​](/sdk/upgrades/.md#parametrization--params "Direct link to Parametrization + params") There are two ways for a field to be positioned on the `name` (or `filename`) key in the database: 1. using `name` as toplevel field name ``` - name = NumberField(...) ``` 2. using `name="name"` as field input argument ``` - tab.field = NumberField(..., name='name') ``` Also make sure to update all parts of the code where `name` (or `filename`) is obtained from the params. Instead, the entity name can be obtained from the signature: ``` - def func(params, **kwargs): + def func(params, entity_name, **kwargs): - entity_name = params.name ... ``` This also holds in case the property is taken from the `last_saved_params` of a different entity: ``` - entity_name = entity.last_saved_params['name'] + entity_name = entity.name ``` ##### Entity mutations[​](/sdk/upgrades/.md#entity-mutations "Direct link to Entity mutations") In functions that involve entity mutation, the `name` of the entity could have been stored in the params. This should be added as explicit `name` argument: ``` entity_name = "my_entity" - params = {"name": entity_name, ...} + params = {...} entity.create_child(..., name=entity_name, params=params) ``` ### U74 - Store table OptionField value in params[​](/sdk/upgrades/.md#U74 "Direct link to U74 - Store table OptionField value in params")- deprecated since: v12.12.0 - automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-17 "Direct link to Current behaviour + reason for change") When an `OptionField` is used within a table, it is not possible to show the `label` of the options in the dropdown menu, while using the `value` of the selected option in the params. This functionality will become available in the future, creating consistency between regular option fields and option fields used within tables. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-17 "Direct link to New behaviour") By setting the controller flag `viktor_store_table_option_field_value` to True, the `label` of options will be shown in the interface, and the `value` of the selected option will be returned in the params. This flag will be True by default in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-17 "Direct link to Conversion") Add a `viktor_store_table_option_field_value` class attribute on the Controller. This can be done automatically by using the CLI command `viktor-cli fix -u 74`: ``` class MyController(ViktorController): + viktor_store_table_option_field_value = True ``` caution Unfortunately we cannot automatically fix your app logic in case your app already defines both a `value` and `label` in options within a table dropdown (i.e. you ignored the warning). In that case you should update your code manually: ``` class MyParametrization(Parametrization): ... table.option = OptionField(..., options=[OptionListElement('a', 'Option A'), OptionListElement('b', 'Option B')]) class MyController(ViktorController): ... + viktor_store_table_option_field_value = True def func(params): - if params.table.option == 'Option A': + if params.table.option == 'a': ... ``` ### U73 - GeometryResult `visualization_group` parameter renamed to `geometry`[​](/sdk/upgrades/.md#U73 "Direct link to U73")- deprecated since: v12.12.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-18 "Direct link to Current behaviour + reason for change") `GeometryResult` and `GeometryAndDataResult` accept the geometry to be visualized through a `visualization_group` parameter. Since not only a `Group` but all sorts of geometry (any (list of) `TransformableObject`(s) or GLB file) can be passed, the naming of this parameter is outdated. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-18 "Direct link to New behaviour") GeometryResult `visualization_group` parameter has been renamed to `geometry`. #### Conversion[​](/sdk/upgrades/.md#conversion-18 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 73`: ``` - GeometryResult(visualization_group=...) - GeometryAndDataResult(visualization_group=...) + GeometryResult(geometry=...) + GeometryAndDataResult(geometry=...) ``` ### U72 - Remove viktor.api module[​](/sdk/upgrades/.md#U72 "Direct link to U72 - Remove viktor.api module")- deprecated since: v12.11.0 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-19 "Direct link to Current behaviour + reason for change") The `viktor.api` module consists of (outdated) functions and classes that are superseded by the entity option fields and functions from the `viktor.api_v1` module, or provide insignificant value such that it's better to replace them with simple app code. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-19 "Direct link to New behaviour") All (useful) functionalities from the `viktor.api` module can be mimicked by using the entity option fields and/or functions from the `viktor.api_v1` module. The `viktor.api` module will be removed completely in the future. #### Conversion[​](/sdk/upgrades/.md#conversion-19 "Direct link to Conversion") ##### `get_database_value_from_entity_id` / `get_entity_id_from_database_value` / `get_entity_option_list_for_designer`[​](/sdk/upgrades/.md#get_database_value_from_entity_id--get_entity_id_from_database_value--get_entity_option_list_for_designer "Direct link to get_database_value_from_entity_id--get_entity_id_from_database_value--get_entity_option_list_for_designer") If the entities are all children/siblings, the `OptionField` can be replaced with a `Child/SiblingEntityOptionField` (or similar for its multi-select counterpart): ``` - options = get_entity_option_list_for_designer(entities) - field = OptionField("...", options=options) + field = ChildEntityOptionField("...") # or similar field ... - entity_id = get_entity_id_from_database_value(params['field']) + entity = params['field'] # obtain its id with entity.id if desired ``` #### `API`, `Entity` & `EntityType`[​](/sdk/upgrades/.md#api-entity--entitytype "Direct link to api-entity--entitytype") The classes `API`, `Entity` and `EntityType` and all of its (useful) functionalities from the `viktor.api` module have a counterpart with equal or similar functionalities in the `viktor.api_v1` module. Below are the main differences: ``` - from viktor.api import API + from viktor.api_v1 import API ... api = API() ... - API.verify_status_code(response, allowed=200) # check the response.status_code yourself + if response.status_code != 200: + ... # handle not allowed status code(s) ``` ``` - entity = API().entity(entity_id) # from viktor.api + entity = API().get_entity(entity_id) # from viktor.api_v1 ... - entity_dict = entity.get() + entity_params = entity.last_saved_params # or any other attribute ... - root_entities = entity.root_entities() # or entity.list() + root_entities = API().get_root_entities() ... - parent_entity_dict = entity.parents()[0] - parent_id = entity_parent_ids()[0] + parent_entity = entity.parent() ... - entity.create_child(entity_dict) + entity.create_child(entity_type_name, name, params=params) ... - entity.post_properties(new_params) + entity.set_params(new_params) ... - entity.update_properties(new_params_subset) + params = entity.last_saved_params + params.update(new_params_subset) + entity.set_params(params) ... - file_content = entity.download() + file = entity.get_file() # file.getvalue_binary() to obtain the binary content ``` ``` - entity_type = API().entity_type(entity_type_id) - entity_type.entities() + API().get_entities_by_type(entity_type_name) ``` Apps already using (unsupported!) code to create a file-type child entity using the `viktor.api` module can make use of the function `generate_upload_url` to fully switch to the `viktor.api_v1` module. This method should not be introduced in an app other than for above-mentioned reason: ``` - result = requests.post(f".../entity_types/{entity_type_id}/upload/", headers=...).json() + result = API().generate_upload_url(entity_type_name) - entity_properties = {"name": entity_name, "filename": result['fields']['key']} - entity.create_child({"properties": entity_properties, "entity_type": entity_type_id}) + entity.create_child(entity_type_name, name=entity_name, filename=result['fields']['key'], params={}) requests.post(result['url'], data=result['fields'], files={'file': ...}) ``` caution An unused import of the `viktor.api` module does not trigger any deprecation warning, but will crash the app when the module is deleted in v13. Be sure to remove all such imports. ### U71 - Remove manifest key `background_image`[​](/sdk/upgrades/.md#U71 "Direct link to U71")- deprecated since: v12.11.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-20 "Direct link to Current behaviour + reason for change") The background image of a single app was customizable using the manifest metadata key `background_image`. This custom background image is frozen since the migration of workspaces to a single organization environment, and can now be changed through the administrator panel per workspace. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-20 "Direct link to New behaviour") The background image can be customized per workspace through the administrator panel. This makes the `background_image` manifest key redundant. #### Conversion[​](/sdk/upgrades/.md#conversion-20 "Direct link to Conversion") Remove the `background_image` metadata key from the manifest, which can be done automatically by using the CLI command `viktor-cli fix -u 71`: ``` metadata: welcome_text: file_path.txt - background_image: file_path.jpg ``` ``` - metadata: - background_image: file_path.jpg ``` ### U70 - Removed `Polyline.from_dict()`[​](/sdk/upgrades/.md#U70 "Direct link to U70")- deprecated since: v12.10.0 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-21 "Direct link to Current behaviour + reason for change") A `Polyline` can be instantiated using the class method `from_dict`, however this should not be part of the public api. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-21 "Direct link to New behaviour") The class method will be removed. #### Conversion[​](/sdk/upgrades/.md#conversion-21 "Direct link to Conversion") ``` polyline_points = [...] # list of dictionaries - polyline = Polyline.from_dict(polyline_points) + polyline = Polyline([Point(p['x'], p['y']) for p in polyline_points]) ``` ### U69 - Autoselect single option in OptionField[​](/sdk/upgrades/.md#U69 "Direct link to U69 - Autoselect single option in OptionField")- deprecated since: v12.10.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-22 "Direct link to Current behaviour + reason for change") The list of available options in an OptionField may consist of a single entry. This can either be achieved by providing a static list of options, or when the options are created dynamically. In the latter case, a single option will automatically be selected in the interface (without user interaction). However, this could lead to unintended behavior. In the following example, the selected option is automatically changed without the user being aware of it: | Action | Options | | ----------------------------------------------------------------------------- | --------------------------------------- | | enter the editor | ⚪ A, ⚪ B, ⚪ C | | options dynamically change to single option A | ⚫ A | | options dynamically change to multiple options | ⚫ A, ⚪ B, ⚪ C | | options dynamically change to single option B (user might not be aware!) | ⚫ B | | options dynamically change to multiple options, excluding the selected option | ⚪ A, ❌ B, ⚪ C (warning in interface) | #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-22 "Direct link to New behaviour") In the future, the new default will be to not automatically select a single option within an `OptionField`. The `autoselect_single_option` flag has been added to explicitly set the behaviour of selecting a single option to `True` or `False`. ``` options = OptionField("Options", options=dynamic_options, autoselect_single_option=False) ``` In case you want to keep the current behavior, this flag can be set to True. #### Conversion[​](/sdk/upgrades/.md#conversion-22 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 69`: ``` - options = OptionField("Options", options=dynamic_options) + options = OptionField("Options", options=dynamic_options, autoselect_single_option=True) ``` ### U68 - Remove `require_all_fields` on buttons[​](/sdk/upgrades/.md#U68 "Direct link to U68")- deprecated since: v12.9.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-23 "Direct link to Current behaviour + reason for change") The argument `require_all_fields` can be specified on an action button, however it is not implemented in the platform. This argument could cause confusion and makes the SDK reference less readable. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-23 "Direct link to New behaviour") The `require_all_fields` argument will be removed. The following fields are affected: * `DownloadButton` * `SetParamsButton` * `ActionButton` (`AnalyseButton`) * `OptimizationButton` (`OptimiseButton`) #### Conversion[​](/sdk/upgrades/.md#conversion-23 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 68`: ``` - download_button = DownloadButton("Download X", method="download_x", require_all_fields=True) + download_button = DownloadButton("Download X", method="download_x") ``` ### U67 - GEOLIB hosting by VIKTOR will be terminated[​](/sdk/upgrades/.md#U67 "Direct link to U67 - GEOLIB hosting by VIKTOR will be terminated")- deprecated since: v12.9.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-24 "Direct link to Current behaviour + reason for change") Deltares' GEOLIB is currently hosted by VIKTOR to make it available for its clients. The GEOLIB (>= 0.1.6) has now become publicly available on pypi, removing the need to host it ourselves. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-24 "Direct link to New behaviour") The GEOLIB can be installed directly from pypi by pointing to the correct package in the app's requirements.txt. #### Conversion[​](/sdk/upgrades/.md#conversion-24 "Direct link to Conversion") In case you are not using the GEOLIB in your app, no action is required. Otherwise, update `requirements.txt` which can be done automatically by using the CLI command `viktor-cli fix -u 67`: ``` # viktor==X.X.X - geolib==0.1.6 + d-geolib==0.1.6 ... ``` caution GEOLIB is available on pypi from version >= 0.1.6. With the termination of the hosting by VIKTOR, older versions will become unavailable. If your app uses a version older than 0.1.6, please update your code accordingly. ### U66 - NumberField.Variant replaced with str-type[​](/sdk/upgrades/.md#U66 "Direct link to U66 - NumberField.Variant replaced with str-type")- deprecated since: v12.8.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-25 "Direct link to Current behaviour + reason for change") The variant of a `NumberField` is currently set with `NumberField.Variant`, which is of type `Enum`. To make the product easier to understand and use, also for starting programmers, this is updated to a simple `str`-type. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-25 "Direct link to New behaviour") The variant of a `NumberField` can be set with a simple `str`-type ('slider', 'standard'). #### Conversion[​](/sdk/upgrades/.md#conversion-25 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 66`: ``` - NumberField("MyField", min=10, max=20, variant=NumberField.Variant.SLIDER) + NumberField("MyField", min=10, max=20, variant='slider') - NumberField("MyField", variant=NumberField.Variant.STANDARD) + NumberField("MyField", variant='standard') # or just NumberField("MyField") ``` ### U65 - Entity selection fields return `Entity` object[​](/sdk/upgrades/.md#U65 "Direct link to U65")- deprecated since: v12.8.0 - automated code fix available: partly #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-26 "Direct link to Current behaviour + reason for change") The value of the entity selection fields as returned in the params is of type integer. Returning objects in the params will become the standard behavior. This allows for already existing fields, such as the entity selection fields, to return more logical types. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-26 "Direct link to New behaviour") Returned values in the params will be strictly of type `Entity` in the future. By defining `viktor_convert_entity_field = True` on a controller, this behavior can be simulated. The following fields are affected: * `ChildEntityOptionField` * `SiblingEntityOptionField` * `ChildEntityMultiSelectField` * `SiblingEntityMultiSelectField` Note that if `viktor_convert_entity_field` is defined, not only the params of the **current** controller are converted, but also the params obtained from API calls. In the example below, the params of an entity of EntityTypeA are converted when retrieved in an entity of EntityTypeB. ``` class ControllerA(ViktorController) # EntityTypeA viktor_convert_entity_field = False ... def func(self, params, **kwargs): entity = params['child_entity_option_field'] # of type int! class ControllerB(ViktorController) # EntityTypeB viktor_convert_entity_field = True ... def func(self, params, **kwargs): params_entity_a = ... # API call to retrieve params of EntityTypeA entity = params_entity_a['child_entity_option_field'] # of type Entity! ``` #### Conversion[​](/sdk/upgrades/.md#conversion-26 "Direct link to Conversion") Add a `viktor_convert_entity_field` class attribute on the `Controller`. This can be done automatically by using the CLI command `viktor-cli fix -u 65`: ``` class MyController(ViktorController): + viktor_convert_entity_field = True ``` caution Unfortunately we cannot automatically fix your app logic. Please update the affected code manually, for example: ``` entity = params.tab.section.child_entity - entity = API().get_entity(entity) ``` An `Entity` is not serializable meaning that it cannot be used as input of a `memoized` function. In case you are passing the complete `params` as input, a conversion is required: ``` - memoized_func(params=params) + params_ = copy.deepcopy(params) + del params_['tab']['section']['child_entity'] + memoized_func(params=params_) ``` ### U64 - Replace PrivilegedAPI by explicit `privileged` flag[​](/sdk/upgrades/.md#U64 "Direct link to U64")- deprecated since: v12.6.0 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-27 "Direct link to Current behaviour + reason for change") Privileged API calls are done by using the `PrivilegedAPI` class. A danger of this approach is that the object may be instantiated well in advance of the actual API call, such that it is no longer transparent whether that call is privileged or not. Furthermore, `PrivilegedAPI` and the default `API` could be mixed within a method which can also result in unwanted privileged calls. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-27 "Direct link to New behaviour") The `PrivilegedAPI` class will be removed and privileged API calls should be done by adding an explicit `privileged` flag in the corresponding method (e.g. `entity.children(privileged=True)`). The following methods are affected: * `API.get_entity()` * `API.get_entity_file()` * `API.get_root_entities()` * `Entity.parent()` * `Entity.children()` * `Entity.siblings()` caution If not used properly, (confidential) information which SHOULD NOT be accessible by a user may leak (for instance by including data in a view). Please consider the following when using the `privileged` flag: * Make sure the app's admin is aware that the code circumvents certain permissions at specific places. * Make sure to test the implementation thoroughly, to ensure no confidential data is leaked. #### Conversion[​](/sdk/upgrades/.md#conversion-27 "Direct link to Conversion") ``` - api = PrivilegedAPI() - privileged_root_entities = api.get_root_entities() + api = API() + privileged_root_entities = api.get_root_entities(privileged=True) ``` ### U63 - Remove `prefix` and `suffix` on DateField[​](/sdk/upgrades/.md#U63 "Direct link to U63")- deprecated since: v12.5.0 - automated code fix available: no #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-28 "Direct link to Current behaviour + reason for change") A `prefix` and / or `suffix` can be defined on a DateField, which is not relevant for this type of field. The attributes will therefore be removed. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-28 "Direct link to New behaviour") It will not be possible to use `prefix` and `suffix` on a DateField. #### Conversion[​](/sdk/upgrades/.md#conversion-28 "Direct link to Conversion") ``` - DateField('Some date', suffix='XYZ') + DateField('Some date (XYZ)') ``` ### U62 - Renamed `threejs_visualisation()` to `visualize_geometry()`[​](/sdk/upgrades/.md#U62 "Direct link to U62")- deprecated since: v12.5.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-29 "Direct link to Current behaviour + reason for change") A `SoilLayout2D` or `SoilLayer2D` can be visualized by calling `threejs_visualisation()` on the corresponding object. The "threejs" part in this name is no longer relevant and might be unclear to the developer. #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-29 "Direct link to New behaviour") Both methods return the geometric representation of the object, which can be used in a GeometryView. Therefore the methods are renamed to `visualize_geometry()`: * `SoilLayout2D.threejs_visualisation()` -> `SoilLayout2D.visualize_geometry()` * `SoilLayer2D.threejs_visualisation()` -> `SoilLayer2D.visualize_geometry()` #### Conversion[​](/sdk/upgrades/.md#conversion-29 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 62`: ``` layout = SoilLayout2D(...) - geometry, labels = layout.threejs_visualisation(...) + geometry, labels = layout.visualize_geometry(...) ``` ### U61 - Move entity-type information from manifest to Controller[​](/sdk/upgrades/.md#U61 "Direct link to U61 - Move entity-type information from manifest to Controller")- deprecated since: v12.3.0 - automated code fix available: yes #### Current behaviour + reason for change[​](/sdk/upgrades/.md#current-behaviour--reason-for-change-30 "Direct link to Current behaviour + reason for change") The entity-type information is currently partly described in the corresponding Controller (parametrization / views / summary), but some data is defined in the `manifest.yml` (label, children, show\_children\_as). This manifest is a concept which is often hard to grasp for a starting developer. In order to improve the onboarding of new developers, as well as consistency of where to define entity-type information, we would like to get rid of the manifest completely. The first step is to move the definition of the following keys to the corresponding controller: * `label` (required) * `children` (if present) * `show_children_as` (if present) #### New behaviour[​](/sdk/upgrades/.md#new-behaviour-30 "Direct link to New behaviour") The keys will become simple class attributes, similar as `parametrization` and `summary`: ``` class EntityTypeController(ViktorController): label = 'Label of the entity-type' children = ['SomeType', 'AnotherType'] show_children_as = 'Cards' # or 'Table' ``` If they are still present in the manifest, you may expect the following warning: ``` Entity.label is present in manifest.yml but is overwritten by the app logic. Remove entry from manifest. ``` Note, when you are defining `label` on the Controller, the SDK will also try to get `children` + `show_children_as` or use the default of "no children" if not found. Therefore you **cannot** define `label` on the Controller, while keeping `children` and `show_children_as` in the manifest! #### Conversion[​](/sdk/upgrades/.md#conversion-30 "Direct link to Conversion") The following conversion has to be performed, which can be done automatically by using the CLI command `viktor-cli fix -u 61`: ``` # manifest.yml version: '1' entity_types: EntityTypeA: - label: This is A - show_children_as: Cards - children: - - EntityTypeB ... EntityTypeB: - label: This is B ... ``` ``` # entity_type_a/controller.py class EntityTypeAController(ViktorController): + label = 'This is A' + children = ['EntityTypeB'] + show_children_as = 'Cards' ... # entity_type_b/controller.py class EntityTypeBController(ViktorController): + label = 'This is B' ... ``` --- # Migrate (v13 to v14) This guide has been written for developers with existing VIKTOR application(s) on v13 who want to upgrade to v14. It provides a general overview of the necessary actions and links to relevant documents for more information. ## Breaking changes[​](/sdk/v13-to-v14/.md#breaking-changes "Direct link to Breaking changes") VIKTOR uses semantic versioning, which means that a major version upgrade (such as v13 -> v14) contains backwards incompatible (breaking) changes: you might need to make changes in your app code to ensure that it functions as expected after the upgrade. Under [Removed in v14](/sdk/upgrades/.md#removed-in-v14) we have listed all the changes: * a description of the change * reason for the change * necessary steps to update your code For some upgrades we provide an [automated code fix](/docs/create-apps/references/cli/.md#fix) which helps you in applying the necessary steps, e.g.: ``` viktor-cli fix -u ID ``` or apply all available upgrades by using: ``` viktor-cli fix ``` ## Upgrade steps[​](/sdk/v13-to-v14/.md#upgrade-steps "Direct link to Upgrade steps") Steps to upgrade: 1. Upgrade to the [latest v13 version](/sdk/changelog/.md#v13). This is backwards compatible, so you can change the version number and run your app without any changes needed. 2. Check the upgrade list below and update your app code accordingly. 3. As a check: run your code + run your tests. It should not emit any deprecation warnings introduced by the SDK. 4. Change the version to 14.0.0. This is backwards incompatible, but you have already implemented the necessary changes, so you're ready to go. caution The absence of deprecation warnings when running your app does not mean that all updates have been applied correctly, so make sure to check the list. You might not cover all your code when testing (warning is not triggered) and sometimes we cannot raise the warning at all On average, we expect this upgrade to take less than 1 hour per app. It depends on the size of the app and how many open updates need to be applied. In case you are experiencing difficulties upgrading, either manually or using the provided `fix` command, please contact VIKTOR. The table below shows an overview of the upgrades introduced in v13 and the estimated duration to fix: | ID | Deprecation | Upgrade duration | deprecated since | codemod available | | -- | -------------------------------------------------------------------------- | ---------------- | ---------------- | ----------------- | | 86 | Remove support for Python 3.7 | ? | CLI v0.29.2 | no | | 85 | Remove leading hashtag for viktor dependency | 5 minutes | CLI v0.29.0 | yes | | 84 | UserException replaced by UserError | 5 minutes | SDK v13.7.0 | yes | | 83 | Violated field constraints block actions | 15 minutes | SDK v13.7.0 | partly | | 82 | Specific image views replaced by `ImageView` | 5 minutes | SDK v13.7.0 | yes | | 81 | Removed `open_ends` from `CircularExtrusion` | 5 minutes | SDK v13.6.0 | yes | | 80 | Removed `min_messages` and `max_message` from `NumberField`/`IntegerField` | 5 minutes | SDK v13.5.0 | yes | | 79 | Remove `hex_to_rgb` and `rgb_to_hex` from geometry module | 5 minutes | SDK v13.5.0 | yes | | 78 | viktor.config.toml requires `app_type` entry | 5 minutes | SDK v13.3.0 | yes | | 77 | Removal of the manifest | 5 minutes | SDK v13.2.0 | yes | ---