Skip to content

feat: refactor Animator and add MeshesContainer.animate - #1997

Open
PProfizi wants to merge 16 commits into
mainfrom
feat/meshes_container.animate
Open

feat: refactor Animator and add MeshesContainer.animate#1997
PProfizi wants to merge 16 commits into
mainfrom
feat/meshes_container.animate

Conversation

@PProfizi

@PProfizi PProfizi commented Jan 8, 2025

Copy link
Copy Markdown
Contributor

Following new usage with time-varying meshes, this adds the capability to animate a MeshesContainer with a time label.

@PProfizi PProfizi added the enhancement New feature or request label Jan 8, 2025
@PProfizi PProfizi added this to the 0.13.4 milestone Jan 8, 2025
@PProfizi PProfizi self-assigned this Jan 8, 2025
@codecov

codecov Bot commented Jan 8, 2025

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2298 1 2297 236
View the top 3 failed test(s) by shortest run time
tests/test_mesh_info.py::test_output_mesh_info_provider_flprj[in Process CLayer]
Stack Traces | 0.073s run time
fluent_axial_comp = <function fluent_axial_comp.<locals>.return_ds at 0x7fe59c696320>
server_clayer = <ansys.dpf.core.server_types.InProcessServer object at 0x7fe62492a6b0>

    def test_output_mesh_info_provider_flprj(fluent_axial_comp, server_clayer):
>       model = dpf.Model(fluent_axial_comp(server_clayer), server=server_clayer)

tests/test_mesh_info.py:289: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/conftest.py:249: in return_ds
    files = examples.download_fluent_axial_comp(server=server)
