Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/change_log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Change Log

## 2026 R1
- added doc to developer page
13 changes: 13 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/common_issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Common Issues & Solutions

## User Variable metadata and display tags

Many plugins will map variables in the ModelCenter world to objects in the external system. For example, each Excel Plug-In variable will be mapped to a particular workbook range. Instead of storing this mapping themselves, the plug-in should use the existing user variable tags/metadata to consistently handle this.

## Threading

The runner is run on a single, unique, operating system thread and all calls to it are serialized and proxied to this thread for execution. This provides a sane environment from which the plug-in can safely operate without having to worry about thread safety. If the Plug-In writer wishes to use multiple threads, they can start those threads themselves and deal with the ensuing thread synchronization issues.

The plug-in writer may also safely use Task Asynchronous Programming (TAP, or async/await). We install a `SynchronizationContext` so that all continuations will happen by default on the single thread. If the plug-in writer wishes to let work run on the thread pool, they can use `Task.Run()` or `.ContinueWith(false)` calls. For more information, refer to [Microsoft's task based asynchronous pattern documentation](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap).

The builder UI is also run on a single, unique, UI thread and all calls to it are serialized and proxied to this thread for execution. This thread is different than the runner thread. All calls from the UI to the Runner should happen through `IHarnessBuilderUIHost.CallRunnerAsync()`.
118 changes: 118 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/customizing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Customizing The Plug-In

## Creating the UI

### Name the plug-in.

Set `BuilderUI.ComponentName`.

### `LoadFromPaczAsync`

Called when the plug-in is first created or loaded. State should be loaded from the passed-in `IExtractedPacz`. Most of the state is likely stored in the `Config.Properties` and the `Config.InstanceFiles`. Variables will be saved and loaded as part of the `viewModel`; it may not be necessary to load them here.

Note that the Model object (type `VariableBasedBuilderModel`) is directly accessible in this function's scope and can be used to create input/output variables. The following example shows inputs and outputs being created if none exist when the `LoadFromPaczAsync(...)` function is called:

```java
protected override async Task LoadFromPaczAsync(IExtractedPacz extractedPacz)
{
if (Model.InputVariables.Count == 0)
{
// Create the initial set of variables for the view
Model.MoveInputVariablesFrom(_createInputs());
Model.MoveOutputVariablesFrom(_createOutputs());
}

await Task.CompletedTask;
}

private IEnumerable<IRuntimeVariable> _createInputs()
{
RuntimeVariable x1 = new RuntimeVariable("x1", VariableType.Real, new RealValue(0.5));
RuntimeVariable x2 = new RuntimeVariable("x2", VariableType.Real, new RealValue(1.75));

IEnumerable<IRuntimeVariable> inputs = new List<IRuntimeVariable>() { x1, x2 };
return inputs;
}

private IEnumerable<IRuntimeVariable> _createOutputs()
{
RuntimeVariable y = new RuntimeVariable("y", VariableType.Real, new RealValue(0.01));

IEnumerable<IRuntimeVariable> outputs = new List<IRuntimeVariable>() { y };
return outputs;
}
```

### GetFileLoadProperties

If instances of the plug-in will use an existing file, usually from another application, as part of the setup or run evaluation, override `GetFileLoadProperties` to enable the built-in file load dialog. Create a `FileLoadProperties` object with an action that will be called when the user selects a new file and a file filter for the open dialog to use. The file will likely need to be copied to the `Host.ExtractedPacz.ExtractionFolder` and added to the `Config.InstanceFiles`.

An example of this would be choosing a CAD file for a CAD plug-in. The builder may then interrogate this file in the `FileLoadProperties` Action to determine which inputs and outputs to add to the plug-in.

### SelectVariables

In some plug-ins, users will create all the variables manually in the variable tree, but usually a better option is for the plug-in to assist with variable creation. This can be done in the `Action` called when the build in file dialog is used to select a file or from a menu button press.

This can be done entirely without user input by adding the variables into the `viewModel.Variable` List or the `SelectVariables` form can be used to allow some customization of the available variables.

To use the `SelectVariables` form, you must pass lists of available inputs and outputs. Call the `SelectVariables` method of the `AbstractBuilderUI`, and it will provide a form with the variables to allow the user to filter and select the variables they wish to include.

### GetTreeProperties

Allows customization of the variable tree.

- `componentName`: Name to display at the root of the `VariableTree`.
- `canAddRemove`: If the UI controls can be used to add and remove variables.<br>If variables are created programmatically or using `SelectVariables`, this can allow user from creating additional variables or editing the properties of the programmatically created ones.
- `hasNamedVariables`: If the variables use a named variable property.<br>`NamedVariables` allow variables to have a mapping to another name that can be used by the plug-in. An example of this could be that a plug-in that uses Excel could use a named variable to provide a mapping to a range. The variable's name in the plug-in may be *cost* but could map to a range in Excel. The plug-in could use the range when communicating with Excel, while the variable is displayed as "Cost".
- `namedVariableDisplayName`: The display name of named variables.<br>This defines the label to use for the `namedVariable` field. In the example using Excel, this might be "Range".
- `namedVariableToken`: The token to use for named variables in the Text Based Variable Editor.<br>This is like the `namedVariableDisplayName` but is used in sterilization (by the text based variable editor) and must be alphanumeric characters.

### SetupView

This method is called after the form is created and allows customization. This is typically done by adding menu items to the main `Menu`. By default, `VariableBasedPlugIns` will have an **Apply** button that saves the plug-in instance. Additional menu items can be added as either buttons or containers of subItems.

Use the `AddMenuItem` method of the `AbstractBuilderUI` base class to add items and provide an event handler as the action to perform on click. The `VariableBasedBuilderViewModel` can be made available to use in the event handler if desired.

Common usages of additional menu items are to show an options dialog or a help page for the plug-in. The following code sample shows a simple Windows Form made accessible through a custom options menu item. No further code is required to make a `Form1` object accessible to the user.

```java
public class BasicPaczPluginBuilderUI : AbstractVariableBasedBuilderUI<BasicPaczPluginRunner>
{

protected override void SetupView(IExtractedPacz pacz, VariableBasedBuilderViewModel viewModel, Menu mainMenu)
{
AddMenuItem(parent: mainMenu, header: "Options", imageType: ImageType.OPTIONS, hasDownArrow: false, eventHandler: (s, e) => _editOptions(viewModel));
}

private void _editOptions(VariableBasedBuilderViewModel viewModel)
{
Form1 form1 = new Form1();
Form1.Show();
}

}

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
```

### SaveToPaczAsync

This is called to allow the plug-in to save any necessary information into the PACZ. Most settings will be stored as name-value pairs in the `pacz.Config.Properties` dictionary. Instance files may also need to be updated. Variables are part of the `ViewModel` and will be saved and loaded by the `ViewModel`; typically, there is no need to do anything with the variables in `SaveToPaczAsync`.

## Creating the Runner

### ConstructAsync

Will always be called first allowing initialization of the runner. Most plug-ins will want to capture the `IHarnessRunnerHost` that is passed in to use later. If execution relies on resource intensive or slow-to-load applications, it may be advisable to delay loading the application until the first run.

### RunAsync

Called to perform a run evaluation. Input variables are passed in with a value and a validity. Plug-Ins that do not support invalid inputs can use `SafeValue` to ensure that all input values are valid. After evaluation, the outputs dictionary should be updated with new a new `VariableState` for each output.
13 changes: 13 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/docfx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"build": {
"globalMetadata": {
"title": "ModelCenter Component Plugin SDK Getting Started",
"summary": "",
"version": "2026 R1",
"product": "ModelCenter",
"programming language": "java",
"product collection": "Connect",
"physics": "Connect"
}
}
}
141 changes: 141 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Frequently Asked Questions

