Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/107 add option to read input snapshots from memory rather than disk #123

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: 3 additions & 1 deletion doc/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ BasedOnStyles = Vale, Google

# Removing Google-specific rule - Not applicable under some circumstances
Google.WordList = NO
Google.Colons = NO
Google.Colons = NO
Google.Spacing = NO
Google.Headings = NO
Binary file added doc/source/_static/TBROM_Group1_bolts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/_static/TBROM_Group2_body.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/_static/TBROM_named_selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"matplotlib": ("https://matplotlib.org/stable", None),
"pandas": ("https://pandas.pydata.org/pandas-docs/stable", None),
"pyvista": ("https://docs.pyvista.org/", None),
"pypim": ("https://pypim.docs.pyansys.com/", None),
"pypim": ("https://pypim.docs.pyansys.com/version/stable/", None),
}

# SS01, SS02, SS03, GL08 all need clean up in the code to be reactivated.
Expand Down
2 changes: 1 addition & 1 deletion doc/styles/Vocab/ANSYS/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ Pythonic
ROM
ROMs
runtimes

pytwin
4 changes: 2 additions & 2 deletions examples/evaluate/04-TBROM_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def snapshot_to_cfd(snapshot_file, geometry_file, field_name, outputFilePath):

###############################################################################
# Postprocess with image generated by PyFluent
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Postprocess with the image generated by PyFluent.

solver = pyfluent.launch_fluent(precision="double", processor_count=2, mode="solver")
Expand All @@ -144,7 +144,7 @@ def snapshot_to_cfd(snapshot_file, geometry_file, field_name, outputFilePath):

###############################################################################
# Postprocess ROM results in 3D Viewer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Postprocess the ROM results in the 3D Viewer enabled by PyFluent.

graphics = Graphics(session=solver)
Expand Down
54 changes: 39 additions & 15 deletions examples/evaluate/06-TBROM_input_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@

# sphinx_gallery_thumbnail_path = '_static/TBROM_input_field.png'

###############################################################################
# The example model is a valve that takes fluid pressure magnitude as a scalar input and wall
# temperature as vector input and gives deformation, in meters, as an output.
#
# Results are available on the full model, or can be exported on two subgroups:
#
# **Group_1**: Bolts
#
# .. image:: /_static/TBROM_Group1_bolts.png
# :width: 150pt
# :align: center
#
# **Group_2**: Body
#
# .. image:: /_static/TBROM_Group2_body.png
# :width: 150pt
# :align: center

###############################################################################
# .. note::
# To be able to use the functionalities to project an input field snapshot, you must have a
Expand Down Expand Up @@ -51,11 +69,18 @@
# :width: 200pt
# :align: center

###############################################################################
# .. note::
# To be able to use the functionalities to generate points or snapshot on a named selection, you
# need to have a Twin with 1 or more TBROM, for which Named Selections are defined.
# .. image:: /_static/TBROM_named_selection.png
# :width: 207pt
# :align: center

###############################################################################
# Perform required imports
# ~~~~~~~~~~~~~~~~~~~~~~~~
# Perform required imports, which include downloading and importing the input
# files.
# Perform required imports, which include downloading and importing the input files.

import matplotlib.pyplot as plt
import numpy as np
Expand All @@ -69,14 +94,6 @@
download_file("TEMP_3.bin", "twin_input_files/inputFieldSnapshots", force_download=True),
]

###############################################################################
# Define ROM inputs
# ~~~~~~~~~~~~~~~~~
# Define the ROM inputs.

rom_inputs = [4000000, 5000000, 6000000]


###############################################################################
# Define auxiliary functions
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -136,16 +153,23 @@ def norm_vector_field(field: np.ndarray):


###############################################################################
# Load the twin runtime and generate temperature results
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Load the twin runtime and generate temperature results from the TBROM.
# Define ROM scalar inputs
# ~~~~~~~~~~~~~~~~~~~~~~~~
# Define the ROM scalar inputs.

