diff --git a/doc/changelog.d/4887.maintenance.md b/doc/changelog.d/4887.maintenance.md new file mode 100644 index 00000000000..0ff8e9b7a54 --- /dev/null +++ b/doc/changelog.d/4887.maintenance.md @@ -0,0 +1 @@ +Update examples to use modern API diff --git a/examples/00-fluent/DOE_ML.py b/examples/00-fluent/DOE_ML.py index 02876c9778f..b7d48d74c4e 100644 --- a/examples/00-fluent/DOE_ML.py +++ b/examples/00-fluent/DOE_ML.py @@ -8,6 +8,7 @@ # "scikit-learn", # "seaborn", # "tensorflow", +# "xgboost", # ] # /// @@ -62,8 +63,9 @@ # flake8: noqa: E402 -import os +import itertools from pathlib import Path +from typing import TYPE_CHECKING, cast import matplotlib.pyplot as plt import numpy as np @@ -76,6 +78,14 @@ import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + Initialization, + SurfaceIntegrals, + VelocityInlet, + iterate, + read_case, +) +from ansys.units.common import m, s ########################################################################### # Specifying save path @@ -84,7 +94,7 @@ import_filename = examples.download_file( "elbow.cas.h5", "pyfluent/examples/DOE-ML-Mixing-Elbow", - save_path=os.getcwd(), + save_path=Path.cwd(), ) ####################### @@ -95,69 +105,67 @@ # Launch Fluent session with solver mode and print Fluent version # =============================================================== -solver_session = pyfluent.launch_fluent( - precision="double", +solver = pyfluent.Solver.from_install( + precision=pyfluent.Precision.SINGLE, processor_count=4, ) -print(solver_session.get_fluent_version()) +print(solver.get_fluent_version()) ############################################################################# # Read case # ========= -solver_session.settings.file.read_case(file_name=import_filename) +solver.upload(import_filename) +read_case(solver, file_name=import_filename) ############################################################################################## # Design of Experiments # ===================== # Specify inlet velocities for the cold and hot streams. -# Each pair of (coldVel, hotVel) will be used to run one Fluent case. -coldVelArr = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]) -hotVelArr = np.array([0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]) +# Each pair of (cold_value, hot_value) will be used to run one Fluent case. +cold_velocities = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7] * m / s + +hot_velocities = [0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0] * m / s + # Allocate a results array. Entry (i, j) will hold the Mass‑Weighted -# Average Temperature at the outlet for coldVelArr[i] and hotVelArr[j]. -resArr = np.zeros((coldVelArr.size, hotVelArr.size)) - -for idx1, coldVel in np.ndenumerate(coldVelArr): - for idx2, hotVel in np.ndenumerate(hotVelArr): - cold_inlet = solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "cold-inlet" - ] - cold_inlet.momentum.velocity.value = coldVel - - hot_inlet = solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "hot-inlet" - ] - hot_inlet.momentum.velocity.value = hotVel - - solver_session.settings.solution.initialization.initialization_type = "standard" - solver_session.settings.solution.initialization.standard_initialize() - solver_session.settings.solution.run_calculation.iterate(iter_count=200) - - res_tui = solver_session.scheme.exec( - ( - "(ti-menu-load-string " - '"/report/surface-integrals/mass-weighted-avg outlet () ' - 'temperature no")', - ) - ) - resArr[idx1][idx2] = eval(res_tui.split(" ")[-1]) +# Average Temperature at the outlet for cold_velocities[i] and hot_velocities[j]. +results = np.zeros((len(cold_velocities), len(hot_velocities))) + +for (idx1, cold_value), (idx2, hot_value) in itertools.product( + enumerate(cold_velocities), enumerate(hot_velocities) +): + cold_inlet = VelocityInlet.get(solver, name="cold-inlet") + cold_inlet.momentum.velocity = cold_value + hot_inlet = VelocityInlet.get(solver, name="hot-inlet") + hot_inlet.momentum.velocity = hot_value + + initialize = Initialization(solver) + initialize.initialization_type = "standard" + initialize.standard_initialize() + + iterate(solver, iter_count=200) + + temperatures = SurfaceIntegrals(solver).get_mass_weighted_avg( + surface_names=["outlet"], report_of="temperature" + ) + + results[idx1][idx2] = temperatures["outlet"] ############################################################################################## # Close the session # ================= -solver_session.exit() +solver.exit() #################################### # Plot Response Surface using Plotly # ================================== -fig = go.Figure(data=[go.Surface(z=resArr.T, x=coldVelArr, y=hotVelArr)]) +fig = go.Figure(data=[go.Surface(z=results.T, x=cold_velocities, y=hot_velocities)]) fig.update_layout( title={ @@ -170,14 +178,14 @@ ) fig.update_layout( - scene=dict( - xaxis_title="Cold Inlet Vel (m/s)", - yaxis_title="Hot Inlet Vel (m/s)", - zaxis_title="Outlet Temperature (K)", - ), + scene={ + "xaxis_title": "Cold Inlet Vel (m/s)", + "yaxis_title": "Hot Inlet Vel (m/s)", + "zaxis_title": "Outlet Temperature (K)", + }, width=600, height=600, - margin=dict(l=80, r=80, b=80, t=80), + margin={"l": 80, "r": 80, "b": 80, "t": 80}, ) fig.show() @@ -189,19 +197,16 @@ ############################################ # Create Pandas Dataframe for ML Model Input # ========================================== -coldVelList = [] -hotVelList = [] -ResultList = [] +df = pd.DataFrame({"cold_velocities": [], "hot_velocities": [], "result": []}) -for idx1, coldVel in np.ndenumerate(coldVelArr): - for idx2, hotVel in np.ndenumerate(hotVelArr): - coldVelList.append(coldVel) - hotVelList.append(hotVel) - ResultList.append(resArr[idx1][idx2]) -tempDict = {"coldVel": coldVelList, "hotVel": hotVelList, "Result": ResultList} +for (idx1, cold_vel_val), (idx2, hot_vel_val) in itertools.product( + enumerate(cold_velocities), enumerate(hot_velocities) +): + df["cold_velocities"].append(cold_vel_val) + df["hot_velocities"].append(hot_vel_val) + df["result"].append(results[idx1][idx2]) -df = pd.DataFrame.from_dict(tempDict) from sklearn.compose import ColumnTransformer from sklearn.model_selection import train_test_split @@ -227,7 +232,7 @@ x_ct = ColumnTransformer( [ - ("transformer1", transformer1, ["coldVel", "hotVel"]), + ("transformer1", transformer1, ["cold_velocities", "hot_velocities"]), ], remainder="drop", ) @@ -237,8 +242,8 @@ X_train = x_ct.fit_transform(train_set) X_test = x_ct.fit_transform(test_set) -y_train = train_set["Result"] -y_test = test_set["Result"] +y_train = train_set["result"] +y_test = test_set["result"] y_train = np.ravel(y_train.T) y_test = np.ravel(y_test.T) @@ -258,18 +263,24 @@ # from sklearn.linear_model import LinearRegression from xgboost import XGBRegressor +if TYPE_CHECKING: + from sklearn.ensemble import RandomForestRegressor + from sklearn.linear_model import LinearRegression + from xgboost import XGBRegressor + np.set_printoptions(precision=2) +out_file = Path.cwd() / "PyFluent_Output.csv" -def display_scores(scores): +def display_scores(scores: np.ndarray): """Display scores.""" print("\nCross-Validation Scores:", scores) - print("Mean:%0.2f" % (scores.mean())) - print("Std. Dev.:%0.2f" % (scores.std())) + print(f"Mean:{scores.mean():0.2f}") + print(f"Std. Dev.:{scores.std():0.2f}") -def fit_and_predict(model): - """Fit abd predict.""" +def fit_and_predict(model: LinearRegression | XGBRegressor | RandomForestRegressor): + """Fit and predict.""" cv = RepeatedKFold(n_splits=5, n_repeats=3, random_state=42) cv_scores = cross_val_score( model, X_train, y_train, scoring="neg_mean_squared_error", cv=cv @@ -282,8 +293,8 @@ def fit_and_predict(model): test_predictions = model.predict(X_test) print(train_predictions.shape[0]) print("\n\nCoefficient Of Determination") - print("Train Data R2 Score: %0.3f" % (r2_score(train_predictions, y_train))) - print("Test Data R2 Score: %0.3f" % (r2_score(test_predictions, y_test))) + print(f"Train Data R2 Score: {r2_score(train_predictions, y_train):0.3f}") + print(f"Test Data R2 Score: {r2_score(test_predictions, y_test):0.3f}") print( "\n\nPredictions - Ground Truth (Kelvin): ", (test_predictions - y_test), "\n" ) @@ -291,24 +302,17 @@ def fit_and_predict(model): com_train_set = train_set com_test_set = test_set - train_list = [] - for i in range(train_predictions.shape[0]): - train_list.append("Train") + train_list = ["train"] * cast(int, train_predictions.shape[0]) + test_list = ["test"] * cast(int, test_predictions.shape[0]) - test_list = [] - for i in range(test_predictions.shape[0]): - test_list.append("Test") - - com_train_set["Result"] = train_predictions.tolist() - com_train_set["Set"] = train_list - com_test_set["Result"] = test_predictions.tolist() - com_test_set["Set"] = test_list + com_train_set["result"] = train_predictions.tolist() + com_train_set["set"] = train_list + com_test_set["result"] = test_predictions.tolist() + com_test_set["set"] = test_list df_combined = pd.concat([com_train_set, com_test_set]) - df_combined.to_csv( - os.path.join(os.getcwd(), "PyFluent_Output.csv"), header=True, index=False - ) + df_combined.to_csv(out_file, header=True, index=False) fig = plt.figure(figsize=(12, 5)) @@ -334,10 +338,10 @@ def fit_and_predict(model): # * Call fit_and_predict # model = LinearRegression() +# model = RandomForestRegressor(random_state=42) model = XGBRegressor( n_estimators=100, max_depth=10, eta=0.3, subsample=0.8, random_state=42 ) -# model = RandomForestRegressor(random_state=42) fit_and_predict(model) @@ -359,13 +363,15 @@ def fit_and_predict(model): # 3D Visualization of Model Predictions on Train & Test Set # ========================================================= -df = pd.read_csv("PyFluent_Output.csv") +df = pd.read_csv(out_file) -fig = px.scatter_3d(df, x="coldVel", y="hotVel", z="Result", color="Set") -fig.update_traces(marker=dict(size=4)) -fig.update_layout(legend=dict(yanchor="top", y=1, xanchor="left", x=0.0)) +fig = px.scatter_3d( + df, x="cold_velocities", y="hot_velocities", z="result", color="set" +) +fig.update_traces(marker={"size": 4}) +fig.update_layout(legend={"yanchor": "top", "y": 1, "xanchor": "left", "x": 0.0}) -fig.add_traces(go.Surface(z=resArr.T, x=coldVelArr, y=hotVelArr)) +fig.add_traces(go.Surface(z=results.T, x=cold_velocities, y=hot_velocities)) fig.update_layout( title={ @@ -378,14 +384,14 @@ def fit_and_predict(model): ) fig.update_layout( - scene=dict( - xaxis_title="Cold Inlet Vel (m/s)", - yaxis_title="Hot Inlet Vel (m/s)", - zaxis_title="Outlet Temperature (K)", - ), + scene={ + "xaxis_title": "Cold Inlet Vel (m/s)", + "yaxis_title": "Hot Inlet Vel (m/s)", + "zaxis_title": "Outlet Temperature (K)", + }, width=500, height=500, - margin=dict(l=80, r=80, b=80, t=80), + margin={"l": 80, "r": 80, "b": 80, "t": 80}, ) fig.show() @@ -416,7 +422,7 @@ def fit_and_predict(model): ] ) -optimizer = tf.keras.optimizers.Adam(learning_rate=0.1, beta_1=0.9, beta_2=0.999) +optimizer = keras.optimizers.Adam(learning_rate=0.1, beta_1=0.9, beta_2=0.999) model.compile(loss="mean_squared_error", optimizer=optimizer) checkpoint_cb = keras.callbacks.ModelCheckpoint( @@ -451,8 +457,8 @@ def fit_and_predict(model): test_predictions = np.ravel(test_predictions.T) print(test_predictions.shape) -print("\n\nTrain R2: %0.3f" % (r2_score(train_predictions, y_train))) -print("Test R2: %0.3f" % (r2_score(test_predictions, y_test))) +print(f"\n\nTrain R2: {r2_score(train_predictions, y_train):0.3f}") +print(f"Test R2: {r2_score(test_predictions, y_test):0.3f}") print("Predictions - Ground Truth (Kelvin): ", (test_predictions - y_test)) fig = plt.figure(figsize=(12, 5)) diff --git a/examples/00-fluent/Electrolysis_Modeling_workflow.py b/examples/00-fluent/Electrolysis_Modeling_workflow.py index 23441455825..124aac17f30 100644 --- a/examples/00-fluent/Electrolysis_Modeling_workflow.py +++ b/examples/00-fluent/Electrolysis_Modeling_workflow.py @@ -1,3 +1,9 @@ +# /// script +# dependencies = [ +# "ansys-fluent-core", +# ] +# /// + # Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -74,7 +80,7 @@ # Importing the following classes offer streamlined access to key solver settings, # eliminating the need to manually browse through the full settings structure. -import os +from pathlib import Path import ansys.fluent.core as pyfluent from ansys.fluent.core import examples @@ -82,13 +88,20 @@ BoundaryConditions, Contour, Controls, + EChemistry, Graphics, Initialization, + MassFlowInlet, Materials, Mesh, - RunCalculation, - Setup, + SolidMaterial, + iterate, + write_case_data, ) +from ansys.units.common import A, K, V, degree, m, ohm, s + +# a Siemen +S = 1 / ohm # %% # Launch Fluent session in solver mode @@ -105,22 +118,25 @@ mesh_file = examples.download_file( "electrolysis.msh.h5", "pyfluent/electrolysis", - save_path=os.getcwd(), + save_path=Path.cwd(), ) +# upload mesh to solver (required for some remote/meshing workflows) +solver.upload(mesh_file) + solver.settings.file.read_mesh(file_name=mesh_file) # %% # Display mesh # ------------ graphics = Graphics(solver) -mesh = Mesh(solver, new_instance_name="mesh-1") +mesh = Mesh(solver).create(name="mesh-1") graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio -all_walls = mesh.surfaces_list.allowed_values() +all_walls = mesh.surfaces_list.all() mesh.surfaces_list = all_walls mesh.options.edges = True @@ -136,117 +152,92 @@ # %% # Enable Electrolysis Model # ------------------------- -setup = Setup(solver) - -setup.models.echemistry = { - "potential": True, - "echemistry_enabled": True, - "electrolysis": { - "options": { - "bc_type": "Total voltage", - "tot_voltage": 1.730202, # V - }, - "parameters": { - "anode_jref": 1.36e-09, # A/m² - "anode_jea": 181411, # A/m² - "anode_exp": 0, # Concentration exponent - "cathode_jref": 200, # A/m² - "cathode_jea": 24359, # A/m² - "cathode_ex_a": 1, # Anodic transfer coefficient - "cathode_ex_c": 1, # Cathodic transfer coefficient - "open_voltage": 1.1999, # V - }, - "anode": { - "anode_cc_zone": { - "anode_cc_zone_list": ["anode_cc"], - "anode_cc_material": "collector-default", - }, - "anode_fc_zone": {"anode_fc_zone_list": ["anode_fc"]}, - "anode_pl_zone": { - "anode_pl_zone_list": ["anode_pl"], - "anode_pl_material": "porous-default", - "anode_pl_porosity": 0.75, # Porosity of porous layer - "anode_pl_kr": 4.9e-11, # m² Absolute permeability - "anode_pl_angle": 70, # Degrees - }, - "anode_cl_zone": { - "anode_cl_zone_list": ["anode_cl"], - "anode_cl_material": "catalyst-default", - "anode_cl_porosity": 0.2, # Catalyst layer porosity - "anode_cl_kr": 4.9e-12, # m² Catalyst layer permeability - "anode_cl_angle": 80, # Degrees - }, - }, - "electrolyte": { - "mem_zone": { - "mem_zone_list": ["mem"], - "mem_material": "electrolyte-default", - } - }, - "cathode": { - "cathode_cc_zone": { - "cathode_cc_zone_list": ["cathode_cc"], - "cathode_cc_material": "collector-default", - }, - "cathode_fc_zone": {"cathode_fc_zone_list": ["cathode_fc"]}, - "cathode_pl_zone": { - "cathode_pl_zone_list": ["cathode_pl"], - "cathode_pl_material": "porous-default", - "cathode_pl_porosity": 0.75, # Porosity - "cathode_pl_kr": 1e-11, # m² Permeability - }, - "cathode_cl_zone": { - "cathode_cl_zone_list": ["cathode_cl"], - "cathode_cl_material": "catalyst-default", - "cathode_cl_porosity": 0.2, # Catalyst layer porosity - "cathode_cl_kr": 2e-12, # m² Permeability - }, - }, - "electrical_tab": { - "anode_tab": ["anode_tab", "anode_tab.1", "anode_tab.1.1"], - "cathode_tab": ["cathode_tab", "cathode_tab.1", "cathode_tab.1.1"], - }, - }, -} +echem = EChemistry(solver) +echem.potential = True +echem.echemistry_enabled = True +echem.electrolysis.options.bc_type = echem.electrolysis.options.bc_type.TOTAL_VOLTAGE +echem.electrolysis.options.tot_voltage = 1.730202 * V + +electrolysis_params = echem.electrolysis.parameters +electrolysis_params.anode_jref = 1.36e-09 * A / m**2 +electrolysis_params.anode_jea = 181411 * A / m**2 +electrolysis_params.anode_exp = 0 +electrolysis_params.cathode_jref = 200 * A / m**2 +electrolysis_params.cathode_jea = 24359 * A / m**2 +electrolysis_params.cathode_ex_a = 1 +electrolysis_params.cathode_ex_c = 1 +electrolysis_params.open_voltage = 1.1999 * V + +anode = echem.electrolysis.anode +anode.anode_cc_zone.anode_cc_zone_list = ["anode_cc"] +anode.anode_cc_zone.anode_cc_material = "collector-default" + +anode.anode_fc_zone.anode_fc_zone_list = ["anode_fc"] + +anode.anode_pl_zone.anode_pl_zone_list = ["anode_pl"] +anode.anode_pl_zone.anode_pl_material = "porous-default" +anode.anode_pl_zone.anode_pl_porosity = 0.75 +anode.anode_pl_zone.anode_pl_kr = 4.9e-11 * m**2 +anode.anode_pl_zone.anode_pl_angle = 70 * degree + +anode.anode_cl_zone.anode_cl_zone_list = ["anode_cl"] +anode.anode_cl_zone.anode_cl_material = "catalyst-default" +anode.anode_cl_zone.anode_cl_porosity = 0.2 +anode.anode_cl_zone.anode_cl_kr = 4.9e-12 * m**2 +anode.anode_cl_zone.anode_cl_angle = 80 * degree + +electrolyte = echem.electrolysis.electrolyte +electrolyte.mem_zone.mem_zone_list = ["mem"] +electrolyte.mem_zone.mem_material = "electrolyte-default" + +cathode = echem.electrolysis.cathode +cathode.cathode_cc_zone.cathode_cc_zone_list = ["cathode_cc"] +cathode.cathode_cc_zone.cathode_cc_material = "collector-default" + +cathode.cathode_fc_zone.cathode_fc_zone_list = ["cathode_fc"] +cathode.cathode_pl_zone.cathode_pl_zone_list = ["cathode_pl"] +cathode.cathode_pl_zone.cathode_pl_material = "porous-default" +cathode.cathode_pl_zone.cathode_pl_porosity = 0.75 +cathode.cathode_pl_zone.cathode_pl_kr = 1e-11 * m**2 +cathode.cathode_pl_zone.cathode_pl_angle = 70 * degree +cathode.cathode_cl_zone.cathode_cl_zone_list = ["cathode_cl"] +cathode.cathode_cl_zone.cathode_cl_material = "catalyst-default" +cathode.cathode_cl_zone.cathode_cl_porosity = 0.2 +cathode.cathode_cl_zone.cathode_cl_kr = 2e-12 * m**2 +cathode.cathode_cl_zone.cathode_cl_angle = 80 * degree + +electrical_tab = echem.electrolysis.electrical_tab +electrical_tab.anode_tab = ["anode_tab", "anode_tab.1", "anode_tab.1.1"] +electrical_tab.cathode_tab = ["cathode_tab", "cathode_tab.1", "cathode_tab.1.1"] -# %% -# Define solid materials # ---------------------- materials = Materials(solver) -# Current collector -materials.solid["collector-default"] = { - "electric_conductivity": {"value": 20000} # S/m -} - -# Porous layer -materials.solid["porous-default"] = {"electric_conductivity": {"value": 20000}} # S/m +solid_material = SolidMaterial(solver) +solid_material.create( + name="collector-default", electric_conductivity=20000 * S / m +) +solid_material.create(name="porous-default", electric_conductivity=20000 * S / m) -# Catalyst layer: dual conductivity -materials.solid["catalyst-default"] = { - "electric_conductivity": {"value": 5000}, # S/m Electronic - "dual_electric_conductivity": {"value": 4.5}, # S/m Ionic in catalyst -} +solid_material.create( + name="catalyst-default", + electrical_conductivity=5000 * S / m, + dual_electric_conductivity=4.5 * S / m, +) -# Membrane: ionic conductivity -materials.solid["electrolyte-default"] = { - "dual_electric_conductivity": {"value": 11} # S/m Proton conductivity -} +solid_material.create( + name="electrolyte-default", dual_electric_conductivity=11 * S / m +) # %% # Boundary conditions # ------------------- conditions = BoundaryConditions(solver) -# Mixture phase: thermal condition -conditions.mass_flow_inlet["anode_in"] = { - "phase": {"mixture": {"thermal": {"total_temperature": {"value": 333.15}}}} # K -} - -# Phase-2 (liquid water): mass flow rate -conditions.mass_flow_inlet["anode_in"] = { - "phase": {"phase-2": {"momentum": {"mass_flow_rate": {"value": 0.000404}}}} # kg/s -} +# Configure mass flow inlet for anode using typed MassFlowInlet API +anode_in = MassFlowInlet(solver, name="anode_in") +anode_in.phase.mixture.thermal.total_temperature = 333.15 * K +anode_in.phase.phase_2.momentum.mass_flow_rate = 0.000404 # kg/s # %% # Solution controls @@ -254,7 +245,7 @@ controls = Controls(solver) -controls.under_relaxation = {"mp": 1} +controls.under_relaxation.mp = 1 # %% # Initialize solution @@ -262,27 +253,24 @@ initialize = Initialization(solver) initialize.initialization_type = "standard" -initialize.defaults = { - "temperature": 333.15, # K - "phase-2-mp": 1, # Initial volume fraction of liquid -} +initialize.defaults["temperature"] = 333.15 * K +initialize.defaults["phase-2-mp"] = 1 # %% # Run calculation # --------------- -calculation = RunCalculation(solver) - -calculation.iterate(iter_count=300) +iterate(solver, iter_count=300) # %% # Post-processing # --------------- -potential_contour = Contour(solver, new_instance_name="potential_contour") +potential_contour = Contour.create( + solver, name="potential_contour", field="potential", surfaces_list=["zmid"] +) + -potential_contour.field = "potential" -potential_contour.surfaces_list = ["zmid"] graphics.views.restore_view(view_name="front") potential_contour.display() @@ -294,10 +282,12 @@ # :align: center # :alt: Potential Contour -volume_fraction_contour = Contour(solver, new_instance_name="volume_fraction_contour") - -volume_fraction_contour.field = "phase-1-vof" -volume_fraction_contour.surfaces_list = ["zmid", "xmid"] +volume_fraction_contour = Contour.create( + solver, + name="volume_fraction_contour", + field="phase-1-vof", + surfaces_list=["zmid", "xmid"], +) graphics.views.restore_view(view_name="isometric") volume_fraction_contour.display() @@ -310,7 +300,7 @@ # :alt: Volume Fraction Contour # save case and data file -solver.settings.file.write(file_type="case-data", file_name="electrolysis") +write_case_data(solver, file_name="electrolysis") # %% # Close session diff --git a/examples/00-fluent/Modeling_solidification_workflow.py b/examples/00-fluent/Modeling_solidification_workflow.py index 4361bd1b6c9..662765faaf6 100644 --- a/examples/00-fluent/Modeling_solidification_workflow.py +++ b/examples/00-fluent/Modeling_solidification_workflow.py @@ -77,14 +77,17 @@ # Importing the following classes offer streamlined access to key solver settings, # eliminating the need to manually browse through the full settings structure. -import os +from pathlib import Path import ansys.fluent.core as pyfluent from ansys.fluent.core import examples from ansys.fluent.core.solver import ( - BoundaryConditions, + BoundaryCondition, Contour, Controls, + FluidCellZone, + write_case_data, + FluidMaterial, General, Graphics, Initialization, @@ -96,15 +99,19 @@ Setup, Solution, VelocityInlet, + WallBoundary, + Models, ) +from ansys.units import VariableCatalog +from ansys.units.common import J, K, N, Pa, W, kg, m, radian, s # %% # Launch Fluent session in solver mode # ------------------------------------ -solver = pyfluent.launch_fluent( +solver = pyfluent.Solver.from_install( precision=pyfluent.Precision.DOUBLE, - mode="solver", dimension=pyfluent.Dimension.TWO, + fluent_path=r"C:\ANSYSDev\v261\fluent\ntbin\win64\fluent.exe", ) # %% @@ -113,7 +120,7 @@ mesh_file = examples.download_file( "solid.msh", "pyfluent/solidification", - save_path=os.getcwd(), + save_path=Path.cwd(), ) solver.settings.file.read_mesh(file_name=mesh_file) @@ -122,19 +129,18 @@ # Display mesh # ------------ graphics = Graphics(solver) -mesh = Mesh(solver, new_instance_name="mesh-1") -boundary_conditions = BoundaryConditions(solver) +mesh = Mesh.create(solver) graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio -all_walls = mesh.surfaces_list.allowed_values() +all_walls = mesh.surfaces_list.all() mesh.surfaces_list = all_walls mesh.options.edges = True mesh.display() -graphics.picture.save_picture(file_name="modeling_solidification_1.png") +# graphics.picture.save_picture(file_name="modeling_solidification_1.png") # %% # .. image:: ../../_static/modeling_solidification_1.png @@ -144,14 +150,12 @@ # %% # Configure solver # ---------------- -solver_general_settings = General(solver) +general = General(solver) -solver_general_settings.solver.two_dim_space = "swirl" +general.solver.two_dim_space = "swirl" -solver_general_settings.operating_conditions.gravity = { - "enable": True, - "components": [-9.81], -} +general.operating_conditions.gravity.enable = True +general.operating_conditions.gravity.components = [-9.81 * m / s**2] # %% # Enable models @@ -164,93 +168,92 @@ setup.models.viscous.model = "laminar" -# Enable the Solidification/Melting solver.tui.define.models.solidification_melting( - "yes", "constant", "100000", "yes", "no" # 100000 for the Mushy Zone Constant. + "yes", # Enable Solidification/Melting model + "constant", # Mushy Zone Parameter + "100000", # Mushy Zone Constant + "yes", # Include Pull Velocities + "no", # Compute Pull Velocities ) +Models(solver) + # %% # Define material # --------------- -materials = Materials(solver) - -materials.database.copy_by_name(type="fluid", name="air", new_name="liquid-metal") - -materials.fluid["liquid-metal"] = { - "density": { - "polynomial": { - "coefficients": [ - 8000, - -0.1, - ], # [Density (kg/m³), Linear temp coefficient (kg/(m³·K))] - "function_of": "temperature", - }, - "option": "polynomial", - }, - "viscosity": {"value": 0.00553}, # Pa·s - "specific_heat": {"value": 680.0}, # J/kg·K - "thermal_conductivity": {"value": 30.0}, # W/m·K - "melting_heat": {"value": 100000.0}, # J/kg - "tsolidus": {"value": 1150.0}, # K - "tliqidus": {"value": 1150.0}, # K -} - -# Assign material to fluid zone -setup.cell_zone_conditions.fluid["fluid"] = {"general": {"material": "liquid-metal"}} +Materials(solver).database.copy_by_name(type="fluid", name="air", new_name="liquid-metal") + +liquid_metal = FluidMaterial( + solver, + name="liquid-metal", + viscosity=0.00553 * Pa * s, + specific_heat=680.0 * J / kg / K, + thermal_conductivity=30.0 * W / m / K, + melting_heat=100000.0 * J / kg, + tsolidus=1150.0 * K, + tliqidus=1150.0 * K, +) +liquid_metal.density.option = "polynomial" +liquid_metal.density.polynomial.coefficients = [ + 8000, + -0.1, +] # [Density (kg/m³), Linear temp coefficient (kg/(m³·K))] + +# Assign material to fluid zone using a typed cell-zone object +fluid_zone = FluidCellZone.get(solver, name="fluid") +fluid_zone.general.material = liquid_metal # %% # Boundary conditions # ------------------- # Inlet: liquid injection -inlet = VelocityInlet(solver, name="inlet") +inlet = VelocityInlet.get(solver, name="inlet") -inlet.momentum.velocity_magnitude.value = 0.00101 # m/s -inlet.thermal.temperature.value = 1300 # K +inlet.momentum.velocity_magnitude = 0.00101 * m / s +inlet.thermal.temperature = 1300 * K # Outlet: solid pull-out (velocity inlet with axial + swirl) -outlet = VelocityInlet(solver, name="outlet") +outlet = VelocityInlet.get(solver, name="outlet") outlet.momentum.velocity_specification_method = "Components" -outlet.momentum.swirl_angular_velocity = 1 # rad/s -outlet.momentum.velocity_components = [0.001, 0, 0] # Axial = 0.001 m/s -outlet.thermal.temperature.value = 500 # K - - -conditions = BoundaryConditions(solver) +outlet.momentum.swirl_angular_velocity = 1 * radian / s +outlet.momentum.velocity_components = (0.001, 0, 0) * m / s # axial, radial, tangential +outlet.thermal.temperature.value = 500 * K # Bottom wall: fixed temperature -conditions.wall["bottom-wall"] = { - "thermal": {"thermal_condition": "Temperature", "temperature": 1300} # K -} +bottom_wall = WallBoundary.get(solver, name="bottom-wall") +bottom_wall.thermal.thermal_condition = ( + bottom_wall.thermal.thermal_condition.TEMPERATURE +) +bottom_wall.thermal.temperature = 1300 * K # Free surface: Marangoni stress + convection -conditions.wall["free-surface"] = { - "momentum": { - "shear_condition": "Marangoni Stress", - "surface_tension_gradient": -0.00036, # N/m·K - }, - "thermal": { - "thermal_condition": "Convection", - "free_stream_temp": 1500, # K - "heat_transfer_coeff": 100, # W/m²·K - }, -} +free_surface = WallBoundary.get(solver, name="free-surface") +free_surface.momentum.shear_condition = ( + free_surface.momentum.shear_condition.MARANGONI_STRESS +) +free_surface.momentum.surface_tension_gradient = -0.00036 * N / (m * K) +free_surface.thermal.thermal_condition = ( + free_surface.thermal.thermal_condition.CONVECTION +) +free_surface.thermal.convection.free_stream_temperature = 1500 * K +free_surface.thermal.convection.convective_heat_transfer_coefficient = ( + 100 * W / (m**2 * K) +) # Side wall: fixed temperature -conditions.wall["side-wall"] = { - "thermal": {"thermal_condition": "Temperature", "temperature": 1400} # K -} +side_wall = WallBoundary.get(solver, name="side-wall") +side_wall.thermal.thermal_condition = side_wall.thermal.thermal_condition.TEMPERATURE +side_wall.thermal.temperature = 1400 * K # Solid wall: rotating + cold -conditions.wall["solid-wall"] = { - "momentum": { - "wall_motion": "Moving Wall", - "velocity_spec": "Rotational", - "rotation_speed": 1, # rad/s - }, - "thermal": {"thermal_condition": "Temperature", "temperature": 500}, # K -} +solid_wall = WallBoundary.get(solver, name="solid-wall") +solid_wall.momentum.wall_motion = "Moving Wall" +solid_wall.momentum.velocity_spec = "Rotational" +solid_wall.momentum.rotation_speed = 1 * radian / s +solid_wall.thermal.thermal_condition = solid_wall.thermal.thermal_condition.TEMPERATURE +solid_wall.thermal.temperature = 500 * K # %% # Solution methods @@ -258,15 +261,16 @@ methods = Methods(solver) methods.p_v_coupling.flow_scheme = "Coupled" -methods.spatial_discretization.discretization_scheme = {"pressure": "presto!"} -methods.pseudo_time_method.formulation = {"coupled_solver": "global-time-step"} +methods.spatial_discretization.discretization_scheme["pressure"] = "presto!" +methods.pseudo_time_method.formulation.coupled_solver = "global-time-step" # %% # Disable flow equations # ---------------------- controls = Controls(solver) -controls.equations = {"flow": False, "w-swirl": False} +controls.equations["flow"] = False +controls.equations["w-swirl"] = False # %% @@ -280,8 +284,9 @@ # ---------------------------- results = Results(solver) -results.custom_field_functions.create( - name="omegar", custom_field_function="1 * radial_coordinate" # ω = 1 rad/s +omega_r = results.custom_field_functions.create( + name="omegar", + custom_field_function="1 * radial_coordinate", # ω = 1 rad/s ) # %% @@ -294,7 +299,7 @@ variable="x-pull-velocity", reference_frame="Relative to Cell Zone", use_custom_field_function=True, - custom_field_function_name="omegar", + custom_field_function_name=omega_r.name(), value=0.001, ) @@ -304,28 +309,27 @@ variable="z-pull-velocity", reference_frame="Relative to Cell Zone", use_custom_field_function=True, - custom_field_function_name="omegar", + custom_field_function_name=omega_r.name(), ) # %% # Pseudo-transient settings # ------------------------- -solver.settings.solution.run_calculation.pseudo_time_settings.time_step_method = { - "time_step_method": "user-specified", - "auto_time_size_calc_solid_zone": False, -} +calculation = RunCalculation(solver) + +calculation.pseudo_time_settings.time_step_method.time_step_method = "user-specified" +calculation.pseudo_time_settings.time_step_method.auto_time_size_calc_solid_zone = False -calculation = RunCalculation(solver) calculation.iterate(iter_count=20) # %% # Post-processing # --------------- -temp_contour = Contour(solver, new_instance_name="temperature_contour") - +temp_contour = Contour.create( + solver, name="temperature_contour", field=VariableCatalog.TEMPERATURE +) temp_contour.coloring.option = "banded" -temp_contour.field = "temperature" temp_contour.display() graphics.views.restore_view(view_name="front") @@ -337,13 +341,15 @@ # :alt: Temperature Contours -mushy_temp = Contour(solver, new_instance_name="temperature-mushy") +mushy_temp = Contour.create( + solver, name="temperature-mushy", field=VariableCatalog.TEMPERATURE +) mushy_temp.coloring.option = "banded" -mushy_temp.field = "temperature" -mushy_temp.range_option = { - "option": "auto-range-off", - "auto_range_off": {"clip_to_range": True, "minimum": 1100, "maximum": 1200}, -} +# set explicit contour range +mushy_temp.range.option = "auto-range-off" +mushy_temp.range.auto_range_off.clip_to_range = True +mushy_temp.range.auto_range_off.minimum = 1100 * K +mushy_temp.range.auto_range_off.maximum = 1200 * K mushy_temp.display() graphics.views.restore_view(view_name="front") @@ -356,17 +362,18 @@ # Save steady state case -solver.settings.file.write_case_data(file_name="steady_state") +write_case_data(file_name="steady_state") # %% # Enable transient flow and heat transfer # --------------------------------------- -solver_general_settings.solver.time = "unsteady-1st-order" # First-order implicit +general.solver.time = "unsteady-1st-order" # First-order implicit -controls.equations = {"flow": True, "w-swirl": True} +controls.equations["flow"] = True +controls.equations["w-swirl"] = True -controls.under_relaxation = {"delh": 0.1} +controls.under_relaxation["delh"] = 0.1 # %% # Transient controls @@ -378,9 +385,9 @@ solutions.run_calculation.calculate() # Liquid fraction at t = 0.2 s -liquid_fraction_contour = Contour(solver, new_instance_name="liquid-fraction") - -liquid_fraction_contour.field = "liquid-fraction" +liquid_fraction_contour = Contour.create( + solver, name="liquid-fraction", field="liquid-fraction" +) liquid_fraction_contour.display() graphics.picture.save_picture(file_name="modeling_solidification_4.png") @@ -396,9 +403,9 @@ solutions.run_calculation.calculate() # Liquid fraction at t = 5.0 s -liquid_fraction_contour_t_5_sec = Contour(solver, new_instance_name="liquid-fraction") - -liquid_fraction_contour_t_5_sec.field = "liquid-fraction" +liquid_fraction_contour_t_5_sec = Contour.create( + solver, name="liquid-fraction", field="liquid-fraction" +) liquid_fraction_contour_t_5_sec.display() graphics.picture.save_picture(file_name="modeling_solidification_5.png") @@ -409,7 +416,7 @@ # :alt: Liquid Fraction at t = 5 s # Save transient case -solver.settings.file.write_case_data(file_name="unsteady_state") +write_case_data(file_name="unsteady_state") # %% # Close session diff --git a/examples/00-fluent/ahmed_body_workflow.py b/examples/00-fluent/ahmed_body_workflow.py index a0318f5fb8b..8694f97ac42 100644 --- a/examples/00-fluent/ahmed_body_workflow.py +++ b/examples/00-fluent/ahmed_body_workflow.py @@ -61,18 +61,36 @@ # Import required libraries/modules # ===================================================================================== -import os +from pathlib import Path import platform import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + FluidMaterial, + Initialization, + IsoSurface, + Methods, + Monitor, + OutputParameters, + PressureOutlet, + ReferenceValues, + ReportDefinitions, + Residual, + VelocityInlet, + Viscous, + iterate, + write_case, +) from ansys.fluent.visualization import Contour, GraphicsWindow +from ansys.units import VariableCatalog +from ansys.units.common import kg, m, s ####################################################################################### # Launch Fluent session with meshing mode and print Fluent version # ===================================================================================== -session = pyfluent.launch_fluent(mode="meshing", cleanup_on_exit=True) -print(session.get_fluent_version()) +meshing = pyfluent.Meshing.from_install() +print(meshing.get_fluent_version()) ####################################################################################### # Meshing Workflow @@ -82,7 +100,7 @@ # Initialize the Meshing Workflow # ===================================================================================== -workflow = session.workflow +workflow = meshing.workflow filenames = { "Windows": "ahmed_body_20_0degree_boi_half.scdoc", @@ -92,54 +110,49 @@ geometry_filename = examples.download_file( filenames.get(platform.system(), filenames["Other"]), "pyfluent/examples/Ahmed-Body-Simulation", - save_path=os.getcwd(), + save_path=Path.cwd(), ) +meshing.upload(geometry_filename) workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") -workflow.TaskObject["Import Geometry"].Arguments = dict(FileName=geometry_filename) +workflow.TaskObject["Import Geometry"].Arguments = {"FileName": geometry_filename} workflow.TaskObject["Import Geometry"].Execute() ####################################################################################### # Add Local Face Sizing # ===================================================================================== add_local_sizing = workflow.TaskObject["Add Local Sizing"] -add_local_sizing.Arguments = dict( - { - "AddChild": "yes", - "BOIControlName": "facesize_front", - "BOIFaceLabelList": ["wall_ahmed_body_front"], - "BOIGrowthRate": 1.15, - "BOISize": 8, - } -) +add_local_sizing.Arguments = { + "AddChild": "yes", + "BOIControlName": "facesize_front", + "BOIFaceLabelList": ["wall_ahmed_body_front"], + "BOIGrowthRate": 1.15, + "BOISize": 8, +} add_local_sizing.Execute() add_local_sizing.InsertCompoundChildTask() workflow.TaskObject["Add Local Sizing"].Execute() add_local_sizing = workflow.TaskObject["Add Local Sizing"] -add_local_sizing.Arguments = dict( - { - "AddChild": "yes", - "BOIControlName": "facesize_rear", - "BOIFaceLabelList": ["wall_ahmed_body_rear"], - "BOIGrowthRate": 1.15, - "BOISize": 5, - } -) +add_local_sizing.Arguments = { + "AddChild": "yes", + "BOIControlName": "facesize_rear", + "BOIFaceLabelList": ["wall_ahmed_body_rear"], + "BOIGrowthRate": 1.15, + "BOISize": 5, +} add_local_sizing.Execute() add_local_sizing.InsertCompoundChildTask() workflow.TaskObject["Add Local Sizing"].Execute() add_local_sizing = workflow.TaskObject["Add Local Sizing"] -add_local_sizing.Arguments = dict( - { - "AddChild": "yes", - "BOIControlName": "facesize_main", - "BOIFaceLabelList": ["wall_ahmed_body_main"], - "BOIGrowthRate": 1.15, - "BOISize": 12, - } -) +add_local_sizing.Arguments = { + "AddChild": "yes", + "BOIControlName": "facesize_main", + "BOIFaceLabelList": ["wall_ahmed_body_main"], + "BOIGrowthRate": 1.15, + "BOISize": 12, +} add_local_sizing.Execute() ####################################################################################### @@ -147,15 +160,13 @@ # ===================================================================================== add_boi_sizing = workflow.TaskObject["Add Local Sizing"] add_boi_sizing.InsertCompoundChildTask() -add_boi_sizing.Arguments = dict( - { - "AddChild": "yes", - "BOIControlName": "boi_1", - "BOIExecution": "Body Of Influence", - "BOIFaceLabelList": ["ahmed_body_20_0degree_boi_half-boi"], - "BOISize": 20, - } -) +add_boi_sizing.Arguments = { + "AddChild": "yes", + "BOIControlName": "boi_1", + "BOIExecution": "Body Of Influence", + "BOIFaceLabelList": ["ahmed_body_20_0degree_boi_half-boi"], + "BOISize": 20, +} add_boi_sizing.Execute() add_boi_sizing.InsertCompoundChildTask() @@ -164,17 +175,15 @@ # Add Surface Mesh Sizing # ===================================================================================== generate_surface_mesh = workflow.TaskObject["Generate the Surface Mesh"] -generate_surface_mesh.Arguments = dict( - { - "CFDSurfaceMeshControls": { - "CurvatureNormalAngle": 12, - "GrowthRate": 1.15, - "MaxSize": 50, - "MinSize": 1, - "SizeFunctions": "Curvature", - } +generate_surface_mesh.Arguments = { + "CFDSurfaceMeshControls": { + "CurvatureNormalAngle": 12, + "GrowthRate": 1.15, + "MaxSize": 50, + "MinSize": 1, + "SizeFunctions": "Curvature", } -) +} generate_surface_mesh.Execute() generate_surface_mesh.InsertNextTask(CommandName="ImproveSurfaceMesh") @@ -185,10 +194,10 @@ ####################################################################################### # Describe Geometry, Update Boundaries, Update Regions # ===================================================================================== -workflow.TaskObject["Describe Geometry"].Arguments = dict( - CappingRequired="Yes", - SetupType="The geometry consists of only fluid regions with no voids", -) +workflow.TaskObject["Describe Geometry"].Arguments = { + "CappingRequired": "Yes", + "SetupType": "The geometry consists of only fluid regions with no voids", +} workflow.TaskObject["Describe Geometry"].Execute() workflow.TaskObject["Update Boundaries"].Execute() workflow.TaskObject["Update Regions"].Execute() @@ -220,7 +229,7 @@ ####################################################################################### # Switch to the Solver Mode # ===================================================================================== -session = session.switch_to_solver() +solver = meshing.switch_to_solver() ####################################################################################### # Mesh Visualization @@ -243,107 +252,110 @@ ####################################################################################### # Define Constants # ===================================================================================== -density = 1.225 -inlet_velocity = 30 -inlet_area = 0.11203202 +density = 1.225 * kg / m**3 +inlet_velocity = 30 * m / s +inlet_area = 0.11203202 * m**2 ####################################################################################### # Define Materials # ===================================================================================== -session.tui.define.materials.change_create("air", "air", "yes", "constant", density) -session.settings.setup.models.viscous.model = "k-epsilon" -session.settings.setup.models.viscous.k_epsilon_model = "realizable" -session.settings.setup.models.viscous.options.curvature_correction = True +air = FluidMaterial.get(solver, name="air") +air.density = density + +viscous = Viscous(solver=solver) +viscous.model = viscous.model.K_EPSILON +viscous.k_epsilon_model = viscous.k_epsilon_model.REALIZABLE +viscous.options.curvature_correction = True ####################################################################################### # Define Boundary Conditions # ===================================================================================== -inlet = session.settings.setup.boundary_conditions.velocity_inlet["inlet"] +inlet = VelocityInlet.get(solver, name="inlet") inlet.turbulence.turb_intensity = 0.05 inlet.momentum.velocity.value = inlet_velocity inlet.turbulence.turb_viscosity_ratio = 5 -outlet = session.settings.setup.boundary_conditions.pressure_outlet["outlet"] +outlet = PressureOutlet.get(solver, name="outlet") outlet.turbulence.turb_intensity = 0.05 ####################################################################################### # Define Reference Values # ===================================================================================== -session.settings.setup.reference_values.area = inlet_area -session.settings.setup.reference_values.density = density -session.settings.setup.reference_values.velocity = inlet_velocity +ref_values = ReferenceValues(solver) +ref_values.area = inlet_area +ref_values.density = density +ref_values.velocity = inlet_velocity ####################################################################################### # Define Solver Settings # ===================================================================================== -session.tui.solve.set.p_v_coupling(24) - -session.tui.solve.set.discretization_scheme("pressure", 12) -session.tui.solve.set.discretization_scheme("k", 1) -session.tui.solve.set.discretization_scheme("epsilon", 1) -session.tui.solve.initialize.set_defaults("k", 0.000001) - -session.settings.solution.monitor.residual.equations["continuity"].absolute_criteria = ( - 0.0001 -) -session.settings.solution.monitor.residual.equations["x-velocity"].absolute_criteria = ( - 0.0001 -) -session.settings.solution.monitor.residual.equations["y-velocity"].absolute_criteria = ( - 0.0001 -) -session.settings.solution.monitor.residual.equations["z-velocity"].absolute_criteria = ( - 0.0001 -) -session.settings.solution.monitor.residual.equations["k"].absolute_criteria = 0.0001 -session.settings.solution.monitor.residual.equations["epsilon"].absolute_criteria = ( - 0.0001 -) +methods = Methods(solver) +methods.p_v_coupling.flow_scheme = "Coupled" + +discretization_scheme = methods.spatial_discretization.discretization_scheme +discretization_scheme["pressure"] = "second-order" +discretization_scheme["k"] = "second-order-upwind" +discretization_scheme["epsilon"] = "second-order-upwind" +initialization = Initialization(solver) +initialization.defaults.k = 0.000001 + +residual = Residual(solver) +for monitor in ( + "continuity", + "x-velocity", + "y-velocity", + "z-velocity", + "k", + "epsilon", +): + residual.equations[monitor].absolute_criteria = 1e-4 ####################################################################################### # Define Report Definitions # ===================================================================================== -session.settings.solution.report_definitions.drag["cd-mon1"] = {} -session.settings.solution.report_definitions.drag["cd-mon1"] = { - "zones": ["wall_ahmed_body_main", "wall_ahmed_body_front", "wall_ahmed_body_rear"], - "force_vector": [0, 0, 1], -} -session.settings.parameters.output_parameters.report_definitions.create( - name="parameter-1" +drag = ReportDefinitions(solver).drag.create( + name="cd-mon1", + zones=[ + "wall_ahmed_body_main", + "wall_ahmed_body_front", + "wall_ahmed_body_rear", + ], + force_vector=(0, 0, 1), ) -session.settings.parameters.output_parameters.report_definitions["parameter-1"] = { - "report_definition": "cd-mon1" -} -session.settings.solution.monitor.report_plots.create(name="cd-mon1") -session.settings.solution.monitor.report_plots["cd-mon1"] = {"report_defs": ["cd-mon1"]} +params_report_defs = OutputParameters(solver).report_definitions +param_1 = params_report_defs.create(report_def_name=drag) + +monitor = Monitor(solver) +plot_mon = monitor.report_plots.create(name=drag, print=True, report_defs=[drag]) ####################################################################################### # Initialize and Run Solver # ===================================================================================== -session.settings.solution.run_calculation.iter_count = 5 -session.settings.solution.initialization.initialization_type = "standard" -session.settings.solution.initialization.standard_initialize() -session.settings.solution.run_calculation.iterate(iter_count=5) +init = Initialization(solver) +init.initialization_type = "standard" +init.standard_initialize() +iterate(solver, iter_count=5) ####################################################################################### # Post-Processing Workflow # ===================================================================================== -session.settings.results.surfaces.iso_surface.create(name="xmid") -session.settings.results.surfaces.iso_surface["xmid"].field = "x-coordinate" -session.settings.results.surfaces.iso_surface["xmid"] = {"iso_values": [0]} +iso = IsoSurface.create(solver, name="xmid", field="x-coordinate", iso_values=[0 * m]) -contour1 = Contour(solver=session, field="velocity-magnitude", surfaces=["xmid"]) +velocity_mag = Contour( + solver=solver, field=VariableCatalog.VELOCITY_MAGNITUDE, surfaces=["xmid"] +) disp1 = GraphicsWindow() -disp1.add_graphics(contour1) +disp1.add_graphics(velocity_mag) disp1.show() -contour2 = Contour(solver=session, field="pressure-coefficient", surfaces=["xmid"]) -assert "pressure-coefficient" in contour2.field.allowed_values +pressure_coeff = Contour( + solver=solver, field=VariableCatalog.PRESSURE_COEFFICIENT, surfaces=["xmid"] +) disp2 = GraphicsWindow() -disp2.add_graphics(contour2) +disp2.add_graphics(pressure_coeff) disp2.show() ####################################################################################### @@ -369,12 +381,12 @@ ####################################################################################### # Save the case file # ===================================================================================== -session.settings.file.write(file_type="case-data", file_name="ahmed_body_final.cas.h5") +write_case(solver, file_name="ahmed_body_final.cas.h5") ####################################################################################### # Close the session # ===================================================================================== -session.exit() +solver.exit() ####################################################################################### diff --git a/examples/00-fluent/battery_pack.py b/examples/00-fluent/battery_pack.py index 2b94a025256..f9c171abb7b 100644 --- a/examples/00-fluent/battery_pack.py +++ b/examples/00-fluent/battery_pack.py @@ -1,3 +1,10 @@ +# /// script +# dependencies = [ +# "ansys-fluent-core", +# "ansys-fluent-visualization", +# ] +# /// + # Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -72,14 +79,12 @@ # Importing the following classes offers streamlined access to key solver settings, # eliminating the need to manually browse through the full hierarchy of settings APIs structure. -import os +from pathlib import Path import ansys.fluent.core as pyfluent from ansys.fluent.core import examples from ansys.fluent.core.solver import ( Battery, - BoundaryConditions, - CellZoneConditions, Contour, Controls, General, @@ -88,19 +93,33 @@ Materials, Mesh, ReportDefinitions, + ReportPlot, RunCalculation, + SolidCellZone, + SolidMaterial, Solution, Vector, + WallBoundary, + read_mesh, + write_case_data, ) from ansys.fluent.visualization import GraphicsWindow, Monitor +from ansys.units import VariableCatalog +from ansys.units.common import K, W, m, ohm + +# %% +# Define constants +# ---------------- + +S = 1 / ohm # 1 siemens + # %% # Launch Fluent in solver mode # ---------------------------- -solver = pyfluent.launch_fluent( +solver = pyfluent.Solver.from_install( precision=pyfluent.Precision.DOUBLE, - mode=pyfluent.FluentMode.SOLVER, ) # %% @@ -110,7 +129,7 @@ mesh_file = examples.download_file( "1P3S_battery_pack.msh", "pyfluent/battery_pack", - save_path=os.getcwd(), + save_path=Path.cwd(), ) solver.settings.file.read_mesh(file_name=mesh_file) @@ -120,13 +139,12 @@ # ------------ graphics = Graphics(solver) -mesh = Mesh(solver, new_instance_name="mesh-1") - -all_walls = mesh.surfaces_list.allowed_values() +mesh = Mesh.create(solver, name="mesh-1") graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio +all_walls = mesh.surfaces_list.all() mesh.surfaces_list = all_walls mesh.options.edges = True mesh.display() @@ -142,9 +160,9 @@ # Solver settings # --------------- -solver_general_settings = General(solver) +general = General(solver) -solver_general_settings.solver.time = "unsteady-1st-order" +general.solver.time = "unsteady-1st-order" # %% # Enable Battery Model (NTGK/DCIR) @@ -162,7 +180,7 @@ battery_model.enabled = True battery_model.echem_model = "ntgk/dcir" battery_model.eload_condition.eload_settings.eload_type = "specified-system-power" -battery_model.eload_condition.eload_settings.power_value = 200 # W (Total pack power) +battery_model.eload_condition.eload_settings.power_value = 200 * W # Total pack power # Conductive zones battery_model.zone_assignment.active_zone = "cell_*" # Active cells @@ -179,67 +197,41 @@ materials = Materials(solver) # Active material (cells): conductivity via UDS-0 and UDS-1 -materials.solid.create("e_material") - -materials.solid["e_material"] = { - "chemical_formula": "e", - "thermal_conductivity": {"value": 20}, # W/(m·K) - "uds_diffusivity": { - "option": "defined-per-uds", - "uds_diffusivities": { - "uds-0": {"value": 1000000}, # S/m (Electronic conductivity) - "uds-1": {"value": 1000000}, # S/m (Ionic conductivity) - }, - }, -} +e_material = SolidMaterial.create(solver, name="e_material", chemical_formula="e") +e_material.thermal_conductivity = 20 * W / (m * K) +e_material.uds_diffusivity.option = "defined-per-uds" +e_material.uds_diffusivity.uds_diffusivities["uds-0"] = ( + 1e6 * S / m +) # Electronic conductivity +e_material.uds_diffusivity.uds_diffusivities["uds-1"] = ( + 1e6 * S / m +) # Ionic conductivity # Passive material (busbars & tabs): high constant conductivity -materials.solid.create("busbar_material") - -materials.solid["busbar_material"] = { - "chemical_formula": "bus", - "uds_diffusivity": { - "option": "value", - "value": 3.541e7, # S/m (Copper-like conductivity) - }, -} +busbar_material = SolidMaterial.create( + solver, name="busbar_material", chemical_formula="bus" +) +busbar_material.uds_diffusivity.option = "value" +busbar_material.uds_diffusivity.value = 3.541e7 * S / m # Copper-like conductivity # %% # Assign materials to cell zones # ------------------------------ -cell_zone_conditions = CellZoneConditions(solver) - -# Assign e_material to cell_1 -cell_zone_conditions.solid["cell_1"] = {"general": {"material": "e_material"}} - -# Copy to cell_2 and cell_3 -cell_zone_conditions.copy(from_="cell_1", to="cell_*") +# Assign e_material to cell_1 2 and 3 all at once +SolidCellZone.get(solver, name="cell_*").general.material = e_material -# Assign busbar_material to bar1 -cell_zone_conditions.solid["bar1"] = {"general": {"material": "busbar_material"}} - -# Copy to all passive zones -cell_zone_conditions.copy(from_="bar1", to="*bar*|*tabzone*") -# '*bar*' matches any zone containing 'bar', -# '|*tabzone*' matches any zone containing 'tabzone' → OR logic +# Assign busbar_material to bar1 and all passive zones +SolidCellZone.get(solver, name="*bar*|*tabzone*").general.material = busbar_material # %% # Boundary conditions # ------------------- -conditions = BoundaryConditions(solver) - -# Convection on wall-cell_1 -conditions.wall["wall-cell_1"] = { - "thermal": { - "thermal_condition": "Convection", - "heat_transfer_coeff": {"value": 5}, # W/(m²·K) - } -} - -# Copy to all other walls (tabs, busbars, cells) -conditions.copy(from_="wall-cell_1", to="wall*") +# Convection on all walls (tabs, busbars, cells) +wall_bc = WallBoundary.get(solver, name="wall*") +wall_bc.thermal.thermal_condition = wall_bc.thermal.thermal_condition.CONVECTION +wall_bc.thermal.heat_transfer_coeff = 5 * W / (m**2 * K) # %% # Define solution controls and monitors @@ -247,10 +239,8 @@ controls = Controls(solver) # Disable flow and turbulence equations -controls.equations = { - "flow": False, - "kw": False, -} +controls.equations["flow"] = False +controls.equations["kw"] = False solution = Solution(solver) @@ -264,34 +254,36 @@ definitions = ReportDefinitions(solver) # Surface report: voltage at positive tab (area-weighted average) -definitions.surface["voltage_surface_areaavg"] = { - "report_type": "surface-areaavg", - "field": "passive-zone-potential", - "surface_names": ["tab_p"], - "create_report_file": True, - "create_report_plot": True, -} +definitions.surface.create( + name="voltage_surface_areaavg", + report_type="surface-areaavg", + field="passive-zone-potential", + surface_names=["tab_p"], + create_report_file=True, + create_report_plot=True, +) # Format plot axes -report_plot = solver.settings.solution.monitor.report_plots[ - "voltage_surface_areaavg-rplot" -] -report_plot.axes.x.number_format.precision = 0 # Integer time steps -report_plot.axes.y.number_format.precision = 2 # 2 decimal places for voltage +voltage_surface_areaavg = ReportPlot.get(solver, name="voltage_surface_areaavg-rplot") +voltage_surface_areaavg.axes.x.number_format.precision = 0 # Integer time steps +voltage_surface_areaavg.axes.y.number_format.precision = ( + 2 # 2 decimal places for voltage +) # Volume report: maximum temperature in all cell zones -definitions.volume["volume_max_temp"] = { - "report_type": "volume-max", - "field": "temperature", - "cell_zones": "*cell|*bar*|*tabzone*", - "create_report_file": True, - "create_report_plot": True, -} +vol_max = definitions.volume.create( + name="volume_max_temp", + report_type="volume-max", + field=VariableCatalog.TEMPERATURE, + cell_zones=["*cell|*bar*|*tabzone*"], + create_report_file=True, + create_report_plot=True, +) # Format plot axes -report_plot_1 = solver.settings.solution.monitor.report_plots["volume_max_temp-rplot"] -report_plot_1.axes.x.number_format.precision = 0 -report_plot_1.axes.y.number_format.precision = 2 +volume_max_temp = ReportPlot.get(solver, name="volume_max_temp-rplot") +volume_max_temp.axes.x.number_format.precision = 0 +volume_max_temp.axes.y.number_format.precision = 2 # %% # Initialize solution @@ -302,12 +294,13 @@ # %% # Transient controls # ------------------ -Transient_controls = solver.settings.solution.run_calculation.transient_controls +calculation = RunCalculation(solver) -Transient_controls.time_step_count = 50 # Number of time steps -Transient_controls.time_step_size = 30 # s (30 s per step) +transient_controls = calculation.transient_controls +# Use typed quantities for time step settings +transient_controls.time_step_count = 50 # Number of time steps +transient_controls.time_step_size = 30 # 30s per step -calculation = RunCalculation(solver) calculation.calculate() # Run transient simulation # %% @@ -315,11 +308,13 @@ # --------------- # Current density vector plot -vector = Vector(solver, new_instance_name="current-magnitude-vector") - -vector.vector_field = "current-density-j" # A/m² (Current density vector) -vector.field = "current-magnitude" # A/m² (Magnitude for coloring) -vector.surfaces_list = ["tab_n", "tab_p", "wall*"] +vector = Vector.create( + solver, + name="current-magnitude-vector", + vector_field="current-density-j", # A/m² (Current density vector) + field="current-magnitude", # A/m² (Magnitude for coloring) + surfaces_list=["tab_n", "tab_p", "wall*"], +) vector.options.vector_style = "arrow" vector.options.scale = 0.03 # Scale factor for visibility vector.vector_opt.fixed_length = True # Uniform arrow length @@ -334,10 +329,12 @@ # :alt: Current density vector plot # Temperature contour -temp_contour = Contour(solver, new_instance_name="temp_contour") - -temp_contour.field = "temperature" # K -temp_contour.surfaces_list = ["tab_n", "tab_p", "wall*"] +temp_contour = Contour.create( + solver, + name="temp_contour", + field=VariableCatalog.TEMPERATURE, # K + surfaces_list=["tab_n", "tab_p", "wall*"], +) temp_contour.colorings.banded = True temp_contour.display() @@ -350,10 +347,11 @@ # :alt: Temperature contour # Joule heat source contour -joule_contour = Contour(solver, new_instance_name="joule_heating_contour") - -joule_contour.field = "battery-joule-heat-source" # W/m³ -joule_contour.surfaces_list = ["tab_n", "tab_p", "wall*"] +joule_contour = Contour.create( + solver, + field="battery-joule-heat-source", # W/m³ + surfaces_list=["tab_n", "tab_p", "wall*"], +) joule_contour.colorings.banded = True joule_contour.display() @@ -366,10 +364,12 @@ # :alt: Joule heat source contour # Total heat source contour -total_heat_contour = Contour(solver, new_instance_name="total_heating_contour") - -total_heat_contour.field = "total-heat-source" # W/m³ (Joule + reaction heat) -total_heat_contour.surfaces_list = ["tab_n", "tab_p", "wall*"] +total_heat_contour = Contour.create( + solver, + name="total_heating_contour", + field="total-heat-source", # W/m³ (Joule + reaction heat) + surfaces_list=["tab_n", "tab_p", "wall*"], +) total_heat_contour.colorings.banded = True total_heat_contour.display() @@ -403,7 +403,7 @@ # %% # Save case and data # ------------------------ -solver.settings.file.write_case_data(file_name="1P3S_Battery_Pack") +write_case_data(solver, file_name="1P3S_Battery_Pack") # %% # Close Fluent diff --git a/examples/00-fluent/brake.py b/examples/00-fluent/brake.py index 3251c94887c..733a6869c43 100644 --- a/examples/00-fluent/brake.py +++ b/examples/00-fluent/brake.py @@ -50,18 +50,35 @@ # ================================================================================== import csv -import os +import itertools +from pathlib import Path import matplotlib.pyplot as plt import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + Controls, + Energy, + General, + Graphics, + Initialization, + Monitor, + ReportDefinitions, + RunCalculation, + SolidCellZone, + WallBoundary, + read_case, + write_case_data, +) from ansys.fluent.visualization import Contour, GraphicsWindow +from ansys.units import VariableCatalog +from ansys.units.common import K, W, m, radian, s import_filename = examples.download_file( "brake.msh.h5", "pyfluent/examples/Brake-Thermal-PyVista-Matplotlib", - save_path=os.getcwd(), + save_path=Path.cwd(), ) #################################################################################### @@ -72,67 +89,58 @@ # Launch Fluent session with solver mode and print Fluent version # --------------------------------------------------------------- -session = pyfluent.launch_fluent(precision="double", processor_count=2, dimension=3) -print(session.get_fluent_version()) +solver = pyfluent.Solver.from_install( + precision="double", processor_count=2, dimension=3 +) +print(solver.get_fluent_version()) #################################################################################### # Import mesh # ------------ -session.settings.file.read_case(file_name=import_filename) +read_case(solver, file_name=import_filename) ############################ # Define models and material # -------------------------- -session.settings.setup.models.energy = {"enabled": True} -session.settings.setup.general.solver.time = "unsteady-2nd-order-bounded" -session.tui.define.materials.copy("solid", "steel") +energy = Energy(solver) +energy.enabled = True + +general = General(solver) +general.solver.time = "unsteady-2nd-order-bounded" + +Materials(solver).database.copy_by_name(type="solid", name="steel") ######################################### # Solve only energy equation (conduction) # --------------------------------------- -session.tui.solve.set.equations("flow", "no", "kw", "no") +controls = Controls(solver) +controls.equations["kw"] = False # Turbulence +controls.equations["flow"] = False # Flow +controls.equations["temperature"] = True # Energy ########################################################################################## # Define disc rotation # -------------------- -# (15.79 rps corresponds to 100 km/h car speed -# with 0.28 m of axis height from ground) -session.settings.setup.cell_zone_conditions.solid["disc2"] = { - "solid_motion": { - "solid_motion_zone_motion_function": "none", - "solid_motion_axis_direction": [0, 1, 0], - "solid_motion_axis_origin": [-0.035, -0.821, 0.045], - "solid_motion_velocity": [0, 0, 0], - "solid_omega": -15.79, - "solid_relative_to_thread": "absolute", - "enable": True, - } -} -session.settings.setup.cell_zone_conditions.solid["disc1"] = { - "solid_motion": { - "solid_motion_zone_motion_function": "none", - "solid_motion_axis_direction": [0, 1, 0], - "solid_motion_axis_origin": [-0.035, -0.821, 0.045], - "solid_motion_velocity": [0, 0, 0], - "solid_omega": -15.79, - "solid_relative_to_thread": "absolute", - "enable": True, - } -} +discs = SolidCellZone.get(solver, name="disc*") +discs.solid_motion.enable = True +discs.solid_motion.solid_motion_zone_motion_function = "none" +discs.solid_motion.solid_motion_axis_direction = [0, 1, 0] +discs.solid_motion.solid_motion_axis_origin = [-0.035, -0.821, 0.045] * m +discs.solid_motion.solid_motion_velocity = [0, 0, 0] * m / s +discs.solid_motion.solid_omega = ( + -15.79 * radian / s +) # 100 km/h car speed with 0.28 m of axis height from ground +discs.solid_motion.solid_relative_to_thread = "absolute" ########################################################################################## # Apply frictional heating on pad-disc surfaces # ---------------------------------------------- # Wall thickness 0f 2 mm has been assumed and 2e9 w/m3 is the heat generation which # has been calculated from kinetic energy change due to braking. - -session.settings.setup.boundary_conditions.wall["wall-pad-disc2"] = { - "thermal": {"q_dot": {"value": 2000000000}, "wall_thickness": {"value": 0.002}} -} -session.settings.setup.boundary_conditions.wall["wall_pad-disc1"] = { - "thermal": {"q_dot": {"value": 2000000000}, "wall_thickness": {"value": 0.002}} -} +wall_pad_discs = WallBoundary.get(solver, name="wall-pad-disc*") +wall_pad_discs.thermal.q_dot = 2e9 * W / m**3 +wall_pad_discs.thermal.wall_thickness = 0.002 * m ########################################################################################## # Apply convection cooling on outer surfaces due to air flow @@ -140,26 +148,18 @@ # Outer surfaces are applied a constant htc of 100 W/(m2 K) # and 300 K free stream temperature -session.tui.define.boundary_conditions.set.wall( - "wall-disc*", - "wall-geom*", - "()", - "thermal-bc", - "yes", - "convection", - "convective-heat-transfer-coefficient", - "no", - 100, - "q", -) +walls = WallBoundary.get(solver, name="wall-disc*|wall-geom*") +walls.thermal.thermal_condition = walls.thermal.thermal_condition.CONVECTION +walls.thermal.convection.convective_heat_transfer_coefficient = 100 * W / (m**2 * K) +walls.thermal.convection.free_stream_temperature = 300 * K ########################################################################################## # Initialize # ---------- # Initialize with 300 K temperature - -session.settings.solution.initialization.initialization_type = "standard" -session.settings.solution.initialization.standard_initialize() +initialization = Initialization(solver) +initialization.initialization_type = "standard" +initialization.standard_initialize() ############################################################################################### # Post processing setup @@ -169,114 +169,74 @@ # * Set views and camera # * Set animation object -session.settings.solution.report_definitions.volume["max-pad-temperature"] = {} -session.settings.solution.report_definitions.volume[ - "max-pad-temperature" -].report_type = "volume-max" -session.settings.solution.report_definitions.volume["max-pad-temperature"] = { - "field": "temperature", - "cell_zones": ["geom-1-innerpad", "geom-1-outerpad"], -} - -session.settings.solution.report_definitions.volume["max-disc-temperature"] = {} -session.settings.solution.report_definitions.volume[ - "max-disc-temperature" -].report_type = "volume-max" -session.settings.solution.report_definitions.volume["max-disc-temperature"] = { - "field": "temperature", - "cell_zones": ["disc1", "disc2"], -} - -session.settings.solution.monitor.report_plots.create(name="max-temperature") -session.settings.solution.monitor.report_plots["max-temperature"] = { - "report_defs": ["max-pad-temperature", "max-disc-temperature"] -} - -session.settings.solution.monitor.report_files.create(name="max-temperature") -session.settings.solution.monitor.report_files["max-temperature"] = { - "report_defs": ["max-pad-temperature", "max-disc-temperature"], - "file_name": "max-temperature.out", -} -session.settings.solution.monitor.report_files["max-temperature"].report_defs = [ - "max-pad-temperature", - "max-disc-temperature", - "flow-time", -] +report_defs = ReportDefinitions(solver) -session.settings.results.graphics.contour.create(name="contour-1") -session.settings.results.graphics.contour["contour-1"] = { - "surfaces_list": "wall*", - "boundary_values": True, - "range_option": {"auto_range_on": {"global_range": True}}, - "field": "temperature", - "draw_mesh": False, - "coloring": {"smooth": False}, - "color_map": { - "user_skip": 9, - "log_scale": False, - "visible": True, - "width": 6, - "show_all": True, - "font_name": "Helvetica", - "font_size": 0.032, - "font_automatic": True, - "length": 0.54, - "size": 100, - "format": "%0.2e", - "position": 1, - "color": "field-velocity", - }, - "mesh_object": "", - "node_values": True, - "contour_lines": False, - "display_state_name": "None", - "filled": True, -} - -session.settings.results.graphics.contour["temperature"] = { - "field": "temperature", - "surfaces_list": "wall*", - "color_map": { - "visible": True, - "size": 100, - "color": "field-velocity", - "log_scale": False, - "format": "%0.1f", - "user_skip": 9, - "show_all": True, - "position": 1, - "font_name": "Helvetica", - "font_automatic": True, - "font_size": 0.032, - "length": 0.54, - "width": 6, - "bground_transparent": True, - "bground_color": "#CCD3E2", - "title_elements": "Variable and Object Name", - }, -} - -session.settings.results.graphics.contour["temperature"].range_option.option = ( - "auto-range-off" +max_pad_temp = report_defs.volume.create( + name="max-pad-temperature", + report_type="volume-max", + field=VariableCatalog.TEMPERATURE, + cell_zones=["geom-1-innerpad", "geom-1-outerpad"], ) -session.settings.results.graphics.contour["temperature"].range_option.set_state( - { - "auto_range_off": {"maximum": 400.0, "minimum": 300, "clip_to_range": False}, - } + + +max_disc_temp = report_defs.volume.create( + name="max-disc-temperature", + report_type="volume-max", + field="temperature", + cell_zones=["disc1", "disc2"], ) -session.settings.results.graphics.views.restore_view(view_name="top") -session.settings.results.graphics.views.camera.zoom(factor=2) -session.settings.results.graphics.views.save_view(view_name="animation-view") +monitor = Monitor(solver) +temp_plot = monitor.report_plots.create(name="max-temperature") +temp_plot.report_defs = [max_pad_temp, max_disc_temp] + +temp_file = monitor.report_files.create( + name="max-temperature", + report_defs=[max_pad_temp, max_disc_temp, "flow-time"], + file_name="max-temperature.out", +) -session.settings.solution.calculation_activity.solution_animations[ - "animate-temperature" -] = { - "animate_on": "temperature", - "frequency_of": "flow-time", - "flow_time_frequency": 0.05, - "view": "animation-view", -} + +graphics = Graphics(solver) +temp_contour = graphics.contour.create( + name="temperature", field=VariableCatalog.TEMPERATURE, surfaces_list="wall*" +) + +temp_contour.color_map.visible = True +temp_contour.color_map.size = 100 +temp_contour.color_map.color = "field-velocity" +temp_contour.color_map.log_scale = False +temp_contour.color_map.format = "%0.1f" +temp_contour.color_map.user_skip = 9 +temp_contour.color_map.show_all = True +temp_contour.color_map.position = 1 +temp_contour.color_map.font_name = "Helvetica" +temp_contour.color_map.font_automatic = True +temp_contour.color_map.font_size = 0.032 +temp_contour.color_map.length = 0.54 +temp_contour.color_map.width = 6 +temp_contour.color_map.bground_transparent = True +temp_contour.color_map.bground_color = "#CCD3E2" +temp_contour.color_map.title_elements = "Variable and Object Name" + +# range configuration +temp_contour.range.option = "auto-range-off" +temp_contour.range.auto_range_off.minimum = 300.0 +temp_contour.range.auto_range_off.maximum = 400.0 +temp_contour.range.auto_range_off.clip_to_range = False + +# views / camera +graphics.restore_view(view_name="top") +graphics.views.camera.zoom(factor=2) +graphics.views.save_view(view_name="animation-view") + +solver.solution.calculation_activity.solution_animations.create( + name="animate-temperature", + animate_on="temperature", + frequency_of="flow-time", + flow_time_frequency=0.05, + view="animation-view", +) ################################################################################################## # Run simulation @@ -284,17 +244,15 @@ # * Run simulation for 2 seconds flow time # * Set time step size # * Set number of time steps and maximum number of iterations per time step - -session.settings.solution.run_calculation.transient_controls.time_step_size = 0.01 -session.settings.solution.run_calculation.dual_time_iterate( - time_step_count=200, max_iter_per_step=5 -) +run_calc = RunCalculation(solver) +run_calc.transient_controls.time_step_size = 0.01 +run_calc.dual_time_iterate(time_step_count=200, max_iter_per_step=5) ################################################################################################## # Save simulation data # -------------------- # Write case and data files -session.settings.file.write(file_type="case-data", file_name="brake-final.cas.h5") +write_case_data(solver, file_name="brake-final.cas.h5") ############################################### # Post processing with PyVista (3D visualization) @@ -313,7 +271,7 @@ "wall-geom-1-innerpad", "wall-geom-1-outerpad", ] -contour1 = Contour(solver=session, field="temperature", surfaces=contour1_surfaces) +contour1 = Contour(solver=solver, field="temperature", surfaces=contour1_surfaces) ############################################### # Set contour properties @@ -350,15 +308,15 @@ X = [] Y = [] Z = [] -i = -1 -with open(os.path.join(os.getcwd(), "max-temperature.out"), "r") as datafile: - plotting = csv.reader(datafile, delimiter=" ") - for rows in plotting: - i = i + 1 - if i > 2: - X.append(float(rows[3])) - Y.append(float(rows[2])) - Z.append(float(rows[1])) + +with (Path.cwd() / "max-temperature.out").open() as datafile: + for rows in csv.reader( + itertools.islice(datafile, 3, -1), # skip header lines + delimiter=" ", + ): + X.append(float(rows[3])) + Y.append(float(rows[2])) + Z.append(float(rows[1])) ############################################### # Plot graph @@ -390,6 +348,6 @@ # Close the session # ================================================================================== -session.exit() +solver.exit() # sphinx_gallery_thumbnail_path = '_static/brake_surface_temperature-thumbnail.png' diff --git a/examples/00-fluent/catalytic_converter_workflow.py b/examples/00-fluent/catalytic_converter_workflow.py index f7c3b5a54db..8cf8db94c39 100644 --- a/examples/00-fluent/catalytic_converter_workflow.py +++ b/examples/00-fluent/catalytic_converter_workflow.py @@ -1,3 +1,10 @@ +# /// script +# dependencies = [ +# "ansys-fluent-core", +# "ansys-fluent-visualization", +# ] +# /// + # Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -88,26 +95,20 @@ # sphinx_gallery_capture_repr = ('_repr_html_', '__repr__') # sphinx_gallery_thumbnail_path = '_static/catalytic_converter/catalytic_converter_cad_geo.png' -import os +from pathlib import Path import platform import ansys.fluent.core as pyfluent -from ansys.fluent.core import ( - Dimension, - FluentMode, - FluentVersion, - Precision, - UIMode, - examples, -) +from ansys.fluent.core import examples from ansys.fluent.core.solver import ( # noqa: E402 - CellZoneCondition, + CellZoneConditions, + Energy, General, Graphics, Initialization, + IsoSurface, Materials, Mesh, - Models, Monitor, PressureOutlet, ReportDefinitions, @@ -115,16 +116,20 @@ RunCalculation, Scene, VelocityInlet, + WallBoundaries, + write_case_data, ) +from ansys.units import VariableCatalog +from ansys.units.common import K, Pa, m, s +# %% # Launch meshing session -meshing = pyfluent.launch_fluent( - product_version=FluentVersion.v252, - mode=FluentMode.MESHING, - ui_mode=UIMode.GUI, +# ---------------------------- +meshing = pyfluent.Meshing.from_install( + ui_mode=pyfluent.UIMode.GUI, processor_count=4, - precision=Precision.DOUBLE, - dimension=Dimension.THREE, + precision=pyfluent.Precision.DOUBLE, + dimension=pyfluent.Dimension.THREE, ) # %% @@ -152,11 +157,11 @@ geometry_filename = examples.download_file( filenames.get(platform.system(), filenames["Other"]), "/pyfluent/catalytic_converter/", - save_path=os.getcwd(), + save_path=Path.cwd(), ) workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") -workflow.TaskObject["Import Geometry"].Arguments = dict(FileName=geometry_filename) +workflow.TaskObject["Import Geometry"].Arguments = {"FileName": geometry_filename} workflow.TaskObject["Import Geometry"].Execute() # %% @@ -166,23 +171,21 @@ # Add local sizing for sensor components -workflow.TaskObject["Add Local Sizing"].Arguments = dict( - { - "AddChild": "yes", - "BOIControlName": "sensor", - "BOIExecution": "Curvature", - "BOIFaceLabelList": [ - "sensing_element-65-solid", - "sensor_innertube-67-solid", - "sensor_protectiontube-66-solid1", - ], - "BOIMaxSize": 1.2, - "BOIMinSize": 0.1, - } -) +workflow.TaskObject["Add Local Sizing"].Arguments = { + "AddChild": "yes", + "BOIControlName": "sensor", + "BOIExecution": "Curvature", + "BOIFaceLabelList": [ + "sensing_element-65-solid", + "sensor_innertube-67-solid", + "sensor_protectiontube-66-solid1", + ], + "BOIMaxSize": 1.2, + "BOIMinSize": 0.1, +} workflow.TaskObject["Add Local Sizing"].AddChildToTask() workflow.TaskObject["Add Local Sizing"].InsertCompoundChildTask() -workflow.TaskObject["Add Local Sizing"].Arguments = dict({"AddChild": "yes"}) +workflow.TaskObject["Add Local Sizing"].Arguments = {"AddChild": "yes"} workflow.TaskObject["sensor"].Execute() # %% @@ -192,16 +195,14 @@ # Configure surface mesh settings -workflow.TaskObject["Generate the Surface Mesh"].Arguments = dict( - { - "CFDSurfaceMeshControls": {"MinSize": 1.5}, - "SurfaceMeshPreferences": { - "SMQualityImprove": "yes", - "SMQualityImproveLimit": 0.95, - "ShowSurfaceMeshPreferences": True, - }, - } -) +workflow.TaskObject["Generate the Surface Mesh"].Arguments = { + "CFDSurfaceMeshControls": {"MinSize": 1.5}, + "SurfaceMeshPreferences": { + "SMQualityImprove": "yes", + "SMQualityImproveLimit": 0.95, + "ShowSurfaceMeshPreferences": True, + }, +} workflow.TaskObject["Generate the Surface Mesh"].Execute() # %% @@ -212,27 +213,23 @@ # Describe geometry type workflow.TaskObject["Describe Geometry"].UpdateChildTasks(SetupTypeChanged=False) -workflow.TaskObject["Describe Geometry"].Arguments = dict( - {"SetupType": "The geometry consists of both fluid and solid regions and/or voids"} -) +workflow.TaskObject["Describe Geometry"].Arguments = { + "SetupType": "The geometry consists of both fluid and solid regions and/or voids" +} workflow.TaskObject["Describe Geometry"].UpdateChildTasks(SetupTypeChanged=True) # Enable capping and wall-to-internal conversion -workflow.TaskObject["Describe Geometry"].Arguments = dict( - { - "CappingRequired": "Yes", - "SetupType": "The geometry consists of both fluid and solid regions and/or voids", - } -) +workflow.TaskObject["Describe Geometry"].Arguments = { + "CappingRequired": "Yes", + "SetupType": "The geometry consists of both fluid and solid regions and/or voids", +} workflow.TaskObject["Describe Geometry"].UpdateChildTasks(SetupTypeChanged=False) -workflow.TaskObject["Describe Geometry"].Arguments = dict( - { - "CappingRequired": "Yes", - "SetupType": "The geometry consists of both fluid and solid regions and/or voids", - "WallToInternal": "Yes", - } -) +workflow.TaskObject["Describe Geometry"].Arguments = { + "CappingRequired": "Yes", + "SetupType": "The geometry consists of both fluid and solid regions and/or voids", + "WallToInternal": "Yes", +} workflow.TaskObject["Describe Geometry"].Execute() # %% @@ -242,24 +239,20 @@ # Create inlet boundary -workflow.TaskObject["Enclose Fluid Regions (Capping)"].Arguments = dict( - { - "LabelSelectionList": ["in1"], - "PatchName": "inlet", - } -) +workflow.TaskObject["Enclose Fluid Regions (Capping)"].Arguments = { + "LabelSelectionList": ["in1"], + "PatchName": "inlet", +} workflow.TaskObject["Enclose Fluid Regions (Capping)"].AddChildToTask() workflow.TaskObject["Enclose Fluid Regions (Capping)"].InsertCompoundChildTask() workflow.TaskObject["inlet"].Execute() # Create outlet boundary as pressure outlet -workflow.TaskObject["Enclose Fluid Regions (Capping)"].Arguments = dict( - { - "LabelSelectionList": ["out1"], - "PatchName": "outlet", - } -) +workflow.TaskObject["Enclose Fluid Regions (Capping)"].Arguments = { + "LabelSelectionList": ["out1"], + "PatchName": "outlet", +} workflow.TaskObject["Enclose Fluid Regions (Capping)"].AddChildToTask() workflow.TaskObject["Enclose Fluid Regions (Capping)"].InsertCompoundChildTask() workflow.TaskObject["outlet"].Execute() @@ -267,14 +260,12 @@ # Configure outlet as pressure-outlet workflow.TaskObject["outlet"].Revert() -workflow.TaskObject["outlet"].Arguments = dict( - { - "CompleteLabelSelectionList": ["out1"], - "LabelSelectionList": ["out1"], - "PatchName": "outlet", - "ZoneType": "pressure-outlet", - } -) +workflow.TaskObject["outlet"].Arguments = { + "CompleteLabelSelectionList": ["out1"], + "LabelSelectionList": ["out1"], + "PatchName": "outlet", + "ZoneType": "pressure-outlet", +} workflow.TaskObject["outlet"].Execute() # Update boundaries @@ -288,19 +279,17 @@ # Create multiple flow volumes -workflow.TaskObject["Create Regions"].Arguments = dict({"NumberOfFlowVolumes": 3}) +workflow.TaskObject["Create Regions"].Arguments = {"NumberOfFlowVolumes": 3} workflow.TaskObject["Create Regions"].Execute() # Convert solid substrate regions to fluid regions -workflow.TaskObject["Update Regions"].Arguments = dict( - { - "OldRegionNameList": ["honeycomb-solid1", "honeycomb_af0-solid1"], - "OldRegionTypeList": ["solid", "solid"], - "RegionNameList": ["fluid:substrate:1", "fluid:substrate:2"], - "RegionTypeList": ["fluid", "fluid"], - } -) +workflow.TaskObject["Update Regions"].Arguments = { + "OldRegionNameList": ["honeycomb-solid1", "honeycomb_af0-solid1"], + "OldRegionTypeList": ["solid", "solid"], + "RegionNameList": ["fluid:substrate:1", "fluid:substrate:2"], + "RegionTypeList": ["fluid", "fluid"], +} workflow.TaskObject["Update Regions"].Execute() # %% @@ -312,9 +301,9 @@ workflow.TaskObject["Add Boundary Layers"].AddChildToTask() workflow.TaskObject["Add Boundary Layers"].InsertCompoundChildTask() -workflow.TaskObject["smooth-transition_1"].Arguments = dict( - {"BLControlName": "smooth-transition_1"} -) +workflow.TaskObject["smooth-transition_1"].Arguments = { + "BLControlName": "smooth-transition_1" +} workflow.TaskObject["smooth-transition_1"].Execute() @@ -325,9 +314,9 @@ # Generate volume mesh -workflow.TaskObject["Generate the Volume Mesh"].Arguments = dict( - {"VolumeMeshPreferences": {"MergeBodyLabels": "yes"}} -) +workflow.TaskObject["Generate the Volume Mesh"].Arguments = { + "VolumeMeshPreferences": {"MergeBodyLabels": "yes"} +} workflow.TaskObject["Generate the Volume Mesh"].Execute() # %% @@ -349,7 +338,11 @@ # Switch to solver mode -solver_session = meshing.switch_to_solver() +solver = meshing.switch_to_solver() + + +# Create output directory for results +out = Path("out").mkdir(exist_ok=True) # %% Visualize Mesh # ~~~~~~~~~~~~~~~~~ @@ -357,7 +350,7 @@ # Visualize mesh in the graphics window and save a screenshot # Create Graphics object to save the graphics with following settings -graphics = Graphics(solver_session) +graphics = Graphics(solver) graphics.views.auto_scale() if graphics.picture.use_window_resolution.is_active(): graphics.picture.use_window_resolution = False @@ -370,12 +363,14 @@ # Define and display the mesh # First, get all wall boundary names and create a mesh object for visualization context -all_walls = solver_session.settings.setup.boundary_conditions.wall.get_object_names() -mesh = Mesh(solver_session, new_instance_name="mesh-1") -mesh.surfaces_list = all_walls +all_walls = WallBoundaries(solver).get_object_names() +mesh = Mesh( + solver, + new_instance_name="mesh-1", + surfaces_list=all_walls, +) mesh.options.edges = True mesh.display() -os.makedirs("out", exist_ok=True) graphics.picture.save_picture(file_name="out/catalytic_converter_mesh.png") mesh.options.edges = False # Turn off edges after saving the picture @@ -393,16 +388,14 @@ # Set length units to millimeters -general_settings = General(solver_session) +general_settings = General(solver) general_settings.units_settings.new_unit( offset=0.0, units_name="mm", scale_factor=1.0, quantity="length" ) # Enable energy equation -energy_model_settings = Models(solver_session) -energy_model_settings.energy = { - "enabled": True, - "inlet_diffusion": False, -} +energy = Energy(solver) +energy.enabled = True +energy.inlet_diffusion = False # %% # Materials @@ -411,23 +404,14 @@ # Copy nitrogen from database -solver_session.settings.setup.materials.database.copy_by_name( - type="fluid", name="nitrogen" -) - -# Assign material to main fluid zone - -materials = Materials(solver_session) +materials = Materials(solver) materials.database.copy_by_name(type="fluid", name="nitrogen") -material_assignments = CellZoneCondition(solver_session, name="fluid:1") -material_assignments.general = {"material": "nitrogen"} +# Assign material to main fluid zone -# Copy boundary conditions to other fluid zones +material_assignments = CellZoneConditions.get(solver, name="fluid:*") +material_assignments.general.material = "nitrogen" -solver_session.tui.define.boundary_conditions.copy_bc( - "fluid:1", "fluid:2", "fluid:3", "()" -) # %% # Cell Zone Conditions @@ -436,30 +420,32 @@ # Configure first substrate zone as porous media -porous_media_settings = CellZoneCondition(solver_session, name="fluid:substrate:1") -porous_media_settings.general = {"laminar": True, "material": "nitrogen"} -porous_media_settings.porous_zone = { - "solid_material": "aluminum", - "equib_thermal": True, - "relative_viscosity": {"value": 1, "option": "constant"}, - "porosity": 1, - "power_law_model": [0, 0], - "inertial_resistance": [1000.0, 1000.0, 1000.0], - "alt_inertial_form": False, - "viscous_resistance": [1000000.0, 1000000.0, 1000.0], - "rel_vel_resistance": True, - "direction_2_vector": [0, 1, 0], - "direction_1_vector": [1, 0, 0], - "dir_spec_cond": "Cartesian", - "porous": True, -} - +porous_media_settings = CellZoneConditions.get(solver, name="fluid:substrate:*") +porous_media_settings.general.laminar = True +porous_media_settings.general.material = "nitrogen" +porous_media_settings.porous_zone.solid_material = "aluminum" +porous_media_settings.porous_zone.equib_thermal = True +porous_media_settings.porous_zone.relative_viscosity.option = "constant" +porous_media_settings.porous_zone.relative_viscosity.value = 1 +porous_media_settings.porous_zone.porosity = 1 +porous_media_settings.porous_zone.power_law_model = [0, 0] +porous_media_settings.porous_zone.inertial_resistance = [ + 1000.0, + 1000.0, + 1000.0, +] / m +porous_media_settings.porous_zone.alt_inertial_form = False +porous_media_settings.porous_zone.viscous_resistance = [ + 1000000.0, + 1000000.0, + 1000.0, +] / m**2 +porous_media_settings.porous_zone.rel_vel_resistance = True +porous_media_settings.porous_zone.direction_2_vector = (0, 1, 0) +porous_media_settings.porous_zone.direction_1_vector = (1, 0, 0) +porous_media_settings.porous_zone.dir_spec_cond = "Cartesian" +porous_media_settings.porous_zone.porous = True -# Copy porous media settings to second substrate zone - -solver_session.tui.define.boundary_conditions.copy_bc( - "fluid:substrate:1", "fluid:substrate:2", "()" -) # %% # Boundary Conditions @@ -468,25 +454,19 @@ # Configure velocity inlet -velocity_inlet = VelocityInlet(solver_session, name="inlet") -velocity_inlet.momentum = {"velocity_magnitude": {"value": 125.0}} - -velocity_inlet.turbulence = { - "hydraulic_diameter": 0.5, # in meters - "turbulence_specification": "Intensity and Hydraulic Diameter", -} -velocity_inlet.thermal = {"temperature": {"value": 800.0}} # in Kelvin +velocity_inlet = VelocityInlet.get(solver, name="inlet") +velocity_inlet.momentum.velocity_magnitude = 125.0 * m / s +velocity_inlet.turbulence.hydraulic_diameter = 0.5 * m +velocity_inlet.turbulence.turbulence_specification = "Intensity and Hydraulic Diameter" +velocity_inlet.thermal.temperature = 800.0 * K # Configure pressure outlet -pressure_outlet = PressureOutlet(solver_session, name="outlet") -pressure_outlet.momentum = {"gauge_pressure": {"value": 0.0}} -pressure_outlet.turbulence = { - "backflow_hydraulic_diameter": 0.5, # in meters - "turbulence_specification": "Intensity and Hydraulic Diameter", -} -pressure_outlet.thermal = {"backflow_total_temperature": {"value": 800.0}} # in Kelvin - +pressure_outlet = PressureOutlet.get(solver, name="outlet") +pressure_outlet.momentum.gauge_pressure = 0.0 * Pa +pressure_outlet.turbulence.backflow_hydraulic_diameter = 0.5 * m +pressure_outlet.turbulence.turbulence_specification = "Intensity and Hydraulic Diameter" +pressure_outlet.thermal.backflow_total_temperature = 800.0 * K # %% # Solution Monitoring @@ -495,25 +475,27 @@ # Create surface report definition -report_definitions = ReportDefinitions(solver_session) -surface_report = report_definitions.surface.create(name="surf-mon-1") -surface_report.report_type = "surface-massflowrate" -surface_report.surface_names = ["outlet"] +report_definitions = ReportDefinitions(solver) +surface_report = report_definitions.surface.create( + name="surf-mon-1", + report_type="surface-massflowrate", + surface_names=["outlet"], +) # Create report file monitor -monitor = Monitor(solver_session) -surface_monitor = monitor.report_files.create(name="surf-mon-1") -surface_monitor.print = True -surface_monitor.report_defs = ["surf-mon-1"] -os.makedirs("out", exist_ok=True) -surface_monitor.file_name = "out/surf-mon-1.out" - +monitor = Monitor(solver) +monitor.report_files.create( + name=surface_report, + print=True, + report_defs=[surface_report.name], + file_name="out/surf-mon-1.out", +) # Create report plot monitor -surface_plot_monitor = monitor.report_plots.create(name="surf-mon-1") -surface_plot_monitor.print = True -surface_plot_monitor.report_defs = ["surf-mon-1"] +monitor.report_plots.create( + name=surface_report, print=True, report_defs=[surface_report] +) # %% @@ -523,7 +505,7 @@ # Compute initial conditions from inlet -solution_initialization = Initialization(solver_session) +solution_initialization = Initialization(solver) solution_initialization.compute_defaults( from_zone_type="velocity-inlet", from_zone_name="inlet", phase="mixture" @@ -541,7 +523,7 @@ # Set iteration count and run calculation -run_calculation = RunCalculation(solver_session) +run_calculation = RunCalculation(solver) run_calculation.iter_count = ( 150 # Iteration count, keep it at 150 for demo purposes only ) @@ -557,9 +539,7 @@ # ~~~~~~~~~~~~~~~~~~ # Calculate mass flow rate at outlet. -# Ensure the 'out/' directory exists before writing files to it -os.makedirs("out", exist_ok=True) -results = Results(solver_session) +results = Results(solver) results.report.fluxes.mass_flow( zones=["outlet"], write_to_file=True, file_name="out/mass_flow_rate.flp" ) @@ -572,18 +552,18 @@ # Create cross-sectional surfaces surfaces_data = [ - ("y=-425", "y-coordinate", [-0.425]), - ("z=185", "z-coordinate", [0.185]), - ("z=230", "z-coordinate", [0.23]), - ("z=280", "z-coordinate", [0.28]), - ("z=330", "z-coordinate", [0.33]), - ("z=375", "z-coordinate", [0.375]), + ("y=-425", "y-coordinate", [-0.425] * m), + ("z=185", "z-coordinate", [0.185] * m), + ("z=230", "z-coordinate", [0.23] * m), + ("z=280", "z-coordinate", [0.28] * m), + ("z=330", "z-coordinate", [0.33] * m), + ("z=375", "z-coordinate", [0.375] * m), ] for surf_name, field_name, iso_values in surfaces_data: - results.surfaces.iso_surface.create(name=surf_name) - results.surfaces.iso_surface[surf_name].field = field_name - results.surfaces.iso_surface[surf_name].iso_values = iso_values + surface = IsoSurface.create( + solver, name=surf_name, field=field_name, iso_values=iso_values + ) # %% # Velocity Analysis @@ -617,39 +597,36 @@ # Velocity vectors show both flow direction and magnitude using arrow symbols # The scale factor controls arrow size for optimal visualization -results.graphics.vector.create(name="vector-vel") -results.graphics.vector["vector-vel"] = { - "scale": { - "auto_scale": True, # Automatically scale arrows for best visibility - "scale_f": 0.006, # Fine-tune scale factor (smaller = shorter arrows) - }, - "surfaces_list": ["y=-425"], # Display vectors on the y=-425 cross-section -} +vec = results.graphics.vector.create( + name="vector-vel", surfaces_list=["y=-425"] +) # Display vectors on the y=-425 cross-section +vec.scale.auto_scale = True # Automatically scale arrows for best visibility +vec.scale.scale_f = 0.006 # Fine-tune scale factor (smaller = shorter arrows) # Create static pressure contour plot # Pressure contours use color mapping to show pressure distribution # This helps identify high/low pressure regions and pressure gradients -results.graphics.contour.create(name="contour-ps") -results.graphics.contour["contour-ps"] = { - "field": "pressure", # Specify pressure as the contour variable - "surfaces_list": ["y=-425"], # Display on the same cross-section as vectors -} +pressure_contour = results.graphics.contour.create( + name="contour-ps", + field=VariableCatalog.PRESSURE, # Specify pressure as the contour variable + surfaces_list=["y=-425"], # Display on the same cross-section as vectors +) # Create velocity magnitude contour plot # Velocity magnitude shows speed distribution without directional information # Using multiple z-surfaces provides a comprehensive view through the domain -results.graphics.contour.create(name="contour-velmag") -results.graphics.contour["contour-velmag"] = { - "field": "velocity-magnitude", # Specify velocity magnitude as the variable - "surfaces_list": z_surfaces, # Display on all z-coordinate surfaces -} +cont_velmag = results.graphics.contour.create( + name="contour-velmag", + field=VariableCatalog.VELOCITY_MAGNITUDE, # Specify velocity magnitude as the variable + surfaces_list=z_surfaces, # Display on all z-coordinate surfaces +) # Scene 1: Display velocity vectors with mesh context # Scenes combine multiple graphics objects for comprehensive visualization -velocity_vectors_scene = Scene(solver_session, new_instance_name="scene-1") +velocity_vectors_scene = Scene(solver, new_instance_name="scene-1") velocity_vectors_scene.graphics_objects.add(name="vector-vel") # adding mesh for context which is created earlier steps just after switching to solver @@ -657,15 +634,13 @@ velocity_vectors_scene.graphics_objects.add(name="mesh-1") # Configure scene appearance and display settings -solver_session.settings.results.scene["scene-1"] = { - "graphics_objects": { - "vector-vel": {"name": "vectors"}, # Label for the vector plot - "mesh-1": {"transparency": 75}, # Semi-transparent mesh (75% transparent) - } +scene_1 = Scene.create(solver, name="scene-1") +scene_1.graphics_objects = { + "vector-vel": {"name": "vectors"}, # Label for the vector plot + "mesh-1": {"transparency": 75}, # Semi-transparent mesh (75% transparent) } velocity_vectors_scene.display() graphics.views.auto_scale() -os.makedirs("out", exist_ok=True) graphics.picture.save_picture(file_name="out/velocity_vectors.png") # %% @@ -678,22 +653,16 @@ # Scene 2: Display static pressure contours with mesh context # This scene focuses on pressure distribution across the catalytic converter -static_pressure_scene = Scene(solver_session, new_instance_name="scene-2") -static_pressure_scene.graphics_objects.add(name="contour-ps") -static_pressure_scene.graphics_objects.add(name="mesh-1") +static_pressure_scene = Scene.create(solver, name="scene-2") +pressure_contour_scene = static_pressure_scene.graphics_objects.add(name="contour-ps") +mesh_1_scene = static_pressure_scene.graphics_objects.add(name="mesh-1") # Configure pressure contour scene settings +pressure_contour_scene.name = pressure_contour # Label for the pressure contour +mesh_1_scene.transparency = 75 # Consistent mesh transparency -solver_session.settings.results.scene["scene-2"] = { - "graphics_objects": { - "contour-ps": {"name": "contour-ps"}, # Label for the pressure contour - "mesh-1": {"transparency": 75}, # Consistent mesh transparency - } -} static_pressure_scene.display() graphics.views.auto_scale() -# Ensure "out/" directory exists before saving files -os.makedirs("out", exist_ok=True) graphics.picture.save_picture(file_name="out/static_pressure.png") # %% @@ -707,23 +676,20 @@ # Scene 3: Display velocity magnitude contours with mesh context # This scene shows speed distribution across multiple axial locations -velocity_magnitude_scene = Scene(solver_session, new_instance_name="scene-3") -velocity_magnitude_scene.graphics_objects.add(name="contour-velmag") -velocity_magnitude_scene.graphics_objects.add(name="mesh-1") +velocity_magnitude_scene = Scene.create(solver, name="scene-3") +velocity_mag_contour_scene = velocity_magnitude_scene.graphics_objects.add( + name="contour-velmag" +) +mesh_1_scene = velocity_magnitude_scene.graphics_objects.add(name="mesh-1") # Configure velocity magnitude contour scene settings -solver_session.settings.results.scene["scene-3"] = { - "graphics_objects": { - "contour-velmag": { - "name": "contour-velmag" - }, # Label for velocity magnitude contour - "mesh-1": {"transparency": 75}, # Consistent mesh transparency - } -} +velocity_mag_contour_scene.name = ( + velocity_mag_contour # Label for velocity magnitude contour +) +mesh_1_scene.transparency = 75 # Consistent mesh transparency + velocity_magnitude_scene.display() graphics.views.auto_scale() -# Ensure the 'out/' directory exists before saving files -os.makedirs("out", exist_ok=True) graphics.picture.save_picture(file_name="out/velocity_magnitude.png") # %% @@ -741,9 +707,7 @@ # Write final case and data -solver_session.settings.file.write( - file_type="case-data", file_name="out/catalytic_converter_final.cas.h5" -) +write_case_data(solver, file_name="out/catalytic_converter_final.cas.h5") # %% # Solver Exit @@ -752,7 +716,7 @@ # Close solver session -solver_session.exit() +solver.exit() # %% # References diff --git a/examples/00-fluent/conjugate_heat_transfer.py b/examples/00-fluent/conjugate_heat_transfer.py index 65e87aaa8af..03bf067a0f3 100644 --- a/examples/00-fluent/conjugate_heat_transfer.py +++ b/examples/00-fluent/conjugate_heat_transfer.py @@ -57,15 +57,37 @@ # ================================= import csv -import os from pathlib import Path import platform +from ansys.units import VariableCatalog import matplotlib.pyplot as plt import pyvista as pv import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + CellZoneCondition, + FluidMaterial, + Initialization, + Materials, + Monitor, + PressureOutlet, + ReportDefinitions, + RunCalculation, + SolidMaterial, + VelocityInlet, + Viscous, + WallBoundary, + BoundaryCondition, + Energy, + Fluxes, + General, + IsoSurface, + write_case_data, + write_case, + MeshInterfaces, +) from ansys.fluent.visualization import ( Contour, GraphicsWindow, @@ -73,6 +95,7 @@ Vector, XYPlot, ) +from ansys.units.common import J, K, Pa, W, kg, m, s filenames = { "Windows": "cht_fin_htc_new.scdoc", @@ -82,7 +105,7 @@ geom_filename = examples.download_file( filenames.get(platform.system(), filenames["Other"]), "pyfluent/examples/CHT", - save_path=os.getcwd(), + save_path=Path.cwd(), ) ####################### @@ -93,42 +116,35 @@ # Launch Fluent session with meshing mode and print Fluent version # ================================================================ -meshing_session = pyfluent.launch_fluent( - mode="meshing", - precision="double", +meshing = pyfluent.Meshing.from_install( + precision=pyfluent.Precision.DOUBLE, processor_count=4, ) -print(meshing_session.get_fluent_version()) +print(meshing.get_fluent_version()) ############################################################################# # Start Watertight Geometry Meshing Workflow # ========================================== -meshing_session.workflow.InitializeWorkflow(WorkflowType=r"Watertight Geometry") +meshing.workflow.InitializeWorkflow(WorkflowType=r"Watertight Geometry") -meshing_session.workflow.TaskObject["Import Geometry"].Arguments = dict( - FileName=geom_filename -) +meshing.workflow.TaskObject["Import Geometry"].Arguments = {"FileName": geom_filename} -meshing_session.workflow.TaskObject["Import Geometry"].Execute() +meshing.workflow.TaskObject["Import Geometry"].Execute() -meshing_session.workflow.TaskObject["Add Local Sizing"].Execute() +meshing.workflow.TaskObject["Add Local Sizing"].Execute() -meshing_session.workflow.TaskObject["Generate the Surface Mesh"].Arguments = dict( - { - "CFDSurfaceMeshControls": { - "MinSize": 0.3, - "MaxSize": 1, - "ScopeProximityTo": "faces", - }, - } -) -meshing_session.workflow.TaskObject["Generate the Surface Mesh"].Execute() +meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments = { + "CFDSurfaceMeshControls": { + "MinSize": 0.3, + "MaxSize": 1, + "ScopeProximityTo": "faces", + }, +} +meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() -meshing_session.workflow.TaskObject["Describe Geometry"].UpdateChildTasks( - SetupTypeChanged=True -) -meshing_session.workflow.TaskObject["Describe Geometry"].Arguments.setState( +meshing.workflow.TaskObject["Describe Geometry"].UpdateChildTasks(SetupTypeChanged=True) +meshing.workflow.TaskObject["Describe Geometry"].Arguments.setState( { r"CappingRequired": r"No", r"InvokeShareTopology": r"No", @@ -137,13 +153,13 @@ } ) -meshing_session.workflow.TaskObject["Describe Geometry"].Execute() +meshing.workflow.TaskObject["Describe Geometry"].Execute() ############################################################################# # Update Interface Boundaries; Create Region # ========================================== -meshing_session.workflow.TaskObject["Update Boundaries"].Arguments.setState( +meshing.workflow.TaskObject["Update Boundaries"].Arguments.setState( { r"BoundaryLabelList": [ r"interface-out-solid-a", @@ -350,44 +366,38 @@ } ) -meshing_session.workflow.TaskObject["Update Boundaries"].Execute() +meshing.workflow.TaskObject["Update Boundaries"].Execute() -meshing_session.workflow.TaskObject["Create Regions"].Execute() +meshing.workflow.TaskObject["Create Regions"].Execute() ############################################################################# # Custom Journal for Creating Periodicity due to Non-Conformal Objects # ==================================================================== -meshing_session.workflow.TaskObject["Describe Geometry"].InsertNextTask( +meshing.workflow.TaskObject["Describe Geometry"].InsertNextTask( CommandName=r"RunCustomJournal" ) -meshing_session.workflow.TaskObject["Run Custom Journal"].Rename( - NewName=r"set-periodicity" -) -meshing_session.workflow.TaskObject["set-periodicity"].Arguments = dict( - { - r"JournalString": r"""/bo rps translational semi-auto periodic-1-high periodic-2-high periodic-3-high periodic-4-high , 0 0 -2.3 +meshing.workflow.TaskObject["Run Custom Journal"].Rename(NewName=r"set-periodicity") +meshing.workflow.TaskObject["set-periodicity"].Arguments = { + r"JournalString": r"""/bo rps translational semi-auto periodic-1-high periodic-2-high periodic-3-high periodic-4-high , 0 0 -2.3 /bo rps translational semi-auto periodic-5* , 0 0 -2.3 /bo rps translational semi-auto periodic-6-high , 0 0 -2.3 /bo rps translational semi-auto periodic-7-high , 0 0 -2.3 """, - } -) +} -meshing_session.workflow.TaskObject["set-periodicity"].Execute() +meshing.workflow.TaskObject["set-periodicity"].Execute() ############################################################################# # Update Boundary Layer Task # ========================== -meshing_session.workflow.TaskObject["Update Regions"].Execute() -meshing_session.workflow.TaskObject["Add Boundary Layers"].AddChildToTask() -meshing_session.workflow.TaskObject["Add Boundary Layers"].InsertCompoundChildTask() -meshing_session.workflow.TaskObject["smooth-transition_1"].Rename( - NewName=r"aspect-ratio_1" -) +meshing.workflow.TaskObject["Update Regions"].Execute() +meshing.workflow.TaskObject["Add Boundary Layers"].AddChildToTask() +meshing.workflow.TaskObject["Add Boundary Layers"].InsertCompoundChildTask() +meshing.workflow.TaskObject["smooth-transition_1"].Rename(NewName=r"aspect-ratio_1") -meshing_session.workflow.TaskObject["aspect-ratio_1"].Arguments.setState( +meshing.workflow.TaskObject["aspect-ratio_1"].Arguments.setState( { "BLControlName": r"aspect-ratio_1", "BLRegionList": [ @@ -432,23 +442,23 @@ } ) -meshing_session.workflow.TaskObject["aspect-ratio_1"].Execute() +meshing.workflow.TaskObject["aspect-ratio_1"].Execute() ############################################################################# # Generate Mesh # ============= -meshing_session.workflow.TaskObject["Generate the Volume Mesh"].Execute() +meshing.workflow.TaskObject["Generate the Volume Mesh"].Execute() ############################################################################# # Improve Volume Mesh # =================== -meshing_session.workflow.TaskObject["Generate the Volume Mesh"].InsertNextTask( +meshing.workflow.TaskObject["Generate the Volume Mesh"].InsertNextTask( CommandName=r"ImproveVolumeMesh" ) -meshing_session.workflow.TaskObject["Improve Volume Mesh"].Arguments.setState( +meshing.workflow.TaskObject["Improve Volume Mesh"].Arguments.setState( { r"CellQualityLimit": 0.05, r"VMImprovePreferences": { @@ -460,7 +470,7 @@ } ) -meshing_session.workflow.TaskObject["Improve Volume Mesh"].Execute() +meshing.workflow.TaskObject["Improve Volume Mesh"].Execute() ############################################################################# # Save Mesh File @@ -473,25 +483,25 @@ # Switch to Solution Mode # ======================= -solver_session = meshing_session.switch_to_solver() +solver = meshing.switch_to_solver() ############################################################################# # Auto-create Mesh Interfaces # =========================== -solver_session.tui.define.mesh_interfaces.create("int", "yes", "no") +MeshInterfaces(solver).create(si_name="int", all_bnd=True) ############################################################################# # Mesh Check; Review Fluent transcript for errors # =============================================== -solver_session.settings.mesh.check() +solver.settings.mesh.check() ############################################################################# # Create boundary lists for display and post-processing # ===================================================== -mesh1 = Mesh(solver=solver_session, surfaces=[]) +mesh1 = Mesh(solver=solver, surfaces=[]) wall_list = [ boundary_name @@ -523,243 +533,140 @@ # * Enable Energy Equation # * Enable Laminar Viscous Model -solver_session.settings.setup.general.units.set_units( +General(solver).units.set_units( quantity="temperature", units_name="C", scale_factor=1.0, offset=273.15 ) -solver_session.settings.setup.models.energy.enabled = True -solver_session.settings.setup.models.viscous.model.set_state("laminar") +Energy(solver).enabled = True +viscous = Viscous(solver) +viscous.model = viscous.model.LAMINAR ############################################################################# # Change a few material properties of default Air # =============================================== -air_dict = solver_session.settings.setup.materials.fluid["air"].get_state() -air_dict["density"]["value"] = 1.2 -air_dict["viscosity"]["value"] = 1.5e-5 -air_dict["thermal_conductivity"]["value"] = 0.026 -air_dict["specific_heat"]["value"] = 1006.0 -solver_session.settings.setup.materials.fluid["air"].set_state(air_dict) +# Air +air = FluidMaterial.get(solver, name="air") +air.density = 1.2 * kg / m**3 +air.viscosity = 1.5e-5 * Pa * s +air.thermal_conductivity = 0.026 * W / (m * K) +air.specific_heat = 1006.0 * J / (kg * K) + +# Aluminum +al = SolidMaterial.create(solver, name="aluminum") +al.density = 2719.0 * kg / m**3 +al.thermal_conductivity = 200.0 * W / (m * K) +al.specific_heat = 871.0 * J / (kg * K) + +# Copy Copper and set properties +materials = Materials(solver) +materials.database.copy_by_name(type="solid", name="copper") +cu = SolidMaterial.create(solver, name="copper") +cu.density = 8978.0 * kg / m**3 +cu.thermal_conductivity = 340.0 * W / (m * K) +cu.specific_heat = 381.0 * J / (kg * K) -############################################################################# -# Change a few material properties of default Aluminum -# ==================================================== +# Set Tube Cell Zone Material as Copper +cell_zones = CellZoneCondition(solver, name="solid-tube-*") +cell_zones.general.material = "copper" -al_dict = solver_session.settings.setup.materials.solid["aluminum"].get_state() -al_dict["density"]["value"] = 2719.0 -al_dict["thermal_conductivity"]["value"] = 200.0 -al_dict["specific_heat"]["value"] = 871.0 -solver_session.settings.setup.materials.solid["aluminum"].set_state(al_dict) +# Boundary conditions +inlet = VelocityInlet.get(solver, name="inlet") +inlet.momentum.velocity = 4.0 * m / s +inlet.thermal.temperature = 293.15 * K -############################################################################# -# Copy Copper and change a few material properties of default Copper -# ================================================================== +outlet = PressureOutlet.get(solver, name="outlet") +outlet.thermal.backflow_total_temperature = 293.15 * K -solver_session.settings.setup.materials.database.copy_by_name( - type="solid", name="copper" -) -cu_dict = solver_session.settings.setup.materials.solid["copper"].get_state() -cu_dict["density"]["value"] = 8978.0 -cu_dict["thermal_conductivity"]["value"] = 340.0 -cu_dict["specific_heat"]["value"] = 381.0 -solver_session.settings.setup.materials.solid["copper"].set_state(cu_dict) +# Wall thermal BC +walls_inner = WallBoundary.get(solver, name="wall-inner-tube-*") +walls_inner.thermal.thermal_condition = walls_inner.thermal.thermal_condition.CONVECTION +walls_inner.thermal.heat_transfer_coeff = 1050.0 * W / (m**2 * K) +walls_inner.thermal.free_stream_temp = 353.15 * K -############################################################################# -# Set Tube Cell Zone Material as Copper -# ===================================== - -tube_dict = solver_session.settings.setup.cell_zone_conditions.solid[ - "solid-tube-1" -].get_state() -tube_dict["material"] = "copper" -solver_session.settings.setup.cell_zone_conditions.solid["solid-tube-1"].set_state( - tube_dict +# Enable HOTR +solver.settings.solution.methods.high_order_term_relaxation.enable = True + +# Define Report Definitions using typed API +rdefs = ReportDefinitions(solver) +out_ent = rdefs.surface.create( + name="outlet-enthalpy-flow", + report_type="surface-flowrate", + field=VariableCatalog.ENTHALPY, + surface_names=["outlet"], ) -tube_dict = solver_session.settings.setup.cell_zone_conditions.solid[ - "solid-tube-2" -].get_state() -tube_dict["material"] = "copper" -solver_session.settings.setup.cell_zone_conditions.solid["solid-tube-2"].set_state( - tube_dict +avg_pressure = rdefs.surface.create( + name="avg-pressure-inlet", + report_type="surface-areaavg", + field=VariableCatalog.PRESSURE, + surface_names=["inlet"], ) -############################################################################# -# Set Boundary Condition for Inlet and Outlet -# =========================================== - -solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "inlet" -].momentum.velocity = 4.0 -solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "inlet" -].thermal.temperature = 293.15 # Need to specify in Kelvin - -solver_session.settings.setup.boundary_conditions.pressure_outlet[ - "outlet" -].thermal.backflow_total_temperature = 293.15 - -############################################################################# -# Set Thermal Boundary Condition for Wall Inner Tube -# ================================================== - -solver_session.settings.setup.boundary_conditions.wall[ - "wall-inner-tube-1" -].thermal.thermal_condition = "Convection" -solver_session.settings.setup.boundary_conditions.wall[ - "wall-inner-tube-1" -].thermal.heat_transfer_coeff = 1050.0 -solver_session.settings.setup.boundary_conditions.wall[ - "wall-inner-tube-1" -].thermal.free_stream_temp = 353.15 - -solver_session.settings.setup.boundary_conditions.copy( - from_="wall-inner-tube-1", to="wall-inner-tube-2" +vol_max = rdefs.volume.create( + name="max-vel-louvers4", + report_type="volume-max", + field=VariableCatalog.VELOCITY_MAGNITUDE, + cell_zones=["fluid-sweep-fin4"], ) -############################################################################# -# Enable HOTR -# =========== - -solver_session.settings.solution.methods.high_order_term_relaxation.enable = True -############################################################################# -# Define Report Definitions -# ========================= - -solver_session.settings.solution.report_definitions.surface["outlet-enthalpy-flow"] = {} -solver_session.settings.solution.report_definitions.surface[ - "outlet-enthalpy-flow" -].report_type = "surface-flowrate" -solver_session.settings.solution.report_definitions.surface[ - "outlet-enthalpy-flow" -].field = "enthalpy" -solver_session.settings.solution.report_definitions.surface[ - "outlet-enthalpy-flow" -].surface_names = ["outlet"] - -solver_session.settings.solution.report_definitions.surface["avg-pressure-inlet"] = {} -solver_session.settings.solution.report_definitions.surface[ - "avg-pressure-inlet" -].report_type = "surface-areaavg" -solver_session.settings.solution.report_definitions.surface[ - "avg-pressure-inlet" -].field = "pressure" -solver_session.settings.solution.report_definitions.surface[ - "avg-pressure-inlet" -].surface_names = ["inlet"] - -solver_session.settings.solution.report_definitions.volume["max-vel-louvers4"] = {} -solver_session.settings.solution.report_definitions.volume[ - "max-vel-louvers4" -].report_type = "volume-max" -solver_session.settings.solution.report_definitions.volume["max-vel-louvers4"].field = ( - "velocity-magnitude" -) -solver_session.settings.solution.report_definitions.volume[ - "max-vel-louvers4" -].cell_zones = ["fluid-tet-4"] - -solver_session.settings.solution.report_definitions.surface["wall-shear-int"] = {} -solver_session.settings.solution.report_definitions.surface[ - "wall-shear-int" -].report_type = "surface-integral" -solver_session.settings.solution.report_definitions.surface["wall-shear-int"].field = ( - "wall-shear" +wall_shear = rdefs.surface.create( + name="wall-shear-int", + report_type="surface-integral", + field=VariableCatalog.WALL_SHEAR, + surface_names=[ + "wall-fluid-sweep-fin-solid-sweep-fin-shadow", + "wall-fluid-tet-1-solid-tet-1", + "wall-fluid-tet-2-solid-tet-2", + "wall-fluid-tet-3-solid-tet-3", + "wall-fluid-tet-4-solid-tet-4", + ], ) -solver_session.settings.solution.report_definitions.surface[ - "wall-shear-int" -].surface_names = [ - "wall-fluid-sweep-fin-solid-sweep-fin-shadow", - "wall-fluid-tet-1-solid-tet-1", - "wall-fluid-tet-2-solid-tet-2", - "wall-fluid-tet-3-solid-tet-3", - "wall-fluid-tet-4-solid-tet-4", -] -solver_session.settings.solution.monitor.report_plots.create( - name="outlet-enthalpy-flow-plot" +monitor = Monitor(solver) +monitor.report_plots.create(report_defs=[out_ent]) +monitor.report_files.create(report_defs=[out_ent], file_name="outlet-enthalpy-flow.out") +monitor.report_plots.create(report_defs=[avg_pressure]) +monitor.report_files.create( + report_defs=[avg_pressure], file_name="avg-pressure-inlet.out" ) -solver_session.settings.solution.monitor.report_plots[ - "outlet-enthalpy-flow-plot" -].report_defs = "outlet-enthalpy-flow" - -solver_session.settings.solution.monitor.report_files["outlet-enthalpy-flow-file"] = {} -solver_session.settings.solution.monitor.report_files["outlet-enthalpy-flow-file"] = { - "report_defs": ["outlet-enthalpy-flow"], - "file_name": r"outlet-enthalpy-flow.out", -} - -solver_session.settings.solution.monitor.report_plots["avg-pressure-inlet-plot"] = {} -solver_session.settings.solution.monitor.report_plots["avg-pressure-inlet-plot"] = { - "report_defs": ["avg-pressure-inlet"] -} - -solver_session.settings.solution.monitor.report_files["avg-pressure-inlet-file"] = {} -solver_session.settings.solution.monitor.report_files["avg-pressure-inlet-file"] = { - "report_defs": ["avg-pressure-inlet"], - "file_name": r"avg-pressure-inlet.out", -} - -solver_session.settings.solution.monitor.report_plots["max-vel-louvers4-plot"] = {} -solver_session.settings.solution.monitor.report_plots["max-vel-louvers4-plot"] = { - "report_defs": ["max-vel-louvers4"] -} - -solver_session.settings.solution.monitor.report_files["max-vel-louvers4-file"] = {} -solver_session.settings.solution.monitor.report_files["max-vel-louvers4-file"] = { - "report_defs": ["max-vel-louvers4"], - "file_name": r"max-vel-louvers4.out", -} - -solver_session.settings.solution.monitor.report_plots["wall-shear-int-plot"] = {} -solver_session.settings.solution.monitor.report_plots["wall-shear-int-plot"] = { - "report_defs": ["wall-shear-int"] -} - -solver_session.settings.solution.monitor.report_files["wall-shear-int-file"] = {} -solver_session.settings.solution.monitor.report_files["wall-shear-int-file"] = { - "report_defs": ["wall-shear-int"], - "file_name": r"wall-shear-int.out", -} +monitor.report_plots.create(report_defs=[vol_max]) +monitor.report_files.create(report_defs=[vol_max], file_name="max-vel-louvers4.out") +monitor.report_plots.create(report_defs=[wall_shear]) +monitor.report_files.create(report_defs=[wall_shear], file_name="wall-shear-int.out") ############################################################################# # Hybrid Initialization; Slit Interior between Solid Zones; Save Case # =================================================================== -solver_session.settings.solution.initialization.initialization_type = "hybrid" -solver_session.settings.solution.initialization.hybrid_initialize() +initialization = Initialization(solver) +initialization.initialization_type = "hybrid" +initialization.hybrid_initialize() -solver_session.settings.setup.boundary_conditions.slit_interior_between_diff_solids() -solver_session.settings.file.write(file_type="case", file_name="hx-fin-2mm.cas.h5") +BoundaryCondition(solver).slit_interior_between_diff_solids() +write_case(solver, file_name="hx-fin-2mm.cas.h5") ############################################################################# # Set Aggressive Length Scale Method; Run Calculation & Save Data # =============================================================== -solver_session.settings.solution.run_calculation.pseudo_time_settings.time_step_method.time_step_method = ( - "automatic" -) -solver_session.settings.solution.run_calculation.pseudo_time_settings.time_step_method.length_scale_methods = ( - "aggressive" -) +run_calc = RunCalculation(solver) +run_calc.pseudo_time_settings.time_step_method.time_step_method = "automatic" +run_calc.pseudo_time_settings.time_step_method.length_scale_methods = "aggressive" -solver_session.settings.solution.run_calculation.iterate(iter_count=250) +run_calc.iterate(iter_count=250) -solver_session.settings.file.write(file_type="case-data", file_name="hx-fin-2mm.dat.h5") +write_case_data(solver, file_name="hx-fin-2mm.dat.h5") ############################################################################# # Post-Processing Mass Balance Report # =================================== -inlet_mfr = solver_session.scheme.exec( - ('(ti-menu-load-string "/report/fluxes/mass-flow no inlet () no")',) -).split(" ")[-1] -outlet_mfr = solver_session.scheme.exec( - ('(ti-menu-load-string "/report/fluxes/mass-flow no outlet () no")',) -).split(" ")[-1] -net_mfr = solver_session.scheme.exec( - ('(ti-menu-load-string "/report/fluxes/mass-flow no inlet outlet () no")',) -).split(" ")[-1] +fluxes = Fluxes(solver) +inlet_mfr = fluxes.get_mass_flow(zones=["inlet"]) +outlet_mfr = fluxes.get_mass_flow(zones=["outlet"]) +net_mfr = inlet_mfr - outlet_mfr + print("Mass Balance Report\n") print("Inlet (kg/s): ", inlet_mfr) print("Outlet (kg/s): ", outlet_mfr) @@ -769,9 +676,8 @@ # Heat Balance Report # =================== -htr = solver_session.scheme.exec( - ('(ti-menu-load-string "/report/fluxes/heat-transfer yes no")',) -).split(" ")[-1] +htr = fluxes.get_heat_transfer() + print("Heat Balance Report\n") print("Net Imbalance (Watt): ", htr) @@ -782,22 +688,14 @@ fig, axs = plt.subplots(2, 2, figsize=(10, 8)) fig.suptitle("Monitor Plots") -outFilesList = [] -fileList = os.listdir(os.getcwd()) -for tempFile in fileList: - fName, ext = os.path.splitext(tempFile) - if ext == ".out": - outFilesList.append(tempFile) -outFilesList.sort() - +out_files = sorted(Path.cwd().glob("*.out")) index = 0 -for ax in axs.flat: +for ax, file in zip(axs.flat, out_files): X = [] Y = [] i = -1 - with open(outFilesList[index], "r") as datafile: - plotting = csv.reader(datafile, delimiter=" ") - for rows in plotting: + with file.open() as fp: + for rows in csv.reader(fp, delimiter=" "): i += 1 if i == 1: var = rows[1] @@ -829,7 +727,7 @@ # Contour Plot # ============ -contour1 = Contour(solver=solver_session, field="temperature", surfaces=wall_list) +contour1 = Contour(solver=solver, field="temperature", surfaces=wall_list) window2 = GraphicsWindow() window2.add_graphics(contour1) window2.show() @@ -861,23 +759,22 @@ # Create Iso-Surface of X=0.012826 m # ================================== -solver_session.settings.results.surfaces.iso_surface["x=0.012826"] = {} -solver_session.settings.results.surfaces.iso_surface["x=0.012826"].field = ( - "x-coordinate" +IsoSurface.create( + solver, + name="x=0.012826", + field="x-coordinate", + iso_values=[0.012826 * m], ) -solver_session.settings.results.surfaces.iso_surface["x=0.012826"] = { - "iso_values": [0.012826] -} ############################################################################# # Vector Plot # =========== vector1 = Vector( - solver=solver_session, + solver=solver, field="velocity", color_by="x-velocity", - surfaces=["x=0.012826"], + surfaces=[iso_x.name], scale=2.0, skip=5, ) @@ -911,8 +808,8 @@ # =================== p1 = XYPlot( - solver=solver_session, - surfaces=["x=0.012826"], + solver=solver, + surfaces=[iso_x.name], y_axis_function="pressure", x_axis_function="direction-vector", direction_vector=[0, 1, 0], @@ -937,4 +834,4 @@ ############################################################################# # Exit Fluent Session # =================== -solver_session.exit() +solver.exit() diff --git a/examples/00-fluent/exhaust_system_settings_api.py b/examples/00-fluent/exhaust_system_settings_api.py index af5ff3a8eda..efa4218a577 100644 --- a/examples/00-fluent/exhaust_system_settings_api.py +++ b/examples/00-fluent/exhaust_system_settings_api.py @@ -73,8 +73,24 @@ # the geometry file. # sphinx_gallery_thumbnail_path = '_static/exhaust_system_settings.png' + import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + Graphics, + Initialization, + IsoSurface, + Pathline, + PressureOutlet, + RunCalculation, + Scene, + Surfaces, + VelocityInlet, + Viscous, + iterate, + write_case_data, +) +from ansys.units.common import m, s import_file_name = examples.download_file( "exhaust_system.fmd", "pyfluent/exhaust_system" @@ -86,22 +102,22 @@ # Launch Fluent as a service in meshing mode with double precision running on # two processors and print Fluent version. -meshing_session = pyfluent.launch_fluent( +meshing = pyfluent.Meshing.from_install( precision="double", processor_count=2, - mode="meshing", ) -print(meshing_session.get_fluent_version()) +meshing.upload(import_file_name) +print(meshing.get_fluent_version()) ############################################################################### # Initialize workflow # ~~~~~~~~~~~~~~~~~~~ # Initialize the fault-tolerant meshing workflow. -meshing_session.workflow.InitializeWorkflow(WorkflowType="Fault-tolerant Meshing") +meshing.workflow.InitializeWorkflow(WorkflowType="Fault-tolerant Meshing") ############################################################################### -# Fault-folerant meshing workflow +# Fault-tolerant meshing workflow # ------------------------------- # The fault-tolerant meshing workflow guides you through the many tasks that # follow. @@ -111,11 +127,11 @@ # Import the CAD geometry file (``exhaust_system.fmd``) and selectively manage some # parts. -meshing_session.PartManagement.InputFileChanged( +meshing.PartManagement.InputFileChanged( FilePath=import_file_name, IgnoreSolidNames=False, PartPerBody=False ) -meshing_session.PMFileManagement.FileManager.LoadFiles() -meshing_session.PartManagement.Node["Meshing Model"].Copy( +meshing.PMFileManagement.FileManager.LoadFiles() +meshing.PartManagement.Node["Meshing Model"].Copy( Paths=[ "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/main,1", "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/flow-pipe,1", @@ -124,10 +140,10 @@ "/dirty_manifold-for-wrapper," + "1/dirty_manifold-for-wrapper,1/object1,1", ] ) -meshing_session.PartManagement.ObjectSetting[ - "DefaultObjectSetting" -].OneZonePer.set_state("part") -cad_import = meshing_session.workflow.TaskObject["Import CAD and Part Management"] +meshing.PartManagement.ObjectSetting["DefaultObjectSetting"].OneZonePer.set_state( + "part" +) +cad_import = meshing.workflow.TaskObject["Import CAD and Part Management"] cad_import.Arguments.set_state( { "Context": 0, @@ -149,7 +165,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ # Describe the geometry and the flow characteristics. -describe_geom = meshing_session.workflow.TaskObject["Describe Geometry and Flow"] +describe_geom = meshing.workflow.TaskObject["Describe Geometry and Flow"] describe_geom.Arguments.set_state( { "AddEnclosure": "No", @@ -186,7 +202,7 @@ # .. image:: /_static/exhaust_system_012.png # :width: 400pt # :align: center -capping = meshing_session.workflow.TaskObject["Enclose Fluid Regions (Capping)"] +capping = meshing.workflow.TaskObject["Enclose Fluid Regions (Capping)"] capping.Arguments.set_state( { "CreatePatchPreferences": { @@ -221,7 +237,7 @@ capping.InsertCompoundChildTask() capping.Arguments.set_state({}) -meshing_session.workflow.TaskObject["inlet-1"].Execute() +meshing.workflow.TaskObject["inlet-1"].Execute() capping.Arguments.set_state( { "PatchName": "inlet-2", @@ -250,7 +266,7 @@ capping.InsertCompoundChildTask() capping.Arguments.set_state({}) -meshing_session.workflow.TaskObject["inlet-2"].Execute() +meshing.workflow.TaskObject["inlet-2"].Execute() capping.Arguments.set_state( { "PatchName": "inlet-3", @@ -279,7 +295,7 @@ capping.InsertCompoundChildTask() capping.Arguments.set_state({}) -meshing_session.workflow.TaskObject["inlet-3"].Execute() +meshing.workflow.TaskObject["inlet-3"].Execute() capping.Arguments.set_state( { "PatchName": "outlet-1", @@ -310,13 +326,13 @@ capping.InsertCompoundChildTask() capping.Arguments.set_state({}) -meshing_session.workflow.TaskObject["outlet-1"].Execute() +meshing.workflow.TaskObject["outlet-1"].Execute() ############################################################################### # Extract edge features # ~~~~~~~~~~~~~~~~~~~~~ # Extract edge features. -edge_features = meshing_session.workflow.TaskObject["Extract Edge Features"] +edge_features = meshing.workflow.TaskObject["Extract Edge Features"] edge_features.Arguments.set_state( { "ExtractMethodType": "Intersection Loops", @@ -326,7 +342,7 @@ edge_features.AddChildToTask() edge_features.InsertCompoundChildTask() -edge_group = meshing_session.workflow.TaskObject["edge-group-1"] +edge_group = meshing.workflow.TaskObject["edge-group-1"] edge_group.Arguments.set_state( { "ExtractEdgesName": "edge-group-1", @@ -342,7 +358,7 @@ # Identify regions # ~~~~~~~~~~~~~~~~ # Identify regions. -identify_regions = meshing_session.workflow.TaskObject["Identify Regions"] +identify_regions = meshing.workflow.TaskObject["Identify Regions"] identify_regions.Arguments.set_state( { "SelectionType": "zone", @@ -374,7 +390,7 @@ identify_regions.AddChildToTask() identify_regions.InsertCompoundChildTask() -fluid_region_1 = meshing_session.workflow.TaskObject["fluid-region-1"] +fluid_region_1 = meshing.workflow.TaskObject["fluid-region-1"] fluid_region_1.Arguments.set_state( { "MaterialPointsName": "fluid-region-1", @@ -414,13 +430,13 @@ identify_regions.Arguments.set_state({}) -meshing_session.workflow.TaskObject["void-region-1"].Execute() +meshing.workflow.TaskObject["void-region-1"].Execute() ############################################################################### # Define thresholds for leakages # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Define thresholds for potential leakages. -leakage_threshold = meshing_session.workflow.TaskObject["Define Leakage Threshold"] +leakage_threshold = meshing.workflow.TaskObject["Define Leakage Threshold"] leakage_threshold.Arguments.set_state( { "AddChild": "yes", @@ -432,7 +448,7 @@ leakage_threshold.AddChildToTask() leakage_threshold.InsertCompoundChildTask() -leakage_1 = meshing_session.workflow.TaskObject["leakage-1"] +leakage_1 = meshing.workflow.TaskObject["leakage-1"] leakage_1.Arguments.set_state( { "AddChild": "yes", @@ -453,7 +469,7 @@ # Review region settings # ~~~~~~~~~~~~~~~~~~~~~~ # Review the region settings. -update_region = meshing_session.workflow.TaskObject["Update Region Settings"] +update_region = meshing.workflow.TaskObject["Update Region Settings"] update_region.Arguments.set_state( { "AllRegionFilterCategories": ["2"] * 5 + ["1"] * 2, @@ -496,7 +512,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~ # Set mesh control options. -meshing_session.workflow.TaskObject["Choose Mesh Control Options"].Execute() +meshing.workflow.TaskObject["Choose Mesh Control Options"].Execute() ############################################################################### # Generate surface mesh @@ -508,32 +524,32 @@ # :width: 500pt # :align: center -meshing_session.workflow.TaskObject["Generate the Surface Mesh"].Execute() +meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() ############################################################################### # Confirm and update boundaries # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Confirm and update the boundaries. -meshing_session.workflow.TaskObject["Update Boundaries"].Execute() +meshing.workflow.TaskObject["Update Boundaries"].Execute() ############################################################################### # Add boundary layers # ~~~~~~~~~~~~~~~~~~~ # Add boundary layers. -meshing_session.workflow.TaskObject["Add Boundary Layers"].AddChildToTask() +meshing.workflow.TaskObject["Add Boundary Layers"].AddChildToTask() -meshing_session.workflow.TaskObject["Add Boundary Layers"].InsertCompoundChildTask() +meshing.workflow.TaskObject["Add Boundary Layers"].InsertCompoundChildTask() -meshing_session.workflow.TaskObject["aspect-ratio_1"].Arguments.set_state( +meshing.workflow.TaskObject["aspect-ratio_1"].Arguments.set_state( { "BLControlName": "aspect-ratio_1", } ) -meshing_session.workflow.TaskObject["Add Boundary Layers"].Arguments.set_state({}) +meshing.workflow.TaskObject["Add Boundary Layers"].Arguments.set_state({}) -meshing_session.workflow.TaskObject["aspect-ratio_1"].Execute() +meshing.workflow.TaskObject["aspect-ratio_1"].Execute() ############################################################################### # Generate volume mesh @@ -544,7 +560,7 @@ # .. image:: /_static/exhaust_system_014.png # :width: 500pt # :align: center -volume_mesh_gen = meshing_session.workflow.TaskObject["Generate the Volume Mesh"] +volume_mesh_gen = meshing.workflow.TaskObject["Generate the Volume Mesh"] volume_mesh_gen.Arguments.set_state( { "AllRegionNameList": [ @@ -568,7 +584,7 @@ # ~~~~~~~~~~ # Check the mesh. -meshing_session.tui.mesh.check_mesh() +meshing.tui.mesh.check_mesh() ############################################################################### # Solve and postprocess @@ -580,64 +596,44 @@ # ~~~~~~~~~~~~~~~~~~~~~~~ # Switch to the solution mode. -solver_session = meshing_session.switch_to_solver() +solver = meshing.switch_to_solver() -solver_session.settings.mesh.check() +solver.settings.mesh.check() ############################################################################### # Select turbulence model # ~~~~~~~~~~~~~~~~~~~~~~~ # Select the kw sst turbulence model. -viscous = solver_session.settings.setup.models.viscous - -viscous.model = "k-omega" -viscous.k_omega_model = "sst" +viscous = Viscous(solver) +viscous.model = viscous.model.K_OMEGA +viscous.k_omega_model = viscous.k_omega_model.SST ############################################################################### # Set velocity and turbulence boundary conditions for first inlet # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Set the velocity and turbulence boundary conditions for the first inlet -# (``inlet-1``). +# Set the velocity and turbulence boundary conditions for the inlets -boundary_conditions = solver_session.settings.setup.boundary_conditions - -boundary_conditions.velocity_inlet["inlet-1"] = { - "momentum": { - "velocity_specification_method": "Magnitude, Normal to Boundary", - "velocity": { - "value": 1, - }, - }, -} - -############################################################################### -# Set same boundary conditions for other velocity inlets -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Set the same boundary conditions for the other velocity inlets (``inlet_2`` -# and ``inlet_3``). +inlets = VelocityInlet.get(solver, name="inlet-*") -boundary_conditions.copy( - from_="inlet-1", - to=["inlet-2", "inlet-3"], -) +inlets.momentum.velocity_specification_method = "Magnitude, Normal to Boundary" +inlets.momentum.velocity_magnitude = 1 * m / s ############################################################################### # Set boundary conditions at outlet # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the boundary conditions at the outlet (``outlet-1``). - -boundary_conditions.pressure_outlet["outlet-1"].turbulence.turbulent_intensity = 0.05 -boundary_conditions.pressure_outlet[ - "outlet-1" -].turbulence.backflow_turbulent_intensity = 0.05 +outlet = PressureOutlet.get(solver, name="outlet-1") +outlet.turbulence.turbulent_intensity = 0.05 +outlet.turbulence.backflow_turbulent_intensity = 0.05 ############################################################################### # Initialize flow field # ~~~~~~~~~~~~~~~~~~~~~ # Initialize the flow field using hybrid initialization. -solver_session.settings.solution.initialization.hybrid_initialize() +initialize = Initialization(solver) +initialize.hybrid_initialize() ############################################################################### # Start calculation @@ -649,14 +645,14 @@ # :width: 500pt # :align: center -solver_session.settings.solution.run_calculation.iterate(iter_count=100) +iterate(solver, iter_count=100) ############################################################################### # Write the case and data files # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -solver_session.settings.file.write( - file_type="case-data", +write_case_data( + solver, file_name="exhaust_system.cas.h5", ) @@ -667,7 +663,6 @@ # picture files. Edit the picture settings to use a custom resolution so that # the images are large enough. -graphics = solver_session.settings.results.graphics # use_window_resolution option not active inside containers or Ansys Lab environment if graphics.picture.use_window_resolution.is_active(): graphics.picture.use_window_resolution = False @@ -686,15 +681,15 @@ # :width: 500pt # :align: center -graphics.pathline["pathlines-1"] = { - "field": "time", - "accuracy_control": { - "tolerance": 0.001, - }, - "skip": 5, - "release_from_surfaces": ["inlet-1", "inlet-2", "inlet-3"], -} -graphics.pathline["pathlines-1"].display() +pathlines = Pathline.create( + solver, + name="pathlines-1", + field="time", + skip=5, + release_from_surfaces=list(inlets), +) +pathlines.accuracy_control.tolerance = 0.001 +pathlines.display() graphics.views.restore_view(view_name="isometric") graphics.views.auto_scale() @@ -705,11 +700,13 @@ # ~~~~~~~~~~~~~~~~~~ # Create an iso-surface through the manifold geometry. -solver_session.settings.results.surfaces.iso_surface["surf-x-coordinate"] = { - "field": "x-coordinate", - "zones": ["fluid-region-1"], - "iso_values": [0.38], -} +IsoSurface.create( + solver, + name="surf-x-coordinate", + field="x-coordinate", + zones=["fluid-region-1"], + iso_values=[0.38] * m, +) ############################################################################### # Create contours of velocity magnitude @@ -722,22 +719,21 @@ # :width: 500pt # :align: center -graphics.contour["contour-velocity"] = { - "field": "velocity-magnitude", - "surfaces_list": ["surf-x-coordinate"], - "node_values": False, - "range_option": { - "option": "auto-range-on", - "auto_range_on": { - "global_range": False, - }, - }, -} -graphics.mesh["mesh-1"] = { - "surfaces_list": "*", -} -graphics.contour["contour-velocity"].display() +graphics = Graphics(solver) +vel_contour = Contour.create( + solver, + name="contour-velocity", + field="velocity-magnitude", + surfaces_list=["surf-x-coordinate"], + node_values=False, +) +vel_contour.range_option.option = "auto-range-on" +vel_contour.range_option.auto_range_on.global_range = False +mesh_1 = graphics.mesh.create("mesh-1") +mesh_1.surfaces_list = "*" + +vel_contour.display() graphics.views.restore_view(view_name="right") graphics.views.auto_scale() graphics.picture.save_picture(file_name="contour-velocity.png") @@ -753,13 +749,11 @@ # :width: 500pt # :align: center -solver_session.settings.results.scene["scene-1"] = {} -scene1 = solver_session.settings.results.scene["scene-1"] -scene1.graphics_objects.add(name="mesh-1") -scene1.graphics_objects["mesh-1"].transparency = 90 -scene1.graphics_objects.add(name="contour-velocity") -scene1.display() - +scene_1 = Scene.create(solver, name="scene-1") +added_mesh = scene_1.graphics_objects.add(name=mesh_1) +added_mesh.transparency = 90 +scene_1.graphics_objects.add(name=vel_contour.name) +scene_1.display() graphics.views.camera.position = [1.70, 1.14, 0.29] graphics.views.camera.up_vector = [-0.66, 0.72, -0.20] graphics.picture.save_picture(file_name="scene-1.png") @@ -769,4 +763,4 @@ # ~~~~~~~~~~~~ # Close Fluent. -solver_session.exit() +solver.exit() diff --git a/examples/00-fluent/external_compressible_flow.py b/examples/00-fluent/external_compressible_flow.py index 4cb142e3b88..e14f1052851 100644 --- a/examples/00-fluent/external_compressible_flow.py +++ b/examples/00-fluent/external_compressible_flow.py @@ -78,6 +78,16 @@ import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + FluidMaterial, + General, + Initialization, + PressureFarFieldBoundary, + RunCalculation, + Viscous, + write_case, +) +from ansys.units.common import K, Pa, kg, m, s wing_spaceclaim_file, wing_intermediary_file = [ examples.download_file(CAD_file, "pyfluent/external_compressible") @@ -90,22 +100,21 @@ # Launch Fluent as a service in meshing mode with double precision running on # four processors and print Fluent version. -meshing_session = pyfluent.launch_fluent( - precision="double", +meshing = pyfluent.Meshing.from_install( + precision=pyfluent.Precision.DOUBLE, processor_count=4, - mode="meshing", ) -print(meshing_session.get_fluent_version()) +print(meshing.get_fluent_version()) tmpdir = tempfile.mkdtemp() -meshing_session.preferences.MeshingWorkflow.TempFolder = tmpdir +meshing.preferences.MeshingWorkflow.TempFolder = tmpdir ############################################################################### # Initialize workflow # ~~~~~~~~~~~~~~~~~~~ # Initialize the watertight geometry meshing workflow. -meshing_session.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") +meshing.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") ############################################################################### # Watertight geometry meshing workflow @@ -116,7 +125,7 @@ # Import CAD and set length units # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Import the CAD geometry and set the length units to inches. -geo_import = meshing_session.workflow.TaskObject["Import Geometry"] +geo_import = meshing.workflow.TaskObject["Import Geometry"] geo_import.Arguments.set_state( { "FileName": wing_intermediary_file, @@ -129,7 +138,7 @@ # Add local sizing # ~~~~~~~~~~~~~~~~ # Add local sizing controls to the faceted geometry. -local_sizing = meshing_session.workflow.TaskObject["Add Local Sizing"] +local_sizing = meshing.workflow.TaskObject["Add Local Sizing"] local_sizing.Arguments.set_state( { "AddChild": "yes", @@ -168,7 +177,7 @@ # Generate surface mesh # ~~~~~~~~~~~~~~~~~~~~~ # Generate the surface mash. -surface_mesh_gen = meshing_session.workflow.TaskObject["Generate the Surface Mesh"] +surface_mesh_gen = meshing.workflow.TaskObject["Generate the Surface Mesh"] surface_mesh_gen.Arguments.set_state( {"CFDSurfaceMeshControls": {"MaxSize": 1000, "MinSize": 2}} ) @@ -179,7 +188,7 @@ # Describe geometry # ~~~~~~~~~~~~~~~~~ # Describe geometry and define the fluid region. -describe_geo = meshing_session.workflow.TaskObject["Describe Geometry"] +describe_geo = meshing.workflow.TaskObject["Describe Geometry"] describe_geo.UpdateChildTasks(SetupTypeChanged=False) describe_geo.Arguments.set_state( @@ -195,21 +204,21 @@ # ~~~~~~~~~~~~~~~~~ # Update the boundaries. -meshing_session.workflow.TaskObject["Update Boundaries"].Execute() +meshing.workflow.TaskObject["Update Boundaries"].Execute() ############################################################################### # Update regions # ~~~~~~~~~~~~~~ # Update the regions. -meshing_session.workflow.TaskObject["Update Regions"].Execute() +meshing.workflow.TaskObject["Update Regions"].Execute() ############################################################################### # Add boundary layers # ~~~~~~~~~~~~~~~~~~~ # Add boundary layers, which consist of setting properties for the # boundary layer mesh. -add_boundary_layer = meshing_session.workflow.TaskObject["Add Boundary Layers"] +add_boundary_layer = meshing.workflow.TaskObject["Add Boundary Layers"] add_boundary_layer.Arguments.set_state({"NumberOfLayers": 12}) add_boundary_layer.AddChildAndUpdate() @@ -219,7 +228,7 @@ # ~~~~~~~~~~~~~~~~~~~~ # Generate the volume mesh, which consists of setting properties for the # volume mesh. -volume_mesh_gen = meshing_session.workflow.TaskObject["Generate the Volume Mesh"] +volume_mesh_gen = meshing.workflow.TaskObject["Generate the Volume Mesh"] volume_mesh_gen.Arguments.set_state( { "VolumeFill": "poly-hexcore", @@ -238,14 +247,14 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ # Check the mesh in meshing mode. -meshing_session.tui.mesh.check_mesh() +meshing.tui.mesh.check_mesh() ############################################################################### # Save mesh file # ~~~~~~~~~~~~~~ # Save the mesh file (``wing.msh.h5``). -meshing_session.meshing.File.WriteMesh(FileName="wing.msh.h5") +meshing.meshing.File.WriteMesh(FileName="wing.msh.h5") ############################################################################### # Solve and postprocess @@ -259,7 +268,7 @@ # using Fluent in meshing mode, you can switch to solver mode to complete the # setup of the simulation. -solver_session = meshing_session.switch_to_solver() +solver = meshing.switch_to_solver() ############################################################################### # Check mesh in solver mode @@ -269,7 +278,7 @@ # reports a number of other mesh features that are checked. Any errors in the # mesh are reported. -solver_session.settings.mesh.check() +solver.settings.mesh.check() ############################################################################### # Define model @@ -279,24 +288,17 @@ # model : k-omega # k-omega model : sst -viscous = solver_session.settings.setup.models.viscous +viscous = Viscous(solver) -viscous.model = "k-omega" -viscous.k_omega_model = "sst" +viscous.model = viscous.model.K_OMEGA +viscous.k_omega_model = viscous.k_omega_model.SST ############################################################################### # Define materials # ~~~~~~~~~~~~~~~~ # Modify the default material ``air`` to account for compressibility and variations of the thermophysical properties with temperature. -# density : ideal-gas -# viscosity : sutherland -# viscosity method : three-coefficient-method -# reference viscosity : 1.716e-05 [kg/(m s)] -# reference temperature : 273.11 [K] -# effective temperature : 110.56 [K] - -air = solver_session.settings.setup.materials.fluid["air"] +air = FluidMaterial.get(solver, name="air") air.density.option = "ideal-gas" @@ -304,92 +306,76 @@ air.viscosity.sutherland.option = "three-coefficient-method" -air.viscosity.sutherland.reference_viscosity = 1.716e-05 +air.viscosity.sutherland.reference_viscosity = 1.716e-05 * kg / (m * s) -air.viscosity.sutherland.reference_temperature = 273.11 +air.viscosity.sutherland.reference_temperature = 273.11 * K -air.viscosity.sutherland.effective_temperature = 110.56 +air.viscosity.sutherland.effective_temperature = 110.56 * K ############################################################################### # Boundary Conditions # ~~~~~~~~~~~~~~~~~~~ # Set the boundary conditions for ``pressure_farfield``. -# gauge pressure : 0 [Pa] -# mach number : 0.8395 -# temperature : 255.56 [K] -# x-component of flow direction : 0.998574 -# z-component of flow direction : 0.053382 -# turbulent intensity : 5 [%] -# turbulent viscosity ratio : 10 - -pressure_farfield = ( - solver_session.settings.setup.boundary_conditions.pressure_far_field[ - "pressure_farfield" - ] -) +pressure_far_field = PressureFarFieldBoundary.get(solver, name="pressure_farfield") -pressure_farfield.momentum.gauge_pressure = 0 +pressure_far_field.momentum.gauge_pressure = 0 * Pa -pressure_farfield.momentum.mach_number = 0.8395 +pressure_far_field.momentum.mach_number = 0.8395 -pressure_farfield.thermal.temperature = 255.56 +pressure_far_field.thermal.temperature = 255.56 * K -pressure_farfield.momentum.flow_direction[0] = 0.998574 +pressure_far_field.momentum.flow_direction[0] = 0.998574 # x-component -pressure_farfield.momentum.flow_direction[2] = 0.053382 +pressure_far_field.momentum.flow_direction[2] = 0.053382 # z-component -pressure_farfield.turbulence.turbulent_intensity = 0.05 +pressure_far_field.turbulence.turbulent_intensity = 0.05 -pressure_farfield.turbulence.turbulent_viscosity_ratio = 10 +pressure_far_field.turbulence.turbulent_viscosity_ratio = 10 ############################################################################### # Operating Conditions # ~~~~~~~~~~~~~~~~~~~~ # Set the operating conditions. -# operating pressure : 80600 [Pa] - -solver_session.settings.setup.general.operating_conditions.operating_pressure = 80600 +general = General(solver) +general.operating_conditions.operating_pressure = 80_600 * Pa ############################################################################### # Initialize flow field # ~~~~~~~~~~~~~~~~~~~~~ # Initialize the flow field using hybrid initialization. -solver_session.settings.solution.initialization.hybrid_initialize() +initialize = Initialization(solver) +initialize.hybrid_initialize() ############################################################################### # Save case file # ~~~~~~~~~~~~~~ # Save the case file ``external_compressible1.cas.h5``. -solver_session.settings.file.write( - file_name="external_compressible.cas.h5", file_type="case" -) +write_case(solver, file_name="external_compressible.cas.h5") ############################################################################### # Solve for 25 iterations # ~~~~~~~~~~~~~~~~~~~~~~~~ # Solve for 25 iterations (100 iterations is recommended, however for this example 25 is sufficient). -solver_session.settings.solution.run_calculation.iterate(iter_count=25) +RunCalculation(solver).iterate(iter_count=25) ############################################################################### # Write final case file and data # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Write the final case file and the data. -solver_session.settings.file.write( - file_name="external_compressible1.cas.h5", file_type="case" -) +write_case(solver, file_name="external_compressible1.cas.h5") ############################################################################### # Close Fluent # ~~~~~~~~~~~~ # Close Fluent. -solver_session.exit() +solver.exit() shutil.rmtree(tmpdir, ignore_errors=True) shutil.rmtree("wing_workflow_files", ignore_errors=True) diff --git a/examples/00-fluent/frozen_rotor_workflow.py b/examples/00-fluent/frozen_rotor_workflow.py index a789437dc28..56804b45a3d 100644 --- a/examples/00-fluent/frozen_rotor_workflow.py +++ b/examples/00-fluent/frozen_rotor_workflow.py @@ -1,6 +1,7 @@ # /// script # dependencies = [ # "ansys-fluent-core", +# "ansys-fluent-visualization", # ] # /// @@ -80,10 +81,35 @@ # Import required libraries/modules # ============================================================================================================== import math -import os +from pathlib import Path import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import ( + BoundaryConditions, + FluidCellZone, + General, + Initialization, + MassFlowOutlet, + Materials, + MeshInterfaces, + Methods, + Monitor, + NamedExpression, + PlaneSurface, + PressureInlet, + ReportDefinitions, + ReportPlot, + RunCalculation, + Setup, + Viscous, + WallBoundary, + write_case, + write_case_data, +) +from ansys.fluent.visualization import Contour, Graphics +from ansys.units import VariableCatalog +from ansys.units.common import Pa, kg, m, s ################################################################################################################ # Download the mesh file @@ -94,37 +120,40 @@ impeller_mesh = examples.download_file( "impeller.msh.h5", "pyfluent/examples/pump-volute", - save_path=os.getcwd(), + save_path=Path.cwd(), ) volute_mesh = examples.download_file( "volute.msh.h5", "pyfluent/examples/pump-volute", - save_path=os.getcwd(), + save_path=Path.cwd(), ) + ################################################################################################################ # Define Constants # ============================================================================================================== -density_water = 998.2 # kg/m^3 -viscosity_water = 0.001002 # kg/(m.s) -g = 9.81 # m/s^2 -# Impeller speed +density_water = 998.2 * kg / m**3 +viscosity_water = 0.001002 * Pa * s +g = 9.81 * m / s**2 impeller_speed = 1450 # rpm # Convert to rad/s -impeller_speed_rad = impeller_speed * 2 * math.pi / 60 # rad/s +impeller_speed_rad = impeller_speed * 2 * math.pi / 60 ################################################################################################################ # Launch Fluent with solver mode and print Fluent version # ============================================================================================================== -solver_session = pyfluent.launch_fluent( - mode="solver", +solver = pyfluent.Solver.from_install( processor_count=4, cleanup_on_exit=True, ) -print(solver_session.get_fluent_version()) +print(solver.get_fluent_version()) + +# upload mesh files to the solver +solver.upload(impeller_mesh) +solver.upload(volute_mesh) ################################################################################################################ @@ -132,19 +161,19 @@ # ============================================================================================================== # Read Impeller mesh file -solver_session.settings.file.read_mesh(file_name=impeller_mesh) +solver.settings.file.read_mesh(file_name=impeller_mesh) # Append Volute mesh file -solver_session.settings.mesh.modify_zones.append_mesh(file_name=volute_mesh) +solver.settings.mesh.modify_zones.append_mesh(file_name=volute_mesh) ################################################################################################################ # Display the mesh # ============================================================================================================== # Access the graphics object -graphics = solver_session.settings.results.graphics +graphics = Graphics(solver) # Create a mesh object and configure its settings -mesh_object = solver_session.settings.results.graphics.mesh.create(name="mesh-1") +mesh_object = graphics.mesh.create(name="mesh-1") mesh_object.surfaces_list = [ "inlet", "mass-flow-inlet-11", @@ -183,108 +212,88 @@ # Set the unit for angular velocity, rad/s to rev/min # ============================================================================================================== -solver_session.settings.setup.general.units.set_units( - quantity="angular-velocity", units_name="rev/min" -) +general = General(solver) +general.units.set_units(quantity="angular-velocity", units_name="rev/min") ################################################################################################################ # Define the Viscous Model # ============================================================================================================== # Models setting -viscous = solver_session.settings.setup.models.viscous -viscous = solver_session.settings.setup.models.viscous -viscous.model = "k-omega" -viscous.k_omega_model = "sst" +viscous = Viscous(solver) +viscous.model = viscous.model.K_OMEGA +viscous.k_omega_model = viscous.k_omega_model.SST ################################################################################################################ # Define Materials # ============================================================================================================== -solver_session.settings.setup.materials.database.copy_by_name( - type="fluid", name="water-liquid" -) +Materials(solver).database.copy_by_name(type="fluid", name="water-liquid") ################################################################################################################ # Define Cell Zone Conditions # ============================================================================================================== -impeller_cell_zone = solver_session.settings.setup.cell_zone_conditions.fluid[ - "impeller" -] +impeller_cell_zone = FluidCellZone.get(solver, name="impeller") impeller_cell_zone.general.material = "water-liquid" -impeller_cell_zone.reference_frame.reference_frame_axis_origin = [0, 0, 0] -impeller_cell_zone.reference_frame.reference_frame_axis_direction = [0, 0, 1] +impeller_cell_zone.reference_frame.reference_frame_axis_origin = (0, 0, 0) +impeller_cell_zone.reference_frame.reference_frame_axis_direction = (0, 0, 1) impeller_cell_zone.reference_frame.frame_motion = True -# impeller rotation -impeller_cell_zone.reference_frame.mrf_omega.value = impeller_speed_rad +impeller_cell_zone.reference_frame.mrf_omega = impeller_speed_rad -# Volute Cell Zone Conditions -volute_cell_zone = solver_session.settings.setup.cell_zone_conditions.fluid["volute"] +volute_cell_zone = FluidCellZone.get(solver, name="volute") volute_cell_zone.general.material = "water-liquid" # Boundary Conditions -# impeller hub -impeller_hub = solver_session.settings.setup.boundary_conditions.wall[ - "impeller-hub" -].momentum -impeller_hub.wall_motion = "Moving Wall" -impeller_hub.relative = True -impeller_hub.velocity_spec = "Rotational" - -# inblock-shroud - -inblock_shroud = solver_session.settings.setup.boundary_conditions.wall[ - "inblock-shroud" -].momentum -inblock_shroud.wall_motion = "Moving Wall" -inblock_shroud.relative = False -inblock_shroud.velocity_spec = "Rotational" +impeller_hub = WallBoundary.get(solver, name="impeller-hub") +impeller_hub.momentum.wall_motion = impeller_hub.momentum.wall_motion.MOVING_WALL +impeller_hub.momentum.relative = True +impeller_hub.momentum.velocity_spec = impeller_hub.momentum.velocity_spec.ROTATIONAL + +inblock_shroud = WallBoundary.get(solver, name="inblock-shroud") +inblock_shroud.momentum.wall_motion = inblock_shroud.momentum.wall_motion.MOVING_WALL +inblock_shroud.momentum.relative = False +inblock_shroud.momentum.velocity_spec = "Rotational" ################################################################################################################ # Define Boundary Conditions # ============================================================================================================== # Inlet Boundary Condition -pressure_inlet = solver_session.settings.setup.boundary_conditions.pressure_inlet[ - "inlet" -] -pressure_inlet.momentum.supersonic_or_initial_gauge_pressure.value = -100 +pressure_inlet = PressureInlet.get(solver, name="inlet") +pressure_inlet.momentum.supersonic_or_initial_gauge_pressure = -100 * Pa # It seems, need to change the boundary condition to mass flow outlet -solver_session.settings.setup.boundary_conditions.set_zone_type( +BoundaryConditions(solver).set_zone_type( zone_list=["mass-flow-inlet-11"], new_type="mass-flow-outlet" ) # Outlet Boundary Condition -mass_flow_outlet = solver_session.settings.setup.boundary_conditions.mass_flow_outlet[ - "mass-flow-inlet-11" -] -mass_flow_outlet.momentum.mass_flow_rate.value = 90 # kg/s +mass_flow_outlet = MassFlowOutlet.get(solver, name="mass-flow-inlet-11") +mass_flow_outlet.momentum.mass_flow_rate.value = 90 * kg / s # Create a turbo interfaces # enable the turbo models -solver_session.settings.setup.turbo_models.enabled = True - -impeller_volute_interface = ( - solver_session.settings.setup.mesh_interfaces.turbo_create.create( - adjacent_cell_zone_1="impeller", - adjacent_cell_zone_2="volute", - mesh_interface_name="imp-volute-interface", - turbo_choice="No-Pitch-Scale", - zone1="interface-impeller-outlet", - zone2="interface-volute-inlet", - ) +turbo_models = Setup(solver).turbo_models +turbo_models.enabled = True + +impeller_volute_interface = MeshInterfaces(solver).turbo_create.create( + adjacent_cell_zone_1="impeller", + adjacent_cell_zone_2="volute", + mesh_interface_name="imp-volute-interface", + turbo_choice="No-Pitch-Scale", + zone1="interface-impeller-outlet", + zone2="interface-volute-inlet", ) ################################################################################################################ # Define Solver Settings # ============================================================================================================== -methods = solver_session.settings.solution.methods +methods = Methods(solver) methods.spatial_discretization.gradient_scheme = "green-gauss-node-based" methods.high_order_term_relaxation.enable = True @@ -292,80 +301,77 @@ # Define Named Expressions # ============================================================================================================== -pump_head = solver_session.settings.setup.named_expressions.create("head") -pump_head.definition = "(({p-out} - {p-in}) / (998.2 [kg/m^3] * 9.81[m/s^2]))" -pump_head.output_parameter = True +pump_head = NamedExpression.create( + solver, + name="head", + definition="(({p-out} - {p-in}) / (998.2 [kg/m^3] * 9.81[m/s^2]))", + output_parameter=True, +) ################################################################################################################ # Define Report Definitions # ============================================================================================================== +monitor = Monitor(solver) +report_definitions = ReportDefinitions(solver) + # Create a report definition # p-out -outlet_pressure_report_def = ( - solver_session.settings.solution.report_definitions.surface.create("p-out") +outlet_pressure_report_def = report_definitions.surface.create( + "p-out", + report_type="surface-massavg", + surface_names=["mass-flow-inlet-11"], + field="total-pressure", + per_surface=False, ) -outlet_pressure_report_def.report_type = "surface-massavg" -outlet_pressure_report_def.surface_names = ["mass-flow-inlet-11"] -outlet_pressure_report_def.field = "total-pressure" -outlet_pressure_report_def.per_surface = False -outlet_pressure_report_plot = ( - solver_session.settings.solution.monitor.report_plots.create("p-out-rplot") +outlet_pressure_report_plot = ReportPlot( + solver, name="p-out-rplot", report_defs="p-out" ) -outlet_pressure_report_plot.report_defs = "p-out" -outlet_pressure_report_file = ( - solver_session.settings.solution.monitor.report_files.create("p-out-rfile") +outlet_pressure_report_file = ReportPlot( + solver, name="p-out-rfile", report_defs="p-out" ) -outlet_pressure_report_file.report_defs = "p-out" # p-in -inlet_pressure_report_def = ( - solver_session.settings.solution.report_definitions.surface.create("p-in") +inlet_pressure_report_def = report_definitions.surface.create( + "p-in", + report_type="surface-massavg", + surface_names=["inlet"], + field="total-pressure", + per_surface=False, ) -inlet_pressure_report_def.report_type = "surface-massavg" -inlet_pressure_report_def.surface_names = ["inlet"] -inlet_pressure_report_def.field = "total-pressure" -inlet_pressure_report_def.per_surface = False # Pump Head -pump_head_report_def = ( - solver_session.settings.solution.report_definitions.single_valued_expression.create( - "pump-head" - ) -) +pump_head_report_def = report_definitions.single_valued_expression.create("pump-head") pump_head_report_def.definition = "head" # report plot -pump_head_report_plot = solver_session.settings.solution.monitor.report_plots.create( - "pump-head-rplot" +pump_head_report_plot = monitor.report_plots.create( + "pump-head-rplot", report_defs=pump_head_report_def ) -pump_head_report_plot.report_defs = "pump-head" # report file -pump_head_report_file = solver_session.settings.solution.monitor.report_files.create( - "pump-head-rfile" +pump_head_report_file = monitor.report_files.create( + "pump-head-rfile", report_defs=pump_head_report_def ) -pump_head_report_file.report_defs = "pump-head" # p-blade -blade_pressure_report_def = ( - solver_session.settings.solution.report_definitions.surface.create("p-blade") +blade_pressure_report_def = report_definitions.surface.create( + "p-blade", + report_type="surface-massavg", + surface_names=["blade"], + field="pressure", + per_surface=False, ) -blade_pressure_report_def.report_type = "surface-massavg" -blade_pressure_report_def.surface_names = ["blade"] -blade_pressure_report_def.field = "pressure" -blade_pressure_report_def.per_surface = False - ################################################################################################################ # Initialization and run solver # ============================================================================================================== -initialization = solver_session.settings.solution.initialization +initialization = Initialization(solver) initialization.reference_frame = "absolute" initialization.hybrid_init_options.general_settings.initialization_options.initial_pressure = ( True @@ -373,14 +379,12 @@ initialization.hybrid_initialize() # Run calculation settings -run_calculation = solver_session.settings.solution.run_calculation +run_calculation = RunCalculation(solver) run_calculation.pseudo_time_settings.time_step_method.time_step_size_scale_factor = 10 run_calculation.iter_count = 200 # Write the case file -solver_session.settings.file.write( - file_type="case", file_name="pump_voulte_setup.cas.h5" -) +write_case(solver, file_name="pump_volute_setup.cas.h5") # Run the calculation run_calculation.calculate() @@ -389,24 +393,18 @@ # ============================================================================================================== # Create a mid-plane surface at z = -0.015 m -z_mid_plane = solver_session.settings.results.surfaces.plane_surface.create( - name="z_mid_plane" +z_mid_plane = PlaneSurface.create( + solver, name="z_mid_plane", method="xy-plane", z=-0.015 ) -z_mid_plane.method = "xy-plane" -z_mid_plane.z = -0.015 z_mid_plane.display() -# Define the contour for static pressure -pressure_contour = solver_session.settings.results.graphics.contour.create( - name="static-pressure-contour" +# Define and display the contour for static pressure using typed API +graphics = Graphics(solver) +pressure_contour = Contour.create( + solver=solver, field=VariableCatalog.PRESSURE, surfaces=["z_mid_plane"] ) -pressure_contour.field = "pressure" -pressure_contour.surfaces_list = ["z_mid_plane"] - -# Display the contour and save the image - -graphics.views.restore_view(view_name="front") pressure_contour.display() +graphics.views.restore_view(view_name="front") graphics.views.auto_scale() graphics.picture.save_picture(file_name="static-pressure-contour.png") @@ -419,14 +417,12 @@ ################################################################################################################ # Save the case file # ============================================================================================================== -solver_session.settings.file.write( - file_type="case-data", file_name="pump_volute_setup_solved.cas.h5" -) +write_case_data(solver, file_name="pump_volute_setup_solved.cas.h5") ################################################################################################################ # Close the session # ============================================================================================================== -solver_session.exit() +solver.exit() ################################################################################################################ # References diff --git a/examples/00-fluent/fsi_1way_workflow.py b/examples/00-fluent/fsi_1way_workflow.py index 8bba0da9184..e8a2553e4cc 100644 --- a/examples/00-fluent/fsi_1way_workflow.py +++ b/examples/00-fluent/fsi_1way_workflow.py @@ -1,3 +1,9 @@ +# /// script +# dependencies = [ +# "ansys-fluent-core", +# ] +# /// + # Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -67,29 +73,35 @@ # Importing the following classes offer streamlined access to key solver settings, # eliminating the need to manually browse through the full settings structure. -import os +from pathlib import Path import ansys.fluent.core as pyfluent -from ansys.fluent.core import FluentMode, Precision, examples +from ansys.fluent.core import examples from ansys.fluent.core.solver import ( - BoundaryConditions, + BoundaryCondition, Contour, + Controls, Graphics, Initialization, - RunCalculation, + Materials, Setup, - Solution, + SolidCellZone, + Structure, VelocityInlet, + WallBoundary, + iterate, + read_case, + write_case, + write_case_data, ) +from ansys.units import VariableCatalog +from ansys.units.common import m, s # %% # Launch Fluent session in solver mode # ------------------------------------ -solver = pyfluent.launch_fluent( - precision=Precision.DOUBLE, - mode=FluentMode.SOLVER, -) +solver = pyfluent.Solver.from_install(precision=pyfluent.Precision.DOUBLE) # %% # Download and read the mesh file @@ -98,16 +110,16 @@ mesh_file = examples.download_file( "fsi_1way.msh.h5", "pyfluent/fsi_1way", - save_path=os.getcwd(), + save_path=Path.cwd(), ) -solver.settings.file.read_case(file_name=mesh_file) +read_case(solver, file_name=mesh_file) # %% # Configure solver settings for fluid flow # ---------------------------------------- -velocity_inlet = VelocityInlet(solver, name="velocity_inlet") -velocity_inlet.momentum.velocity_magnitude = 100.0 # High-speed inlet flow (m/s) +velocity_inlet = VelocityInlet.get(solver, name="velocity_inlet") +velocity_inlet.momentum.velocity_magnitude = 100.0 * m / s # High-speed inlet flow velocity_inlet.turbulence.turbulent_viscosity_ratio = ( 5 # Dimensionless, typically 1-10 for moderate turbulence ) @@ -119,8 +131,7 @@ initialize = Initialization(solver) initialize.hybrid_initialize() -calculation = RunCalculation(solver) -calculation.iterate(iter_count=100) +iterate(solver, iter_count=100) # %% # Post-processing @@ -130,13 +141,14 @@ graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio -graphics.contour["contour-vel"] = { - "field": "velocity-magnitude", - "surfaces_list": ["fluid-symmetry"], - "coloring": {"option": "banded"}, -} - -graphics.contour["contour-vel"].display() +contour_vel = Contour.create( + solver, + name="contour-vel", + field=VariableCatalog.VELOCITY_MAGNITUDE, + surfaces_list=["fluid-symmetry"], +) +contour_vel.colorings.banded = True +contour_vel.display() graphics.views.restore_view(view_name="front") graphics.picture.save_picture(file_name="fsi_1way_2.png") @@ -154,12 +166,13 @@ # Linear Elasticity Structural model is chosen setup = Setup(solver) -setup.models.structure.model = "linear-elasticity" +structure = Structure(solver) +structure.model = "linear-elasticity" # Copy materials from the database and assign to solid zone - -setup.materials.database.copy_by_name(type="solid", name="steel") -setup.cell_zone_conditions.solid["solid"] = {"general": {"material": "steel"}} +steel = Materials(solver).database.copy_by_name(type="solid", name="steel") +solid_zone = SolidCellZone.get(solver, name="solid") +solid_zone.general.material = steel # %% # Structural boundary conditions @@ -167,39 +180,28 @@ # configure Fluent to define the steel probe's support and movement using # structural boundary conditions -wall_boundary = BoundaryConditions(solver) - # Configure solid-symmetry boundary -wall_boundary.wall["solid-symmetry"] = { - "structure": { - "z_disp_boundary_value": 0, - "z_disp_boundary_condition": "Node Z-Displacement", - } -} +solid_sym = WallBoundary.get(solver, name="solid-symmetry") +solid_sym.structure.z_disp_boundary_value = 0 +solid_sym.structure.z_disp_boundary_condition = "Node Z-Displacement" # Set solid-top boundary (fully fixed) -wall_boundary.wall["solid-top"] = { - "structure": { - "z_disp_boundary_value": 0, - "z_disp_boundary_condition": "Node Z-Displacement", - "y_disp_boundary_value": 0, - "y_disp_boundary_condition": "Node Y-Displacement", - "x_disp_boundary_value": 0, - "x_disp_boundary_condition": "Node X-Displacement", - } -} - -# Copy boundary conditions from solid-symmetry to solid-symmetry:011 -wall_boundary.copy(from_="solid-symmetry", to=["solid-symmetry:011"]) +solid_top = WallBoundary.get(solver, name="solid-top") +solid_top.structure.z_disp_boundary_value = 0 +solid_top.structure.z_disp_boundary_condition = "Node Z-Displacement" +solid_top.structure.y_disp_boundary_value = 0 +solid_top.structure.y_disp_boundary_condition = "Node Y-Displacement" +solid_top.structure.x_disp_boundary_value = 0 +solid_top.structure.x_disp_boundary_condition = "Node X-Displacement" + +# Copy boundary conditions +BoundaryCondition(solver).copy(from_="solid-symmetry", to=["solid-symmetry:011"]) # Configure FSI surface -wall_boundary.wall["fsisurface-solid"] = { - "structure": { - "x_disp_boundary_condition": "Intrinsic FSI", - "y_disp_boundary_condition": "Intrinsic FSI", - "z_disp_boundary_condition": "Intrinsic FSI", - } -} +fsisurface = WallBoundary.get(solver, name="fsisurface-solid") +fsisurface.structure.x_disp_boundary_condition = "Intrinsic FSI" +fsisurface.structure.y_disp_boundary_condition = "Intrinsic FSI" +fsisurface.structure.z_disp_boundary_condition = "Intrinsic FSI" # %% # Inclusion of Operating Pressure in Fluid-Structure Interaction Forces @@ -207,40 +209,42 @@ # Fluent uses gauge pressure for fluid-structure interaction force calculations. # By setting ``include_pop_in_fsi_force`` to ``True``, Fluent uses absolute pressure. -setup.models.structure.expert.include_pop_in_fsi_force = True +structure.expert.include_pop_in_fsi_force = True # %% # Configure flow settings # ----------------------- # Disable flow equations for structural simulation -solution = Solution(solver) -solution.controls.equations["flow"] = False -solution.controls.equations["kw"] = False +controls = Controls(solver) +controls.equations["flow"] = False +controls.equations["kw"] = False # %% # Run FSI simulation # ------------------ -solver.settings.file.write_case(file_name="probe_fsi_1way.cas.h5") +write_case(solver, file_name="probe_fsi_1way.cas.h5") -calculation.iterate(iter_count=2) +iterate(solver, iter_count=2) # %% # Structural Postprocessing # ------------------------- -displacement_contour = Contour(solver, new_instance_name="displacement_contour") - -displacement_contour.field = "total-displacement" -displacement_contour.surfaces_list = ["fsisurface-solid"] +displacement_contour = Contour.create( + solver, + name="displacement_contour", + field=VariableCatalog.TOTAL_DISPLACEMENT, + surfaces_list=["fsisurface-solid"], +) displacement_contour.display() graphics.views.restore_view(view_name="isometric") graphics.picture.save_picture(file_name="fsi_1way_3.png") # save the case and data file -solver.settings.file.write_case_data(file_name="probe_fsi_1way") +write_case_data(solver, file_name="probe_fsi_1way") # %% # .. image:: ../../_static/fsi_1way_3.png diff --git a/examples/00-fluent/lunar_lander_thermal.py b/examples/00-fluent/lunar_lander_thermal.py index ee93a571f90..7ebb9e50a18 100644 --- a/examples/00-fluent/lunar_lander_thermal.py +++ b/examples/00-fluent/lunar_lander_thermal.py @@ -95,18 +95,38 @@ # flake8: noqa: E402 from itertools import chain -import os +from pathlib import Path import numpy as np import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.session_solver import Solver +from ansys.fluent.core.solver import ( + BoundaryCondition, + CellZoneCondition, + Energy, + General, + Initialization, + Monitor, + Radiation, + ReportDefinitions, + RunCalculation, + SolidCellZone, + SolidMaterial, + Viscous, + WallBoundary, + calculate, + write_case, +) +from ansys.units import VariableCatalog +from ansys.units.common import J, K, W, kg, m, s lander_spaceclaim_file, lander_mesh_file, apollo17_temp_data = [ examples.download_file( f, "pyfluent/lunar_lander_thermal", - save_path=os.getcwd(), + save_path=Path.cwd(), ) for f in [ "lander_geom.scdoc", @@ -133,15 +153,15 @@ # Lunar axial obliquity relative to ecliptic moon_obliquity = np.deg2rad(1.54) -# Louver setpoint temperature [K] -louver_setpoint_temp = 273 +# Louver setpoint temperature +louver_setpoint_temp = 273 * K # Lander coordinates (Apollo 17 landing site) land_lat = np.deg2rad(20.1908) land_lon = np.deg2rad(30.7717) # Timestep size of 1 Earth day -step_size = 86400 +step_size = 86400 * s # Run simulation for 60 Earth days n_steps = 60 @@ -235,7 +255,7 @@ def sun_vec_to_beam_dir( def get_surf_mean_temp( surf_names: list[str], - solver: pyfluent.session_solver.Solver, + solver: Solver, ) -> float: """Calculate mean surface temperature.""" # Get surface IDs @@ -263,18 +283,17 @@ def get_surf_mean_temp( # Launch Fluent and print Fluent version # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -solver_session = pyfluent.launch_fluent( - precision="double", +solver = pyfluent.Solver.from_install( + precision=pyfluent.Precision.DOUBLE, processor_count=12, - mode="solver", ) -print(solver_session.get_fluent_version()) +print(solver.get_fluent_version()) ############################################################################### # Load the mesh # ~~~~~~~~~~~~~ -solver_session.settings.file.read_mesh(file_name=lander_mesh_file) +solver.settings.file.read_mesh(file_name=lander_mesh_file) ############################################################################### # Case Setup @@ -288,11 +307,10 @@ def get_surf_mean_temp( # Since we are only running 1 timestep at a time, the time step count is set to # 1. -# Set solution to transient -solver_session.settings.setup.general.solver.time = "unsteady-2nd-order" +general = General(solver) +general.solver.time = "unsteady-2nd-order" -# Set transient settings -trans_controls = solver_session.settings.solution.run_calculation.transient_controls +trans_controls = RunCalculation(solver).transient_controls trans_controls.type = "Fixed" trans_controls.max_iter_per_time_step = 20 trans_controls.time_step_count = 1 @@ -304,9 +322,11 @@ def get_surf_mean_temp( # Enable the energy model. Since fluid flow is not simulated, we will set the # viscosity model to laminar. -models = solver_session.settings.setup.models -models.energy.enabled = True -models.viscous.model = "laminar" +energy = Energy(solver) +energy.enabled = True + +viscous = Viscous(solver) +viscous.model = "laminar" ############################################################################### # Set up radiation model @@ -322,23 +342,15 @@ def get_surf_mean_temp( # space industry best practices [4_]. -# Set up radiation model -radiation = models.radiation +radiation = Radiation(solver) radiation.model = "monte-carlo" radiation.monte_carlo.number_of_histories = 1e7 -# Define range of solar wavelengths -radiation.multiband["solar"] = { - "start": 0, - "end": 2.8, -} -# Define range of thermal IR wavelengths -radiation.multiband["thermal-ir"] = { - "start": 2.8, - "end": 100, -} - -# Solve radiation once per timestep +radiation.multiband["solar"].start = 0 +radiation.multiband["solar"].end = 2.8 +radiation.multiband["thermal-ir"].start = 2.8 +radiation.multiband["thermal-ir"].end = 100 + radiation_freq = radiation.solve_frequency radiation_freq.method = "time-step" radiation_freq.time_step_interval = 1 @@ -351,38 +363,25 @@ def get_surf_mean_temp( # (soil). The thermal conductivity of the regolith and the surface 'fluff' is # strongly temperature-dependent and so must be modelled using an expression. -# --- Properties of vacuum --- -# Thermal conductivity: 0 - -vacuum = solver_session.settings.setup.materials.solid.create("vacuum") -vacuum.chemical_formula = "" -vacuum.thermal_conductivity.value = 0 -vacuum.absorption_coefficient.value = 0 -vacuum.refractive_index.value = 1 - -# --- Properties of fluff (see ref. [2]) --- -# Density: 1000 [kg m^-3] -# Specific heat capacity: 1050 [J kg^-1 K^-1] -# Thermal conductivity: 9.22e-4*(1 + 1.48*(temperature/350 K)^3) [W m^-1 K^-1] +vacuum = SolidMaterial.create( + solver, + name="vacuum", + thermal_conductivity=0 * W / (m * K), + absorption_coefficient=0, + refractive_index=1, +) -fluff = solver_session.settings.setup.materials.solid.create("fluff") -fluff.chemical_formula = "" -fluff.density.value = 1000 -fluff.specific_heat.value = 1050 +fluff = SolidMaterial.create( + solver, name="fluff", density=1000 * kg / m**3, specific_heat=1050 * J / (kg * K) +) fluff.thermal_conductivity.option = "expression" fluff.thermal_conductivity.expression = ( "9.22e-4[W m^-1 K^-1]*(1 + 1.48*(StaticTemperature/350[K])^3)" ) -# --- Properties of regolith (see ref. [2]) --- -# Density: 2000 [kg m^-3] -# Specific heat capacity: 1050 [J kg^-1 K^-1] -# Thermal conductivity: 9.30e-4*(1 + 0.73*(temperature/350 K)^3) [W m^-1 K^-1] - -regolith = solver_session.settings.setup.materials.solid.create("regolith") -regolith.chemical_formula = "" -regolith.density.value = 2000 -regolith.specific_heat.value = 1050 +regolith = SolidMaterial.create( + solver, name="regolith", density=2000 * kg / m**3, specific_heat=1050 * J / (kg * K) +) regolith.thermal_conductivity.option = "expression" regolith.thermal_conductivity.expression = ( "9.30e-4[W m^-1 K^-1]*(1 + 0.73*(StaticTemperature/350[K])^3)" @@ -396,12 +395,13 @@ def get_surf_mean_temp( # lander. This cell zone must be set to be a solid so that the fluid equations # are not solved there, then it must be assigned to the vacuum material. -cellzones = solver_session.settings.setup.cell_zone_conditions -cellzones.set_zone_type( +CellZoneCondition(solver).set_zone_type( zone_list=["geom-2_domain"], new_type="solid", ) -cellzones.solid["geom-2_domain"].material = "vacuum" + +vacuum_zone = SolidCellZone.get(solver, name="geom-2_domain") +vacuum_zone.general.material = vacuum ############################################################################### # Regolith boundary condition @@ -411,15 +411,9 @@ def get_surf_mean_temp( # used to represent the geothermal heat from the Moon's interior that heats # the regolith from the bottom. -# --- Regolith BC --- -# Thickness of layers: 0.02, 0.04, 0.08, 0.16, 0.32 [m] -# Heating at base: 0.031 [W m^-2] -# Surface absorptivity: 0.87 -# Surface emissivity: 0.97 +regolith_bc = WallBoundary.get(solver, name="regolith") -regolith_bc = solver_session.settings.setup.boundary_conditions.wall["regolith"] - -regolith_bc.thermal.q.value = 0.031 +regolith_bc.thermal.q = 0.031 * W / m**2 regolith_bc.thermal.planar_conduction = True regolith_bc.thermal.shell_conduction = [ { @@ -451,24 +445,23 @@ def get_surf_mean_temp( # The space boundary condition represents deep space and also acts as the # source of the Sun's illumination in the simulation. -# --- Set up space boundary condition --- -# Temperature: 3 [K] -# Emissivity: 1 -# Absorptivity: 1 -# Solar flux: 1414 [W m^-2] - -space_bc = solver_session.settings.setup.boundary_conditions.wall["space"] +space_bc = WallBoundary.get(solver, name="space") space_bc.thermal.thermal_bc = "Temperature" -space_bc.thermal.t.value = 3 -space_bc.thermal.material = "vacuum" +space_bc.thermal.t.value = 3 * K +space_bc.thermal.material = vacuum space_bc.radiation.mc_bsource_p = True -space_bc.radiation.direct_irradiation_settings.direct_irradiation["solar"] = 1414 -space_bc.radiation.diffuse_irradiation_settings.diffuse_fraction_band = { - "solar": 0, - "thermal-ir": 0, -} -space_bc.radiation.internal_emissivity_band = {"solar": 1, "thermal-ir": 1} +space_bc.radiation.direct_irradiation_settings.direct_irradiation.create( + "solar", value=1414 * W / m**2 +) +space_bc.radiation.diffuse_irradiation_settings.diffuse_fraction_band.create( + "solar", value=0 +) +space_bc.radiation.diffuse_irradiation_settings.diffuse_fraction_band.create( + "thermal-ir", value=0 +) +space_bc.radiation.internal_emissivity_band.create("solar", value=1) +space_bc.radiation.internal_emissivity_band.create("thermal-ir", value=1) ############################################################################### # Spacecraft walls boundary condition @@ -476,13 +469,7 @@ def get_surf_mean_temp( # The spacecraft is covered in reflective MLI (multilayer insulation) and heat # transfer through the aluminum shell can be simulated using shell conduction. -# --- Set up spacecraft shell boundary condition --- -# Thickness: 0.03 [m] -# Material: aluminum -# Absorptivity: 0.05 -# Emissivity: 0.05 - -sc_mli_bc = solver_session.settings.setup.boundary_conditions.wall["sc-mli"] +sc_mli_bc = WallBoundary.get(solver, name="sc-mli") sc_mli_bc.thermal.planar_conduction = True sc_mli_bc.thermal.shell_conduction = [ @@ -491,7 +478,8 @@ def get_surf_mean_temp( "material": "aluminum", }, ] -sc_mli_bc.radiation.internal_emissivity_band = {"solar": 0.05, "thermal-ir": 0.05} +sc_mli_bc.radiation.internal_emissivity_band.create("solar", value=0.05) +sc_mli_bc.radiation.internal_emissivity_band.create("thermal-ir", value=0.05) ############################################################################### # Spacecraft radiator boundary condition @@ -500,13 +488,7 @@ def get_surf_mean_temp( # walls, but the emissivity is left unset as it will be changed dynamically by # our PyFluent script depending on its temperature during the simulation. -# --- Set up spacecraft radiator boundary condition --- -# Thickness: 0.03 [m] -# Material: aluminum -# Absorptivity: 0.17 -# Emissivity: 0.09 below 273 K, 0.70 otherwise - -sc_rad_bc = solver_session.settings.setup.boundary_conditions.wall["sc-radiator"] +sc_rad_bc = WallBoundary.get(solver, name="sc-radiator") sc_rad_bc.thermal.planar_conduction = True sc_rad_bc.thermal.shell_conduction = [ @@ -515,7 +497,7 @@ def get_surf_mean_temp( "material": "aluminum", }, ] -sc_rad_bc.radiation.internal_emissivity_band = {"solar": 0.17} +sc_rad_bc.radiation.internal_emissivity_band.create("solar", value=0.17) ############################################################################### # Initialize simulation @@ -525,8 +507,8 @@ def get_surf_mean_temp( # definitions on them in the next step. The entire domain will be initialized # to a temperature of 230 K, or -43 °C. -sim_init = solver_session.settings.solution.initialization -sim_init.defaults["temperature"] = 230 +sim_init = Initialization(solver) +sim_init.defaults.temperature = 230 * K sim_init.initialize() ############################################################################### @@ -534,73 +516,79 @@ def get_surf_mean_temp( # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create reports for the spacecraft's minimum, mean, and maximum temperatures. -surf_report_defs = solver_session.settings.solution.report_definitions.surface +report_defs = ReportDefinitions(solver) sc_surfs = ["sc-radiator", "sc-mli"] -surf_report_defs["sc-min-temp"] = { - "surface_names": sc_surfs, - "report_type": "surface-facetmin", - "field": "temperature", -} -surf_report_defs["sc-avg-temp"] = { - "surface_names": sc_surfs, - "report_type": "surface-facetavg", - "field": "temperature", -} -surf_report_defs["sc-max-temp"] = { - "surface_names": sc_surfs, - "report_type": "surface-facetmax", - "field": "temperature", -} - +sc_min_temp = report_defs.surface.create( + name="sc-min-temp", + surface_names=sc_surfs, + report_type="surface-facetmin", + field=VariableCatalog.TEMPERATURE, +) +sc_avg_temp = report_defs.surface.create( + name="sc-avg-temp", + surface_names=sc_surfs, + report_type="surface-facetavg", + field=VariableCatalog.TEMPERATURE, +) +sc_max_temp = report_defs.surface.create( + name="sc-max-temp", + surface_names=sc_surfs, + report_type="surface-facetmax", + field=VariableCatalog.TEMPERATURE, +) ############################################################################### # Regolith temperature reports # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create reports for the mean temperatures of each regolith layer. We will # store the report names for use later. -surf_report_defs = solver_session.settings.solution.report_definitions.surface - -# Loop over all regolith reports to set common properties -regolith_report_names = [] -for i in range(1, 5 + 1): - report_name = f"regolith-layer-{i}-temp" - surf_report_defs[report_name] = { - "report_type": "surface-facetavg", - "field": "temperature", - } - regolith_report_names.extend([report_name]) +regolith_reports = [ + report_defs.surface.create( + name=f"regolith-layer-{i}-temp", + report_type="surface-facetavg", + field=VariableCatalog.TEMPERATURE, + surface_names=[f"regolith{f'-{i - 1}:{i}' if i > 1 else ''}"], + ) + for i in range(1, 5 + 1) +] -surf_report_defs["regolith-layer-1-temp"].surface_names = ["regolith"] -surf_report_defs["regolith-layer-2-temp"].surface_names = ["regolith-1:2"] -surf_report_defs["regolith-layer-3-temp"].surface_names = ["regolith-2:3"] -surf_report_defs["regolith-layer-4-temp"].surface_names = ["regolith-3:4"] -surf_report_defs["regolith-layer-5-temp"].surface_names = ["regolith-4:5"] ############################################################################### # Temperature report files # ~~~~~~~~~~~~~~~~~~~~~~~~ # Create temperature report files for post-processing. -surf_report_files = solver_session.settings.solution.monitor.report_files +monitor = Monitor(solver) +surf_report_files = monitor.report_files # Spacecraft temperatures -surf_report_files["sc-temps-rfile"] = { - "report_defs": ["flow-time", "sc-min-temp", "sc-avg-temp", "sc-max-temp"], -} +surf_report_files.create( + "sc-temps-rfile", + report_defs=[ + "flow-time", + "sc-min-temp", + "sc-avg-temp", + "sc-max-temp", + ], +) # Regolith temperatures -surf_report_files["regolith-temps-rfile"] = { - "report_defs": [*regolith_report_names, "flow-time"], -} +surf_report_files.create( + "regolith-temps-rfile", + report_defs=[ + *regolith_reports, + "flow-time", + ], +) ############################################################################### # Autosave # ~~~~~~~~ # Set the case to save only the data file at each timestep for post-processing. -autosave = solver_session.settings.file.auto_save +autosave = solver.settings.file.auto_save autosave.case_frequency = "if-mesh-is-modified" autosave.data_frequency = 1 @@ -613,7 +601,7 @@ def get_surf_mean_temp( # Turn off the convergence criteria pertaining to fluid flow as there is no # fluid flow in this simulation. Keep only the energy convergence criterion. -residuals = solver_session.settings.solution.monitor.residual.equations +residuals = monitor.residual.equations for criterion in ["continuity", "x-velocity", "y-velocity", "z-velocity"]: residuals[criterion].check_convergence = False @@ -622,10 +610,10 @@ def get_surf_mean_temp( ############################################################################### # Write case file # ~~~~~~~~~~~~~~~ -# Write the case file. Enable overwrite. +# Write the case file. -solver_session.settings.file.batch_options.confirm_overwrite = True -solver_session.settings.file.write( +write_case( + solver, file_name="lunar_lander_thermal.cas.h5", file_type="case", ) @@ -643,7 +631,7 @@ def get_surf_mean_temp( for i in range(n_steps): # Get current simulation time - t = solver_session.rp_vars("flow-time") + t = solver.rp_vars("flow-time") # Calculate sun vector sun_alt, sun_azm = calc_sun_vecs_for_moon( @@ -659,9 +647,8 @@ def get_surf_mean_temp( ) # Set beam direction - solver_session.settings.setup.boundary_conditions.wall[ - "space" - ].radiation.direct_irradiation_settings.beam_direction = [ + bcs = BoundaryCondition(solver) + bcs.wall["space"].radiation.direct_irradiation_settings.beam_direction = [ beam_x, beam_y, beam_z, @@ -670,27 +657,27 @@ def get_surf_mean_temp( # Calculate radiator mean temperature rad_mean_temp = get_surf_mean_temp( ["sc-radiator"], - solver_session, + solver, ) # Simulate closing louvers below 273 K by changing emissivity - radiation_emission = solver_session.settings.setup.boundary_conditions.wall[ - "sc-radiator" - ].radiation.internal_emissivity_band["thermal-ir"] + radiation_emission = bcs.wall["sc-radiator"].radiation.internal_emissivity_band[ + "thermal-ir" + ] if rad_mean_temp < 273: radiation_emission.value = 0.09 else: radiation_emission.value = 0.70 # Run simulation for 1 timestep - solver_session.settings.solution.run_calculation.calculate() + calculate(solver) ############################################################################### # Close Fluent # ~~~~~~~~~~~~ # Shut down the solver. -solver_session.exit() +solver.exit() ############################################################################### # Post-process @@ -729,7 +716,7 @@ def clean_col_names(df): # alphabetical character, implemented as negative lookarounds in a regular # expression. -root = Path(os.getcwd()) +root = Path.cwd() sep = r"(?`_. # sphinx_gallery_thumbnail_path = '_static/Single_Battery_Cell_4.png' +# +# .. _Reference: +# [3] Simulating a Single Battery Cell Using the MSMD Battery Model, `Ansys Fluent documentation​ `_. + +# sphinx_gallery_thumbnail_path = '_static/Single_Battery_Cell_4.png' diff --git a/examples/00-fluent/species_transport.py b/examples/00-fluent/species_transport.py index 15633ecf523..14ac7fc6539 100644 --- a/examples/00-fluent/species_transport.py +++ b/examples/00-fluent/species_transport.py @@ -87,12 +87,14 @@ # sphinx_gallery_capture_repr = ('_repr_html_', '__repr__') # sphinx_gallery_thumbnail_path = '_static/species_transport/setup.png' -import os +from pathlib import Path import ansys.fluent.core as pyfluent +from ansys.units import VariableCatalog +from ansys.units.common import K, Pa, W, m, s -solver_session = pyfluent.launch_fluent(dimension=2) -print(solver_session.get_fluent_version()) +solver = pyfluent.Solver.from_install(dimension=2) +print(solver.get_fluent_version()) # %% # Import some direct settings classes which will be used in the following sections. @@ -102,16 +104,30 @@ from ansys.fluent.core import FluentVersion # noqa: E402 from ansys.fluent.core.examples import download_file # noqa: E402 from ansys.fluent.core.solver import ( # noqa: E402 + BoundaryCondition, Contour, Energy, + Fluxes, + General, + Graphics, + Initialize, + Iterate, Mesh, + Methods, MixtureMaterial, + Monitor, PressureOutlet, + RunCalculation, + SolverIntegrals, Species, + SurfaceIntegrals, Vector, VelocityInlet, Viscous, WallBoundary, + WriteCase, + WriteCaseData, + write_case, ) # %% @@ -121,9 +137,9 @@ # Download the mesh file and read it into the Fluent session. mesh_file = download_file( - "gascomb.msh.gz", "pyfluent/tutorials/species_transport", save_path=os.getcwd() + "gascomb.msh.gz", "pyfluent/tutorials/species_transport", save_path=Path.cwd() ) -solver_session.settings.file.read_mesh(file_name=mesh_file) +solver.settings.file.read_mesh(file_name=mesh_file) # %% # General Settings @@ -133,7 +149,7 @@ # Fluent will perform various checks on the mesh and will report the progress in the console. # Ensure that the reported minimum volume reported is a positive number. -solver_session.settings.mesh.check() +solver.settings.mesh.check() # %% # Scale the mesh and check it again. @@ -144,17 +160,17 @@ # # We should check the mesh after we manipulate it (scale, convert to polyhedra, merge, separate, fuse, add zones, or smooth and swap). # This will ensure that the quality of the mesh has not been compromised. - -solver_session.settings.mesh.scale(x_scale=0.001, y_scale=0.001) -solver_session.settings.mesh.check() +mesh = Mesh(solver) +mesh.scale(x_scale=0.001, y_scale=0.001) +mesh.check() # %% # Display the mesh in Fluent and save the image to a file to examine locally. -mesh = Mesh(solver_session, new_instance_name="mesh") +mesh = Mesh.create(solver, name="mesh") mesh.surfaces_list = mesh.surfaces_list.allowed_values() mesh.display() -graphics = solver_session.settings.results.graphics +graphics = Graphics(solver) graphics.views.auto_scale() if graphics.picture.use_window_resolution.is_active(): graphics.picture.use_window_resolution = False @@ -173,34 +189,61 @@ # %% # Inspect the available options for the two-dimensional space setting and set it to axisymmetric. -solver_session.settings.setup.general.solver.two_dim_space.allowed_values() +solver_ = General(solver).solver + +solver_.two_dim_space.allowed_values() # %% -solver_session.settings.setup.general.solver.two_dim_space = "axisymmetric" +solver_.two_dim_space = "axisymmetric" # %% # Models # ^^^^^^ # Enable heat transfer by enabling the energy model. -Energy(solver_session).enabled = True +Energy(solver).enabled = True # %% # Inspect the default settings for the k-ω SST viscous model. -Viscous(solver_session).print_state() +Viscous(solver).print_state() + + +# %% +# Materials +# ^^^^^^^^^ +# In this step, we will examine the default settings for the mixture material. +# This tutorial uses mixture properties copied from the Ansys Fluent database. +# In general, we can modify these or create our own mixture properties for our specific problem as necessary. + +# %% +# Print some specific properties of the mixture material (methane-air). +# We avoid printing the entire state of the mixture material to keep the output concise. + +mixture_material = MixtureMaterial(solver, name="methane-air") +print(f"Species list: {mixture_material.species.volumetric_species.get_object_names()}") +print(f"Reactions option: {mixture_material.reactions.option()}") +print(f"Density option: {mixture_material.density.option()}") +print(f"Cp (specific heat) option: {mixture_material.specific_heat.option()}") +print(f"Thermal conductivity value: {mixture_material.thermal_conductivity.value()}") +print(f"Viscosity value: {mixture_material.viscosity.value()}") +if solver.get_fluent_version() < FluentVersion.v252: + print(f"Mass diffusivity value: {mixture_material.mass_diffusivity.value()}") +else: + print( + f"Mass diffusivity value: {mixture_material.mass_diffusivity.constant_mass_diffusivity()}" + ) # %% # Inspect the available options for the species model and set it to species transport. -species = Species(solver_session) +species = Species(solver) species.model.option.allowed_values() # %% -species.model.option = "species-transport" - +species.model.option = species.model.option.SPECIES_TRANSPORT # %% # Inspect the species model settings. @@ -221,7 +264,7 @@ # The chemical species in the system and their physical and thermodynamic properties are defined by our selection of the mixture material. # We can alter the mixture material selection or modify the mixture material properties using the material settings (see `Materials`_). -species.model.material = "methane-air" +species.model.material = mixture_material # %% # Set the turbulence-chemistry interaction model to eddy-dissipation. @@ -235,31 +278,6 @@ species.print_state() -# %% -# Materials -# ^^^^^^^^^ -# In this step, we will examine the default settings for the mixture material. -# This tutorial uses mixture properties copied from the Ansys Fluent database. -# In general, we can modify these or create our own mixture properties for our specific problem as necessary. - -# %% -# Print some specific properties of the mixture material (methane-air). -# We avoid printing the entire state of the mixture material to keep the output concise. - -mixture_material = MixtureMaterial(solver_session, name="methane-air") -print(f"Species list: {mixture_material.species.volumetric_species.get_object_names()}") -print(f"Reactions option: {mixture_material.reactions.option()}") -print(f"Density option: {mixture_material.density.option()}") -print(f"Cp (specific heat) option: {mixture_material.specific_heat.option()}") -print(f"Thermal conductivity value: {mixture_material.thermal_conductivity.value()}") -print(f"Viscosity value: {mixture_material.viscosity.value()}") -if solver_session.get_fluent_version() < FluentVersion.v252: - print(f"Mass diffusivity value: {mixture_material.mass_diffusivity.value()}") -else: - print( - f"Mass diffusivity value: {mixture_material.mass_diffusivity.constant_mass_diffusivity()}" - ) - # %% # Boundary Conditions # ^^^^^^^^^^^^^^^^^^^ @@ -267,9 +285,7 @@ # # *The symmetry zone must be converted to an axis to prevent numerical difficulties where the radius reduces to zero.* -solver_session.settings.setup.boundary_conditions.set_zone_type( - zone_list=["symmetry-5"], new_type="axis" -) +BoundaryCondition(solver).set_zone_type(zone_list=["symmetry-5"], new_type="axis") # %% # Set the boundary conditions for the air inlet (velocity-inlet-8). @@ -278,9 +294,7 @@ # # *This name is more descriptive for the zone than velocity-inlet-8.* -solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "velocity-inlet-8" -].rename("air-inlet") +VelocityInlet.get(solver, name="velocity-inlet-8").rename("air-inlet") # %% # Set the following boundary conditions for the air-inlet: @@ -295,12 +309,12 @@ # # * Species mass fraction for o2: 0.23 -air_inlet = VelocityInlet(solver_session, name="air-inlet") -air_inlet.momentum.velocity_magnitude = 0.5 +air_inlet = VelocityInlet.get(solver, name="air-inlet") +air_inlet.momentum.velocity_magnitude = 0.5 * m / s air_inlet.turbulence.turbulence_specification = "Intensity and Hydraulic Diameter" air_inlet.turbulence.turbulent_intensity = 0.1 -air_inlet.turbulence.hydraulic_diameter = 0.44 -air_inlet.thermal.temperature = 300 +air_inlet.turbulence.hydraulic_diameter = 0.44 * m +air_inlet.thermal.temperature = 300 * K air_inlet.species.species_mass_fraction["o2"] = 0.23 # %% @@ -315,9 +329,7 @@ # # *This name is more descriptive for the zone than velocity-inlet-6.* -solver_session.settings.setup.boundary_conditions.velocity_inlet[ - "velocity-inlet-6" -].rename("fuel-inlet") +VelocityInlet.get(solver, name="velocity-inlet-6").rename("fuel-inlet") # %% # Set the following boundary conditions for the fuel-inlet: @@ -332,12 +344,12 @@ # # * Species mass fraction for ch4: 1 -fuel_inlet = VelocityInlet(solver_session, name="fuel-inlet") -fuel_inlet.momentum.velocity_magnitude = 80 +fuel_inlet = VelocityInlet(solver, name="fuel-inlet") +fuel_inlet.momentum.velocity_magnitude = 80 * m / s fuel_inlet.turbulence.turbulence_specification = "Intensity and Hydraulic Diameter" fuel_inlet.turbulence.turbulent_intensity = 0.1 -fuel_inlet.turbulence.hydraulic_diameter = 0.01 -fuel_inlet.thermal.temperature = 300 +fuel_inlet.turbulence.hydraulic_diameter = 0.01 * m +fuel_inlet.thermal.temperature = 300 * K fuel_inlet.species.species_mass_fraction["ch4"] = 1 # %% @@ -346,27 +358,17 @@ fuel_inlet.print_state() # %% -# Set the following boundary conditions for the exit boundary (pressure-outlet-9): -# -# * Gauge pressure: 0 Pa -# -# * Backflow turbulence intensity: 10% -# -# * Backflow Hydraulic diameter: 0.45 m -# -# * Backflow total temperature: 300 K -# -# * Backflow species mass fraction for o2: 0.23 +# Set the boundary conditions for the exit boundary (pressure-outlet-9): # # *The Backflow values in the pressure outlet boundary condition are utilized only when backflow occurs at the pressure outlet. # Always assign reasonable values because backflow may occur during intermediate iterations and could affect the solution stability.* -pressure_outlet = PressureOutlet(solver_session, name="pressure-outlet-9") -pressure_outlet.momentum.gauge_pressure = 0 +pressure_outlet = PressureOutlet.get(solver, name="pressure-outlet-9") +pressure_outlet.momentum.gauge_pressure = 0 * Pa pressure_outlet.turbulence.turbulence_specification = "Intensity and Hydraulic Diameter" pressure_outlet.turbulence.backflow_turbulent_intensity = 0.1 -pressure_outlet.turbulence.backflow_hydraulic_diameter = 0.45 -pressure_outlet.thermal.backflow_total_temperature = 300 +pressure_outlet.turbulence.backflow_hydraulic_diameter = 0.45 * m +pressure_outlet.thermal.backflow_total_temperature = 300 * K pressure_outlet.species.backflow_species_mass_fraction["o2"] = 0.23 # %% @@ -381,16 +383,14 @@ # # *This name is more descriptive for the zone than wall-7.* -solver_session.settings.setup.boundary_conditions.wall["wall-7"].rename("outer-wall") +WallBoundary.get(solver, name="wall-7").rename("outer-wall") # %% # Set the following boundary conditions for the outer-wall: -# -# * Temperature: 300 K -outer_wall = WallBoundary(solver_session, name="outer-wall") +outer_wall = WallBoundary.get(solver, name="outer-wall") outer_wall.thermal.thermal_condition = "Temperature" -outer_wall.thermal.temperature = 300 +outer_wall.thermal.temperature = 300 * K # %% # Verify the state of thermal properties of the outer-wall boundary condition after the changes. @@ -404,16 +404,16 @@ # # *This name is more descriptive for the zone than wall-2.* -solver_session.settings.setup.boundary_conditions.wall["wall-2"].rename("nozzle") +WallBoundary.get(solver, name="wall-2").rename("nozzle") # %% # Set the following boundary conditions for the nozzle for adiabatic wall conditions: # # * Heat flux: 0 :math:`W/m^2` -nozzle = WallBoundary(solver_session, name="nozzle") -nozzle.thermal.thermal_condition = "Heat Flux" -nozzle.thermal.heat_flux = 0 +nozzle = WallBoundary.get(solver, name="nozzle") +nozzle.thermal.thermal_condition = nozzle.thermal.thermal_condition.HEAT_FLUX +nozzle.thermal.heat_flux = 0 * W * m**-2 # %% # Verify the state of thermal properties of the nozzle boundary condition after the changes. @@ -427,27 +427,27 @@ # # Inspect the solution methods settings. -solver_session.settings.solution.methods.print_state() +Methods(solver).print_state() # %% # Ensure that plot is enabled in residual monitor options. -solver_session.settings.solution.monitor.residual.options.plot() +Monitor(solver).residual.options.plot() # %% # Initialize the field variables. -solver_session.settings.solution.initialization.hybrid_initialize() +Initialize(solver).hybrid_initialize() # %% # Save the case file (gascomb1.cas.h5). -solver_session.settings.file.write_case(file_name="gascomb1.cas.h5") +WriteCase(file_name="gascomb1.cas.h5") # %% # Run the calculation for 200 iterations. -solver_session.settings.solution.run_calculation.iterate(iter_count=200) +Iterate(solver, iter_count=200) # %% # Set time scale factor to 5. @@ -455,19 +455,18 @@ # *The Time Scale Factor allows us to further manipulate the computed time step size calculated by Fluent. # Larger time steps can lead to faster convergence. However, if the time step is too large it can lead to solution instability.* -solver_session.settings.solution.run_calculation.pseudo_time_settings.time_step_method.time_step_size_scale_factor = ( - 5 -) +RunCalculation( + solver +).pseudo_time_settings.time_step_method.time_step_size_scale_factor = 5 # %% # Run the calculation for 200 iterations. -solver_session.settings.solution.run_calculation.iterate(iter_count=200) +Iterate(solver, iter_count=200) # %% # Save the case and data files (gascomb1.cas.h5 and gascomb1.dat.h5). - -solver_session.settings.file.write_case_data(file_name="gascomb1.cas.h5") +WriteCaseData(solver, file_name="gascomb1.cas.h5") # %% # Postprocessing @@ -477,13 +476,14 @@ # Report the total sensible heat flux. # We shall use wildcards to specify all zones. -solver_session.settings.results.report.fluxes.get_heat_transfer_sensible(zones="*") +Fluxes.get_heat_transfer_sensible(zones="*") # %% # Display filled contours of temperature and save the image to a file. -contour1 = Contour(solver_session, new_instance_name="contour-temp") -contour1.field = "temperature" +contour1 = Contour.create( + solver, name="contour-temp", field=VariableCatalog.TEMPERATURE +) contour1.surfaces_list = contour1.surfaces_list.allowed_values() contour1.colorings.banded = True contour1.display() @@ -502,8 +502,7 @@ # %% # Display velocity vectors and save the image to a file. -vector1 = Vector(solver_session, new_instance_name="vector-vel") -vector1.surfaces_list = ["interior-4"] +vector1 = Vector.create(solver, name="vector-vel", surfaces_list=["interior-4"]) vector1.options.scale = 0.01 vector1.vector_opt.fixed_length = True @@ -529,8 +528,7 @@ # %% # Display filled contours of mass fraction of :math:`CH_4` and save the image to a file. -contour2 = Contour(solver_session, new_instance_name="contour-ch4-mass-fraction") -contour2.field = "ch4" +contour2 = Contour.create(solver, name="contour-ch4-mass-fraction", field="ch4") contour2.surfaces_list = contour2.surfaces_list.allowed_values() contour2.display() graphics.views.auto_scale() @@ -547,8 +545,7 @@ # %% # Display filled contours of mass fraction of :math:`O_2` and save the image to a file. -contour3 = Contour(solver_session, new_instance_name="contour-o2-mass-fraction") -contour3.field = "o2" +contour3 = Contour.create(solver, name="contour-o2-mass-fraction", field="o2") contour3.surfaces_list = contour3.surfaces_list.allowed_values() contour3.display() graphics.views.auto_scale() @@ -564,8 +561,7 @@ # %% # Display filled contours of mass fraction of :math:`CO_2` and save the image to a file. -contour4 = Contour(solver_session, new_instance_name="contour-co2-mass-fraction") -contour4.field = "co2" +contour4 = Contour.create(solver, name="contour-co2-mass-fraction", field="co2") contour4.surfaces_list = contour4.surfaces_list.allowed_values() contour4.display() graphics.views.auto_scale() @@ -581,8 +577,7 @@ # %% # Display filled contours of mass fraction of :math:`H_2O` and save the image to a file. -contour5 = Contour(solver_session, new_instance_name="contour-h2o-mass-fraction") -contour5.field = "h2o" +contour5 = Contour.create(solver, name="contour-h2o-mass-fraction", field="h2o") contour5.surfaces_list = contour5.surfaces_list.allowed_values() contour5.display() graphics.views.auto_scale() @@ -604,7 +599,7 @@ # # *The mass-averaged temperature at the exit is approximately 1840 K.* -solver_session.settings.results.report.surface_integrals.get_mass_weighted_avg( +SurfaceIntegrals(solver).get_mass_weighted_avg( report_of="temperature", surface_names=["pressure-outlet-9"] ) @@ -617,20 +612,20 @@ # # *The Area-Weighted Average field will show that the exit velocity is approximately 3.37 m/s.* -solver_session.settings.results.report.surface_integrals.get_area_weighted_avg( +SolverIntegrals(solver).get_area_weighted_avg( report_of="velocity-magnitude", surface_names=["pressure-outlet-9"] ) # %% # Save the case file (gascomb1.cas.h5). -solver_session.settings.file.write_case(file_name="gascomb1.cas.h5") +write_case(solver, file_name="gascomb1.cas.h5") # %% # Close Fluent # ^^^^^^^^^^^^ -solver_session.exit() +solver.exit() # %% # Summary diff --git a/examples/00-fluent/steady_vortex.py b/examples/00-fluent/steady_vortex.py index 2f88d31ebaa..a4098289c8c 100644 --- a/examples/00-fluent/steady_vortex.py +++ b/examples/00-fluent/steady_vortex.py @@ -79,18 +79,19 @@ # sphinx_gallery_capture_repr = ('_repr_html_', '__repr__') # sphinx_gallery_thumbnail_path = '_static/steady_vortex/steady_vortex_setup.png' -import os +from pathlib import Path import imageio.v2 as imageio import ansys.fluent.core as pyfluent -from ansys.fluent.core import Dimension, FluentMode, Precision from ansys.fluent.core.examples import download_file from ansys.fluent.core.solver import ( # noqa: E402 LIC, + CalculationActivity, CellRegister, CellZoneCondition, Contour, + FluidMaterial, General, Graphics, Initialization, @@ -100,12 +101,17 @@ Mesh, Methods, Models, + Multiphase, NamedExpression, PlaneSurface, - RunCalculation, Scene, + Viscous, WallBoundary, + iterate, + read_case, + write_case_data, ) +from ansys.units.common import m, s # %% # Launch Fluent @@ -113,14 +119,13 @@ # # Launch Fluent in 3D double precision solver mode. -solver_session = pyfluent.launch_fluent( - mode=FluentMode.SOLVER, - dimension=Dimension.THREE, - precision=Precision.DOUBLE, +solver = pyfluent.Solver.from_install( + dimension=pyfluent.Dimension.THREE, + precision=pyfluent.Precision.DOUBLE, cleanup_on_exit=True, - cwd=os.getcwd(), + cwd=Path.cwd(), ) -print(solver_session.get_fluent_version()) # Print the Fluent version +print(solver.get_fluent_version()) # Print the Fluent version pyfluent.set_console_logging_level("INFO") # Set the console logging level # %% @@ -132,7 +137,7 @@ vortex_mesh = download_file( "vortex-mixingtank.msh.h5", "pyfluent/examples/Steady-Vortex-VOF", - save_path=os.getcwd(), + save_path=Path.cwd(), ) # %% @@ -141,7 +146,7 @@ # # Define constants. -g = 9.81 # m/s^2 +g = 9.81 * m / s**2 # %% # @@ -150,25 +155,22 @@ # # Import the mesh file into the Fluent session. -solver_session.settings.file.read_case(file_name=vortex_mesh) +read_case(solver, file_name=vortex_mesh) # %% # Display the mesh in Fluent and save the image to a file to examine locally. # Create a middle plane to display the mesh -y_mid_plane = PlaneSurface(solver_session, new_instance_name="y_mid_plane") -y_mid_plane.method = "zx-plane" -y_mid_plane.y = 0 +y_mid_plane = PlaneSurface.create(solver, name="y_mid_plane", method="zx-plane", y=0) y_mid_plane.display() # Define and display the mesh -mesh = Mesh(solver_session, new_instance_name="mesh") -mesh.surfaces_list = y_mid_plane.name() +mesh = Mesh.create(solver, name="mesh", surfaces_list=y_mid_plane.name()) mesh.options.edges = True mesh.display() # Create Graphics object to save the mesh image -graphics = Graphics(solver_session) +graphics = Graphics(solver) graphics.views.auto_scale() if graphics.picture.use_window_resolution.is_active(): graphics.picture.use_window_resolution = False @@ -193,28 +195,27 @@ # # Set gravity -general_settings = General(solver_session) -general_settings.operating_conditions.gravity.enable = True -general_settings.operating_conditions.gravity.components = [0.0, 0.0, -g] +general = General(solver) +general.operating_conditions.gravity.enable = True +general.operating_conditions.gravity.components = (0.0, 0.0, -g) # %% # Copy Materials from Fluent Database # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # -# Copy water liquid materials from the Fluent database. +# Copy liquid water material from the Fluent database and get a reference to air material (it's predefined in Fluent). -materials = Materials(solver_session) -materials.database.copy_by_name(type="fluid", name="water-liquid") +water = Materials(solver).database.copy_by_name(type="fluid", name="water-liquid") +air = FluidMaterial.get(solver, name="air") # %% # Define Named Expression for Agitation Speed # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # Create a named expression for the agitation speed and specify as an input parameter. -stirring_speed = NamedExpression(solver_session, new_instance_name="stirring_speed") - -stirring_speed.definition = "240 [rev min^-1]" -stirring_speed.input_parameter = True +stirring_speed = NamedExpression.create( + solver, name="stirring_speed", definition="240 [rev min^-1]", input_parameter=True +) # %% # MRF zone parameters @@ -222,11 +223,11 @@ # # Define MRF zone parameters for the mrf cell zone. -fluid_cell_zone = CellZoneCondition(solver_session, name="mrf") -fluid_cell_zone.reference_frame.frame_motion = True -fluid_cell_zone.reference_frame.reference_frame_axis_origin = [0, 0, 0] -fluid_cell_zone.reference_frame.reference_frame_axis_direction = [0, 0, 1] -fluid_cell_zone.reference_frame.mrf_omega.value = "stirring_speed" +reference_frame = CellZoneCondition(solver, name="mrf").reference_frame +reference_frame.frame_motion = True +reference_frame.reference_frame_axis_origin = (0, 0, 0) +reference_frame.reference_frame_axis_direction = (0, 0, 1) +reference_frame.mrf_omega.value = "stirring_speed" # %% # Rotating Wall BC parameters @@ -234,11 +235,11 @@ # # Define the rotating wall boundary condition for the shaft. -wall_boundary = WallBoundary(solver_session, name="shaft_tank") +wall_boundary = WallBoundary(solver, name="shaft_tank") wall_boundary.momentum.wall_motion = "Moving Wall" wall_boundary.momentum.relative = False wall_boundary.momentum.rotating = True -wall_boundary.momentum.rotation_axis_direction = [0, 0, 1] +wall_boundary.momentum.rotation_axis_direction = (0, 0, 1) wall_boundary.momentum.rotation_speed = "stirring_speed" # %% @@ -246,15 +247,19 @@ # ^^^^^^^^^^^^^^^^^^^^^^^ # # Enable the VOF multiphase model and update the curvature correction setting for the viscous model. -model_setup = Models(solver_session) -model_setup.multiphase.model = "vof" -model_setup.multiphase.vof_parameters.vof_formulation = "implicit" -model_setup.multiphase.vof_parameters.vof_cutoff = 1e-06 -model_setup.multiphase.advanced_formulation.implicit_body_force = True - -model_setup.viscous.options.curvature_correction = True - -solution_methods = Methods(solver_session) +model_setup = Models(solver) +multiphase = Multiphase(solver) +multiphase.model = "vof" +multiphase.vof_parameters.vof_formulation = "implicit" +multiphase.vof_parameters.vof_cutoff = 1e-06 +multiphase.advanced_formulation.implicit_body_force = True +model_setup.multiphase = multiphase + +viscous = Viscous(solver) +viscous.options.curvature_correction = True +model_setup.viscous = viscous + +solution_methods = Methods(solver) solution_methods.multiphase_numerics.solution_stabilization.execute_settings_optimization = ( True ) @@ -263,10 +268,14 @@ ) # Change phase names -solver_session.tui.define.phases.set_domain_properties.change_phases_names( - "water", "air" -) -general_settings.solver.time = "steady" # steady solver +# TODO check +primary_phase = multiphase.phases["phase-1"] +primary_phase.name = "water" +primary_phase.material = water +secondary_phase = multiphase.phases["phase-2"] +secondary_phase.name = "air" +secondary_phase.material = air +general.solver.time = "steady" # steady solver # %% # Define Initial Conditions @@ -282,29 +291,24 @@ # the tank's minimum height coordinate and Z-max to 0.19 m. Utilize the minimum and maximum X & Y # values to ensure cells across the entire tank diameter are included. -solution_initialization = Initialization(solver_session) -solution_initialization.reference_frame = "absolute" -solution_initialization.defaults["k"] = 0.001 -solution_initialization.localized_turb_init.enabled = False +initialization = Initialization(solver) +initialization.reference_frame = "absolute" +initialization.defaults["k"] = 0.001 +initialization.localized_turb_init.enabled = False -solver_session.settings.solution.cell_registers.create(name="liquid_patch") -cell_register = CellRegister(solver_session, name="liquid_patch") -cell_register.type = { - "option": "hexahedron", - "hexahedron": { - "inside": True, - "max_point": [100.0, 100.0, 0.19], - "min_point": [-100.0, -100.0, -100.0], - }, -} +cell_register = CellRegister(solver, new_instance_name="liquid_patch") +cell_register.type.option = "hexahedron" +cell_register.type.hexahedron.inside = True +cell_register.type.hexahedron.max_point = (100.0, 100.0, 0.19) +cell_register.type.hexahedron.min_point = (-100.0, -100.0, -100.0) -solution_initialization.initialize() +initialization.initialize() # Patch the water volume fraction in the defined cell register to set the initial # liquid region in the tank. # "mp" refers to the volume fraction of the primary phase (here water). # Setting value=1 fills the patch region entirely with water. -solution_initialization.patch.calculate_patch( +initialization.patch.calculate_patch( domain="water", cell_zones=[], registers=["liquid_patch"], @@ -322,117 +326,100 @@ # e.g., to visualize the free surface and wetted walls and dry walls. # Free surface iso-surface -solver_session.settings.results.surfaces.iso_surface.create(name="freesurface") -freesurface = IsoSurface(solver_session, name="freesurface") -freesurface.field = "water-vof" -freesurface.iso_values = [0.5] +free_surface = IsoSurface.create( + solver, name="freesurface", field="water-vof", iso_values=[0.5] * m +) # Wetted wall and dry wall iso-clips -solver_session.settings.results.surfaces.iso_clip.create(name="wet_wall") -wet_wall = IsoClip(solver_session, name="wet_wall") -wet_wall.field = "water-vof" -wet_wall.range = { - "minimum": 0.5, - "maximum": 1.0, -} -wet_wall.surfaces = ["wall_tank"] - - -solver_session.settings.results.surfaces.iso_clip.create(name="dry_wall") -dry_wall = IsoClip(solver_session, name="dry_wall") -dry_wall.field = "water-vof" -dry_wall.range = { - "minimum": 0.0, - "maximum": 0.499, -} -dry_wall.surfaces = ["wall_tank"] +wet_wall = IsoClip.create( + solver, name="wet_wall", field="water-vof", surfaces=["wall_tank"] +) +wet_wall.range.minimum = 0.5 +wet_wall.range.maximum = 1.0 + + +dry_wall = IsoClip.create( + solver, name="dry_wall", field="water-vof", surfaces=["wall_tank"] +) +dry_wall.range.minimum = 0.0 +dry_wall.range.maximum = 0.499 # Meshes -internal_comp_mesh = Mesh(solver_session, new_instance_name="internals") -internal_comp_mesh.surfaces_list = [ - "wall_impeller", - "shaft_mrf", - "shaft_tank", -] +internal_comp_mesh = Mesh.create( + solver, + name="internals", + surfaces_list=[ + "wall_impeller", + "shaft_mrf", + "shaft_tank", + ], +) internal_comp_mesh.surfaces_list() # dry wall -dry_wall_comp_mesh = Mesh(solver_session, new_instance_name="drywall") -dry_wall_comp_mesh.surfaces_list = ["dry_wall"] +dry_wall_comp_mesh = Mesh.create(solver, name="drywall", surfaces_list=[dry_wall]) dry_wall_comp_mesh.surfaces_list() # wet wall -wet_wall_comp_mesh = Mesh(solver_session, new_instance_name="wetwall") -wet_wall_comp_mesh.surfaces_list = ["wet_wall"] +wet_wall_comp_mesh = Mesh.create(solver, name="wetwall", surfaces_list=[wet_wall]) wet_wall_comp_mesh.surfaces_list() wet_wall_comp_mesh.coloring.option = "manual" wet_wall_comp_mesh.coloring.manual.faces = "pastel cyan" # liquid level -liquidlevel_comp_mesh = Mesh(solver_session, new_instance_name="liquidlevel") -liquidlevel_comp_mesh.surfaces_list = ["freesurface"] +liquidlevel_comp_mesh = Mesh.create( + solver, name="liquidlevel", surfaces_list=[free_surface] +) liquidlevel_comp_mesh.surfaces_list() liquidlevel_comp_mesh.coloring.option = "manual" liquidlevel_comp_mesh.coloring.manual.faces = "pastel cyan" # Scenes -vortex_scene = Scene(solver_session, new_instance_name="scene-1") -vortex_scene.graphics_objects.add(name="liquidlevel") -vortex_scene.graphics_objects.add(name="drywall") -vortex_scene.graphics_objects.add(name="wetwall") -vortex_scene.graphics_objects.add(name="internals") - -solver_session.settings.results.scene["scene-1"] = { - "graphics_objects": { - "liquidlevel": { - "transparency": 50, - "name": "tank", - "colormap_position": 0, - "colormap_left": 0.0, - "colormap_bottom": 0.0, - "colormap_width": 0.0, - "colormap_height": 0.0, - }, - "internals": { - "transparency": 35, - "name": "internals", - "colormap_position": 0, - "colormap_left": 0.0, - "colormap_bottom": 0.0, - "colormap_width": 0.0, - "colormap_height": 0.0, - }, - "drywall": { - "transparency": 75, - "name": "fs", - "colormap_position": 0, - "colormap_left": 0.0, - "colormap_bottom": 0.0, - "colormap_width": 0.0, - "colormap_height": 0.0, - }, - "wetwall": { - "transparency": 75, - "name": "wetwall", - "colormap_position": 0, - "colormap_left": 0.0, - "colormap_bottom": 0.0, - "colormap_width": 0.0, - "colormap_height": 0.0, - }, - } -} +vortex_scene = Scene.create(solver, name="scene-1") +liquid_gobj = vortex_scene.graphics_objects.add(name=liquidlevel_comp_mesh.name()) +liquid_gobj.transparency = 50 +liquid_gobj.color_map.position = 0 +liquid_gobj.color_map.left = 0.0 +liquid_gobj.color_map.bottom = 0.0 +liquid_gobj.color_map.width = 0.0 +liquid_gobj.color_map.height = 0.0 + +internal_gobj = vortex_scene.graphics_objects.add(name=internal_comp_mesh.name()) +internal_gobj.transparency = 35 +internal_gobj.color_map.position = 0 +internal_gobj.color_map.left = 0.0 +internal_gobj.color_map.bottom = 0.0 +internal_gobj.color_map.width = 0.0 +internal_gobj.color_map.height = 0.0 + +dry_gobj = vortex_scene.graphics_objects.add(name=dry_wall_comp_mesh.name()) +dry_gobj.transparency = 75 +dry_gobj.color_map.position = 0 +dry_gobj.color_map.left = 0.0 +dry_gobj.color_map.bottom = 0.0 +dry_gobj.color_map.width = 0.0 +dry_gobj.color_map.height = 0.0 + +wet_gobj = vortex_scene.graphics_objects.add(name=wet_wall_comp_mesh.name()) +wet_gobj.transparency = 75 +wet_gobj.color_map.position = 0 +wet_gobj.color_map.left = 0.0 +wet_gobj.color_map.bottom = 0.0 +wet_gobj.color_map.width = 0.0 +wet_gobj.color_map.height = 0.0 # Contour plot on Y-Mid plane -solver_session.settings.results.surfaces.iso_surface.create(name="ymid") -y_mid_iso_surface = IsoSurface(solver_session, name="ymid") -y_mid_iso_surface.field = "y-coordinate" -y_mid_iso_surface.iso_values = [0] - -volume_fraction_contour = Contour(solver_session, new_instance_name="contour-1") -volume_fraction_contour.surfaces_list = y_mid_iso_surface.name() -volume_fraction_contour.field = "water-vof" +y_mid_iso_surface = IsoSurface.create( + solver, name="ymid", field="y-coordinate", iso_values=[0] * m +) + +volume_fraction_contour = Contour.create( + solver, + name="contour-1", + surfaces_list=y_mid_iso_surface.name(), + field="water-vof", +) volume_fraction_contour.surfaces_list() volume_fraction_contour.display() @@ -456,28 +443,22 @@ # Animation Setup -solver_session.settings.solution.calculation_activity.solution_animations.create( - "animation-2" +CalculationActivity(solver).solution_animations.create( + name="animation-2", + animate_on="scene-1", + frequency=10, + storage_type="png", + view="top", ) -solver_session.settings.solution.calculation_activity.solution_animations[ - "animation-2" -] = { - "animate_on": "scene-1", - "frequency": 10, - "storage_type": "png", - "view": "top", -} # %% # Save Initial Files & Run Calculation # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # Save the initial case file and run the calculation for 500 iterations. -solver_session.settings.file.write_case_data(file_name="vortex_init.cas.h5") +write_case_data(solver, file_name="vortex_init.cas.h5") -run_calculation = RunCalculation(solver_session) -run_calculation.iter_count = 50 # Iteration count keep it 50 for demo only purpose -run_calculation.calculate() +iterate(solver, iter_count=50) # Iteration count keep it 50 for demo only purpose # %% # LIC Visualization @@ -485,12 +466,15 @@ # # Set up the LIC (Line Integral Convolution) visualization for the midplane. -lic_visualization = LIC(solver_session, new_instance_name="lic-1") -lic_visualization.surfaces_list = y_mid_plane.name() -lic_visualization.field = "velocity-magnitude" -lic_visualization.lic_image_filter = "Strong Sharpen" -lic_visualization.lic_intensity_factor = 10 -lic_visualization.texture_size = 10 +lic_visualization = LIC.create( + solver, + name="lic-1", + surfaces_list=y_mid_plane.name(), + field="velocity-magnitude", + lic_image_filter="Strong Sharpen", + lic_intensity_factor=10, + texture_size=10, +) lic_visualization.display() graphics.views.restore_view(view_name="top") @@ -534,14 +518,14 @@ # *Steady vortex shape in the stirred tank.* # Save final case and data files -solver_session.settings.file.write_case_data(file_name="vortex_final.cas.h5") +write_case_data(solver, file_name="vortex_final.cas.h5") # %% # Close Fluent # ^^^^^^^^^^^^ # # Exit the Fluent session. -solver_session.exit() +solver.exit() # %% # Generate GIF Animation: Vortex Formation @@ -554,12 +538,7 @@ # Install imageio package if not already installed. You can install it via pip: # `pip install imageio` -png_dir = os.getcwd() -images = [] -for file_name in sorted(os.listdir(png_dir)): - if file_name.startswith("animation") and file_name.endswith(".png"): - file_path = os.path.join(png_dir, file_name) - images.append(imageio.imread(file_path)) +images = list(map(imageio.imread, sorted(Path.cwd().glob("animation*.png")))) imageio.mimsave(uri="vortex.gif", ims=images, duration=0.2) diff --git a/examples/00-fluent/transient_compressible_nozzle_workflow.py b/examples/00-fluent/transient_compressible_nozzle_workflow.py index b8b7db7fe7b..ba2e75e0e99 100644 --- a/examples/00-fluent/transient_compressible_nozzle_workflow.py +++ b/examples/00-fluent/transient_compressible_nozzle_workflow.py @@ -1,3 +1,9 @@ +# /// script +# dependencies = [ +# "ansys-fluent-core", +# ] +# /// + # Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -66,16 +72,17 @@ # Importing the following classes offer streamlined access to key solver settings, # eliminating the need to manually browse through the full settings structure. -import os +from pathlib import Path import platform import ansys.fluent.core as pyfluent from ansys.fluent.core import examples from ansys.fluent.core.solver import ( - BoundaryConditions, - CellRegisters, + BoundaryCondition, + CellRegister, Contour, Controls, + FluidMaterial, General, Graphics, Initialization, @@ -83,24 +90,29 @@ PressureInlet, PressureOutlet, ReportDefinitions, - ReportFiles, - ReportPlots, + ReportFile, + ReportPlot, RunCalculation, Setup, + calculate, + iterate, + write_case, ) from ansys.fluent.visualization import GraphicsWindow, Monitor +from ansys.units import VariableCatalog +from ansys.units.common import Pa, s # %% # Launch Fluent session in meshing mode # ------------------------------------- -session = pyfluent.launch_fluent(mode="meshing") +meshing = pyfluent.Meshing.from_install() # %% # Meshing workflow # ---------------- -workflow = session.workflow +workflow = meshing.workflow filenames = { "Windows": "nozzle.dsco", @@ -110,9 +122,12 @@ geometry_filename = examples.download_file( filenames.get(platform.system(), filenames["Other"]), "pyfluent/transient_compressible_simulation", - save_path=os.getcwd(), + save_path=Path.cwd(), ) +# Upload geometry to the Meshing session so tasks can operate on it +meshing.upload(geometry_filename) + workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") workflow.TaskObject["Import Geometry"].Arguments = {"FileName": geometry_filename} workflow.TaskObject["Import Geometry"].Execute() @@ -199,22 +214,20 @@ # Switch to solver # ---------------- -solver = session.switch_to_solver() +solver = meshing.switch_to_solver() # %% # Display mesh # ------------ graphics = Graphics(solver) -mesh = Mesh(solver, new_instance_name="mesh-1") -boundary_conditions = BoundaryConditions(solver) +mesh = Mesh.create(solver, name="mesh-1") +boundary_conditions = BoundaryCondition(solver) graphics.picture.x_resolution = 650 # Horizontal resolution for clear visualization graphics.picture.y_resolution = 450 # Vertical resolution matching typical aspect ratio -all_walls = mesh.surfaces_list.allowed_values() - -mesh.surfaces_list = all_walls +mesh.surfaces_list = mesh.surfaces_list.allowed_values() mesh.options.edges = True mesh.display() graphics.views.restore_view(view_name="isometric") @@ -242,22 +255,23 @@ setup = Setup(solver) setup.models.energy.enabled = True -setup.materials.fluid["air"].density = {"option": "ideal-gas"} +air = FluidMaterial(solver, name="air") +air.density.option = "ideal-gas" # %% # Set boundary conditions # ----------------------- -inlet = PressureInlet(solver, name="inlet") -outlet = PressureOutlet(solver, name="outlet") +inlet = PressureInlet.get(solver, name="inlet") +outlet = PressureOutlet.get(solver, name="outlet") -inlet.momentum.gauge_total_pressure.value = 91192.5 # Pa -inlet.momentum.supersonic_or_initial_gauge_pressure.value = 74666.3925 # Pa +inlet.momentum.gauge_total_pressure = 91192.5 * Pa +inlet.momentum.supersonic_or_initial_gauge_pressure = 74666.3925 * Pa # Low turbulent intensity of 1.5% for smooth inlet flow, typical for nozzle simulations. inlet.turbulence.turbulent_intensity = 0.015 -outlet.momentum.gauge_pressure.value = 74666.3925 # Pa +outlet.momentum.gauge_pressure = 74666.3925 * Pa outlet.turbulence.backflow_turbulent_intensity = 0.015 # %% @@ -271,94 +285,71 @@ # Define report definition # ------------------------ -report_definitions = ReportDefinitions(solver) - - -report_definitions.surface.create("mass-flow-rate") -report_definitions.surface["mass-flow-rate"] = { - "report_type": "surface-massflowrate", - "surface_names": ["outlet"], -} - -report_files = ReportFiles(solver) -report_files.create(name="mass_flow_rate_out_rfile") -report_files["mass_flow_rate_out_rfile"] = { - "report_defs": ["mass-flow-rate"], - "print": True, - "file_name": "nozzle_ss.out", -} +mass_report = ReportDefinitions(solver).surface.create( + name="mass-flow-rate", + report_type="surface-massflowrate", + surface_names=[outlet], +) -report_plots = ReportPlots(solver) +mass_rfile = ReportFile.create( + solver, + name="mass_flow_rate_out_rfile", + report_defs=[mass_report], + print=True, + file_name="nozzle_ss.out", +) -report_plots.create("mass_flow_rate_out_rplot") -report_plots["mass_flow_rate_out_rplot"] = { - "report_defs": ["mass-flow-rate"], - "print": True, -} +mass_rplot = ReportPlot.create( + solver, "mass_flow_rate_out_rplot", report_defs=[mass_report], print=True +) # %% # Steady-State Initialization and Mesh Adaptation -# -------------- +# ----------------------------------------------- -solver.settings.file.write_case(file_name="nozzle_steady.cas.h5") +write_case(solver, file_name="nozzle_steady.cas.h5") initialize = Initialization(solver) initialize.hybrid_initialize() -cell_register = CellRegisters(solver) +cell_register = CellRegister(solver) # Refinement register: Mark cells where density gradient >50% of domain average -cell_register.create(name="density_scaled_gradient_refn") -cell_register["density_scaled_gradient_refn"] = { - "type": { - "option": "field-value", - "field_value": { - "derivative": {"option": "gradient"}, - "scaling": {"option": "scale-by-global-average"}, - "option": { - "option": "more-than", - "more_than": 0.5, # Threshold: >50% average - }, - "field": "density", - }, - } -} +density_refn = CellRegister.create(solver, name="density_scaled_gradient_refn") +density_refn.type.option = "field-value" +density_refn.type.field_value.derivative = "gradient" +density_refn.type.field_value.scaling = "scale-by-global-average" +density_refn.type.field_value.option.option = "more-than" +density_refn.type.field_value.option.more_than = 0.5 # Threshold: >50% average +density_refn.type.field_value.field = "density" + # Coarsening register: Mark cells where density gradient <45% of domain average -cell_register.create(name="density_scaled_gradient_crsn") -cell_register["density_scaled_gradient_crsn"] = { - "type": { - "option": "field-value", - "field_value": { - "derivative": {"option": "gradient"}, - "scaling": {"option": "scale-by-global-average"}, - "option": { - "option": "less-than", - "less_than": 0.45, # Threshold: <45% average - }, - "field": "density", - }, - } -} +density_crsn = CellRegister.create(solver, name="density_scaled_gradient_crsn") +density_crsn.type.option = "field-value" +density_crsn.type.field_value.derivative = "gradient" +density_crsn.type.field_value.scaling = "scale-by-global-average" +density_crsn.type.field_value.option.option = "less-than" +density_crsn.type.field_value.option.less_than = 0.45 # Threshold: <45% average +density_crsn.type.field_value.field = "density" # Define adaptation criteria: Refine if gradient is high and refinement level <2; coarsen if low -solver.settings.mesh.adapt.manual_refinement_criteria = ( +mesh.adapt.manual_refinement_criteria = ( "AND(density_scaled_gradient_refn, CellRefineLevel < 2)" ) -solver.settings.mesh.adapt.manual_coarsening_criteria = "density_scaled_gradient_crsn" +mesh.adapt.manual_coarsening_criteria = "density_scaled_gradient_crsn" -solver.tui.mesh.adapt.manage_criteria.add("adaption_criteria_0") +mesh.adapt.manage_criteria.add("F") -calculation = RunCalculation(solver) -calculation.iterate(iter_count=400) +iterate(solver, iter_count=400) # %% # Post-processing # --------------- # Create pressure contour -pressure_contour = Contour(solver, new_instance_name="pressure_contour") - -pressure_contour.surfaces_list = ["symmetry"] +pressure_contour = Contour.create( + solver, name="pressure_contour", surfaces_list=["symmetry"] +) pressure_contour.display() graphics.views.restore_view(view_name="front") @@ -370,17 +361,19 @@ # :alt: Transient Compressible Flow Pressure Contour # Create velocity contour -velocity_contour = Contour(solver, new_instance_name="velocity_contour") - -velocity_contour.field = "velocity-magnitude" -velocity_contour.surfaces_list = ["symmetry"] +velocity_contour = Contour.create( + solver, + name="velocity_contour", + field=VariableCatalog.VELOCITY_MAGNITUDE, + surfaces_list=["symmetry"], +) velocity_contour.display() graphics.views.restore_view(view_name="front") graphics.picture.save_picture(file_name="transient_compressible_4.jpg") # save the case and data file -solver.settings.file.write_case_data(file_name="steady_state_nozzle") +write_case(solver, file_name="steady_state_nozzle.cas.h5") # %% # .. image:: ../../_static/transient_compressible_4.jpg @@ -394,28 +387,23 @@ solver_general_settings.solver.time = "unsteady-1st-order" # Sinusoidal pressure variation at 2200 Hz simulates pulsating flow, with mean pressure of 0.737 atm. -outlet.momentum.gauge_pressure.value = "(0.12*sin(2200[Hz]*t)+0.737)*101325.0[Pa]" +outlet.momentum.gauge_pressure = "(0.12*sin(2200[Hz]*t)+0.737)*101325.0[Pa]" # Configure mesh adaptation: Refine every 25 iterations -solver.tui.mesh.adapt.manage_criteria.edit("adaption_criteria_0", "frequency", "25") +mesh.adapt.manage_criteria.edit("adaption_criteria_0", "frequency", "25") -report_files["mass_flow_rate_out_rfile"] = { - "file_name": "trans-nozzle-rfile.out", -} - -report_plots["mass_flow_rate_out_rplot"].x_label = "time-step" +mass_rfile.file_name = "trans-nozzle-rfile.out" -solver.settings.file.write_case(file_name="nozzle_unsteady.cas.h5") +mass_rplot.x_label = "time-step" -Transient_controls = solver.settings.solution.run_calculation.transient_controls +write_case(solver, file_name="nozzle_unsteady.cas.h5") -Transient_controls.time_step_count = 100 -Transient_controls.time_step_size = 2.85596e-05 # s: Resolves 2200 Hz oscillations -Transient_controls.max_iter_per_time_step = ( - 10 # Ensures convergence within each time step -) +transient_controls = RunCalculation(solver).transient_controls +transient_controls.time_step_count = 100 +transient_controls.time_step_size = 2.85596e-05 * s +transient_controls.max_iter_per_time_step = 10 -calculation.calculate() +calculate(solver) mass_bal_rplot = Monitor(solver=solver, monitor_set_name="mass_flow_rate_out_rplot") plot_window = GraphicsWindow() diff --git a/examples/00-fluent/tyler_sofrin_modes.py b/examples/00-fluent/tyler_sofrin_modes.py index 72cc4ca62fa..30488aa64e7 100644 --- a/examples/00-fluent/tyler_sofrin_modes.py +++ b/examples/00-fluent/tyler_sofrin_modes.py @@ -114,7 +114,6 @@ # ===================================================================================== import csv import math -import os from pathlib import Path import random @@ -123,6 +122,8 @@ import ansys.fluent.core as pyfluent from ansys.fluent.core import examples +from ansys.fluent.core.solver import PointSurface, ReportDefinitions, read_case_data +from ansys.units.common import m ####################################################################################### # Downloading cas/dat file @@ -130,22 +131,20 @@ import_filename = examples.download_file( "axial_comp_fullWheel_DFT_23R2.cas.h5", "pyfluent/examples/Tyler-Sofrin-Modes-Compressor", - save_path=os.getcwd(), + save_path=Path.cwd(), ) examples.download_file( "axial_comp_fullWheel_DFT_23R2.dat.h5", "pyfluent/examples/Tyler-Sofrin-Modes-Compressor", - save_path=os.getcwd(), + save_path=Path.cwd(), ) ####################################################################################### # Launch Fluent session and print Fluent version # ===================================================================================== -session = pyfluent.launch_fluent( - processor_count=4, -) -print(session.get_fluent_version()) +solver = pyfluent.Solver.from_install(processor_count=4) +print(solver.get_fluent_version()) ####################################################################################### # Reading case and data file @@ -153,8 +152,7 @@ # # .. note:: # The dat file should correspond to the already completed DFT simulation. - -session.settings.file.read(file_type="case-data", file_name=import_filename) +read_case_data(solver, file_name=import_filename) ####################################################################################### # Define User constant/variables @@ -167,15 +165,15 @@ # .. image:: ../../_static/var_names.jpg # :alt: variable names -varname = [ +var_names = [ "mean-static-pressure-dataset", "dft-static-pressure_10.00kHz-ta", "dft-static-pressure-1_21.43kHz-ta", "dft-static-pressure-2_30.00kHz-ta", ] n_mode = [0, 1, 2, 3] # Impeller frequency harmonics -r = 0.082 # meters -z = -0.037 # meters +r = 0.082 * m +z = -0.037 * m d_theta = 5 # degrees m_max = 50 # maximum TS mode number @@ -188,49 +186,45 @@ for angle in range(0, 360, d_theta): x = math.cos(math.radians(angle)) * r y = math.sin(math.radians(angle)) * r - pt_name = "point-" + str(angle) - session.settings.results.surfaces.point_surface[pt_name] = {} - session.settings.results.surfaces.point_surface[pt_name].point = [x, y, z] + PointSurface.create(solver, name=f"point-{angle}", point=(x, y, z)) ####################################################################################### # Compute Fourier coefficients at each monitor point (An, Bn) # ===================================================================================== -An = np.zeros((len(varname), int(360 / d_theta))) -Bn = np.zeros((len(varname), int(360 / d_theta))) +An = np.zeros((len(var_names), int(360 / d_theta))) +Bn = np.zeros((len(var_names), int(360 / d_theta))) +report_defs = ReportDefinitions(solver) for angle_ind, angle in enumerate(range(0, 360, d_theta)): - for n_ind, variable in enumerate(varname): + for n_ind, variable in enumerate(var_names): if variable.startswith("mean"): - session.settings.solution.report_definitions.surface["mag-report"] = { - "report_type": "surface-vertexavg", - "surface_names": ["point-" + str(angle)], - "field": str(variable), - } - mag = session.settings.solution.report_definitions.compute( - report_defs=["mag-report"] + mag_report = report_defs.surface.create( + name="mag-report", + report_type="surface-vertexavg", + surface_names=[f"point-{angle}"], + field=variable, ) - mag = mag[0]["mag-report"][0] + mag_res = report_defs.compute(report_defs=[mag_report]) + mag = mag_res[0][mag_report.name][0] An[n_ind][angle_ind] = mag Bn[n_ind][angle_ind] = 0 else: - session.settings.solution.report_definitions.surface["mag-report"] = { - "report_type": "surface-vertexavg", - "surface_names": ["point-" + str(angle)], - "field": str(variable) + "-mag", - } - mag = session.settings.solution.report_definitions.compute( - report_defs=["mag-report"] + mag_report = report_defs.surface.create( + name="mag-report", + report_type="surface-vertexavg", + surface_names=[f"point-{angle}"], + field=f"{variable}-mag", ) - mag = mag[0]["mag-report"][0] - session.settings.solution.report_definitions.surface["phase-report"] = { - "report_type": "surface-vertexavg", - "surface_names": ["point-" + str(angle)], - "field": str(variable) + "-phase", - } - phase = session.settings.solution.report_definitions.compute( - report_defs=["phase-report"] + mag_res = report_defs.compute(report_defs=[mag_report]) + mag = mag_res[0][mag_report.name][0] + phase_report = report_defs.surface.create( + name="phase-report", + report_type="surface-vertexavg", + surface_names=[f"point-{angle}"], + field=f"{variable}-phase", ) - phase = phase[0]["phase-report"][0] + phase_res = report_defs.compute(report_defs=[phase_report]) + phase = phase_res[0][phase_report.name][0] An[n_ind][angle_ind] = mag * math.cos(phase) Bn[n_ind][angle_ind] = -mag * math.sin(phase) @@ -247,7 +241,7 @@ writer = csv.writer(f) writer.writerow(["n", "theta", "An", "Bn"]) - for n_ind, variable in enumerate(varname): + for n_ind, variable in enumerate(var_names): for ind, _ in enumerate(An[n_ind, :]): writer.writerow( [n_mode[n_ind], ind * d_theta, An[n_ind, ind], Bn[n_ind, ind]] @@ -265,21 +259,23 @@ m_mode = range(-m_max, m_max + m_inc, m_inc) # Initialize solution matrices with zeros -Anm = np.zeros((len(varname), len(m_mode))) -Bnm = np.zeros((len(varname), len(m_mode))) -Pnm = np.zeros((len(varname), len(m_mode))) +Anm = np.zeros((len(var_names), len(m_mode))) +Bnm = np.zeros((len(var_names), len(m_mode))) +Pnm = np.zeros((len(var_names), len(m_mode))) -for n_ind, variable in enumerate(varname): # loop over n modes - for m_ind, m in enumerate(m_mode): # loop over m modes +for n_ind, variable in enumerate(var_names): # loop over n modes + for m_ind, _m in enumerate(m_mode): # loop over m modes for angle_ind, angle in enumerate( np.arange(0, math.radians(360), math.radians(d_theta)) ): # loop over all angles, in radians - Anm[n_ind][m_ind] += An[n_ind][angle_ind] * math.cos(m * angle) - Bn[n_ind][ - angle_ind - ] * math.sin(m * angle) - Bnm[n_ind][m_ind] += An[n_ind][angle_ind] * math.sin(m * angle) + Bn[n_ind][ - angle_ind - ] * math.cos(m * angle) + Anm[n_ind][m_ind] += ( # fmt: skip + An[n_ind][angle_ind] * math.cos(_m * angle) + - Bn[n_ind][angle_ind] * math.sin(_m * angle) + ) + Bnm[n_ind][m_ind] += ( # fmt: skip + An[n_ind][angle_ind] * math.sin(_m * angle) + + Bn[n_ind][angle_ind] * math.cos(_m * angle) + ) Anm[n_ind][m_ind] = Anm[n_ind][m_ind] / (2 * math.pi) * math.radians(d_theta) Bnm[n_ind][m_ind] = Bnm[n_ind][m_ind] / (2 * math.pi) * math.radians(d_theta) Pnm[n_ind][m_ind] = math.sqrt(Anm[n_ind][m_ind] ** 2 + Bnm[n_ind][m_ind] ** 2) @@ -316,7 +312,7 @@ ####################################################################################### # Close the session # ===================================================================================== -session.exit() +solver.exit() #######################################################################################