## Q1. How do I programmatically define a ModelCenter assembly in the Component Tree?

**A1.** Write nested variable names using "`.`" separators:

![step1](graphics/faq_q1_step1.png)

ModelCenter takes care of assembly creation automatically:

![step2](graphics/faq_q1_step2.png)

Then use the same name in the `RunAsync` method to access the nested variable:

![step3](graphics/faq_q1_step3.png)

## Q2. What characters are allowed for plugin variable names?

**A2.** ModelCenter variables use the same convention as Java variables, except dollar signs (`$`) are not supported.

Essentially alphanumeric + underscore, but first character must be either a letter or underscore.

Periods are only supported as the separator between different levels of a hierarchy.

Spaces, punctuation, and special characters are not allowed.

For more information, see https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html.

## Q3. How do I access Value and DefaultValue from the Runner context?

**A3.** Access both read-only values as follows:

![step1](graphics/faq_q3_step1.png)

Accessing `DefaultValue` is done with integer index rather than name. The user must search (LINQ function or traditional iterator) through the available indices to find the desired name / `DefaultValue`. You are technically reading directly from the PACZ file created during the Builder context.

Note that `Value` can only be accessed from the Runner context. There is no access to `Value` from the Builder context. In the Builder context, only `DefaultValue` can be set, which is later copied to create the variable's `Value`. This copy process occurs in ModelCenter’s core process outside the Plug-In environment.

