Skip to content

Conversation

@EDCarman
Copy link
Contributor

@EDCarman EDCarman commented Jun 16, 2025

Description

Add an example showing how PyMAPDL and PyDPF can be use to export training data to be used to create a Static Reduced Order model in Ansys Twin Builder.

Issue linked

None.

Checklist

Summary by Sourcery

Add a new documentation example demonstrating how to generate static reduced-order model (ROM) training data with PyMAPDL, DPF, and PyTwin for use in Ansys Twin Builder

Documentation:

  • Introduce a Python script and RST guide for Static ROM data generation example under extended examples
  • Update examples index and links to include the new Static ROM example
  • Add intersphinx mapping for the pytwin package in conf.py to enable cross-references to PyTwin documentation

@EDCarman EDCarman requested a review from a team as a code owner June 16, 2025 07:30
@EDCarman EDCarman requested review from clatapie and germa89 June 16, 2025 07:30
@ansys-reviewer-bot
Copy link
Contributor

Thanks for opening a Pull Request. If you want to perform a review write a comment saying:

@ansys-reviewer-bot review

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jun 16, 2025

Reviewer's Guide

This PR enriches the documentation by adding a comprehensive example for generating static ROM training data—demonstrating parametric sweeps, data compression, and export to Ansys Twin Builder via PyMAPDL, DPF, and Pytwin—and updates the docs configuration to include Pytwin intersphinx mappings.

High-Level Sequence Diagram for Static ROM Data Generation

sequenceDiagram
    participant Script as static_rom_data_generation.py
    participant PyMAPDL
    participant PyDPF
    participant Pytwin
    participant FileSystem as Output Files

    Script->>PyMAPDL: Run parametric simulations (run_mapdl_variations)
    PyMAPDL-->>Script: Simulation results (list of .rst paths & params)

    loop For each simulation result (idx, rst_path, params)
        Script->>PyDPF: Load model from rst_path (dpf.Model)
        PyDPF-->>Script: dpf_model
        Script->>PyDPF: Get common node scoping (get_scoping)
        PyDPF-->>Script: scoping

        loop For each result_type in ["displacement", "stress"]
            note over Script, FileSystem: Operations target result_type specific folder (e.g., ./displacement/ or ./stress/)
            opt First simulation result (idx == 0)
                Script->>FileSystem: Write points.bin (via write_points to result_type folder)
                Script->>FileSystem: Write settings.json (via write_settings to result_type folder)
                Script->>FileSystem: Write doe.csv headers (via write_doe_headers to result_type folder)
            end
            Script->>PyDPF: Get result_field_data (for result_type, from dpf_model)
            PyDPF-->>Script: result_field_data
            Script->>Pytwin: Write snapshot .bin (pytwin.write_binary to result_type/snapshots/)
            Pytwin-->>FileSystem: Saves snapshot .bin
            Script->>FileSystem: Append entry to doe.csv (via write_doe_entry to result_type folder)
        end
    end
Loading

Class Diagram for static_rom_data_generation Module Functions

classDiagram
    namespace static_rom_data_generation {
        class functions {
            +compress_id_list(id_list: np.ndarray) list
            +write_settings(path: Path, field: dpf.Field, name: str, is_deformation: bool) void
            +get_scoping(model: dpf.Model) dpf.Scoping
            +write_points(model: dpf.Model, scoping: dpf.Scoping, output_folder: Path) void
            +write_doe_headers(output_folder: Path, name: str, parameters: dict) void
            +write_doe_entry(output_folder: Path, snapshot_name: str, parameters: dict) void
            +export_static_ROM_variation(model: dpf.Model, scoping: dpf.Scoping, name: str, output_folder: Path, parameters: dict, snap_idx: int, new_metadata: bool) void
            +export_static_ROM_data(mapdl_results: list, output_folder: Path) void
            +run_mapdl_variations() list
            +run() void
        }
    }
    note for functions "Helper and orchestration functions within the new Python script."
Loading

File-Level Changes

Change Details Files
Added Pytwin intersphinx mapping
  • Insert “pytwin” entry into intersphinx_mapping in conf.py
doc/source/conf.py
Extended documentation with static ROM data generation example
  • Add Python example illustrating parametric MAPDL runs and export helpers
  • Create accompanying .rst guide for the static ROM workflow
  • Update extended_examples index to link the new static ROM guide
  • Add link entry in links.rst for the static ROM example