..../test-api/lib/python3.10.../core/examples/downloads.py:1308: in download_fluent_axial_comp
    "flprj": _download_file(
..../test-api/lib/python3.10.../core/examples/downloads.py:116: in _download_file
    local_path = _retrieve_file(url, filename, directory)
..../test-api/lib/python3.10.../core/examples/downloads.py:110: in _retrieve_file
    _, resp = urlretrieve(url, local_path)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:241: in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:216: in urlopen
    return opener.open(url, data, timeout)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:525: in open
    response = meth(req, response)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:634: in http_response
    response = self.parent.error(
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:563: in error
    return self._call_chain(*args)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:496: in _call_chain
    result = func(*args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib.request.HTTPDefaultErrorHandler object at 0x7fe622e445e0>
req = <urllib.request.Request object at 0x7fe55d197580>
fp = <http.client.HTTPResponse object at 0x7fe5e614cbb0>, code = 502
msg = 'Bad Gateway or Proxy Error'
hdrs = <http.client.HTTPMessage object at 0x7fe5e61242e0>

    def http_error_default(self, req, fp, code, msg, hdrs):
>       raise HTTPError(req.full_url, code, msg, hdrs, fp)
E       urllib.error.HTTPError: HTTP Error 502: Bad Gateway or Proxy Error

.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:643: HTTPError
tests/test_mesh_info.py::test_output_mesh_info_provider_flprj[gRPC CLayer]
Stack Traces | 0.075s run time
fluent_axial_comp = <function fluent_axial_comp.<locals>.return_ds at 0x7fe59c8b5480>
server_clayer = <ansys.dpf.core.server_types.GrpcServer object at 0x7fe59c8a47f0>

    def test_output_mesh_info_provider_flprj(fluent_axial_comp, server_clayer):
>       model = dpf.Model(fluent_axial_comp(server_clayer), server=server_clayer)

tests/test_mesh_info.py:289: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/conftest.py:249: in return_ds
    files = examples.download_fluent_axial_comp(server=server)
..../test-api/lib/python3.10.../core/examples/downloads.py:1308: in download_fluent_axial_comp
    "flprj": _download_file(
..../test-api/lib/python3.10.../core/examples/downloads.py:116: in _download_file
    local_path = _retrieve_file(url, filename, directory)
..../test-api/lib/python3.10.../core/examples/downloads.py:110: in _retrieve_file
    _, resp = urlretrieve(url, local_path)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:241: in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:216: in urlopen
    return opener.open(url, data, timeout)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:525: in open
    response = meth(req, response)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:634: in http_response
    response = self.parent.error(
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:563: in error
    return self._call_chain(*args)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:496: in _call_chain
    result = func(*args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib.request.HTTPDefaultErrorHandler object at 0x7fe622e445e0>
req = <urllib.request.Request object at 0x7fe59c8a4c70>
fp = <http.client.HTTPResponse object at 0x7fe59c8a4820>, code = 502
msg = 'Bad Gateway or Proxy Error'
hdrs = <http.client.HTTPMessage object at 0x7fe59c8a7370>

    def http_error_default(self, req, fp, code, msg, hdrs):
>       raise HTTPError(req.full_url, code, msg, hdrs, fp)
E       urllib.error.HTTPError: HTTP Error 502: Bad Gateway or Proxy Error

.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:643: HTTPError
tests/test_faces.py::test_face
Stack Traces | 0.247s run time
fluent_axial_comp = <function fluent_axial_comp.<locals>.return_ds at 0x7f2b64d0acb0>

    @pytest.fixture()
    def model_faces(fluent_axial_comp):
>       model = dpf.Model(fluent_axial_comp())

tests/test_faces.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/conftest.py:249: in return_ds
    files = examples.download_fluent_axial_comp(server=server)
..../test-api/lib/python3.10.../core/examples/downloads.py:1323: in download_fluent_axial_comp
    _download_file(
..../test-api/lib/python3.10.../core/examples/downloads.py:116: in _download_file
    local_path = _retrieve_file(url, filename, directory)
..../test-api/lib/python3.10.../core/examples/downloads.py:110: in _retrieve_file
    _, resp = urlretrieve(url, local_path)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:241: in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:216: in urlopen
    return opener.open(url, data, timeout)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:525: in open
    response = meth(req, response)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:634: in http_response
    response = self.parent.error(
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:563: in error
    return self._call_chain(*args)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:496: in _call_chain
    result = func(*args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib.request.HTTPDefaultErrorHandler object at 0x7f2c08cc51e0>
req = <urllib.request.Request object at 0x7f2bb02182e0>
fp = <http.client.HTTPResponse object at 0x7f2bb021b5b0>, code = 502
msg = 'Bad Gateway or Proxy Error'
hdrs = <http.client.HTTPMessage object at 0x7f2bb0219de0>

    def http_error_default(self, req, fp, code, msg, hdrs):
>       raise HTTPError(req.full_url, code, msg, hdrs, fp)
E       urllib.error.HTTPError: HTTP Error 502: Bad Gateway or Proxy Error

.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:643: HTTPError
tests\test_animator.py::test_animator::test_animator_animate_scale_factor_none
Stack Traces | 0.648s run time
displacement_fields = <ansys.dpf.core.fields_container.FieldsContainer object at 0x000001BA4995A260>

    def test_animator_animate_scale_factor_none(displacement_fields):
        """Passing scale_factor=None is accepted (treated internally as no scaling)."""
>       displacement_fields.animate(scale_factor=None, off_screen=True)

tests\test_animator.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox\test-api\lib\site-packages\ansys\dpf\core\fields_container.py:707: in animate
    return anim.animate(
.tox\test-api\lib\site-packages\ansys\dpf\core\animator.py:401: in animate
    return self._internal_animator.animate_workflow(
.tox\test-api\lib\site-packages\ansys\dpf\core\animator.py:228: in animate_workflow
    render_frame(0)
.tox\test-api\lib\site-packages\ansys\dpf\core\animator.py:163: in render_frame
    self.add_field(
.tox\test-api\lib\site-packages\ansys\dpf\core\plotter.py:430: in add_field
    meshed_region.deform_by(deform_by, scale_factor), as_linear=as_linear
.tox\test-api\lib\site-packages\ansys\dpf\core\meshed_region.py:550: in deform_by
    scale_op = scale(field=deform_by, weights=scale_factor)
.tox\test-api\lib\site-packages\ansys\dpf\core\operators\math\scale.py:95: in __init__
    self.inputs.weights.connect(weights)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <ansys.dpf.core.inputs.weights object at 0x000001BA4995AB00>
inpt = False

    def connect(self, inpt: Union[T, Output[T]]):
        """Connect any input (entity or operator output) to a specified input pin of this operator."""
        from pathlib import Path
    
        # always convert ranges to lists
        if isinstance(inpt, range):
            inpt = list(inpt)
        elif isinstance(inpt, core.Operator):
            if hasattr(inpt, "outputs"):
                inpt = inpt.outputs
            else:
                raise ValueError(
                    "The operator to connect in input has no outputs "
                    "available. It cannot be connected."
                )
        elif isinstance(inpt, core.Model):
            inpt = inpt.metadata.data_sources
        elif isinstance(inpt, Path):
            inpt = str(inpt)
        elif isinstance(inpt, core.UnitSystem):
            if inpt.ID != -2:  # Ansys UnitSystem
                inpt = inpt.ID
            else:  # Custom UnitSystem
                inpt = inpt.unit_names
        elif isinstance(inpt, Enum):
            inpt = inpt.value
    
        input_type_name = type(inpt).__name__
        if input_type_name == "list":
            input_type_name = f"list[{type(inpt[0]).__name__}]"
        if not (input_type_name in self._python_expected_types or ["Outputs", "Output", "Any"]):
            for types in self._python_expected_types:
                print(types, end=" ")
            print("types are expected for", self._spec.name, "pin")
            return
    
        corresponding_pins = []
        self._operator()._find_outputs_corresponding_pins(
            self._python_expected_types, inpt, self._pin, corresponding_pins, input_type_name
        )
        # We can have a single output with multiple types compatible with this input
        # if it accepts several of these types so we need to check for unique combinations
        corresponding_pins = list(set(corresponding_pins))
        if len(corresponding_pins) > 1:
            op_name = (
                self._operator().specification.properties["scripting_name"]
                if "scripting_name" in self._operator().specification.properties
                else self._operator().name
            )
            err_str = f"Operator {op_name}:\n"
            err_str += "Pin connection is ambiguous, specify the input to connect to with:\n"
            inpt_name = inpt._operator.name
            for pin in corresponding_pins:
                err_str += (
                    f"   - {op_name}.inputs."
                    + self._spec.name
                    + f"({inpt_name}."
                    + inpt._dict_outputs[pin[1]].name
                    + ")\n"
                )
            err_str += "Connecting to first input in the list.\n"
            warnings.warn(message=err_str)
            corresponding_pins = [corresponding_pins[0]]
    
        if len(corresponding_pins) == 0:
            err_str = (
                f"The input for the {self._spec.name} pin is of type {input_type_name} but must be "
                "one of the following types:\n"
            )
            err_str += "\n".join([f"- {py_type}" for py_type in self._python_expected_types])
>           raise TypeError(err_str)
E           TypeError: The input for the weights pin is of type bool but must be one of the following types:
E           - float
E           - Field
E           - list[float]

.tox\test-api\lib\site-packages\ansys\dpf\core\inputs.py:146: TypeError
tests/test_faces.py::test_faces
Stack Traces | 0.997s run time
fluent_axial_comp = <function fluent_axial_comp.<locals>.return_ds at 0x7f2b64d0bc70>

    @pytest.fixture()
    def model_faces(fluent_axial_comp):
>       model = dpf.Model(fluent_axial_comp())

tests/test_faces.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/conftest.py:249: in return_ds
    files = examples.download_fluent_axial_comp(server=server)
..../test-api/lib/python3.10.../core/examples/downloads.py:1323: in download_fluent_axial_comp
    _download_file(
..../test-api/lib/python3.10.../core/examples/downloads.py:116: in _download_file
    local_path = _retrieve_file(url, filename, directory)
..../test-api/lib/python3.10.../core/examples/downloads.py:110: in _retrieve_file
    _, resp = urlretrieve(url, local_path)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:241: in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:216: in urlopen
    return opener.open(url, data, timeout)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:525: in open
    response = meth(req, response)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:634: in http_response
    response = self.parent.error(
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:563: in error
    return self._call_chain(*args)
.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:496: in _call_chain
    result = func(*args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib.request.HTTPDefaultErrorHandler object at 0x7f2c08cc51e0>
req = <urllib.request.Request object at 0x7f2b64de33d0>
fp = <http.client.HTTPResponse object at 0x7f2b64de3430>, code = 502
msg = 'Bad Gateway or Proxy Error'
hdrs = <http.client.HTTPMessage object at 0x7f2b64de3700>

    def http_error_default(self, req, fp, code, msg, hdrs):
>       raise HTTPError(req.full_url, code, msg, hdrs, fp)
E       urllib.error.HTTPError: HTTP Error 502: Bad Gateway or Proxy Error

.../hostedtoolcache/Python/3.10.20...................../x64/lib/python3.10/urllib/request.py:643: HTTPError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@PProfizi PProfizi modified the milestones: 0.13.4, 0.13.5 Jan 17, 2025
@PProfizi PProfizi linked an issue Feb 19, 2025 that may be closed by this pull request
@PProfizi PProfizi modified the milestones: 0.13.5, 0.13.6, 0.13.7 Mar 6, 2025
@PProfizi PProfizi removed this from the 0.13.7 milestone May 12, 2025
@moe-ad
moe-ad changed the base branch from master to main July 28, 2025 09:51
PProfizi added 4 commits April 8, 2026 10:47
- Add MeshesContainer.animate() using extract_sub_mc + merge_meshes server-side
  workflow. Exposes 'to_render' (MeshedRegion) and optional 'to_render_field'
  (Field) for coloring, consistent with FieldsContainer.animate.

- Rewrite FieldsContainer.animate to use extract_sub_fc + merge_fields +
  mesh.from_field, exposing the same 'to_render' / 'to_render_field' contract.

- Unify animate_workflow in _PyVistaAnimator: remove mode_number/mode_frequency
  flags; per-frame connect is either a label-space dict (collection path) or a
  0-based index list (direct-Animator fallback). Remove dead branches.

- Rewrite animate_mode to pre-build a FieldsContainer of amplitude-scaled frames
  and delegate to FieldsContainer.animate, making mode-shape animation a
  degenerate case of collection animation and eliminating a bespoke code path.
  Fixes the bug where scoping IDs were used as scale weights instead of the
  actual amplitude values.

- Add list-length guard for scale_factor in animate_workflow.

- Improve animation.py module and animate_mode docstrings: add type hints to
  signature, remove types from docstring, add Returns/Raises sections, fix
  type_mode=1 amplitude description (1 -> 0 -> 1, always non-negative).

- Extend test_animation.py with save_as, deform_scale_factor, frame_number,
  and error-path coverage. Fix two broken test_animator.py expectations
  (NotImplementedError -> ValueError for Field/FC scale_factor types).
@PProfizi
PProfizi force-pushed the feat/meshes_container.animate branch from bd52a3b to da605a8 Compare April 13, 2026 15:34
@PProfizi PProfizi changed the title Add MeshesContainer.animate over time feat: refactor Animator and add MeshesContainer.animate Apr 13, 2026
@PProfizi
PProfizi marked this pull request as ready for review April 14, 2026 08:53
@PProfizi PProfizi added the deploy-pr-doc For deploying a PR's documentation label Apr 14, 2026
@PProfizi PProfizi added this to the 0.16.1 milestone Apr 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The documentation for this pull request will be available at https://dpf.docs.pyansys.com/pull/1997. Please allow some time for the documentation to be deployed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the animation pipeline to support animating workflows that yield either Fields or MeshedRegions, and adds a first-class MeshesContainer.animate() API to animate time- (or other label-) varying meshes with optional coloring/deformation.

Changes:

  • Added MeshesContainer.animate() that builds a label-space workflow (extract_sub_mc + merge_meshes) and drives it via Animator.animate(...).
  • Refactored FieldsContainer.animate() to use the same label-space workflow convention and mesh-mode rendering (with optional to_render_field coloring).
  • Enhanced Animator.animate_workflow() to support label-space inputs and mesh-mode rendering, plus stricter scale_factor list length validation; updated/added tests accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/test_meshescontainer.py Adds new animation-focused tests for MeshesContainer.animate().
tests/test_animator.py Updates scale-factor error expectations for animator/FC animations.
tests/test_animation.py Adds additional behavioral tests around animation.animate_mode() and saving GIFs.
src/ansys/dpf/core/plotter.py Prevents index error when plotting overall fields with empty data (fills with NaN).
src/ansys/dpf/core/meshes_container.py Adds MeshesContainer.animate() and updates typing/imports around MeshedRegion.
src/ansys/dpf/core/fields_container.py Refactors FC animation to label-based iteration + mesh-mode rendering; adds label parameter.
src/ansys/dpf/core/animator.py Adds mesh-mode + label-space support to workflow animation; validates scale-factor list length.
src/ansys/dpf/core/animation.py Refactors animate_mode() to build a scaled FC and delegate to FieldsContainer.animate().
Comments suppressed due to low confidence (1)

src/ansys/dpf/core/animator.py:113

  • Animator.animate and other call sites type scale_factor as Sequence[float], but animate_workflow only accepts list explicitly (type(scale_factor) == list). This will unexpectedly reject tuples, numpy arrays, etc. Consider using isinstance(scale_factor, Sequence) (excluding str/bytes) and converting to a list, then performing the length check.
        type_scale = type(scale_factor)
        if type_scale in [int, float]:
            scale_factor = [float(scale_factor)] * len(indices)
        elif type_scale == list:
            if len(scale_factor) != len(indices):
                raise ValueError(
                    f"The scale_factor list length ({len(scale_factor)}) must match the "
                    f"number of animation frames ({len(indices)})."
                )
        else:
            raise ValueError(
                "Argument scale_factor must be an int, a float, or a list of either, "
                f"(not {type_scale})"
            )

Comment thread tests/test_animator.py Outdated
Comment thread tests/test_animator.py Outdated
Comment thread tests/test_animator.py Outdated
Comment thread tests/test_meshescontainer.py
Comment thread tests/test_meshescontainer.py Outdated
Comment thread src/ansys/dpf/core/meshes_container.py Outdated
Comment thread src/ansys/dpf/core/meshes_container.py
Comment thread src/ansys/dpf/core/meshes_container.py
Comment thread src/ansys/dpf/core/meshes_container.py
Comment thread src/ansys/dpf/core/animation.py
…st_animator.py

Agent-Logs-Url: https://github.com/ansys/pydpf-core/sessions/86e7ae6e-8d64-4f63-a83c-38ebf04038ca

Co-authored-by: PProfizi <100710998+PProfizi@users.noreply.github.com>
Copilot AI and others added 2 commits April 24, 2026 15:16
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@PProfizi

Copy link
Copy Markdown
Contributor Author

@copilot add more tests to cover all lines.

Copilot AI and others added 2 commits April 27, 2026 13:51
…ieldsContainer.animate, MeshesContainer.animate

Agent-Logs-Url: https://github.com/ansys/pydpf-core/sessions/ddf2a4cf-0db1-4ec5-8d34-0f585ce94875

Co-authored-by: PProfizi <100710998+PProfizi@users.noreply.github.com>

Copilot AI commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

@copilot add more tests to cover all lines.

Added in commits 07ccbb6 and 4fb7a3e. New tests cover:

animation.py (animate_mode): type_mode=1, even frame_number auto-correction, invalid type_mode → ValueError, invalid mode number → ValueError.

animator.py (animate_workflow): scale_factor=None (converted to [False]*n).

fields_container.py (animate): label not in FC → ValueError, time_freq_support with None time_frequencies → ValueError.

meshes_container.py (animate): deform_by=True → ValueError, save_as as pathlib.Path, time label with valid TimeFreqSupport, empty TimeFreqSupport (None time_frequencies) → ValueError.

Comment thread tests/test_animator.py Outdated
Comment thread tests/test_meshescontainer.py Outdated
@PProfizi PProfizi modified the milestones: 0.16.1, 0.16.2 Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deploy-pr-doc For deploying a PR's documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add animate function to the class MeshesContainer

4 participants