## Q4. How do I create an array variable?

**A4.** Using a two-item boolean array as an example:

```java
bool[] val = { true, false };
BooleanArrayValue booleanArrayValue = val;
RuntimeVariable boolVar = new RuntimeVariable("bool_arr_var", VariableType.BooleanArray, booleanArrayValue);

```

## Q5. Is it possible to query relative path from inside the plugin?

**A5.** The plugin's "model" object is aware of both relative and absolute paths:

![step1](graphics/faq_q5_step1.png)

Note that the "FilePath" property will change depending on whether the path is inside or outside the extraction folder:

![step2](graphics/faq_q5_step2.png)

## Q6. How do I remove a single input/output variable from the model?

**A6.** Call the following function as follows: `_removeOutput(viewModel, "x2");`

![step1](graphics/faq_q6_step1.png)

```java
private void _removeOutput(VariableBasedBuilderViewModel viewModel, string outputToRemove)
{
IEnumerable<IRuntimeVariable> oldOutputs = viewModel.OutputVariables;
List<IRuntimeVariable> listToPopulate = new List<IRuntimeVariable>() { };
foreach (var item in oldOutputs)
{
if (item.Name != outputToRemove)
{
listToPopulate.Add(item);
}
}
IEnumerable<IRuntimeVariable> newOutputs = listToPopulate;
viewModel.MoveOutputVariablesFrom(newOutputs);
}

```

## Q7. How do I define a file as an output variable?

**A7.** During output list construction you would have:

```java
private IEnumerable<IRuntimeVariable> _createOutputs()
{
RuntimeVariable y = new RuntimeVariable("y", VariableType.Real, new RealValue(0.01));
RuntimeVariable outvar = new RuntimeVariable("NASTRANMAP", VariableType.File, FileValue.CreateFromString(null, null, "c:\\thermal\\stress\\case1.txt", null));

IEnumerable<IRuntimeVariable> outputs = new List<IRuntimeVariable>() { y, outvar };
return outputs;
}

```

During execution time you would have:

```java
public async Task RunAsync(IReadOnlyDictionary<string, VariableState> inputs, VariableValueScope outputs, CancellationToken cancellation)
{
//TODO: Run the component, set the outputs as a function of the inputs
// e.g.
double x1 = (RealValue)inputs["a1.a2.x1"].SafeValue;
double x2 = (RealValue)inputs["x2"].SafeValue;
outputs["y"] = new VariableState(new RealValue(x1*x2));

FileValue outvarOld = (FileValue) outputs["NASTRANMAP"].SafeValue;
outputs["NASTRANMAP"] = new VariableState(FileValue.ReadFromFile(outvarOld.OriginalFileName));

await Task.CompletedTask;
//throw new NotImplementedException("Run method has not been implemented.");
}

```

## Q8. From the runner context, I can iterate through input variables using `foreach (var key in inputs.Keys)`. I need to determine whether each input is type string or type real. I currently have `(StringValue)inputs[key].SafeValue`. That crashes when it is a real. Is there a way to check what type of input it is?

**A8.** There is a method `SafeValue.GetModelCenterType`. It returns a string which is either "string" or "double".

## Q9. How to create a multi-dimensional ModelCenter array?

**A9.** Example using integers:

```java
long[,] intArr = new long[3, 4] {
{0, 1, 2, 3} , /* initializers for row indexed by 0 */
{4, 5, 6, 7} , /* initializers for row indexed by 1 */
{8, 9, 10, 11} /* initializers for row indexed by 2 */
};
IntegerArrayValue intArrVal = new IntegerArrayValue(intArr);
RuntimeVariable x3 = new RuntimeVariable("x3", VariableType.IntegerArray, intArrVal);

```

## Q10. How to add a description to an IRuntimeVariable instance?

**A10.** See "x3" variable definition in the `BasicPaczPlugin` example (provided).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ModelCenter Component Plug-In Getting Started Guide

## Introduction

Welcome to the ModelCenter Component Plug-In Getting Started Guide. This document intends to help Plug-In developers who would like to extend the capabilities of ModelCenter by adding connections to external data and analysis tools like Excel and Databases.

To obtain access to the ModelCenter Component Plug-In SDK, please contact Ansys ModelCenter support.

## Definitions

**Builder UI** – The UI portion of the Plug-In which is responsible for allowing a user to edit a PACZ.

**Component** – A workflow element that has inputs, some black box execution, and produces outputs. Often used interchangeably with the term Analysis.

**Component Plug-In** – A Plug-In to the ModelCenter framework that implements a Runner and optionally a Builder UI.

**Driver** – A workflow element that "drives" or controls other sub-workflows. If this is what you want to do, you are in the wrong document.

**PACZ** – The standard file format for a harnessed external component. The PACZ may be stored compressed as a zip, or uncompressed as a set of files in a directory. The PACZ contains a common metadata definition, component.pacj, which sufficiently describes the instance so that it can be generically managed in an "app store" and jobs can be submitted without needing to instantiate the required plug-in.

**Runner** – The non-UI portion of the Plug-In which is responsible for batch execution.

**Workflow** – An automated set of Components, Drivers, and other control elements that together compute some type of engineering simulation.

54 changes: 54 additions & 0 deletions 2026R1/ModelCenter_ComponentPlugin_SDK-26-r1/new_project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# New Project Overview (.NET)

## Project Files

### `[Name].cs` implements `IHarnessRunner`

- This is the class that is used to execute runs of the plug-in.
- There should be no UI associated with this class.
- There are 2 Public Methods that will be called:
- `ConstructAsync`
- Always called first.
- Provides the `HarnessRunnerHost`
- Initial setup and loading from the config should be done here.
- `RunAsync`
- Used to execute a run.
- Provides inputs to evaluate.
- Update output dictionary with execution results.

### `[Name]BuilderUI.cs` extends `AbstractVariableBasedBuilderUI<[Name]Runner>`

- This is the class that holds the UI of the plug-in.
- It builds on top of a pre-built UI form that allows for editing variables.
- The `ComponentName` property should be overridden to provide a display name for the plug-in.
- There are 5 base class methods that can be overridden:
- `LoadFromPaczAsync`: Used to load the plug-in instance.
- `GetTreeProperties`: Used to customize the properties tree.
- `GetFileLoadProperties`: Configures the built-in file open feature.
- `SetupView`: Used to add `menuItems` to the `mainMenu`.
- `SaveToPaczAsync`: Used to save the plug-in instance.

## `AbstractBuilderUI` Base Class

The `AbstractBuilderUI` base class contains some properties and methods that are useful:

### Properties:

- Host (`HarnessBuilderUIHost`)
- Properties
- `ExtractedPacz`: The pacz object and config.
- `Logger`: Provides logging for the plug-in.
- Methods
- `CallRunnerAsync`
- `TestRunAsync`
- `SaveAsync`

### Methods:

- `AddMenuItem` and `AddAsyncMenuItem` (requires reference to `PresentationCore`)
- `SelectVariables`: Opens the `CommonSelectVariables` Form.
- `SetPaczIcon`

## `VariableBasedBuilderViewModel`

This class provides access to the variables in the plug-in. It is provided as an argument to the method called after a new file is opened and to the `SetupView` method. Since this is provided to the `SetupView` method, it can also be made available to the functions that are called when custom `menuItems` are clicked.
Loading