doc/source/examples/extended_examples/static_rom/static_rom_data_generation.py
doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst
doc/source/examples/extended_examples/index.rst
doc/source/links.rst

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @EDCarman - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.py:108` </location>
<code_context>
+        json.dump(settings, fw, default=int, indent=4)
+
+
+def get_scoping(model: dpf.Model):
+    """Return scoping of unique node IDs connected to elements in model."""
+    op = dpf.operators.scoping.connectivity_ids(
</code_context>

<issue_to_address>
Avoid multiple mesh_scoping calls and sort scoping IDs

Call `mesh_scoping()` once, then assign `sorted(set(...))` to `scoping.ids` to ensure deterministic ordering.
</issue_to_address>

### Comment 2
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.py:130` </location>
<code_context>
+    write_binary(Path(output_folder).joinpath("points.bin"), points_coordinates)
+
+
+def write_doe_headers(output_folder: str | Path, name: str, parameters: dict):
+    """Write blank doe.csv file with headers."""
+    with open(Path(output_folder).joinpath("doe.csv"), "w") as fw:
</code_context>

<issue_to_address>
Use the csv module for CSV writing

Manual concatenation can lead to incorrect quoting or line endings. Using `csv.writer` handles these cases reliably.

Suggested implementation:

```python
import csv

def write_doe_headers(output_folder: str | Path, name: str, parameters: dict):
    """Write blank doe.csv file with headers."""
    with open(Path(output_folder).joinpath("doe.csv"), "w", newline="") as fw:
        writer = csv.writer(fw)
        writer.writerow([name] + list(parameters.keys()))

```

```python
def write_doe_entry(output_folder: str | Path, snapshot_name: str, parameters: dict):
    """Write entry to doe.csv file."""
    with open(Path(output_folder).joinpath("doe.csv"), "a", newline="") as fw:
        writer = csv.writer(fw)
        writer.writerow([snapshot_name] + list(parameters.values()))

```
</issue_to_address>

### Comment 3
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst:7` </location>
<code_context>
+Creating training data for a 3D Static reduced order model (ROM)
+================================================================
+
+This example how a parametric sweep may be run on and MAPDL model and the output displacement and
+stress data exported into the format required to build a Static ROM with Ansys Twin Builder.
+
</code_context>

<issue_to_address>
Grammatical error: missing verb.

Consider revising to 'This example shows how...' or 'This example demonstrates how...'.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
This example how a parametric sweep may be run on and MAPDL model and the output displacement and
stress data exported into the format required to build a Static ROM with Ansys Twin Builder.
=======
This example shows how a parametric sweep may be run on an MAPDL model and the output displacement and
stress data exported into the format required to build a Static ROM with Ansys Twin Builder.
>>>>>>> REPLACE

</suggested_fix>

### Comment 4
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst:58` </location>
<code_context>
+running:
+
+* `NumPy <https://numpy.org>`_ is used for using NumPy arrays.
+* `PyPDF <dpf_core_docs_>`_ is used to efficiently manipulate result data.
+* `PyTwin <pytwin_docs_>`_ is used convert result data to binary snapshots.
+
</code_context>

<issue_to_address>
Incorrect package name?

Should this reference be 'PyDPF' or 'PyDPF-Core' instead, given the context and the link? 'PyPDF' appears unrelated.
</issue_to_address>

### Comment 5
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst:59` </location>
<code_context>
+
+* `NumPy <https://numpy.org>`_ is used for using NumPy arrays.
+* `PyPDF <dpf_core_docs_>`_ is used to efficiently manipulate result data.
+* `PyTwin <pytwin_docs_>`_ is used convert result data to binary snapshots.
+
+
</code_context>

<issue_to_address>
Grammatical error: missing 'to'.

The phrase should read 'used to convert result data to binary snapshots.'
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
* `PyTwin <pytwin_docs_>`_ is used convert result data to binary snapshots.
=======
* `PyTwin <pytwin_docs_>`_ is used to convert result data to binary snapshots.
>>>>>>> REPLACE

</suggested_fix>