rom_inputs = [4000000, 5000000, 6000000]

###############################################################################
# Load the twin runtime and generate displacement results
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Load the twin runtime and generate displacement results from the TBROM.

print("Loading model: {}".format(twin_file))
twin_model = TwinModel(twin_file)

###############################################################################
# Evaluate the twin with different input values and collect corresponding outputs
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Because the twin is based on a static model, two options can be considered:
#
# - Set the initial input value to evaluate and run the initialization function (current approach).
Expand Down Expand Up @@ -202,7 +226,7 @@ def norm_vector_field(field: np.ndarray):

###############################################################################
# Simulate the twin in batch mode
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Reset/re-initialize the twin and run the simulation in batch mode, which
# passes all the input data, simulates all the data points, and collects all
# the outputs at once. The snapshots are then generated in a post-processing
Expand Down
149 changes: 149 additions & 0 deletions examples/evaluate/07-TBROM_input_numpy_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
""".. _ref_example_TBROM_numpy_inputField:
3D field ROM example for field snapshot input and output as Numpy array
-----------------------------------------------------------------------
This example shows how the example given in :ref:`ref_example_TBROM_inputField`
can be modified to take inputs as Numpy arrays, rather than reading from disk.
Similarly, outputs are produced as Numpy arrays.
The results arrays will be unflattened and results combined into a DataFrame of
x, y and z location and corresponding x, y and z displacement components.
Results will be exported for the whole model and a named selection consisting
only of the bolts.
"""
################################################################################
# .. image:: /_static/TBROM_input_field.png
# :width: 400pt
# :align: center

# sphinx_gallery_thumbnail_path = '_static/TBROM_input_field.png'

################################################################################
# .. note::
# To be able to use the functionalities to generate an output field snapshot
# on demand, you must have a twin with one or more TBROMs.
#
# To project an input field snapshot, one or more of the TBROMs must be
# parameterized by input field data.
#
# To be able to use the functionalities to generate points file on demand for
# a TBROM, the geometry must have been embedded when exporting the TBROMs to
# Twin Builder, prior to building the twin.
#
# The twin inputs and outputs must follow specific naming conventions,
# summarised here and described in detail in
# :ref:`ref_example_TBROM_inputField`.
#
# - If there are multiple TBROMs in the twin, the format for the name of the
# twin input must be ``{input_field_name}_mode_{mode_index}_{tbrom_name}``
# and the output must be ``outField_mode_{mode_index}_{tbrom_name}``.
# - If there is a single TBROM in the twin, the format for the name of the
# twin input must be ``{input_field_name}_mode_{mode_index}`` and the output
# must be ``outField_mode_{mode_index}``.
#

################################################################################
# Perform required imports
# ~~~~~~~~~~~~~~~~~~~~~~~~
# Perform required imports, which include downloading and importing the input
# files.

import numpy as np
import pandas as pd
from pytwin import TwinModel, download_file

twin_file = download_file("ThermalTBROM_FieldInput_23R1.twin", "twin_files", force_download=True)
inputfieldsnapshot = download_file("TEMP_1.bin", "twin_input_files/inputFieldSnapshots", force_download=True)

################################################################################
# Define auxiliary functions
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define auxiliary function to unflatten a vector.


def unflatten_vector(vector: np.ndarray, dimensionality: int):
"""Unflatten a vector to array with specified number of columns."""
return vector.reshape(-1, dimensionality)


################################################################################
# Define ROM inputs
# ~~~~~~~~~~~~~~~~~
# Define the twin scalar input pressure as 4 MPa.
scalar_input = {"Pressure_Magnitude": 4000000.0}

################################################################################
# Read one vector input from a file (this input could have been generated by a
# separate program).
temperature_array = np.fromfile(inputfieldsnapshot, dtype=np.double, offset=8)

################################################################################
# Enter information regarding TBROM, input fields and output named selection
# (see :ref:`ref_example_TBROM_inputField` for examples of setting this
# programmatically).
romname = "test23R1_1"
fieldname = "inputTemperature"
out_ns = "Group_1"
input_name = "Pressure_Magnitude"
field_input = {romname: {fieldname: temperature_array}}


################################################################################
# Load the twin runtime and generate displacement results
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Load the twin runtime and generate temperature results from the TBROM.

print("Loading model: {}".format(twin_file))
twin_model = TwinModel(twin_file)

################################################################################
# Evaluate the twin with one set of input values and collect corresponding outputs
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Because the twin is based on a static model, results for any inputs can be
# obtained by setting the initial input values to the desired values and running
# the initialization function.

# initialize twin with input values
twin_model.initialize_evaluation(inputs=scalar_input, field_inputs=field_input)
# generate the field output array on the entire domain
outfield = twin_model.generate_snapshot(romname, on_disk=False)
# generate the field output on "Group_1"
outfield_bolts = twin_model.generate_snapshot(romname, on_disk=False, named_selection=out_ns)
# generate the points location array for the whole domain
points = twin_model.generate_points(romname, on_disk=False)
# generate the points location array on "Group_1"
points_bolts = twin_model.generate_points(romname, on_disk=False, named_selection=out_ns)
################################################################################
# Unflatten vectors and combine into DataFrame. Both point location and
# displacement have three components when unflattening.
disp_xyz = unflatten_vector(outfield, 3)
loc_xyz = unflatten_vector(points, 3)
results = pd.DataFrame(
{
"x": loc_xyz[:, 0],
"y": loc_xyz[:, 1],
"z": loc_xyz[:, 2],
"ux": disp_xyz[:, 0],
"uy": disp_xyz[:, 1],
"uz": disp_xyz[:, 2],
}
)
print(f"Full results table:\n{results}")

################################################################################
# Repeat for the subset of results on the bolts only
disp_xyz = unflatten_vector(outfield_bolts, 3)
loc_xyz = unflatten_vector(points_bolts, 3)
results_bolts = pd.DataFrame(
{
"x": loc_xyz[:, 0],
"y": loc_xyz[:, 1],
"z": loc_xyz[:, 2],
"ux": disp_xyz[:, 0],
"uy": disp_xyz[:, 1],
"uz": disp_xyz[:, 2],
}
)
print(f"Bolt results table:\n{results_bolts}")
22 changes: 15 additions & 7 deletions src/ansys/pytwin/evaluate/tbrom.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import os
from pathlib import Path
import struct
from typing import Union

import numpy as np

Expand Down Expand Up @@ -131,20 +133,24 @@ def generate_snapshot(self, on_disk: bool, output_file_path: str, named_selectio
else:
return vec

def _reduce_field_input(self, name: str, snapshot_filepath: str):
def _reduce_field_input(self, name: str, snapshot: Union[str, Path, np.ndarray]):
"""
Project a snapshot file associated to the input field name ``fieldname``
Project a snapshot associated to the input field name ``fieldname``
Parameters
----------
snapshot_filepath: str
Path of the input field snapshot file
name: str (optional)
name: str
Name of the input field to project the snapshot. The name of the field must be specified in case the TBROM
is parameterized with multiple input fields.
snapshot: str | Path | np.ndarray
Path of the input field snapshot file, or numpy array of snapshot data
"""
mc = []
vecnp = TbRom._read_binary(snapshot_filepath)
if isinstance(snapshot, np.ndarray):
vecnp = snapshot
else:
vecnp = TbRom._read_binary(snapshot)

if name is None or self.field_input_count == 1:
basis = list(self._infbasis.values())[0]
else:
Expand Down Expand Up @@ -181,7 +187,9 @@ def _read_basis(filepath):

@staticmethod
def _read_binary(filepath):
return np.fromfile(filepath, dtype=np.double, offset=8).reshape(-1, 1)
return np.fromfile(filepath, dtype=np.double, offset=8).reshape(
-1,
)

@staticmethod
def _write_binary(filepath, vec):
Expand Down
Loading
Loading