### Comment 6
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst:84` </location>
<code_context>
+The ``new_metadata`` Boolean is set to ``True`` on the first loop to trigger the creation of the
+``points.bin`` and ``settings.json`` files and a new ``doe.csv`` file.
+
+The :func:`pytwin.write_binary` function is used to write the result field data a ROM binary file.
+
+
</code_context>

<issue_to_address>
Grammatical error: missing 'to'.

It should read 'write the result field data to a ROM binary file.'
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
The :func:`pytwin.write_binary` function is used to write the result field data a ROM binary file.
=======
The :func:`pytwin.write_binary` function is used to write the result field data to a ROM binary file.
>>>>>>> REPLACE

</suggested_fix>

### Comment 7
<location> `doc/source/examples/extended_examples/static_rom/static_rom_data_generation.rst:241` </location>
<code_context>
+
+.. code-block:: python
+
+    namedSelections: {"first_nodes": [0, -1, 99], "first_nodes": [49, -1, 149]}
</code_context>

<issue_to_address>
Duplicate key in example JSON object.

The second key should be 'second_nodes' to match the description and ensure the example is valid.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

Hi @EDCarman!

Thank you a lot for opening this PR. Since you have started the PR from a fork, the fork does no have access to the secrets. This is fine, the bot will migrate your PR to another PR inside the repo.

You might want in the future "clone" the ansys/pymapdl repo, instead of working from your fork (EDCarman/pymapdl).

Once the migration is done, I will review there (because it will build the docs) that PR and close this one. You should be to work on that PR if needed.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

@pyansys-ci-bot migrate

@pyansys-ci-bot
Copy link
Contributor

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@EDCarman
Copy link
Contributor Author

Hi @EDCarman!

Thank you a lot for opening this PR. Since you have started the PR from a fork, the fork does no have access to the secrets. This is fine, the bot will migrate your PR to another PR inside the repo.

You might want in the future "clone" the ansys/pymapdl repo, instead of working from your fork (EDCarman/pymapdl).

Once the migration is done, I will review there (because it will build the docs) that PR and close this one. You should be to work on that PR if needed.

Thanks @germa89

I do normally clone the repos but in this case I was only able to create a local branch, rather than being able to sync it online. I assume this is a permissions issue not allowing me to create a new branch on the repo itself.

@pyansys-ci-bot
Copy link
Contributor

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

1 similar comment
@pyansys-ci-bot
Copy link
Contributor

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

@EDCarman you are an ansys employee, you should be able now. Before you had to request access, unless you were part of @ansys/developers team.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

P.D.- @EDCarman I will use your PR to troubleshoot a problem with the migrator, so please excuse the spam comments.

Let's try again!

@pyansys-ci-bot migrate

@pyansys-ci-bot
Copy link
Contributor

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

3 similar comments
@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

@pyansys-ci-bot migrate

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

@pyansys-ci-bot migrate

@pyansys-ci-bot
Copy link
Contributor

❌ Error ❌

An error occurred while migrating or syncing the PR. Pinging @pymapdl-maintainers for assistance.

@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

🚀 Migration completed!

The PR #4011 has been created successfully.

Thank you @EDCarman for your contribution! Please review the PR and make any necessary changes.

@germa89 germa89 mentioned this pull request Jun 16, 2025
10 tasks
@germa89
Copy link
Collaborator

germa89 commented Jun 16, 2025

Closing in favour of #4011

@germa89 germa89 closed this Jun 16, 2025
germa89 added a commit that referenced this pull request Jun 17, 2025
…example (#4011)

* build: Add PyTwin to doc dependencies

* docs: Initial static ROM example

* docs: refactor example

* docs: remove local .db file, refactor script

* docs: separate MAPDL DoE and export runs in example

* docs: add Pytwin to links and intersphinx mapping

* docs: add Static ROM example description

* docs: undo commenting out filename_pattern

* build: Undo addition of PyTwin to doc dependencies

* docs: fixed code-block vailing Vale.Spelling

* docs: add corrections suggested by sourcery-ai

* docs: sort scoping IDs

* chore: adding changelog file 4011.miscellaneous.md [dependabot-skip]

* chore: adding changelog file 4011.miscellaneous.md [dependabot-skip]

* docs: address sourcery-ai corrections

* chore: adding changelog file 4011.miscellaneous.md [dependabot-skip]

* chore: adding changelog file 4011.miscellaneous.md [dependabot-skip]

* docs: Apply suggestions from code review

Co-authored-by: Kathy Pippert <[email protected]>

* docs: Apply modified suggestions from code review

* docs: fix failing Vale and pre-commit check after corrections.

---------

Co-authored-by: EDCarman <[email protected]>
Co-authored-by: Edward Carman <[email protected]>
Co-authored-by: pyansys-ci-bot <[email protected]>
Co-authored-by: Kathy Pippert <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants