From 09a23b97c0bbbd9ba43d8613e010a088759b65b3 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Fri, 17 Apr 2026 14:46:19 -0400 Subject: [PATCH 1/6] Relay migrated simulation schema services from flow360-schema --- flow360/component/simulation/conversion.py | 247 +--- .../component/simulation/framework/updater.py | 989 +------------ .../simulation/framework/updater_functions.py | 112 +- .../simulation/framework/updater_utils.py | 191 +-- flow360/component/simulation/services.py | 1046 +------------ .../component/simulation/services_utils.py | 154 +- .../simulation/user_code/core/types.py | 22 +- flow360/component/simulation/utils.py | 65 +- tests/data/simulation/simulation_24_11_0.json | 971 ------------ .../ref/simulation/service_init_geometry.json | 347 ----- .../simulation/service_init_surface_mesh.json | 347 ----- .../simulation/service_init_volume_mesh.json | 308 ---- ...tion_json_with_multi_constructor_used.json | 424 ------ .../data/simulation_force_output_webui.json | 1026 ------------- .../simulation_stopping_criterion_webui.json | 1171 --------------- .../test_meshing_param_validation.py | 441 ------ .../test_refinements_validation.py | 168 --- .../params/test_farfield_enclosed_entities.py | 509 ------- .../params/test_simulation_params.py | 19 - .../params/test_unit_conversions.py | 108 -- .../params/test_validators_bet_disk.py | 140 -- .../params/test_validators_criterion.py | 52 - .../params/test_validators_output.py | 121 -- .../params/test_validators_params.py | 572 -------- .../params/test_validators_solid.py | 162 -- ...ependency_geometry_sphere1_simulation.json | 746 ---------- ...ependency_geometry_sphere2_simulation.json | 746 ---------- .../result_merged_geometry_entity_info1.json | 1048 ------------- .../result_merged_geometry_entity_info2.json | 1048 ------------- .../data/root_geometry_cube_simulation.json | 1154 --------------- .../service/ref/updater_to_25_2_2.json | 705 --------- .../service/test_apply_simulation_setting.py | 488 ------ tests/simulation/service/test_services_v2.py | 1302 ----------------- .../test_entity_processing_service.py | 412 ------ .../services/test_services_utils.py | 54 - tests/simulation/test_updater.py | 16 - 36 files changed, 83 insertions(+), 17348 deletions(-) delete mode 100644 tests/data/simulation/simulation_24_11_0.json delete mode 100644 tests/ref/simulation/service_init_geometry.json delete mode 100644 tests/ref/simulation/service_init_surface_mesh.json delete mode 100644 tests/ref/simulation/service_init_volume_mesh.json delete mode 100644 tests/ref/simulation/simulation_json_with_multi_constructor_used.json delete mode 100644 tests/simulation/params/data/simulation_force_output_webui.json delete mode 100644 tests/simulation/params/data/simulation_stopping_criterion_webui.json delete mode 100644 tests/simulation/params/meshing_validation/test_meshing_param_validation.py delete mode 100644 tests/simulation/params/meshing_validation/test_refinements_validation.py delete mode 100644 tests/simulation/params/test_farfield_enclosed_entities.py delete mode 100644 tests/simulation/params/test_unit_conversions.py delete mode 100644 tests/simulation/params/test_validators_bet_disk.py delete mode 100644 tests/simulation/params/test_validators_criterion.py delete mode 100644 tests/simulation/params/test_validators_output.py delete mode 100644 tests/simulation/params/test_validators_solid.py delete mode 100644 tests/simulation/service/data/dependency_geometry_sphere1_simulation.json delete mode 100644 tests/simulation/service/data/dependency_geometry_sphere2_simulation.json delete mode 100644 tests/simulation/service/data/result_merged_geometry_entity_info1.json delete mode 100644 tests/simulation/service/data/result_merged_geometry_entity_info2.json delete mode 100644 tests/simulation/service/data/root_geometry_cube_simulation.json delete mode 100644 tests/simulation/service/ref/updater_to_25_2_2.json delete mode 100644 tests/simulation/service/test_apply_simulation_setting.py diff --git a/flow360/component/simulation/conversion.py b/flow360/component/simulation/conversion.py index 157826cd5..bf30495ec 100644 --- a/flow360/component/simulation/conversion.py +++ b/flow360/component/simulation/conversion.py @@ -1,239 +1,8 @@ -""" -This module provides functions for handling unit conversion into flow360 solver unit system. -""" - -# pylint: disable=duplicate-code - -import operator -from functools import reduce - -import unyt as u - -from ...exceptions import Flow360ConfigurationError - -LIQUID_IMAGINARY_FREESTREAM_MACH = 0.05 - - -class RestrictedUnitSystem(u.UnitSystem): - """UnitSystem that blocks conversions for unsupported base dimensions. - - Automatically derives supported dimensions from which unit arguments are - provided. Missing base units get placeholder values internally but are - masked so that conversion attempts raise ValueError. - - Examples:: - - # Meshing mode: only length defined, velocity/mass/temperature blocked - RestrictedUnitSystem("nondim", length_unit=0.5 * u.m) - - # Full mode: all units provided, no restrictions - RestrictedUnitSystem("nondim", length_unit=..., mass_unit=..., - time_unit=..., temperature_unit=...) - """ - - def __init__( # pylint: disable=too-many-arguments - self, - name, - length_unit, - mass_unit=None, - time_unit=None, - temperature_unit=None, - **kwargs, - ): - supported = {u.dimensions.length, u.dimensions.angle} - if mass_unit is not None: - supported.add(u.dimensions.mass) - if time_unit is not None: - supported.add(u.dimensions.time) - if temperature_unit is not None: - supported.add(u.dimensions.temperature) - - super().__init__( - name, - length_unit=length_unit, - mass_unit=mass_unit or 1 * u.kg, - time_unit=time_unit or 1 * u.s, - temperature_unit=temperature_unit or 1 * u.K, - **kwargs, - ) - - # All 5 dims provided (length, angle + mass, time, temperature) — no restrictions - if len(supported) == 5: - self._supported_dims = None - return - - # Mask unsupported base dimensions in units_map so that - # get_base_equivalent's fast path doesn't bypass our check - self._supported_dims = supported - for dim in list(self.units_map.keys()): - if not dim.free_symbols <= supported: - self.units_map[dim] = None - - def __getitem__(self, key): - if isinstance(key, str): - key = getattr(u.dimensions, key) - if self._supported_dims is not None: - unsupported = key.free_symbols - self._supported_dims - if unsupported: - names = ", ".join(str(s) for s in unsupported) - raise ValueError( - f"Cannot non-dimensionalize {key}: " - f"base units for {names} are not defined in this context." - ) - return super().__getitem__(key) - - -def get_from_dict_by_key_list(key_list, data_dict): - """ - Get a value from a nested dictionary using a list of keys. - - Parameters - ---------- - key_list : List[str] - List of keys specifying the path to the desired value. - data_dict : dict - The dictionary from which to retrieve the value. - - Returns - ------- - value - The value located at the specified nested path in the dictionary. - """ - - return reduce(operator.getitem, key_list, data_dict) - - -def need_conversion(value): - """ - Check if a value needs conversion to flow360 units. - - Parameters - ---------- - value : Any - The value to check for conversion. - - Returns - ------- - bool - True if conversion is needed (i.e. value carries physical units), False otherwise. - """ - - return hasattr(value, "units") - - -def require(required_parameter, required_by, params): - """ - Ensure that required parameters are present in the provided dictionary. - - Parameters - ---------- - required_parameter : List[str] - List of keys specifying the path to the desired parameter that is required. - required_by : List[str] - List of keys specifying the path to the parameter that requires required_parameter for unit conversion. - params : SimulationParams - The dictionary containing the parameters. - - Raises - ------ - Flow360ConfigurationError - Configuration error due to missing parameter. - """ - - required_msg = f'required by {" -> ".join(required_by)} for unit conversion' - try: - params_as_dict = params - if not isinstance(params_as_dict, dict): - params_as_dict = params.model_dump() - value = get_from_dict_by_key_list(required_parameter, params_as_dict) - if value is None: - raise ValueError - - except Exception as err: - raise Flow360ConfigurationError( - message=f'{" -> ".join(required_parameter)} is {required_msg}.', - field=required_by, - dependency=required_parameter, - ) from err - - -def get_flow360_unit_system_liquid(params, to_flow360_unit: bool = False) -> u.UnitSystem: - """ - Returns the flow360 unit system when liquid operating condition is used. - - Parameters - ---------- - params : SimulationParams - The parameters needed for unit conversion that uses liquid operating condition. - to_flow360_unit : bool, optional - Whether we want user input to be converted to flow360 unit system. - The reverse path requires different conversion logic (from solver output to non-flow360 unit system) - since the solver output is already re-normalized by `reference velocity` due to "velocityScale". - - Returns - ------- - u.UnitSystem - The flow360 unit system. - - ##-- When to_flow360_unit is True, - ##-- time unit should be changed such that it takes into consideration - ##-- the fact that solver output already multiplied by "velocityScale" - """ - - if to_flow360_unit: - base_velocity = params.base_velocity - else: - base_velocity = params.reference_velocity # pylint:disable=protected-access - - time_unit = params.base_length / base_velocity - return u.UnitSystem( - name="flow360_liquid", - length_unit=params.base_length, - mass_unit=params.base_mass, - time_unit=time_unit, - temperature_unit=params.base_temperature, - ) - - -def compute_udf_dimensionalization_factor(params, requested_unit, using_liquid_op): - """ - - Returns the dimensionalization coefficient and factor given a requested unit - - Parameters - ---------- - params : SimulationParams - The parameters needed for unit conversion. - unit: u.Unit - The unit to compute the factors. - using_liquid_op : bool - If True, compute the factor based on the flow360_liquid unit system. - Returns - ------- - coefficient and offset for unit conversion from the requested unit to flow360 unit - - """ - - def _compute_coefficient_and_offset(source_unit: u.Unit, target_unit: u.Unit): - y2 = (2.0 * target_unit).in_units(source_unit).value - y1 = (1.0 * target_unit).in_units(source_unit).value - x2 = 2.0 - x1 = 1.0 - - coefficient = (y2 - y1) / (x2 - x1) - offset = y1 / coefficient - x1 - - return coefficient, offset - - flow360_unit_system = ( - params.flow360_unit_system - if not using_liquid_op - else get_flow360_unit_system_liquid(params=params) - ) - # Note: Effectively assuming that all the solver vars uses radians and also the expressions expect radians - flow360_unit_system["angle"] = u.rad # pylint:disable=no-member - flow360_unit = flow360_unit_system[requested_unit.dimensions] - coefficient, offset = _compute_coefficient_and_offset( - source_unit=requested_unit, target_unit=flow360_unit - ) - return coefficient, offset +"""Relay schema-owned conversion helpers for migrated simulation modules.""" + +from flow360_schema.models.simulation.conversion import ( + LIQUID_IMAGINARY_FREESTREAM_MACH, + RestrictedUnitSystem, + compute_udf_dimensionalization_factor, + get_flow360_unit_system_liquid, +) diff --git a/flow360/component/simulation/framework/updater.py b/flow360/component/simulation/framework/updater.py index 5ef6a9065..5b2ffc9bd 100644 --- a/flow360/component/simulation/framework/updater.py +++ b/flow360/component/simulation/framework/updater.py @@ -1,982 +1,9 @@ -""" -Module containing updaters from version to version - -TODO: remove duplication code with FLow360Params updater. -""" - -# pylint: disable=R0801 - - -import copy -import re -from typing import Any - -from flow360.component.simulation.framework.entity_utils import generate_uuid -from flow360.component.simulation.framework.updater_functions import ( - fix_ghost_sphere_schema, - populate_entity_id_with_name, - remove_entity_bucket_field, - update_symmetry_ghost_entity_name_to_symmetric, -) -from flow360.component.simulation.framework.updater_utils import ( - Flow360Version, - compare_dicts, - recursive_remove_key, +"""Relay schema-owned updater orchestration for simulation models.""" + +from flow360_schema.models.simulation.framework.updater import ( + DEFAULT_PLANAR_FACE_TOLERANCE, + DEFAULT_SLIDING_INTERFACE_TOLERANCE, + FLOW360_SCHEMA_DEFAULT_VERSION, + VERSION_MILESTONES, + updater, ) -from flow360.log import log -from flow360.version import __version__ - -DEFAULT_PLANAR_FACE_TOLERANCE = 1e-6 -DEFAULT_SLIDING_INTERFACE_TOLERANCE = 1e-2 - - -def _to_24_11_1(params_as_dict): - # Check and remove the 'meshing' node if conditions are met - if params_as_dict.get("meshing") is not None: - meshing_defaults = params_as_dict["meshing"].get("defaults", {}) - bl_thickness = meshing_defaults.get("boundary_layer_first_layer_thickness") - max_edge_length = meshing_defaults.get("surface_max_edge_length") - if bl_thickness is None and max_edge_length is None: - del params_as_dict["meshing"] - - # Iterate over models and update 'heat_spec' where necessary - for model in params_as_dict.get("models", []): - if model.get("type") == "Wall" and model.get("heat_spec") is None: - model["heat_spec"] = { - "type_name": "HeatFlux", - "value": {"value": 0, "units": "W / m**2"}, - } - - # Check and remove the 'time_stepping' -> order_of_accuracy node - if "time_stepping" in params_as_dict: - params_as_dict["time_stepping"].pop("order_of_accuracy", None) - - update_symmetry_ghost_entity_name_to_symmetric(params_as_dict=params_as_dict) - return params_as_dict - - -def _to_24_11_7(params_as_dict): - def _add_private_attribute_id_for_point_array(params_as_dict: dict) -> dict: - """ - Check if PointArray has private_attribute_id. If not, generate the uuid and assign the id - to all occurrence of the same PointArray - """ - if params_as_dict.get("outputs") is None: - return params_as_dict - - point_array_list = [] - for output in params_as_dict["outputs"]: - if output.get("entities", None) and output["entities"].get("stored_entities", None): - for entity in output["entities"]["stored_entities"]: - if ( - entity.get("private_attribute_entity_type_name") == "PointArray" - and entity.get("private_attribute_id") is None - ): - new_uuid = generate_uuid() - entity["private_attribute_id"] = new_uuid - point_array_list.append(entity) - - if not params_as_dict["private_attribute_asset_cache"].get("project_entity_info"): - return params_as_dict - if not params_as_dict["private_attribute_asset_cache"]["project_entity_info"].get( - "draft_entities" - ): - return params_as_dict - - for idx, draft_entity in enumerate( - params_as_dict["private_attribute_asset_cache"]["project_entity_info"]["draft_entities"] - ): - if draft_entity.get("private_attribute_entity_type_name") != "PointArray": - continue - for point_array in point_array_list: - if compare_dicts( - dict1=draft_entity, - dict2=point_array, - ignore_keys=["private_attribute_id"], - ): - params_as_dict["private_attribute_asset_cache"]["project_entity_info"][ - "draft_entities" - ][idx] = point_array - continue - return params_as_dict - - params_as_dict = _add_private_attribute_id_for_point_array(params_as_dict=params_as_dict) - update_symmetry_ghost_entity_name_to_symmetric(params_as_dict=params_as_dict) - return params_as_dict - - -# pylint: disable=invalid-name, too-many-branches -def _to_25_2_0(params_as_dict): - # Migrates the old DDES turbulence model interface to the new hybrid_model format. - for model in params_as_dict.get("models", []): - turb_dict = model.get("turbulence_model_solver") - if not turb_dict: - continue - - run_ddes = turb_dict.pop("DDES", None) - grid_size_for_LES = turb_dict.pop("grid_size_for_LES", None) - - if run_ddes: - turb_dict["hybrid_model"] = { - "shielding_function": "DDES", - "grid_size_for_LES": grid_size_for_LES, - } - - if params_as_dict.get("outputs") is not None: - for output in params_as_dict["outputs"]: - if output.get("output_type") == "VolumeOutput": - items = output.get("output_fields", {}).get("items", []) - for old, new in [ - ("SpalartAllmaras_DDES", "SpalartAllmaras_hybridModel"), - ("kOmegaSST_DDES", "kOmegaSST_hybridModel"), - ]: - if old in items: - items.remove(old) - items.append(new) - - # Convert the observers in the AeroAcousticOutput to new schema - if output.get("output_type") == "AeroAcousticOutput": - legacy_observers = output.get("observers", []) - converted_observers = [] - for position in legacy_observers: - converted_observers.append( - {"group_name": "0", "position": position, "private_attribute_expand": None} - ) - output["observers"] = converted_observers - - # Add ramping to MassFlowRate and move velocity direction to TotalPressure - for model in params_as_dict.get("models", []): - if model.get("type") == "Inflow" and "velocity_direction" in model.keys(): - velocity_direction = model.pop("velocity_direction", None) - model["spec"]["velocity_direction"] = velocity_direction - - if model.get("spec") and model["spec"].get("type_name") == "MassFlowRate": - model["spec"]["ramp_steps"] = None - - return params_as_dict - - -def _to_24_11_10(params_as_dict): - fix_ghost_sphere_schema(params_as_dict=params_as_dict) - return params_as_dict - - -def _to_25_2_1(params_as_dict): - ## We need a better mechanism to run updater function once. - fix_ghost_sphere_schema(params_as_dict=params_as_dict) - return params_as_dict - - -def _to_25_2_3(params_as_dict): - populate_entity_id_with_name(params_as_dict=params_as_dict) - return params_as_dict - - -def _to_25_4_1(params_as_dict): - if params_as_dict.get("meshing") is None: - return params_as_dict - meshing_defaults = params_as_dict["meshing"].get("defaults", {}) - if meshing_defaults.get("geometry_relative_accuracy"): - geometry_relative_accuracy = meshing_defaults.pop("geometry_relative_accuracy") - meshing_defaults["geometry_accuracy"] = {"value": geometry_relative_accuracy, "units": "m"} - return params_as_dict - - -def _fix_reynolds_mesh_unit(params_as_dict): - # Handling of the reynolds_mesh_unit rename - if "operating_condition" not in params_as_dict.keys(): - return params_as_dict - if "private_attribute_input_cache" not in params_as_dict["operating_condition"].keys(): - return params_as_dict - if ( - "reynolds" - not in params_as_dict["operating_condition"]["private_attribute_input_cache"].keys() - ): - return params_as_dict - reynolds_mesh_unit = params_as_dict["operating_condition"]["private_attribute_input_cache"].pop( - "reynolds", None - ) - if reynolds_mesh_unit is not None: - params_as_dict["operating_condition"]["private_attribute_input_cache"][ - "reynolds_mesh_unit" - ] = reynolds_mesh_unit - return params_as_dict - - -def _to_25_6_2(params_as_dict): - # Known: There can not be velocity_direction both under Inflow AND TotalPressure - - # Move the velocity_direction under TotalPressure to the Inflow level. - for model in params_as_dict.get("models", []): - if model.get("type") != "Inflow" or model.get("velocity_direction", None): - continue - - if model.get("spec") and model["spec"].get("type_name") == "TotalPressure": - velocity_direction = model["spec"].pop("velocity_direction", None) - if velocity_direction: - model["velocity_direction"] = velocity_direction - - params_as_dict = _fix_reynolds_mesh_unit(params_as_dict) - - # Handling the disable of same entity being in multiple outputs - if params_as_dict.get("outputs") is None: - return params_as_dict - - # Process each output type separately - # pylint: disable=too-many-nested-blocks - for output_type in ["SurfaceOutput", "TimeAverageSurfaceOutput"]: - entity_map = {} - # entity_name -> {"creates_new" : bool, "output_settings":dict, "entity":entity_dict} - for output in params_as_dict["outputs"]: - if output.get("output_type") != output_type: - continue - entity_names = set() - entity_deduplicated = [] - for entity in output["entities"]["stored_entities"]: - if entity["name"] in entity_names: - continue - entity_names.add(entity["name"]) - entity_deduplicated.append(entity) - output["entities"]["stored_entities"] = entity_deduplicated - - for entity in output["entities"]["stored_entities"]: - name = entity["name"] - if name in entity_map: - entity_map[name]["creates_new"] = True - entity_map[entity["name"]]["output_settings"]["output_fields"]["items"] = ( - sorted( - list( - set( - entity_map[entity["name"]]["output_settings"]["output_fields"][ - "items" - ] - + output["output_fields"]["items"] - ) - ) - ) - ) - else: - entity_map[entity["name"]] = {} - entity_map[entity["name"]]["creates_new"] = False - entity_map[entity["name"]]["output_settings"] = copy.deepcopy( - {key: value for key, value in output.items() if key != "entities"} - ) - entity_map[entity["name"]]["entity"] = entity - - for entity_info in entity_map.values(): - if entity_info["creates_new"]: - for index, output in enumerate(params_as_dict["outputs"]): - if output.get("output_type") != output_type: - continue - for entity in output["entities"]["stored_entities"]: - if entity["name"] == entity_info["entity"]["name"]: - params_as_dict["outputs"][index]["entities"]["stored_entities"].remove( - entity - ) - params_as_dict["outputs"].append( - { - **entity_info["output_settings"], - "entities": {"stored_entities": [entity_info["entity"]]}, - } - ) - # remove empty outputs - params_as_dict["outputs"] = [ - output - for output in params_as_dict["outputs"] - if "entities" not in output or output["entities"]["stored_entities"] - ] - - return params_as_dict - - -def _add_default_planar_face_tolerance(params_as_dict): - if params_as_dict.get("meshing") is None: - return params_as_dict - if "defaults" not in params_as_dict["meshing"]: - return params_as_dict - meshing_defaults = params_as_dict["meshing"].get("defaults", {}) - if meshing_defaults.get("planar_face_tolerance") is None: - meshing_defaults["planar_face_tolerance"] = DEFAULT_PLANAR_FACE_TOLERANCE - return params_as_dict - - -def _to_25_6_4(params_as_dict): - return _add_default_planar_face_tolerance(params_as_dict) - - -def _to_25_6_5(params_as_dict): - # Some 25.6.4 JSONs are also missing the planar_face_tolerance. - return _add_default_planar_face_tolerance(params_as_dict) - - -def _to_25_6_6(params_as_dict): - # Remove the "potential_issues" field from all surfaces. - # Recursively go through params_as_dict and remove the "private_attribute_potential_issues" - # field if the "private_attribute_entity_type_name" field is "Surface". - def _remove_potential_issues_recursive(data): - if isinstance(data, dict): - # First recursively process all nested elements - for key, value in data.items(): - if isinstance(value, (dict, list)): - data[key] = _remove_potential_issues_recursive(value) - - # Then check if current dict is a Surface and remove potential_issues - if data.get("private_attribute_entity_type_name") == "Surface": - data.pop("private_attribute_potential_issues", None) - - return data - if isinstance(data, list): - # Process each item in the list - return [_remove_potential_issues_recursive(item) for item in data] - - # Return primitive types as-is - return data - - return _remove_potential_issues_recursive(params_as_dict) - - -def _to_25_7_2(params_as_dict): - # Add post_processing_variable flag to variable_context entries - # Variables that are used in outputs should have post_processing_variable=True - # Variables that are not used in outputs should have post_processing_variable=False - - if params_as_dict.get("private_attribute_asset_cache") is None: - return params_as_dict - - variable_context = params_as_dict["private_attribute_asset_cache"].get("variable_context") - if variable_context is None: - return params_as_dict - - # Collect all user variable names used in outputs - used_variable_names = set() - - if params_as_dict.get("outputs") is not None: - for output in params_as_dict["outputs"]: - if output.get("output_fields") and output["output_fields"].get("items"): - for item in output["output_fields"]["items"]: - # Check if item is a user variable (has name and type_name fields) - if ( - isinstance(item, dict) - and "name" in item - and item.get("type_name") == "UserVariable" - ): - used_variable_names.add(item["name"]) - - # Update variable_context entries with post_processing flag - for var_context in variable_context: - if "name" in var_context: - var_context["post_processing"] = var_context["name"] in used_variable_names - - return params_as_dict - - -def _to_25_7_6(params_as_dict): - """ - - Rename deprecated RotationCylinder discriminator to RotationVolume in meshing.volume_zones - - Remove legacy entity bucket field from all entity dicts - """ - # 1) Update RotationCylinder -> RotationVolume - meshing = params_as_dict.get("meshing") - if isinstance(meshing, dict): - volume_zones = meshing.get("volume_zones") - if isinstance(volume_zones, list): - for volume_zone in volume_zones: - if isinstance(volume_zone, dict) and volume_zone.get("type") == "RotationCylinder": - volume_zone["type"] = "RotationVolume" - - # 2) Cleanup legacy entity bucket fields - return remove_entity_bucket_field(params_as_dict=params_as_dict) - - -def _to_25_7_7(params_as_dict): - """ - 1. Reset frequency and frequency_offset to defaults for steady simulations - 2. Remove invalid output fields based on transition model - """ - - # 1. Handle frequency settings in steady simulations - if params_as_dict.get("time_stepping", {}).get("type_name") == "Steady": - outputs = params_as_dict.get("outputs") or [] - for output in outputs: - # Output types that have frequency/frequency_offset settings - if output.get("output_type") in [ - "VolumeOutput", - "TimeAverageVolumeOutput", - "SurfaceOutput", - "TimeAverageSurfaceOutput", - "SliceOutput", - "TimeAverageSliceOutput", - "IsosurfaceOutput", - "TimeAverageIsosurfaceOutput", - "SurfaceSliceOutput", - ]: - # Reset to defaults: frequency=-1, frequency_offset=0 - if "frequency" in output: - output["frequency"] = -1 - if "frequency_offset" in output: - output["frequency_offset"] = 0 - - # 2. Remove invalid output fields based on transition model - # Get transition model type from models - transition_model_type = "None" - models = params_as_dict.get("models") or [] - for model in models: - if model.get("type") == "Fluid": - transition_solver = model.get("transition_model_solver") or {} - transition_model_type = transition_solver.get("type_name") - break - - # If transition model is None or not found, remove transition-specific fields - if transition_model_type == "None": - transition_output_fields = [ - "residualTransition", - "solutionTransition", - "linearResidualTransition", - ] - - outputs = params_as_dict.get("outputs") or [] - for output in outputs: - if output.get("output_type") in ["AeroAcousticOutput", "StreamlineOutput"]: - continue - if "output_fields" in output: - output_fields = output["output_fields"] - if isinstance(output_fields, dict) and "items" in output_fields: - items = output_fields["items"] - # Remove invalid fields - output_fields["items"] = [ - field for field in items if field not in transition_output_fields - ] - - return params_as_dict - - -def _to_25_8_0(params_as_dict): - # new method of specifying meshing was added, as well as the method discriminator - meshing = params_as_dict.get("meshing") - if meshing: - meshing["type_name"] = "MeshingParams" - - return params_as_dict - - -def _to_25_8_1(params_as_dict): - recursive_remove_key(params_as_dict, "transformation") - return params_as_dict - - -def _to_25_8_3(params_as_dict): - def rename_origin_to_reference_point(params_as_dict): - """ - For all CoordinateSystem instances under asset_cache->coordinate_system_status->coordinate_systems, - Rename the legacy "origin" key to "reference_point" - """ - if params_as_dict.get("private_attribute_asset_cache") is None: - return params_as_dict - - asset_cache = params_as_dict["private_attribute_asset_cache"] - coordinate_system_status = asset_cache.get("coordinate_system_status") - - if coordinate_system_status is None: - return params_as_dict - - coordinate_systems = coordinate_system_status.get("coordinate_systems", []) - - for cs in coordinate_systems: - # Rename "origin" to "reference_point" if it exists - if "origin" in cs: - cs["reference_point"] = cs.pop("origin") - - return params_as_dict - - rename_origin_to_reference_point(params_as_dict) - return params_as_dict - - -def _to_25_8_4(params_as_dict): - """ - Populate wind tunnel ghost surfaces in ghost_entities if they are not present, - ensuring that they are available for entity selection. - """ - - def add_wind_tunnel_ghost_surfaces(params_as_dict): - def _has_wind_tunnel_ghost_surfaces(ghost_entities): - """Check if ghost_entities already contains WindTunnelGhostSurface entities.""" - for entity in ghost_entities: - if entity.get("private_attribute_entity_type_name") == "WindTunnelGhostSurface": - return True - return False - - def _get_all_wind_tunnel_ghost_surfaces(): - """Return a list of all possible WindTunnelGhostSurface dicts.""" - return [ - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelInlet", - "private_attribute_id": "windTunnelInlet", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelOutlet", - "private_attribute_id": "windTunnelOutlet", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelCeiling", - "private_attribute_id": "windTunnelCeiling", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelFloor", - "private_attribute_id": "windTunnelFloor", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelLeft", - "private_attribute_id": "windTunnelLeft", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelRight", - "private_attribute_id": "windTunnelRight", - "used_by": ["all"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelFrictionPatch", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": ["StaticFloor"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelCentralBelt", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": ["CentralBelt", "WheelBelts"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelFrontWheelBelt", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": ["WheelBelts"], - }, - { - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "name": "windTunnelRearWheelBelt", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": ["WheelBelts"], - }, - ] - - # Get asset cache, entity info, and ghost entities - asset_cache = params_as_dict.get("private_attribute_asset_cache") - if asset_cache is None: - return params_as_dict - - entity_info = asset_cache.get("project_entity_info") - if entity_info is None: - return params_as_dict - - ghost_entities = entity_info.get("ghost_entities", []) - - # Check if a wind tunnel ghost surface is already included - if _has_wind_tunnel_ghost_surfaces(ghost_entities): - return params_as_dict - - # Add all wind tunnel ghost surfaces and update entity_info - ghost_entities.extend(_get_all_wind_tunnel_ghost_surfaces()) - entity_info["ghost_entities"] = ghost_entities - return params_as_dict - - def fix_write_single_file_for_paraview_format(params_as_dict): - """ - Fix write_single_file incompatibility with Paraview format. - - Before validation was added, users could set write_single_file=True with - output_format="paraview". This is invalid because write_single_file only - works with Tecplot format. Silently reset write_single_file to False when - Paraview-only format is used. - - Also handles the edge case where output_format is missing from JSON - (e.g., hand-edited files or very old JSONs), in which case we assume - the default value "paraview" and apply the fix. - """ - outputs = params_as_dict.get("outputs") - if not outputs: - return params_as_dict - - for output in outputs: - output_type = output.get("output_type") - # Only process SurfaceOutput and TimeAverageSurfaceOutput - if output_type not in ["SurfaceOutput", "TimeAverageSurfaceOutput"]: - continue - - # Check if write_single_file is True - write_single_file = output.get("write_single_file") - if not write_single_file: - continue - - # Get output_format, default to "paraview" if missing - # (This handles edge cases like hand-edited JSONs or very old versions) - output_format = output.get("output_format", "paraview") - - # Only fix paraview format (which raises error) - # "both" format only shows warning, so it's valid - if output_format == "paraview": - # Silently reset write_single_file to False - output["write_single_file"] = False - - return params_as_dict - - add_wind_tunnel_ghost_surfaces(params_as_dict) - fix_write_single_file_for_paraview_format(params_as_dict) - return params_as_dict - - -def _remove_non_manifold_faces_key(params_as_dict): - """Remove deprecated meshing defaults key ``remove_non_manifold_faces``.""" - meshing = params_as_dict.get("meshing") - if isinstance(meshing, dict): - meshing_defaults = meshing.get("defaults") - if isinstance(meshing_defaults, dict): - meshing_defaults.pop("remove_non_manifold_faces", None) - - -def _migrate_wall_function_bool(params_as_dict): - """Convert `use_wall_function` boolean values to the new WallFunction model format.""" - for model in params_as_dict.get("models", []): - if model.get("type") != "Wall": - continue - wall_fn = model.get("use_wall_function") - if wall_fn is True: - model["use_wall_function"] = {"type_name": "BoundaryLayer"} - elif wall_fn is False: - model.pop("use_wall_function", None) - - -def _add_linear_solver_type_name(params_as_dict): - """Add ``type_name`` discriminator to linear_solver dicts inside navier_stokes_solver.""" - models = params_as_dict.get("models") - if not isinstance(models, list): - return - for model in models: - if not isinstance(model, dict): - continue - ns = model.get("navier_stokes_solver") - if not isinstance(ns, dict): - continue - ls = ns.get("linear_solver") - if isinstance(ls, dict) and "type_name" not in ls: - ls["type_name"] = "LinearSolver" - - -def _remove_local_cfl_for_steady(params_as_dict): - """Remove ``localCFL`` from output fields when the simulation is steady.""" - if params_as_dict.get("time_stepping", {}).get("type_name") != "Steady": - return - - outputs = params_as_dict.get("outputs") or [] - for output in outputs: - if output.get("output_type") in ( - "AeroAcousticOutput", - "StreamlineOutput", - "ForceDistributionOutput", - "TimeAverageForceDistributionOutput", - "RenderOutput", - ): - continue - if "output_fields" in output: - output_fields = output["output_fields"] - if isinstance(output_fields, dict) and "items" in output_fields: - output_fields["items"] = [ - field for field in output_fields["items"] if field != "localCFL" - ] - - -def _to_25_9_0(params_as_dict): - """Remove ``remove_non_manifold_faces``, migrate wall function bools.""" - _remove_non_manifold_faces_key(params_as_dict) - _migrate_wall_function_bool(params_as_dict) - return params_as_dict - - -def _to_25_9_1(params_as_dict): - """Add ``type_name`` to linear_solver, remove ``localCFL`` from steady outputs.""" - _add_linear_solver_type_name(params_as_dict) - _remove_local_cfl_for_steady(params_as_dict) - return params_as_dict - - -def _to_25_9_2(params_as_dict): - """ - - Migrate sphere-based rotation zones from ``RotationVolume`` to ``RotationSphere``. - - Rename ``boundaries`` to ``bounding_entities`` on ``CustomVolume`` dicts. - - Applies to both ``meshing.volume_zones`` and ``meshing.zones``. - """ - - def _migrate_rotation_volume_to_rotation_sphere(params_dict): - meshing = params_dict.get("meshing") - if not isinstance(meshing, dict): - return - - for zone_key in ("volume_zones", "zones"): - zones = meshing.get(zone_key) - if not isinstance(zones, list): - continue - - for zone in zones: - if not isinstance(zone, dict) or zone.get("type") != "RotationVolume": - continue - - entities = zone.get("entities", {}).get("stored_entities", []) - if not entities: - continue - - if entities[0].get("private_attribute_entity_type_name") != "Sphere": - continue - - zone["type"] = "RotationSphere" - zone.pop("spacing_axial", None) - zone.pop("spacing_radial", None) - - def _rename_custom_volume_boundaries(params_dict): - def _rename_in_entity(entity): - if not isinstance(entity, dict): - return - if entity.get("private_attribute_entity_type_name") != "CustomVolume": - return - if "boundaries" in entity and "bounding_entities" not in entity: - entity["bounding_entities"] = entity.pop("boundaries") - - meshing = params_dict.get("meshing") - if not isinstance(meshing, dict): - return - - for zone_key in ("volume_zones", "zones"): - zones = meshing.get(zone_key) - if not isinstance(zones, list): - continue - - for zone in zones: - if not isinstance(zone, dict): - continue - - for container_key in ("entities", "enclosed_entities"): - container = zone.get(container_key) - if not isinstance(container, dict): - continue - for entity in container.get("stored_entities", []): - _rename_in_entity(entity) - - _migrate_rotation_volume_to_rotation_sphere(params_as_dict) - _rename_custom_volume_boundaries(params_as_dict) - - return params_as_dict - - -def _to_25_9_3(params_as_dict): - """Rename ``type_name`` to ``wall_function_type`` in ``use_wall_function`` dicts.""" - for model in params_as_dict.get("models", []): - if model.get("type") != "Wall": - continue - wall_fn = model.get("use_wall_function") - if isinstance(wall_fn, dict) and "type_name" in wall_fn: - wall_fn["wall_function_type"] = wall_fn.pop("type_name") - return params_as_dict - - -_TOTAL_PRESSURE_CONVERTED_KEY = "__total_pressure_nondim_applied" - - -def _convert_total_pressure_expression_from_ratio_to_nondim(params_as_dict): - """Convert TotalPressure string expressions from pressure ratio (P/P∞) to - Flow360 nondimensional pressure (P/(ρ∞a∞²)). - - Old semantics: expression = totalPressureRatio = P_total / P∞ - New semantics: expression = P_total / (ρ∞a∞²) = totalPressureRatio / γ - - Since ThermallyPerfectGas is a new feature that likely will no coexist with old - string expressions, γ=1.4 (standard Air) is safe for all legacy data. - Liquid operating conditions have ratio=1.0, so no conversion is needed. - - Referenced by both _to_25_8_8 and _to_25_10_0 milestones. A sentinel key on - the dict itself prevents double-conversion without module-level mutable state. - """ - if params_as_dict.get(_TOTAL_PRESSURE_CONVERTED_KEY): - return params_as_dict - params_as_dict[_TOTAL_PRESSURE_CONVERTED_KEY] = True - - operating_condition = params_as_dict.get("operating_condition", {}) - if operating_condition.get("type_name") in ("LiquidOperatingCondition",): - return params_as_dict - - gamma = 1.4 - - for model in params_as_dict.get("models", []): - if model.get("type") != "Inflow": - continue - spec = model.get("spec") - if not spec or spec.get("type_name") != "TotalPressure": - continue - if isinstance(spec.get("value"), str): - spec["value"] = f"({spec['value']}) / {gamma}" - - return params_as_dict - - -def _to_25_8_8(params_as_dict): - return _convert_total_pressure_expression_from_ratio_to_nondim(params_as_dict) - - -def _to_25_10_0(params_as_dict): - """Migrate to 25.10.0: output_format string to list, add vtkhdf/ensight support.""" - - def _migrate_output_format_to_list(params_as_dict): - """Convert string ``output_format`` values to list form. - - ``"both"`` becomes ``["paraview", "tecplot"]``, comma-separated strings are - split, and bare strings are wrapped in a list. - """ - outputs = params_as_dict.get("outputs") - if not outputs: - return - - for output in outputs: - fmt = output.get("output_format") - if isinstance(fmt, list): - output["output_format"] = sorted(set(fmt)) - continue - if not isinstance(fmt, str): - continue - if fmt == "both": - output["output_format"] = ["paraview", "tecplot"] - elif "," in fmt: - output["output_format"] = sorted(set(v.strip() for v in fmt.split(","))) - else: - output["output_format"] = [fmt] - - _migrate_output_format_to_list(params_as_dict) - _convert_total_pressure_expression_from_ratio_to_nondim(params_as_dict) - return params_as_dict - - -VERSION_MILESTONES = [ - (Flow360Version("24.11.1"), _to_24_11_1), - (Flow360Version("24.11.7"), _to_24_11_7), - (Flow360Version("24.11.10"), _to_24_11_10), - (Flow360Version("25.2.0"), _to_25_2_0), - (Flow360Version("25.2.1"), _to_25_2_1), - (Flow360Version("25.2.3"), _to_25_2_3), - (Flow360Version("25.4.1"), _to_25_4_1), - (Flow360Version("25.6.2"), _to_25_6_2), - (Flow360Version("25.6.4"), _to_25_6_4), - (Flow360Version("25.6.5"), _to_25_6_5), - (Flow360Version("25.6.6"), _to_25_6_6), - (Flow360Version("25.7.2"), _to_25_7_2), - (Flow360Version("25.7.6"), _to_25_7_6), - (Flow360Version("25.7.7"), _to_25_7_7), - (Flow360Version("25.8.0b4"), _to_25_8_0), - (Flow360Version("25.8.1"), _to_25_8_1), - (Flow360Version("25.8.3"), _to_25_8_3), - (Flow360Version("25.8.4"), _to_25_8_4), - (Flow360Version("25.8.8"), _to_25_8_8), - (Flow360Version("25.9.0"), _to_25_9_0), - (Flow360Version("25.9.1"), _to_25_9_1), - (Flow360Version("25.9.2"), _to_25_9_2), - (Flow360Version("25.9.3"), _to_25_9_3), -] # A list of the Python API version tuple with their corresponding updaters. - - -# pylint: disable=dangerous-default-value -def _find_update_path( - *, - version_from: Flow360Version, - version_to: Flow360Version, - version_milestones: list[tuple[Flow360Version, Any]], -): - - if version_from == version_to: - return [] - - if version_from >= version_milestones[-1][0]: - return [] - - if version_to < version_milestones[0][0]: - raise ValueError( - "Trying to update `SimulationParams` to a version lower than any known version." - ) - - def _get_path_start(): - for index, item in enumerate(version_milestones): - milestone_version = item[0] - if milestone_version > version_from: - # exclude equal because then it is already `milestone_version` version - return index - return None - - def _get_path_end(): - for index, item in enumerate(version_milestones): - milestone_version = item[0] - if milestone_version > version_to: - return index - 1 - return len(version_milestones) - 1 - - path_start = _get_path_start() - path_end = _get_path_end() - - return [ - item[1] for index, item in enumerate(version_milestones) if path_start <= index <= path_end - ] - - -def updater(version_from, version_to, params_as_dict) -> dict: - """ - Update parameters from version_from to version_to. - - Parameters - ---------- - version_from : str - The starting version. - version_to : str - The target version to update to. This has to be equal or higher than `version_from` - params_as_dict : dict - A dictionary containing parameters to be updated. - - Returns - ------- - dict - Updated parameters as a dictionary. - - Raises - ------ - Flow360NotImplementedError - If no update path exists from version_from to version_to. - - Notes - ----- - This function iterates through the update map starting from version_from and - updates the parameters based on the update path found. - """ - log.debug(f"Input SimulationParam has version: {version_from}.") - version_from_is_newer = Flow360Version(version_from) > Flow360Version(version_to) - - if version_from_is_newer: - raise ValueError( - f"[Internal] Misuse of updater, version_from ({version_from}) is higher than version_to ({version_to})" - ) - update_functions = _find_update_path( - version_from=Flow360Version(version_from), - version_to=Flow360Version(version_to), - version_milestones=VERSION_MILESTONES, - ) - for fun in update_functions: - _to_version = re.search(r"_to_(\d+_\d+_\d+)", fun.__name__).group(1) - log.debug(f"Updating input SimulationParam to {_to_version}...") - params_as_dict = fun(params_as_dict) - params_as_dict.pop(_TOTAL_PRESSURE_CONVERTED_KEY, None) - params_as_dict["version"] = str(version_to) - return params_as_dict diff --git a/flow360/component/simulation/framework/updater_functions.py b/flow360/component/simulation/framework/updater_functions.py index 76efb15e6..fec914eb0 100644 --- a/flow360/component/simulation/framework/updater_functions.py +++ b/flow360/component/simulation/framework/updater_functions.py @@ -1,103 +1,9 @@ -"""Implementation of the updater functions. The updated.py should just import functions from here.""" - - -def fix_ghost_sphere_schema(*, params_as_dict: dict): - """ - The previous ghost farfield has wrong schema (bug) and therefore needs data alternation. - """ - - def i_am_outdated_ghost_sphere(*, data: dict): - """Identify if the current dict is a outdated ghost sphere.""" - if "type_name" in data.keys() and data["type_name"] == "GhostSphere": - return True - return False - - def recursive_fix_ghost_surface(*, data): - if isinstance(data, dict): - # 1. Check if this is a ghost sphere instance - if i_am_outdated_ghost_sphere(data=data): - data.pop("type_name") - data["private_attribute_entity_type_name"] = "GhostSphere" - - # 2. Otherwise, recurse into each item in the dictionary - for _, val in data.items(): - recursive_fix_ghost_surface( - data=val, - ) - - elif isinstance(data, list): - # Recurse into each item in the list - for _, item in enumerate(data): - recursive_fix_ghost_surface(data=item) - - recursive_fix_ghost_surface(data=params_as_dict) - - -def is_entity_dict(data: dict): - """Check if current dict is an Entity item""" - return data.get("name") and (data.get("private_attribute_entity_type_name") is not None) - - -def remove_entity_bucket_field(*, params_as_dict: dict): - """Recursively remove legacy private_attribute_registry_bucket_name from all entity dicts.""" - - def _recursive_remove(data): - if isinstance(data, dict): - if is_entity_dict(data=data): - data.pop("private_attribute_registry_bucket_name", None) - for value in data.values(): - _recursive_remove(value) - elif isinstance(data, list): - for element in data: - _recursive_remove(element) - - _recursive_remove(params_as_dict) - return params_as_dict - - -def populate_entity_id_with_name(*, params_as_dict: dict): - """ - Recursively populates the entity item's private_attribute_id with its name if - the private_attribute_id is none. - """ - - def recursive_populate_entity_id_with_name(*, data): - if isinstance(data, dict): - # Check if current dict is an Entity item - if is_entity_dict(data=data): - if "private_attribute_id" not in data or data["private_attribute_id"] is None: - data["private_attribute_id"] = data["name"] - - for value in data.values(): - recursive_populate_entity_id_with_name(data=value) - - elif isinstance(data, list): - for element in data: - recursive_populate_entity_id_with_name(data=element) - - recursive_populate_entity_id_with_name(data=params_as_dict) - - -def update_symmetry_ghost_entity_name_to_symmetric(*, params_as_dict: dict): - """ - Recursively update ghost entity name from symmetric-* to symmetry-* - """ - - def recursive_update_symmetry_ghost_entity_name_to_symmetric(*, data): - if isinstance(data, dict): - # Check if current dict is an Entity item - if ( - is_entity_dict(data=data) - and data["private_attribute_entity_type_name"] == "GhostCircularPlane" - and data["name"].startswith("symmetry") - ): - data["name"] = data["name"].replace("symmetry", "symmetric") - - for value in data.values(): - recursive_update_symmetry_ghost_entity_name_to_symmetric(data=value) - - elif isinstance(data, list): - for element in data: - recursive_update_symmetry_ghost_entity_name_to_symmetric(data=element) - - recursive_update_symmetry_ghost_entity_name_to_symmetric(data=params_as_dict) +"""Relay schema-owned updater helper functions for simulation models.""" + +from flow360_schema.models.simulation.framework.updater_functions import ( + fix_ghost_sphere_schema, + is_entity_dict, + populate_entity_id_with_name, + remove_entity_bucket_field, + update_symmetry_ghost_entity_name_to_symmetric, +) diff --git a/flow360/component/simulation/framework/updater_utils.py b/flow360/component/simulation/framework/updater_utils.py index f16893efa..147709cac 100644 --- a/flow360/component/simulation/framework/updater_utils.py +++ b/flow360/component/simulation/framework/updater_utils.py @@ -1,179 +1,12 @@ -"""Utiliy functions for updater""" - -import re -from functools import wraps -from numbers import Number -from typing import Tuple - -import numpy as np - -from flow360.version import __version__ - - -def recursive_remove_key(data, key: str, *additional_keys: str): - """Recursively remove one or more keys from nested dict/list structures in place. - - This function performs an in-place traversal without unnecessary allocations - to preserve performance. It handles arbitrarily nested combinations of - dictionaries and lists. - """ - keys: Tuple[str, ...] = (key,) + additional_keys - - # Iterative traversal is typically faster than deep recursion in Python and - # avoids recursion depth limits for heavily nested WebUI payloads. - stack = [data] - while stack: - current = stack.pop() - - if isinstance(current, dict): - for item_key in keys: - current.pop(item_key, None) - stack.extend(current.values()) - elif isinstance(current, list): - stack.extend(current) - - -PYTHON_API_VERSION_REGEXP = r"^(\d+)\.(\d+)\.(\d+)(?:b(\d+))?$" - - -def compare_dicts(dict1, dict2, atol=1e-15, rtol=1e-10, ignore_keys=None): - """Check two dictionaries are same or not""" - if ignore_keys is None: - ignore_keys = set() - - # Filter out the keys to be ignored - dict1_filtered = {k: v for k, v in dict1.items() if k not in ignore_keys} - dict2_filtered = {k: v for k, v in dict2.items() if k not in ignore_keys} - - if dict1_filtered.keys() != dict2_filtered.keys(): - print( - f"dict keys not equal:\n dict1 {sorted(dict1_filtered.keys())}\n dict2 {sorted(dict2_filtered.keys())}" - ) - return False - - for key in dict1_filtered: - value1 = dict1_filtered[key] - value2 = dict2_filtered[key] - - if not compare_values(value1, value2, atol, rtol, ignore_keys): - print(f"dict value of key {key} not equal:\n dict1 {dict1[key]}\n dict2 {dict2[key]}") - return False - - return True - - -def compare_values(value1, value2, atol=1e-15, rtol=1e-10, ignore_keys=None): - """Check two values are same or not""" - # Handle numerical comparisons first (including int vs float) - if isinstance(value1, Number) and isinstance(value2, Number): - return np.isclose(value1, value2, rtol, atol) - - # Tuples get converted to lists when writing the JSON file - if isinstance(value1, tuple): - value1 = list(value1) - - if isinstance(value2, tuple): - value2 = list(value2) - - # Handle type mismatches for non-numerical types - if type(value1) != type(value2): - return False - - if isinstance(value1, dict) and isinstance(value2, dict): - return compare_dicts(value1, value2, atol, rtol, ignore_keys) - if isinstance(value1, list) and isinstance(value2, list): - return compare_lists(value1, value2, atol, rtol, ignore_keys) - return value1 == value2 - - -def compare_lists(list1, list2, atol=1e-15, rtol=1e-10, ignore_keys=None): - """Check two lists are same or not""" - if len(list1) != len(list2): - return False - - # Only sort if the lists contain simple comparable types (not dicts, lists, etc.) - def is_simple_type(item): - return isinstance(item, (str, int, float, bool)) or ( - isinstance(item, Number) and not isinstance(item, (dict, list)) - ) - - if list1 and all(is_simple_type(item) for item in list1): - list1, list2 = sorted(list1), sorted(list2) - - for item1, item2 in zip(list1, list2): - if not compare_values(item1, item2, atol, rtol, ignore_keys): - print(f"list value not equal:\n list1 {item1}\n list2 {item2}") - return False - - return True - - -class Flow360Version: - """ - Parser for the Flow360 Python API version. - Expected pattern is `major.minor.patch` (integers). - """ - - __slots__ = ["major", "minor", "patch"] - - def __init__(self, version: str): - """ - Initialize the version by parsing a string like '23.1.2'. - Each of major, minor, patch should be numeric. - """ - # Match three groups of digits separated by dots - match = re.match(PYTHON_API_VERSION_REGEXP, version.strip()) - if not match: - raise ValueError(f"Invalid version string: {version}") - - self.major = int(match.group(1)) - self.minor = int(match.group(2)) - self.patch = int(match.group(3)) - - def __lt__(self, other): - return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch) - - def __le__(self, other): - return (self.major, self.minor, self.patch) <= (other.major, other.minor, other.patch) - - def __gt__(self, other): - return (self.major, self.minor, self.patch) > (other.major, other.minor, other.patch) - - def __ge__(self, other): - return (self.major, self.minor, self.patch) >= (other.major, other.minor, other.patch) - - def __eq__(self, other): - # Also check that 'other' is the same type or has the same attributes - if not isinstance(other, Flow360Version): - return NotImplemented - return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch) - - def __ne__(self, other): - return not self.__eq__(other) - - def __str__(self): - return f"{self.major}.{self.minor}.{self.patch}" - - -def deprecation_reminder(version: str): - """ - If your_package.__version__ > version, raise. - Otherwise, do nothing special. - """ - - def decorator(func): - @wraps(func) - def wrapper(*args, **kwargs): - current = Flow360Version(__version__) - target = Flow360Version(version) - if current > target: - raise ValueError( - f"[INTERNAL] This validator or function is detecting/handling deprecated schema that was" - f" scheduled to be removed since {version}. " - "Please deprecate the schema now, write updater and remove related checks." - ) - return func(*args, **kwargs) - - return wrapper - - return decorator +"""Relay schema-owned updater utilities for simulation models.""" + +from flow360_schema.models.simulation.framework.updater_utils import ( + FLOW360_SCHEMA_DEFAULT_VERSION, + PYTHON_API_VERSION_REGEXP, + Flow360Version, + compare_dicts, + compare_lists, + compare_values, + deprecation_reminder, + recursive_remove_key, +) diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 1dd337041..158f00aa7 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -1,15 +1,11 @@ """Simulation services module.""" -# pylint: disable=duplicate-code, too-many-lines -import copy import json import os -from enum import Enum from typing import ( Any, Collection, Dict, - Iterable, List, Literal, Optional, @@ -18,57 +14,53 @@ ) import pydantic as pd -from flow360_schema.framework.expression.registry import ( # pylint: disable=unused-import +from flow360_schema.framework.physical_dimensions import Angle, Length +from flow360_schema.models.simulation.services import ( # pylint: disable=unused-import + ValidationCalledBy, + _get_default_reference_geometry, + _determine_validation_level, + _insert_forward_compatibility_notice, + _intersect_validation_levels, + _normalize_union_branch_error_location, + _parse_root_item_type_from_simulation_json, + _populate_error_context, + _sanitize_stack_trace, + _store_project_length_unit, + _traverse_error_location, + apply_simulation_setting_to_entity_info, + clean_unrelated_setting_from_params_dict, clear_context, + get_default_params, + handle_generic_exception, + init_unit_system, + initialize_variable_space, + merge_geometry_entity_info, + update_simulation_json, + validate_error_locations, + validate_model as _schema_validate_model, ) -from flow360_schema.framework.expression.variable import ( - RedeclaringVariableError, - get_referenced_expressions_and_user_variables, - restore_variable_space, -) - -# Required for correct global scope initialization -from flow360_schema.framework.physical_dimensions import Angle, Length -from flow360_schema.framework.validation.context import DeserializationContext from pydantic import TypeAdapter -from pydantic_core import ErrorDetails -from flow360.component.simulation.entity_info import GeometryEntityInfo -from flow360.component.simulation.entity_info import ( - merge_geometry_entity_info as merge_geometry_entity_info_obj, -) -from flow360.component.simulation.entity_info import parse_entity_info_model from flow360.component.simulation.exposed_units import supported_units_by_front_end from flow360.component.simulation.framework.entity_materializer import ( materialize_entities_and_selectors_in_place, ) -from flow360.component.simulation.framework.entity_registry import EntityRegistry -from flow360.component.simulation.framework.multi_constructor_model_base import ( - parse_model_dict, -) -from flow360.component.simulation.meshing_param.params import MeshingParams -from flow360.component.simulation.meshing_param.volume_params import AutomatedFarfield from flow360.component.simulation.models.bet.bet_translator_interface import ( generate_polar_file_name_list, translate_xfoil_c81_to_bet_dict, translate_xrotor_dfdc_to_bet_dict, ) -from flow360.component.simulation.models.surface_models import Freestream, Wall # pylint: disable=unused-import # For parse_model_dict from flow360.component.simulation.models.volume_models import BETDisk from flow360.component.simulation.operating_condition.operating_condition import ( - AerospaceCondition, GenericReferenceCondition, ThermalState, ) from flow360.component.simulation.primitives import Box # pylint: enable=unused-import -from flow360.component.simulation.simulation_params import ( - ReferenceGeometry, - SimulationParams, -) +from flow360.component.simulation.simulation_params import SimulationParams # Required for correct global scope initialization from flow360.component.simulation.translator.solver_translator import ( @@ -81,320 +73,14 @@ from flow360.component.simulation.translator.volume_meshing_translator import ( get_volume_meshing_json, ) -from flow360.component.simulation.unit_system import ( - _UNIT_SYSTEMS, - UnitSystem, - _dimensioned_type_serializer, - u, - unit_system_manager, -) -from flow360.component.simulation.units import validate_length -from flow360.component.simulation.validation.validation_context import ( - ALL, - ParamsValidationInfo, - ValidationContext, -) +from flow360.component.simulation.unit_system import _dimensioned_type_serializer, u +from flow360.component.simulation.validation.validation_context import ALL from flow360.exceptions import ( - Flow360RuntimeError, Flow360TranslationError, Flow360ValueError, ) from flow360.version import __version__ -# Required for correct global scope initialization - - -def init_unit_system(unit_system_name) -> UnitSystem: - """Returns UnitSystem object from string representation. - - Parameters - ---------- - unit_system_name : ["SI", "CGS", "Imperial"] - Unit system string representation - - Returns - ------- - UnitSystem - unit system - - Raises - ------ - ValueError - If unit system doesn't exist - RuntimeError - If this function is run inside unit system context - """ - - unit_system = _UNIT_SYSTEMS.get(unit_system_name) - if unit_system is None: - raise ValueError( - f"Unknown unit system: {unit_system_name!r}. " f"Available: {list(_UNIT_SYSTEMS)}" - ) - - if unit_system_manager.current is not None: - raise RuntimeError( - f"Services cannot be used inside unit system context. Used: {unit_system_manager.current.system_repr()}." - ) - return unit_system - - -def _store_project_length_unit(project_length_unit, params: SimulationParams): - if project_length_unit is not None: - # Store the length unit so downstream services/pipelines can use it - # pylint: disable=fixme - # TODO: client does not call this. We need to start using new webAPI for that - # pylint: disable=assigning-non-slot,no-member - params.private_attribute_asset_cache._force_set_attr( # pylint:disable=protected-access - "project_length_unit", project_length_unit - ) - return params - - -def _get_default_reference_geometry(length_unit: Length.Float64): - return ReferenceGeometry( - area=1 * length_unit**2, - moment_center=(0, 0, 0) * length_unit, - moment_length=(1, 1, 1) * length_unit, - ) - - -def get_default_params( - unit_system_name, length_unit, root_item_type: Literal["Geometry", "SurfaceMesh", "VolumeMesh"] -) -> dict: - """ - Returns default parameters in a given unit system. The defaults are not correct SimulationParams object as they may - contain empty required values. When generating default case settings: - - Use Model() if all fields has defaults or there are no required fields - - Use Model.construct() to disable validation - when there are required fields without value - - Parameters - ---------- - unit_system_name : str - The name of the unit system to use for parameter initialization. - - Returns - ------- - dict - Default parameters for Flow360 simulation stored in a dictionary. - - """ - # pylint: disable=import-outside-toplevel - from flow360.component.simulation.outputs.outputs import SurfaceOutput - from flow360.component.simulation.primitives import Surface - - unit_system = init_unit_system(unit_system_name) - dummy_value = 0.1 - project_length_unit = validate_length(length_unit) - with unit_system: - reference_geometry = _get_default_reference_geometry(project_length_unit) - operating_condition = AerospaceCondition(velocity_magnitude=dummy_value) - surface_output = SurfaceOutput( - name="Surface output", - entities=[Surface(name="*")], - output_fields=["Cp", "yPlus", "Cf", "CfVec"], - ) - - if root_item_type in ("Geometry", "SurfaceMesh"): - automated_farfield = AutomatedFarfield(name="Farfield") - with unit_system: - params = SimulationParams( - reference_geometry=reference_geometry, - meshing=MeshingParams( - volume_zones=[automated_farfield], - ), - operating_condition=operating_condition, - models=[ - Wall( - name="Wall", - surfaces=[Surface(name="*")], - roughness_height=0 * project_length_unit, - ), - Freestream(name="Freestream", surfaces=[automated_farfield.farfield]), - ], - outputs=[surface_output], - ) - - params = _store_project_length_unit(project_length_unit, params) - - return params.model_dump( - mode="json", - exclude_none=True, - exclude={ - "operating_condition": {"velocity_magnitude": True}, - "private_attribute_asset_cache": {"registry": True}, - "meshing": { - "defaults": {"edge_split_layers": True} - }, # Due to beta mesher by default is disabled. - }, - ) - - if root_item_type == "VolumeMesh": - with unit_system: - params = SimulationParams( - reference_geometry=reference_geometry, - operating_condition=operating_condition, - models=[ - Wall( - name="Wall", - surfaces=[Surface(name="placeholder1")], - roughness_height=0 * project_length_unit, - ), # to make it consistent with geo - Freestream( - name="Freestream", surfaces=[Surface(name="placeholder2")] - ), # to make it consistent with geo - ], - outputs=[surface_output], - ) - # cleaning up stored entities in default settings to let user decide: - params.models[0].entities.stored_entities = [] # pylint: disable=unsubscriptable-object - params.models[1].entities.stored_entities = [] # pylint: disable=unsubscriptable-object - - params = _store_project_length_unit(project_length_unit, params) - - return params.model_dump( - mode="json", - exclude_none=True, - exclude={ - "operating_condition": {"velocity_magnitude": True}, - "private_attribute_asset_cache": {"registry": True}, - "meshing": True, - }, - ) - raise ValueError( - f"Unknown root item type: {root_item_type}. Expected one of Geometry or SurfaceMesh or VolumeMesh" - ) - - -def _intersect_validation_levels(requested_levels, available_levels): - if requested_levels is not None and available_levels is not None: - if requested_levels == ALL: - validation_levels_to_use = [ - item for item in ["SurfaceMesh", "VolumeMesh", "Case"] if item in available_levels - ] - elif isinstance(requested_levels, str): - if requested_levels in available_levels: - validation_levels_to_use = [requested_levels] - else: - validation_levels_to_use = [] - else: - assert isinstance(requested_levels, list) - validation_levels_to_use = [ - item for item in requested_levels if item in available_levels - ] - return validation_levels_to_use - return [] - - -class ValidationCalledBy(Enum): - """ - Enum as indicator where `validate_model()` is called. - """ - - LOCAL = "Local" - SERVICE = "Service" - PIPELINE = "Pipeline" - - def get_forward_compatibility_error_message(self, version_from: str, version_to: str): - """ - Return error message string indicating that the forward compatibility is not guaranteed. - """ - error_suffix = " Errors may occur since forward compatibility is limited." - if self == ValidationCalledBy.LOCAL: - return { - "type": (f"{version_from} > {version_to}"), - "loc": [], - "msg": "The cloud `SimulationParam` (version: " - + version_from - + ") is too new for your local Python client (version: " - + version_to - + ")." - + error_suffix, - "ctx": {}, - } - if self == ValidationCalledBy.SERVICE: - return { - "type": (f"{version_from} > {version_to}"), - "loc": [], - "msg": "Your `SimulationParams` (version: " - + version_from - + ") is too new for the solver (version: " - + version_to - + ")." - + error_suffix, - "ctx": {}, - } - if self == ValidationCalledBy.PIPELINE: - # These will only appear in log. Ideally we should not rely on pipelines - # to emit useful error messages. Or else the local/service validation is not doing their jobs properly. - return { - # pylint:disable = protected-access - "type": (f"{version_from} > {version_to}"), - "loc": [], - "msg": "[Internal] Your `SimulationParams` (version: " - + version_from - + ") is too new for the solver (version: " - + version_to - + ")." - + error_suffix, - "ctx": {}, - } - return None - - -def _insert_forward_compatibility_notice( - validation_errors: list, - params_as_dict: dict, - validated_by: ValidationCalledBy, - version_to: str = __version__, -): - # If error occurs, inform user that the error message could due to failure in forward compatibility. - # pylint:disable=protected-access - version_from = SimulationParams._get_version_from_dict(model_dict=params_as_dict) - forward_compatibility_failure_error = validated_by.get_forward_compatibility_error_message( - version_from=version_from, version_to=version_to - ) - validation_errors.insert(0, forward_compatibility_failure_error) - return validation_errors - - -def initialize_variable_space(param_as_dict: dict, use_clear_context: bool = False) -> dict: - """Load all user variables from private attributes when a simulation params object is initialized.""" - if "private_attribute_asset_cache" not in param_as_dict.keys(): - return param_as_dict - asset_cache: dict = param_as_dict["private_attribute_asset_cache"] - if "variable_context" not in asset_cache.keys(): - return param_as_dict - if not isinstance(asset_cache["variable_context"], Iterable): - return param_as_dict - - variable_context = asset_cache["variable_context"] - - try: - restore_variable_space(variable_context, clear_first=use_clear_context) - except RedeclaringVariableError as e: - raise ValueError( - f"Loading user variable '{e.variable_name}' from simulation.json which is " - "already defined in local context. Please change your local user variable definition." - ) from e - except pd.ValidationError as e: - # Re-wrap with private_attribute_asset_cache prefix in loc - error_detail: dict = e.errors()[0] - loc = error_detail.get("loc", ()) - raise pd.ValidationError.from_exception_data( - "Invalid user variable/expression", - line_errors=[ - ErrorDetails( - type=error_detail["type"], - loc=("private_attribute_asset_cache",) + tuple(loc), - msg=error_detail.get("msg", "Unknown error"), - ctx=error_detail.get("ctx", {}), - ), - ], - ) from e - - return param_as_dict - - def validate_model( # pylint: disable=too-many-locals *, params_as_dict, @@ -427,361 +113,13 @@ def validate_model( # pylint: disable=too-many-locals validation_warnings : list A list of validation warnings (empty list if no warnings were recorded). """ - - def handle_multi_constructor_model(params_as_dict: dict) -> dict: - """ - Handle input cache of multi-constructor models. - """ - project_length_unit_dict = params_as_dict.get("private_attribute_asset_cache", {}).get( - "project_length_unit", None - ) - parse_model_info = ParamsValidationInfo( - {"private_attribute_asset_cache": {"project_length_unit": project_length_unit_dict}}, - [], - ) - with ( - ValidationContext(levels=validation_levels_to_use, info=parse_model_info), - DeserializationContext(), - ): - # Multi-constructor model support - updated_param_as_dict = parse_model_dict(params_as_dict, globals()) - return updated_param_as_dict - - def dict_preprocessing(params_as_dict: dict) -> dict: - """ - Preprocess the parameters dictionary before validation. - """ - # pylint: disable=protected-access - params_as_dict = SimulationParams._sanitize_params_dict(params_as_dict) - params_as_dict = handle_multi_constructor_model(params_as_dict) - - # Materialize stored_entities (dict -> shared instances) and per-list deduplication - # pylint: disable=fixme - # TODO: The need for materialization on entities? - # * Ideally stored_entities should store entity IDs only. And we do not even need to materialize them here. - # * This change has to wait for the front end to support entity IDs. - # * Although to be fair having entities esp the draft entities inlined allow copy pasting of - # * the SimulationParams, otherwise user will copy a bunch of links which become stale under a new context. - # * Benefits: - # * 1. Much shorter JSON. - # * 2. Deserialization ALL entities just once, not just the persistent ones. - # * 3. Strong requirement that ALL entities must come from entity_info/registry. - # * 4. Data structural-wise single source of truth. - - # TODO: Unifying Materialization and Entity Info? - # * As of now entities will still be separate instances when being - # * 1. materialized here versus - # * 2. deserialized in the entity info. - # * This impacts manually picked entities and all draft entities since they cannot be matched by Selectors. - # * validate_mode() is called in 3 main places: - # * 1. Local validation - # * 2. Service validation - # * 3. Local deserialization of cloud simulation.json - # * Only the last scenario is affected by this issue because in 1 and 2 user has done all the possible - # * editing so keeping data linkage is non-beneficial. - # * Although for the last scenario, if the user makes changes to the entities via create_draft(), the draft's - # * entity_info will be source of truth and the changes should be reflected in - # * both the assignment and the entity_info. - - params_as_dict = materialize_entities_and_selectors_in_place(params_as_dict) - return params_as_dict - - validation_errors = None - validation_warnings: List[Dict[str, Any]] = [] - validated_param = None - validation_context: Optional[ValidationContext] = None - - params_as_dict = clean_unrelated_setting_from_params_dict(params_as_dict, root_item_type) - - # The final validation levels will be the intersection of the requested levels and the levels available - # We always assume we want to run case so that we can expose as many errors as possible - available_levels = _determine_validation_level(up_to="Case", root_item_type=root_item_type) - validation_levels_to_use = _intersect_validation_levels(validation_level, available_levels) - forward_compatibility_mode = False - - # pylint: disable=protected-access - # Note: Need to run updater first to accommodate possible schema change in input caches. - params_as_dict, forward_compatibility_mode = SimulationParams._update_param_dict(params_as_dict) - - # The private_attribute_asset_cache should have been validated/deserialized here before all - # the following processes. And then you would just pass a validated asset cache instant to the SimulationParams. - # By design (not explicitly planned but in reality) The AssetCache is a pure context provider of the - # SimulationParams and its content does not, for most part, interact with each other or depends on the user setting - # part of the simulation.json. Therefore it should be fine for the asset cache to be deserialized independently - # before the user setting part of the simulation.json. - # ** There are several main benefit: - # 1. Validate asset cache gives correct and accurate error location if any. This usually only apply to - # front-end forms but it is also the front-end that rely on accurate link of error location for webUI error viewer - # to work properly. - # 2. We have to deserialize everything during the process anyway. For example the variables, the selectors, - # and the entity info. We are already actually doing this step by step but there are always places that we - # have not covered yet and thus we have issues like [FXC-5256]. - # 3. Validated asset cache gives proper type hint and also object interface instead of pure JSON interface. - # It is just much easier to work with. - # 4. We do not have to validate project_length_unit 10 times here and there. This speeds up the validation process - # as well as restrict to single source of truth even though: - # a) user cannot directly interact with the source and - # b) We manage the asset cache (source of truth). - # 5. I think this also goes well with the general direction of clear separation of different parts of - # simulation.json in terms of responsibility as well as purpose. - - try: - updated_param_as_dict = dict_preprocessing(params_as_dict) - - # Initialize variable space - use_clear_context = validated_by == ValidationCalledBy.SERVICE - initialize_variable_space(updated_param_as_dict, use_clear_context) - referenced_expressions = get_referenced_expressions_and_user_variables( - updated_param_as_dict - ) - - validation_info = ParamsValidationInfo( - param_as_dict=updated_param_as_dict, - referenced_expressions=referenced_expressions, - ) - - with ValidationContext( - levels=validation_levels_to_use, - info=validation_info, - ) as context: - validation_context = context - # Reuse pre-deserialized entity_info to avoid double deserialization - pre_deserialized_entity_info = validation_info.get_entity_info() - if pre_deserialized_entity_info is not None: - # Create shallow copy with entity_info substituted - updated_param_as_dict = {**updated_param_as_dict} - updated_param_as_dict["private_attribute_asset_cache"] = { - **updated_param_as_dict["private_attribute_asset_cache"], - "project_entity_info": pre_deserialized_entity_info, - } - with DeserializationContext(): - validated_param = SimulationParams.model_validate(updated_param_as_dict) - - except pd.ValidationError as err: - validation_errors = err.errors() - except Exception as err: # pylint: disable=broad-exception-caught - import traceback # pylint: disable=import-outside-toplevel - - stack = traceback.format_exc() - validation_errors = handle_generic_exception( - err, validation_errors, loc_prefix=None, error_stack=stack - ) - finally: - if validation_context is not None: - validation_warnings = list(validation_context.validation_warnings) - - if validation_errors is not None: - validation_errors = validate_error_locations(validation_errors, params_as_dict) - - if forward_compatibility_mode and validation_errors is not None: - # pylint: disable=fixme - # TODO: If forward compatibility issue found. Try to tell user how they can get around it. - # TODO: Recommend solver/python client version they should use instead. - validation_errors = _insert_forward_compatibility_notice( - validation_errors, params_as_dict, validated_by - ) - - return validated_param, validation_errors, validation_warnings - - -def clean_unrelated_setting_from_params_dict(params: dict, root_item_type: str) -> dict: - """ - Cleans the parameters dictionary by removing properties if they do not affect the remaining workflow. - - - Parameters - ---------- - params : dict - The original parameters dictionary. - root_item_type : str - The root item type determining specific cleaning actions. - - Returns - ------- - dict - The cleaned parameters dictionary. - """ - - if root_item_type == "VolumeMesh": - params.pop("meshing", None) - - return params - - -def _sanitize_stack_trace(stack: str) -> str: - """ - Sanitize file paths in stack trace to only show paths starting from 'flow360/'. - - Gracefully returns the original stack if sanitization fails. - - Parameters - ---------- - stack : str - The original stack trace string. - - Returns - ------- - str - The sanitized stack trace with shortened file paths, or the original - stack if sanitization fails. - """ - # pylint: disable=import-outside-toplevel - import re - - try: - # Remove the "Traceback (most recent call last):\n" prefix - stack = re.sub(r"^Traceback \(most recent call last\):\n\s*", "", stack) - - # Pattern to match file paths containing 'flow360/' - # Captures everything before 'flow360/' and replaces with just 'flow360/' - pattern = r'File "[^"]*[/\\](flow360[/\\][^"]*)"' - replacement = r'File "\1"' - return re.sub(pattern, replacement, stack) - except Exception: # pylint: disable=broad-exception-caught - return stack - - -def handle_generic_exception( - err: Exception, - validation_errors: Optional[list], - loc_prefix: Optional[list[str]] = None, - error_stack: Optional[str] = None, -) -> list: - """ - Handles generic exceptions during validation, adding to validation errors. - - Parameters - ---------- - err : Exception - The exception caught during validation. - validation_errors : list or None - Current list of validation errors, may be None. - loc_prefix : list or None - Prefix of the location of the generic error to help locate the issue - error_stack : str or None - The error stack trace, if available. - - Returns - ------- - list - The updated list of validation errors including the new error. - """ - if validation_errors is None: - validation_errors = [] - - error_entry = { - "type": err.__class__.__name__.lower().replace("error", "_error"), - "loc": ["unknown"] if loc_prefix is None else loc_prefix, - "msg": str(err), - "ctx": {}, - } - - if error_stack is not None: - error_entry["debug"] = _sanitize_stack_trace(error_stack) - - validation_errors.append(error_entry) - return validation_errors - - -def validate_error_locations(errors: list, params: dict) -> list: - """ - Validates the locations in the errors to ensure they correspond to the params dict. - - Parameters - ---------- - errors : list - The list of validation errors to process. - params : dict - The parameters dictionary being validated. - - Returns - ------- - list - The updated list of errors with validated locations and context. - """ - for error in errors: - current = params - for field in error["loc"][:-1]: - current, valid = _traverse_error_location(current, field) - if not valid: - error["loc"] = tuple(loc for loc in error["loc"] if loc != field) - - _normalize_union_branch_error_location(error, current) - _populate_error_context(error) - return errors - - -def _normalize_union_branch_error_location(error: dict, current) -> None: - """ - Hide internal tagged-union branch names from user-facing error locations. - - ValueOrExpression uses tagged union branches named ``number`` and ``expression``. - Pydantic includes the selected branch tag in ``loc``. When the original input is a - legacy ``{\"value\": ..., \"units\": ...}`` payload, restore the old ``value`` leaf. - Otherwise, collapse the synthetic branch name to the parent field. - """ - loc = error.get("loc") - if not isinstance(loc, tuple) or len(loc) == 0: - return - - branch = loc[-1] - if branch not in {"number", "expression"}: - return - - if isinstance(current, dict): - if branch == "number" and "value" in current: - error["loc"] = (*loc[:-1], "value") - return - if branch == "expression" and "expression" in current: - error["loc"] = (*loc[:-1], "expression") - return - - error["loc"] = loc[:-1] - - -def _traverse_error_location(current, field): - """ - Traverse through the error location path within the parameters. - - Parameters - ---------- - current : any - The current position in the params dict or list. - field : any - The current field being validated. - - Returns - ------- - tuple - The updated current position and whether the traversal was valid. - """ - if isinstance(field, int) and isinstance(current, list) and field in range(len(current)): - return current[field], True - if isinstance(field, str) and isinstance(current, dict) and current.get(field): - return current.get(field), True - return current, False - - -def _populate_error_context(error: dict): - """ - Populates the error context with relevant stringified values. - - Parameters - ---------- - error : dict - The error dictionary to update with context information. - """ - ctx = error.get("ctx") - if isinstance(ctx, dict): - for field_name, context in ctx.items(): - try: - error["ctx"][field_name] = ( - [str(item) for item in context] if isinstance(context, list) else str(context) - ) - except Exception: # pylint: disable=broad-exception-caught - error["ctx"][field_name] = "" - else: - error["ctx"] = {} + return _schema_validate_model( + params_as_dict=params_as_dict, + validated_by=validated_by, + root_item_type=root_item_type, + validation_level=validation_level, + version_to=__version__, + ) # pylint: disable=too-many-arguments @@ -873,16 +211,6 @@ def _get_mesh_unit(params_as_dict: dict) -> str: return mesh_unit -def _determine_validation_level( - up_to: Literal["SurfaceMesh", "VolumeMesh", "Case"], - root_item_type: Union[Literal["Geometry", "SurfaceMesh", "VolumeMesh"], None], -) -> list: - if root_item_type is None: - return None - all_lvls = ["Geometry", "SurfaceMesh", "VolumeMesh", "Case"] - return all_lvls[all_lvls.index(root_item_type) + 1 : all_lvls.index(up_to) + 1] - - def _process_surface_mesh( params: dict, root_item_type: str, mesh_unit: str ) -> Optional[Dict[str, Any]]: @@ -1083,29 +411,6 @@ def change_unit_system(*, data: dict, target_unit_system: Literal["SI", "Imperia return data -def update_simulation_json(*, params_as_dict: dict, target_python_api_version: str): - """ - Run the SimulationParams' updater to update to specified version. - """ - errors = [] - updated_params_as_dict: dict = None - try: - # pylint:disable = protected-access - updated_params_as_dict, input_has_higher_version = SimulationParams._update_param_dict( - params_as_dict, target_python_api_version - ) - if input_has_higher_version: - raise ValueError( - f"[Internal] API misuse. Input version " - f"({SimulationParams._get_version_from_dict(model_dict=params_as_dict)}) is higher than " - f"requested target version ({target_python_api_version})." - ) - except (Flow360RuntimeError, ValueError, KeyError) as e: - # Expected exceptions - errors.append(str(e)) - return updated_params_as_dict, errors - - def _serialize_unit_in_dict(data): """ Recursively serialize unit type data in a dictionary or list. @@ -1240,288 +545,3 @@ def translate_xfoil_c81_bet_disk( # Expected exceptions errors.append(str(e)) return bet_dict_list, errors - - -def _parse_root_item_type_from_simulation_json(*, param_as_dict: dict): - """[External] Deduct the root item entity type from simulation.json""" - try: - entity_info_type = param_as_dict["private_attribute_asset_cache"]["project_entity_info"][ - "type_name" - ] - if entity_info_type == "GeometryEntityInfo": - return "Geometry" - if entity_info_type == "SurfaceMeshEntityInfo": - return "SurfaceMesh" - if entity_info_type == "VolumeMeshEntityInfo": - return "VolumeMesh" - raise ValueError(f"[INTERNAL] Invalid type of the entity info found: {entity_info_type}") - except KeyError: - # pylint:disable = raise-missing-from - raise ValueError("[INTERNAL] Failed to get the root item from the simulation.json!!!") - - -def merge_geometry_entity_info( - draft_param_as_dict: dict, geometry_dependencies_param_as_dict: list[dict] -): - """ - Merge the geometry entity info from geometry dependencies into the draft simulation param dict. - - Parameters - ---------- - draft_param_as_dict : dict - The draft simulation parameters dictionary. - geometry_dependencies_param_as_dict : list of dict - The list of geometry dependencies simulation parameters dictionaries. - - Returns - ------- - dict - The updated draft simulation parameters dictionary with merged geometry entity info. - """ - draft_param_entity_info_dict = draft_param_as_dict.get("private_attribute_asset_cache", {}).get( - "project_entity_info", {} - ) - if draft_param_entity_info_dict.get("type_name") != "GeometryEntityInfo": - return draft_param_as_dict - - current_entity_info = GeometryEntityInfo.deserialize(draft_param_entity_info_dict) - - entity_info_components = [] - for geometry_param_as_dict in geometry_dependencies_param_as_dict: - dependency_entity_info_dict = geometry_param_as_dict.get( - "private_attribute_asset_cache", {} - ).get("project_entity_info", {}) - if dependency_entity_info_dict.get("type_name") != "GeometryEntityInfo": - continue - entity_info_components.append(GeometryEntityInfo.deserialize(dependency_entity_info_dict)) - - merged_entity_info = merge_geometry_entity_info_obj( - current_entity_info=current_entity_info, - entity_info_components=entity_info_components, - ) - merged_entity_info_dict = merged_entity_info.model_dump(mode="json", exclude_none=True) - - return merged_entity_info_dict - - -# Draft entity type names that should be preserved during entity replacement. -# Draft entities (Box, Cylinder, etc.) are user-defined and not tied to uploaded files, -# so they should be kept from the source simulation settings. -# Ghost entities are associated with the geometry/mesh and should be replaced with target's. -def _get_draft_entity_type_names() -> set: - """Extract entity type names from DraftEntityTypes in entity_info.py.""" - # pylint: disable=import-outside-toplevel - import types - from typing import get_args, get_origin - - from flow360.component.simulation.entity_info import EntityInfoModel - - type_names = set() - - # Get draft_entities field type - draft_field = EntityInfoModel.model_fields[ # pylint:disable=unsubscriptable-object - "draft_entities" - ] - draft_annotation = draft_field.annotation - # Unwrap List[Annotated[Union[...], ...]] -> Union[...] - inner_type = get_args(draft_annotation)[0] # Get inner type from List - union_args = get_args(inner_type) # Get Annotated args - if union_args: - actual_union = union_args[0] # First arg is the Union - # Support both typing.Union and types.UnionType (X | Y syntax in Python 3.10+) - if get_origin(actual_union) is Union or isinstance(actual_union, types.UnionType): - for cls in get_args(actual_union): - type_names.add(cls.__name__) - - return type_names - - -DRAFT_ENTITY_TYPE_NAMES = _get_draft_entity_type_names() - - -def _replace_entities_by_type_and_name( - template_dict: dict, - target_registry: EntityRegistry, -) -> Tuple[dict, List[Dict[str, Any]]]: - """ - Traverse template_dict and replace stored_entities with matching entities from target_registry. - - Matching strategy: - - Use private_attribute_entity_type_name (e.g., "Surface", "Edge") to determine type - - Use name field for name matching - - Draft entity types (Box, Cylinder, etc.) are preserved without matching since they are - user-defined and not tied to uploaded files - - Ghost and persistent entity types are matched and replaced - - Parameters - ---------- - template_dict : dict - The simulation settings dictionary to process - target_registry : EntityRegistry - Registry containing target entities for replacement - - Returns - ------- - Tuple[dict, List[Dict[str, Any]]] - (Updated dictionary, List of warnings for unmatched entities) - """ - warnings = [] - - # Pre-build lookup dictionary for performance: {(type_name, name): entity_dict} - entity_lookup: Dict[Tuple[str, str], dict] = {} - for entity_list in target_registry.internal_registry.values(): - for entity in entity_list: - key = (entity.private_attribute_entity_type_name, entity.name) - entity_lookup[key] = entity.model_dump(mode="json", exclude_none=True) - - def process_stored_entities(stored_entities: list) -> list: - """Process stored_entities list, replacing or removing entities.""" - new_stored = [] - for entity_dict in stored_entities: - entity_type_name = entity_dict.get("private_attribute_entity_type_name") - entity_name = entity_dict.get("name") - - # Preserve Draft types directly (user-defined, not tied to uploaded files) - if entity_type_name in DRAFT_ENTITY_TYPE_NAMES: - new_stored.append(entity_dict) - continue - - # Persistent types need matching replacement - key = (entity_type_name, entity_name) - if key in entity_lookup: - new_stored.append(entity_lookup[key]) - else: - # Skip unmatched entities, record warning - warnings.append( - { - "type": "entity_not_found", - "loc": ["stored_entities"], - "msg": f"Entity '{entity_name}' (type: {entity_type_name}) not found in target entity info", - "ctx": {}, - } - ) - return new_stored - - def traverse_and_replace(obj): - """Recursively traverse dict/list to find and process stored_entities.""" - if isinstance(obj, dict): - if "stored_entities" in obj and isinstance(obj["stored_entities"], list): - obj["stored_entities"] = process_stored_entities(obj["stored_entities"]) - for value in obj.values(): - traverse_and_replace(value) - elif isinstance(obj, list): - for item in obj: - traverse_and_replace(item) - - traverse_and_replace(template_dict) - return template_dict, warnings - - -def apply_simulation_setting_to_entity_info( # pylint:disable=too-many-locals - simulation_setting_dict: dict, - entity_info_dict: dict, -): - """ - Apply simulation settings from one project to another project with different entity info. - - This function merges simulation settings (case/meshing configuration) from a source - simulation.json with the entity info from a target simulation.json. It handles entity - matching by type and name, preserving user-defined draft entities while replacing - persistent and ghost entities with those from the target. - - Parameters - ---------- - simulation_setting_dict : dict - A simulation.json dictionary that provides case/meshing settings. - This is the "source" that contains the settings to be applied. - entity_info_dict : dict - A simulation.json dictionary that provides the entity info (surfaces, edges, etc.). - This is the "target" whose entities will be used in the result. - - Returns - ------- - Tuple[dict, Optional[List], List[Dict[str, Any]]] - A tuple containing: - - result_dict: The merged simulation.json dictionary - - errors: List of validation errors, or None if validation passed - - warnings: List of warnings (unmatched entities + validation warnings) - - Notes - ----- - Entity handling: - - Persistent entities (Surface, Edge, GenericVolume, etc.): Matched by (type, name) - and replaced with target's entities. Unmatched entities are removed with warnings. - - Draft entities (Box, Cylinder, Point, etc.): Preserved from source without matching, - as they are user-defined and not tied to uploaded files. - - Ghost entities: Replaced with target's, as they are associated with the geometry/mesh. - - For GeometryEntityInfo, grouping tags (face_group_tag, body_group_tag, edge_group_tag) - are inherited from the source to ensure consistent entity selection. - """ - # pylint:disable=protected-access - # Step 1: Preprocess both input dicts - simulation_setting_dict = SimulationParams._sanitize_params_dict(simulation_setting_dict) - simulation_setting_dict, _ = SimulationParams._update_param_dict(simulation_setting_dict) - entity_info_dict = SimulationParams._sanitize_params_dict(entity_info_dict) - entity_info_dict, _ = SimulationParams._update_param_dict(entity_info_dict) - - # Step 2: Extract entity_info from both dicts - target_entity_info_data = entity_info_dict.get("private_attribute_asset_cache", {}).get( - "project_entity_info", {} - ) - source_entity_info = simulation_setting_dict.get("private_attribute_asset_cache", {}).get( - "project_entity_info", {} - ) - - # Step 3: Merge entity_info (use target's persistent entities, preserve source's draft entities) - merged_entity_info = copy.deepcopy(target_entity_info_data) - # Preserve draft entities from source (user-defined, not tied to uploaded files) - # Ghost entities stay from target as they are associated with the geometry/mesh - merged_entity_info["draft_entities"] = source_entity_info.get("draft_entities", []) - # Preserve grouping tags from source (only for GeometryEntityInfo) - # This ensures the registry is built with the correct grouping selection - # Only copy grouping tags if target is also GeometryEntityInfo to avoid invalid keys - if target_entity_info_data.get("type_name") == "GeometryEntityInfo": - # Map each tag to its corresponding attribute_names field - tag_to_attr_names = { - "face_group_tag": "face_attribute_names", - "body_group_tag": "body_attribute_names", - "edge_group_tag": "edge_attribute_names", - } - for tag_key, attr_names_key in tag_to_attr_names.items(): - source_tag = source_entity_info.get(tag_key) - if source_tag is not None: - # Only use source's tag if it exists in target's attribute_names - # Otherwise keep target's tag to avoid empty registry - target_attr_names = target_entity_info_data.get(attr_names_key, []) - if source_tag in target_attr_names: - merged_entity_info[tag_key] = source_tag - # else: keep target's original tag (already in merged_entity_info from deepcopy) - - # Step 4: Build registry from merged entity_info (with source's grouping tags) - merged_entity_info_obj = parse_entity_info_model(merged_entity_info) - target_registry = EntityRegistry.from_entity_info(merged_entity_info_obj) - - # Update simulation_setting_dict with merged entity_info - simulation_setting_dict["private_attribute_asset_cache"][ - "project_entity_info" - ] = merged_entity_info - - # Step 5: Replace entities in stored_entities - simulation_setting_dict, entity_warnings = _replace_entities_by_type_and_name( - simulation_setting_dict, target_registry - ) - - # Step 6: Validate and return results - root_item_type = _parse_root_item_type_from_simulation_json( - param_as_dict=simulation_setting_dict - ) - _, errors, validation_warnings = validate_model( - params_as_dict=copy.deepcopy(simulation_setting_dict), - validated_by=ValidationCalledBy.SERVICE, - root_item_type=root_item_type, - validation_level=ALL, - ) - - all_warnings = entity_warnings + validation_warnings - return simulation_setting_dict, errors, all_warnings diff --git a/flow360/component/simulation/services_utils.py b/flow360/component/simulation/services_utils.py index a53ecacea..44d41c422 100644 --- a/flow360/component/simulation/services_utils.py +++ b/flow360/component/simulation/services_utils.py @@ -1,154 +1,6 @@ """Utility functions for the simulation services.""" -from typing import TYPE_CHECKING, Any - -from flow360.component.simulation.framework.entity_expansion_utils import ( - get_registry_from_asset_cache, -) -from flow360.component.simulation.framework.entity_selector import _process_selectors -from flow360.component.simulation.framework.entity_utils import ( - walk_object_tree_with_cycle_detection, +from flow360_schema.models.simulation.services_utils import ( + strip_implicit_edge_split_layers_inplace, + strip_selector_matches_and_broken_entities_inplace, ) - -_MIRRORED_ENTITY_TYPE_NAMES = ("MirroredSurface", "MirroredGeometryBodyGroup") - -if TYPE_CHECKING: - from flow360.component.simulation.simulation_params import SimulationParams - - -def strip_implicit_edge_split_layers_inplace(params: "SimulationParams", params_dict: dict) -> dict: - """ - Remove implicitly injected `edge_split_layers` from serialized params. - This extra and specific function was added due to a change in schema during lifecycle of a release (uncommon) - - Why not use `exclude_unset` or `exclude_defaults` globally during `model_dump()`? - - `exclude_unset` strips many unrelated defaulted fields and can affect downstream workflows. - - `exclude_defaults` also strips explicitly user-set values that equal the default. - """ - meshing = getattr(params, "meshing", None) - defaults = getattr(meshing, "defaults", None) - if defaults is None: - return params_dict - - if "edge_split_layers" in defaults.model_fields_set: - # Keep explicit user setting (including explicit value equal to default). - return params_dict - - meshing_dict = params_dict.get("meshing") - if not isinstance(meshing_dict, dict): - return params_dict - - defaults_dict = meshing_dict.get("defaults") - if not isinstance(defaults_dict, dict): - return params_dict - - defaults_dict.pop("edge_split_layers", None) - return params_dict - - -def strip_selector_matches_and_broken_entities_inplace(params) -> Any: - """ - In stored_entities: - 1. Remove entities matched by selectors from each EntityList's stored_entities, in place. - 2. Remove registry-backed entities that are not valid for the current params registry (broken/foreign), - in place. This primarily targets mirrored entities, but also protects against stale persistent entities. - - Rationale: - - Keep user hand-picked entities distinguishable for the UI by stripping items that are - implied by EntitySelector expansion. - - Operate on the deserialized params object to avoid dict-level selector handling. - - Behavior: - - For every EntityList-like object that has a non-empty `selectors` list, compute the set - of entities implied by those selectors over the registry, and remove those implied entities - from its `stored_entities` list. - - For every EntityList-like object, check if it contains any mirror entities that no longer - have a corresponding geometry entity, and remove them from the list. - - Returns the same object for chaining. - """ - asset_cache = getattr(params, "private_attribute_asset_cache", None) - project_entity_info = getattr(asset_cache, "project_entity_info", None) - if asset_cache is None or project_entity_info is None: - # Compatibility with some unit tests. - return params - - selector_cache: dict = {} - registry = get_registry_from_asset_cache(asset_cache) - - valid_mirrored_registry_keys = { - (entity.private_attribute_entity_type_name, entity.private_attribute_id) - for entity in registry.find_by_type_name(list(_MIRRORED_ENTITY_TYPE_NAMES)) - } - - def _extract_entity_key(item) -> tuple: - """Extract stable key from entity object.""" - entity_type = getattr(item, "private_attribute_entity_type_name", None) - entity_id = getattr(item, "private_attribute_id", None) - return (entity_type, entity_id) - - def _matched_keyset_for_selectors(selectors_list: list) -> set[tuple]: - additions_by_class, _ = _process_selectors( - registry, - selectors_list, - selector_cache, - ) - keys: set = set() - for items in additions_by_class.values(): - for entity in items: - keys.add(_extract_entity_key(entity)) - return keys - - def _strip_selector_matches_and_broken_entities(obj) -> bool: - """ - Strip entities matched by selectors from EntityList's stored_entities, then drop mirrored entities - that are not present in the current params registry. - Returns True to continue traversing, False to stop. - """ - selectors_list = getattr(obj, "selectors", None) - stored_entities = getattr(obj, "stored_entities", None) - if not isinstance(stored_entities, list): - return True - - if not stored_entities: - obj.stored_entities = [] - return False - - updated_entities = stored_entities - - if isinstance(selectors_list, list) and selectors_list: - matched_keys = _matched_keyset_for_selectors(selectors_list) - if matched_keys: - updated_entities = [ - item - for item in updated_entities - if _extract_entity_key(item) not in matched_keys - ] - if not updated_entities: - obj.stored_entities = [] - return False - - cleaned_entities = [] - for item in updated_entities: - entity_type, entity_id = _extract_entity_key(item) - # Keep non-entity objects (or entities without stable keys) untouched. - if entity_type is None or entity_id is None: - cleaned_entities.append(item) - continue - - if entity_type in _MIRRORED_ENTITY_TYPE_NAMES: - if (entity_type, entity_id) in valid_mirrored_registry_keys: - cleaned_entities.append(item) - continue - - cleaned_entities.append(item) - - obj.stored_entities = cleaned_entities - - return False # Don't traverse into EntityList internals - # Continue traversing - - walk_object_tree_with_cycle_detection( - params, _strip_selector_matches_and_broken_entities, check_dict=False - ) - return params diff --git a/flow360/component/simulation/user_code/core/types.py b/flow360/component/simulation/user_code/core/types.py index b8232e2fe..0c252efb2 100644 --- a/flow360/component/simulation/user_code/core/types.py +++ b/flow360/component/simulation/user_code/core/types.py @@ -6,7 +6,6 @@ from flow360_schema.framework.expression import ( SerializedValueOrExpression, UnytQuantity, - UserVariable, ValueOrExpression, ) from flow360_schema.framework.expression.value_or_expression import ( @@ -18,30 +17,15 @@ from flow360_schema.framework.expression.variable import ( save_user_variables as _schema_save_user_variables, ) +from flow360_schema.models.simulation.user_code.core.types import ( + get_post_processing_variables, +) from flow360.component.simulation.framework.updater_utils import deprecation_reminder register_deprecation_check(deprecation_reminder) -def get_post_processing_variables(params) -> set[str]: - """ - Get all the post processing related variables from the simulation params. - """ - post_processing_variables = set() - for item in params.outputs if params.outputs else []: - if item.output_type in ("IsosurfaceOutput", "TimeAverageIsosurfaceOutput"): - for isosurface in item.entities.items: - if isinstance(isosurface.field, UserVariable): - post_processing_variables.add(isosurface.field.name) - if "output_fields" not in item.__class__.model_fields: - continue - for output_field in item.output_fields.items: - if isinstance(output_field, UserVariable): - post_processing_variables.add(output_field.name) - return post_processing_variables - - def save_user_variables(params): """Client adapter: extract data from params, delegate to schema.""" post_processing_variables = get_post_processing_variables(params) diff --git a/flow360/component/simulation/utils.py b/flow360/component/simulation/utils.py index 93e07676e..0560af2b1 100644 --- a/flow360/component/simulation/utils.py +++ b/flow360/component/simulation/utils.py @@ -1,60 +1,9 @@ -"""Utility functions for the simulation component.""" - -# pylint: disable=unused-import -from typing import Annotated, Union, get_args, get_origin +"""Relay schema-owned utility functions for the simulation component.""" from flow360_schema.framework.bounding_box import BoundingBox, BoundingBoxType - -from flow360.component.simulation.framework.updater_utils import recursive_remove_key - - -def sanitize_params_dict(model_dict): - """ - !!!WARNING!!!: This function changes the input dict in place!!! - - Clean the redundant content in the params dict from WebUI - """ - recursive_remove_key(model_dict, "_id", "private_attribute_image_id") - - model_dict.pop("hash", None) - - return model_dict - - -def get_combined_subclasses(cls): - """get subclasses of cls""" - if isinstance(cls, tuple): - subclasses = set() - for single_cls in cls: - subclasses.update(single_cls.__subclasses__()) - return list(subclasses) - return cls.__subclasses__() - - -def is_exact_instance(obj, cls): - """Check if an object is an instance of a class and not a subclass.""" - if isinstance(cls, tuple): - return any(is_exact_instance(obj, c) for c in cls) - if not isinstance(obj, cls): - return False - # Check if there are any subclasses of cls - subclasses = get_combined_subclasses(cls) - for subclass in subclasses: - if isinstance(obj, subclass): - return False - return True - - -def is_instance_of_type_in_union(obj, typ) -> bool: - """Check whether input `obj` is instance of the types specified in the `Union`(`typ`)""" - # If typ is an Annotated type, extract the underlying type. - if get_origin(typ) is Annotated: - typ = get_args(typ)[0] - - # If the underlying type is a Union, extract its arguments (which are types). - if get_origin(typ) is Union: - types_tuple = get_args(typ) - return isinstance(obj, types_tuple) - - # Otherwise, do a normal isinstance check. - return isinstance(obj, typ) +from flow360_schema.models.simulation.utils import ( + get_combined_subclasses, + is_exact_instance, + is_instance_of_type_in_union, + sanitize_params_dict, +) diff --git a/tests/data/simulation/simulation_24_11_0.json b/tests/data/simulation/simulation_24_11_0.json deleted file mode 100644 index 3223cb74b..000000000 --- a/tests/data/simulation/simulation_24_11_0.json +++ /dev/null @@ -1,971 +0,0 @@ -{ - "models": [ - { - "_id": "5bf59e61-cd3b-48ae-87de-5b463046f90b", - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1, - "order_of_accuracy": 2, - "relative_tolerance": 0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2, - "DDES": false, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "grid_size_for_LES": "maxEdgeLength", - "linear_solver": { - "max_iterations": 20 - }, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8, - "C_min_rd": 10, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - }, - { - "_id": "6e04f92b-1e83-4f13-9b5c-78dee1fd0875", - "entities": { - "stored_entities": [ - { - "_id": "fluid/centerbody", - "name": "fluid/centerbody", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/centerbody", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "_id": "solid/adiabatic", - "name": "solid/adiabatic", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "solid/adiabatic", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0 - } - }, - "name": "Wall", - "type": "Wall", - "use_wall_function": false - }, - { - "_id": "8c459180-db3a-498e-afee-19ed119373cf", - "entities": { - "stored_entities": [ - { - "_id": "fluid/farfield", - "name": "fluid/farfield", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/farfield", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - } - ] - }, - "name": "Freestream", - "type": "Freestream" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0 - }, - "beta": { - "units": "degree", - "value": 0 - }, - "private_attribute_constructor": "default", - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "private_attribute_constructor": "default", - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": { - "units": "m/s", - "value": 10 - } - }, - "outputs": [ - { - "_id": "4760998d-3716-439f-a4b8-b49ac235383e", - "entities": { - "stored_entities": [ - { - "_id": "fluid/centerbody", - "name": "fluid/centerbody", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/centerbody", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "_id": "solid/adiabatic", - "name": "solid/adiabatic", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "solid/adiabatic", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "_id": "fluid/farfield", - "name": "fluid/farfield", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/farfield", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "write_single_file": false - }, - { - "_id": "3a7cd1f5-6f77-4d19-982a-f924b8891bcd", - "name": "Edited aeroacoustic output", - "observers": [ - { - "group_name": "1", - "position": { - "units": "m", - "value": [ - 12.4, - 5.1, - -50 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "7", - "position": { - "units": "m", - "value": [ - -6.3, - -16.4, - -50 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "1", - "position": { - "units": "m", - "value": [ - 18.3, - 8.8, - -49.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "9", - "position": { - "units": "m", - "value": [ - -13.9, - -5.3, - -49.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "9", - "position": { - "units": "m", - "value": [ - 10.1, - 9.5, - -49.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "9", - "position": { - "units": "m", - "value": [ - -8.3, - -17.7, - -49.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "4", - "position": { - "units": "m", - "value": [ - 11.7, - 14.9, - -49.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "8", - "position": { - "units": "m", - "value": [ - -5.6, - -9.8, - -49.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "1", - "position": { - "units": "m", - "value": [ - 17.8, - 8.2, - -49.6 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "7", - "position": { - "units": "m", - "value": [ - -10.2, - -17.5, - -49.6 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "7", - "position": { - "units": "m", - "value": [ - 11.8, - 14.5, - -49.5 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "4", - "position": { - "units": "m", - "value": [ - -13, - -9.6, - -49.5 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "1", - "position": { - "units": "m", - "value": [ - 18.6, - 5.1, - -49.4 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "4", - "position": { - "units": "m", - "value": [ - -6, - -6.3, - -49.4 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "9", - "position": { - "units": "m", - "value": [ - 8.8, - 17.3, - -49.3 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "6", - "position": { - "units": "m", - "value": [ - -7, - -9.7, - -49.3 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "5", - "position": { - "units": "m", - "value": [ - 7.6, - 19.8, - -49.2 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "2", - "position": { - "units": "m", - "value": [ - -8.9, - -5.9, - -49.2 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "5", - "position": { - "units": "m", - "value": [ - 5.4, - 13.4, - -49.1 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - -5.8, - -13.1, - -49.1 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "8", - "position": { - "units": "m", - "value": [ - 7.8, - 9.1, - -49 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - -11.1, - -16.6, - -49 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "8", - "position": { - "units": "m", - "value": [ - 6.7, - 12.3, - -48.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "8", - "position": { - "units": "m", - "value": [ - -7.9, - -13.7, - -48.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - 14.5, - 19.3, - -48.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - -10.7, - -18, - -48.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "2", - "position": { - "units": "m", - "value": [ - 15.7, - 6.1, - -48.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "5", - "position": { - "units": "m", - "value": [ - -10.5, - -9.6, - -48.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - 19.8, - 15.6, - -48.6 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "4", - "position": { - "units": "m", - "value": [ - -8, - -5.5, - -48.6 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "2", - "position": { - "units": "m", - "value": [ - 11.7, - 8.6, - -48.5 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "6", - "position": { - "units": "m", - "value": [ - -16.9, - -6.4, - -48.5 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "6", - "position": { - "units": "m", - "value": [ - 6.7, - 16.4, - -48.4 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - -12.7, - -8.8, - -48.4 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - 7.3, - 5.3, - -48.3 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "6", - "position": { - "units": "m", - "value": [ - -16.6, - -11.6, - -48.3 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - 19.7, - 6.6, - -48.2 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "7", - "position": { - "units": "m", - "value": [ - -14.5, - -11.8, - -48.2 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "4", - "position": { - "units": "m", - "value": [ - 15.1, - 5.4, - -48.1 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "5", - "position": { - "units": "m", - "value": [ - -15.2, - -19.7, - -48.1 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "8", - "position": { - "units": "m", - "value": [ - 18.8, - 15.4, - -48 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "7", - "position": { - "units": "m", - "value": [ - -11.9, - -15.6, - -48 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - 16.3, - 12.2, - -47.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "1", - "position": { - "units": "m", - "value": [ - -11.7, - -10, - -47.9 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "3", - "position": { - "units": "m", - "value": [ - 13.8, - 19, - -47.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - -8.1, - -10.8, - -47.8 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - 5.3, - 15.7, - -47.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "9", - "position": { - "units": "m", - "value": [ - -9.9, - -17.4, - -47.7 - ] - }, - "private_attribute_expand": true - }, - { - "group_name": "0", - "position": { - "units": "m", - "value": [ - 17.5, - 6.9, - -47.6 - ] - }, - "private_attribute_expand": true - } - ], - "output_type": "AeroAcousticOutput", - "write_per_surface_output": false - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "boundaries": [ - { - "name": "fluid/Interface_solid", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/Interface_solid", - "private_attribute_id": null, - "private_attribute_is_interface": true, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "name": "fluid/centerbody", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/centerbody", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "name": "solid/adiabatic", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "solid/adiabatic", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "name": "solid/Interface_fluid", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "solid/Interface_fluid", - "private_attribute_id": null, - "private_attribute_is_interface": true, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - }, - { - "name": "fluid/farfield", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "fluid/farfield", - "private_attribute_id": null, - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_tag_key": null - } - ], - "type_name": "VolumeMeshEntityInfo", - "zones": [ - { - "axes": null, - "axis": [ - 0, - 0, - 1 - ], - "center": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "fluid", - "private_attribute_entity_type_name": "GenericVolume", - "private_attribute_full_name": "fluid", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": { - "items": [ - "fluid/Interface_solid", - "fluid/centerbody", - "fluid/farfield" - ] - } - }, - { - "axes": null, - "axis": [ - 0, - 0, - 1 - ], - "center": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "solid", - "private_attribute_entity_type_name": "GenericVolume", - "private_attribute_full_name": "solid", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": { - "items": [ - "solid/Interface_fluid", - "solid/adiabatic" - ] - } - } - ] - }, - "project_length_unit": { - "units": "m", - "value": 1 - } - }, - "reference_geometry": { - "area": { - "units": "m**2", - "value": 1 - }, - "moment_center": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1, - 1, - 1 - ] - } - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000, - "max_relative_change": 1, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 10, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_dynamics": null, - "version": "24.11.0" -} diff --git a/tests/ref/simulation/service_init_geometry.json b/tests/ref/simulation/service_init_geometry.json deleted file mode 100644 index 6381799ec..000000000 --- a/tests/ref/simulation/service_init_geometry.json +++ /dev/null @@ -1,347 +0,0 @@ -{ - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": 0.20943951023931956, - "planar_face_tolerance": 1e-06, - "preserve_thin_geometry": false, - "remove_hidden_geometry": false, - "resolve_face_boundaries": false, - "sealing_size": 0.0, - "sliding_interface_tolerance": 0.01, - "surface_edge_growth_rate": 1.2, - "surface_max_adaptation_iterations": 50, - "surface_max_aspect_ratio": 10.0 - }, - "outputs": [], - "refinement_factor": 1.0, - "refinements": [], - "type_name": "MeshingParams", - "volume_zones": [ - { - "method": "auto", - "name": "Farfield", - "relative_size": 50.0, - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": 0.0 - }, - "name": "Wall", - "roughness_height": 0.0, - "type": "Wall" - }, - { - "entities": { - "stored_entities": [ - { - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_id": "farfield" - } - ] - }, - "name": "Freestream", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30, - "type_name": "LinearSolver" - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20, - "type_name": "LinearSolver" - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": 0.0, - "beta": 0.0, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": 0.0, - "beta": 0.0, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": [ - "paraview" - ], - "output_type": "SurfaceOutput", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_length_unit": 1.0, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1.0 - }, - "moment_center": [ - 0.0, - 0.0, - 0.0 - ], - "moment_length": [ - 1.0, - 1.0, - 1.0 - ] - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/ref/simulation/service_init_surface_mesh.json b/tests/ref/simulation/service_init_surface_mesh.json deleted file mode 100644 index 728c47be1..000000000 --- a/tests/ref/simulation/service_init_surface_mesh.json +++ /dev/null @@ -1,347 +0,0 @@ -{ - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": 0.20943951023931956, - "planar_face_tolerance": 1e-06, - "preserve_thin_geometry": false, - "remove_hidden_geometry": false, - "resolve_face_boundaries": false, - "sealing_size": 0.0, - "sliding_interface_tolerance": 0.01, - "surface_edge_growth_rate": 1.2, - "surface_max_adaptation_iterations": 50, - "surface_max_aspect_ratio": 10.0 - }, - "outputs": [], - "refinement_factor": 1.0, - "refinements": [], - "type_name": "MeshingParams", - "volume_zones": [ - { - "method": "auto", - "name": "Farfield", - "relative_size": 50.0, - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": 0.0 - }, - "name": "Wall", - "roughness_height": 0.0, - "type": "Wall" - }, - { - "entities": { - "stored_entities": [ - { - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_id": "farfield" - } - ] - }, - "name": "Freestream", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30, - "type_name": "LinearSolver" - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20, - "type_name": "LinearSolver" - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": 0.0, - "beta": 0.0, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": 0.0, - "beta": 0.0, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": [ - "paraview" - ], - "output_type": "SurfaceOutput", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_length_unit": 0.01, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "cm**2", - "value": 1.0 - }, - "moment_center": [ - 0.0, - 0.0, - 0.0 - ], - "moment_length": [ - 0.01, - 0.01, - 0.01 - ] - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/ref/simulation/service_init_volume_mesh.json b/tests/ref/simulation/service_init_volume_mesh.json deleted file mode 100644 index 81059ed4a..000000000 --- a/tests/ref/simulation/service_init_volume_mesh.json +++ /dev/null @@ -1,308 +0,0 @@ -{ - "models": [ - { - "entities": { - "stored_entities": [] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": 0.0 - }, - "name": "Wall", - "roughness_height": 0.0, - "type": "Wall" - }, - { - "entities": { - "stored_entities": [] - }, - "name": "Freestream", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30, - "type_name": "LinearSolver" - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20, - "type_name": "LinearSolver" - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": 0.0, - "beta": 0.0, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": 0.0, - "beta": 0.0, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": 1.225, - "material": { - "dynamic_viscosity": { - "effective_temperature": 110.4, - "reference_temperature": 273.15, - "reference_viscosity": 1.716e-05 - }, - "name": "air", - "prandtl_number": 0.72, - "thermally_perfect_gas": { - "species": [ - { - "mass_fraction": 1.0, - "name": "Air", - "nasa_9_coefficients": { - "temperature_ranges": [ - { - "coefficients": [ - 0.0, - 0.0, - 3.5, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "temperature_range_max": 6000.0, - "temperature_range_min": 200.0, - "type_name": "NASA9CoefficientSet" - } - ], - "type_name": "NASA9Coefficients" - }, - "type_name": "FrozenSpecies" - } - ], - "type_name": "ThermallyPerfectGas" - }, - "turbulent_prandtl_number": 0.9, - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": 288.15, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": [ - "paraview" - ], - "output_type": "SurfaceOutput", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_length_unit": 1.0, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1.0 - }, - "moment_center": [ - 0.0, - 0.0, - 0.0 - ], - "moment_length": [ - 1.0, - 1.0, - 1.0 - ] - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/ref/simulation/simulation_json_with_multi_constructor_used.json b/tests/ref/simulation/simulation_json_with_multi_constructor_used.json deleted file mode 100644 index d1b845189..000000000 --- a/tests/ref/simulation/simulation_json_with_multi_constructor_used.json +++ /dev/null @@ -1,424 +0,0 @@ -{ - "meshing": { - "defaults": { - "boundary_layer_first_layer_thickness": { - "units": "m", - "value": 1 - }, - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12.0 - }, - "surface_edge_growth_rate": 1.2, - "surface_max_edge_length": { - "units": "m", - "value": 1 - } - }, - "refinement_factor": 1.45, - "refinements": [ - { - "entities": { - "stored_entities": [ - { - "angle_of_rotation": { - "units": "degree", - "value": 20.0 - }, - "axis_of_rotation": [ - 1.0, - 0.0, - 0.0 - ], - "center": { - "units": "m", - "value": [ - 1.0, - 2.0, - 3.0 - ] - }, - "name": "my_box_default", - "private_attribute_constructor": "default", - "private_attribute_entity_type_name": "Box", - "private_attribute_id": "hardcoded_id-1", - "private_attribute_input_cache": { - "axes": [ - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.9396926207859084, - 0.3420201433256687 - ] - ] - }, - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": { - "items": [] - }, - "size": { - "units": "m", - "value": [ - 2.0, - 2.0, - 3.0 - ] - }, - "type_name": "Box" - }, - { - "angle_of_rotation": { - "units": "rad", - "value": -3.141592653589793 - }, - "axis_of_rotation": [ - 0.894427190999916, - 0.447213595499958, - 0.0 - ], - "center": { - "units": "m", - "value": [ - 7.0, - 1.0, - 2.0 - ] - }, - "name": "my_box_from", - "private_attribute_constructor": "from_principal_axes", - "private_attribute_entity_type_name": "Box", - "private_attribute_id": "hardcoded_id-2", - "private_attribute_input_cache": { - "axes": [ - [ - 0.6, - 0.8, - 0.0 - ], - [ - 0.8, - -0.6, - 0.0 - ] - ], - "center": { - "units": "m", - "value": [ - 7.0, - 1.0, - 2.0 - ] - }, - "name": "my_box_from", - "size": { - "units": "m", - "value": [ - 2.0, - 2.0, - 3.0 - ] - } - }, - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": { - "items": [] - }, - "size": { - "units": "m", - "value": [ - 2.0, - 2.0, - 3.0 - ] - }, - "type_name": "Box" - }, - { - "axis": [ - 0.0, - 1.0, - 0.0 - ], - "center": { - "units": "m", - "value": [ - 1.0, - 2.0, - 3.0 - ] - }, - "height": { - "units": "m", - "value": 3.0 - }, - "name": "my_cylinder_default", - "outer_radius": { - "units": "m", - "value": 2.0 - }, - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_id": "hardcoded_id-3", - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": { - "items": [] - } - } - ] - }, - "refinement_type": "UniformRefinement", - "spacing": { - "units": "cm", - "value": 7.5 - } - } - ], - "volume_zones": [ - { - "method": "auto", - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "surface_x", - "private_attribute_entity_type_name": "Surface", - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "face_x_1", - "face_x_2", - "face_x_3" - ] - } - ] - }, - "private_attribute_id": "wall1", - "type": "Wall", - "use_wall_function": false - }, - { - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30, - "type_name": "LinearSolver" - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20, - "type_name": "LinearSolver" - }, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_d": 8.0, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 5.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "private_attribute_constructor": "from_mach", - "private_attribute_input_cache": { - "alpha": { - "units": "degree", - "value": 5.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "mach": 0.8, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "from_standard_atmosphere", - "private_attribute_input_cache": { - "altitude": { - "units": "m", - "value": 1000.0 - }, - "temperature_offset": { - "units": "K", - "value": 0.0 - } - }, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "from_standard_atmosphere", - "private_attribute_input_cache": { - "altitude": { - "units": "m", - "value": 1000.0 - }, - "temperature_offset": { - "units": "K", - "value": 0.0 - } - }, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": { - "units": "m/s", - "value": 272.23520464657025 - } - }, - "private_attribute_asset_cache": { - "project_entity_info": { - "face_attribute_names": [ - "some_tag" - ], - "face_group_tag": "some_tag", - "face_ids": [ - "face_x_1", - "face_x_2", - "face_x_3" - ], - "grouped_faces": [ - [ - { - "name": "surface_x", - "private_attribute_entity_type_name": "Surface", - "private_attribute_is_interface": false, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "face_x_1", - "face_x_2", - "face_x_3" - ] - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": 1.0 - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "version": "24.2.0" -} diff --git a/tests/simulation/params/data/simulation_force_output_webui.json b/tests/simulation/params/data/simulation_force_output_webui.json deleted file mode 100644 index 79143275a..000000000 --- a/tests/simulation/params/data/simulation_force_output_webui.json +++ /dev/null @@ -1,1026 +0,0 @@ -{ - "models": [ - { - "_id": "f94a410b-31d4-4696-97f6-db4ba8d75fcc", - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-09, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 25 - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "f94a410b-31d4-4696-97f6-db4ba8d75fcc", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 15 - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - }, - { - "_id": "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "entities": { - "stored_entities": [ - { - "name": "1", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "1", - "private_attribute_id": "1", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0.0 - } - }, - "name": "wing", - "private_attribute_id": "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "roughness_height": { - "units": "m", - "value": 0.0 - }, - "type": "Wall", - "use_wall_function": false - }, - { - "entities": { - "stored_entities": [ - { - "name": "2", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "2", - "private_attribute_id": "2", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - } - ] - }, - "name": "symmetry", - "private_attribute_id": "d517b40d-cab9-49df-b260-9291937bd86b", - "type": "SlipWall" - }, - { - "_id": "58a41587-1ad2-48d6-afbe-9e8bafc2a51d", - "entities": { - "stored_entities": [ - { - "name": "3", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "3", - "private_attribute_id": "3", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - } - ] - }, - "name": "Freestream", - "private_attribute_id": "58a41587-1ad2-48d6-afbe-9e8bafc2a51d", - "type": "Freestream" - }, - { - "_id": "42a99183-65eb-45eb-956a-7b41cae69efd", - "darcy_coefficient": { - "units": "m**(-2)", - "value": [ - 1000000.0, - 0.0, - 0.0 - ] - }, - "entities": { - "stored_entities": [ - { - "angle_of_rotation": { - "units": "rad", - "value": -2.0943951023931953 - }, - "axis_of_rotation": [ - -0.5773502691896256, - -0.5773502691896256, - -0.577350269189626 - ], - "center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "name": "box", - "private_attribute_constructor": "from_principal_axes", - "private_attribute_entity_type_name": "Box", - "private_attribute_id": "07c017de-b078-48c6-bd65-f6bc11b321a2", - "private_attribute_input_cache": { - "axes": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "name": "box", - "size": { - "units": "m", - "value": [ - 0.2, - 0.3, - 2.0 - ] - } - }, - "private_attribute_zone_boundary_names": { - "items": [] - }, - "size": { - "units": "m", - "value": [ - 0.2, - 0.3, - 2.0 - ] - }, - "type_name": "Box" - } - ] - }, - "forchheimer_coefficient": { - "units": "1/m", - "value": [ - 1.0, - 0.0, - 0.0 - ] - }, - "name": "Porous medium", - "private_attribute_id": "42a99183-65eb-45eb-956a-7b41cae69efd", - "type": "PorousMedium", - "volumetric_heat_source": { - "units": "kg/(m*s**3)", - "value": 0.0 - } - }, - { - "_id": "38c82a7f-b0cf-4b38-a93f-31fd1561a946", - "blade_line_chord": { - "units": "m", - "value": 0 - }, - "name": "BET11222", - "number_of_blades": null, - "private_attribute_constructor": "from_xrotor", - "private_attribute_id": "38c82a7f-b0cf-4b38-a93f-31fd1561a946", - "private_attribute_input_cache": { - "angle_unit": { - "units": "degree", - "value": 1 - }, - "blade_line_chord": { - "units": "m", - "value": 0 - }, - "chord_ref": { - "units": "m", - "value": 3 - }, - "entities": { - "stored_entities": [ - { - "axis": [ - 0, - 1, - 0 - ], - "center": { - "units": "cm", - "value": [ - 0, - -10, - 0 - ] - }, - "height": { - "units": "cm", - "value": 1 - }, - "inner_radius": { - "units": "m", - "value": 0 - }, - "name": "Cylinder", - "outer_radius": { - "units": "cm", - "value": 1 - }, - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_id": "9e2d69cd-460e-456d-b0df-b232be7198a3" - }, - { - "axis": [ - 0, - 1, - 0 - ], - "center": { - "units": "cm", - "value": [ - 0, - -8, - 0 - ] - }, - "height": { - "units": "cm", - "value": 1 - }, - "inner_radius": { - "units": "m", - "value": 0 - }, - "name": "Cylinder3", - "outer_radius": { - "units": "cm", - "value": 1 - }, - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_id": "41cc394a-0ac6-4e0f-97f9-e1971edacbe3" - } - ] - }, - "file": { - "content": "XROTOR VERSION: 7.54\nxv15_fromXrotor\n! Rho Vso Rmu Alt\n 1.00 342.00 0.17170E-04 2000.0\n! Rad Vel Adv Rake\n 150.00 1.0 4.23765e-3 0.0000\n! XI0 XIW\n 0.13592 0.0000\n! Naero\n 5\n! Xisection\n 0.09\n! A0deg dCLdA CLmax CLmin\n -6.5 4.00 1.2500 -0.0000\n! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n! CDmin CLCDmin dCDdCL^2\n 0.075000E-01 0.00000 0.40000E-02\n! REref REexp\n 0.30000E+06 -0.70000\n! Xisection\n 0.17\n! A0deg dCLdA CLmax CLmin\n -6.0 6.0 1.300 -0.55000\n! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n! CDmin CLCDmin dCDdCL^2\n 0.075000E-01 0.10000 0.40000E-02\n! REref REexp\n 0.30000E+06 -0.70000\n! Xisection\n 0.51\n! A0deg dCLdA CLmax CLmin\n-1.0 6.00 1.400 -1.4000\n! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n! CDmin CLCDmin dCDdCL^2\n 0.05000E-01 0.10000 0.40000E-02\n! REref REexp\n 0.30000E+06 -0.70000\n! Xisection\n 0.8\n! A0deg dCLdA CLmax CLmin\n -1.0 6.0 1.600 -1.500\n! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n! CDmin CLCDmin dCDdCL^2\n 0.03000E-01 0.10000 0.40000E-02\n! REref REexp\n 0.30000E+06 -0.70000\n! Xisection\n 1.0\n! A0deg dCLdA CLmax CLmin\n -1 6.0 1.0 -1.8000\n! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n! CDmin CLCDmin dCDdCL^2\n 0.04000E-01 0.10000 0.40000E-02\n! REref REexp\n 0.30000E+06 -0.70000\n!LVDuct LDuct LWind\n T F F\n! II Nblds\n 63 3\n! r/R C/R Beta0deg Ubody\n0.023003943\t0.113428403\t33.27048712\t0\n0.039116227\t0.113428403\t32.37853609\t0\n0.060384093\t0.113428403\t31.42712165\t0\n0.083584992\t0.113428403\t30.65409742\t0\n0.093024104\t0.113428403\t30.13214089\t0\n0.108253499\t0.113428403\t29.41523066\t0\n0.122239679\t0.111608996\t28.75567325\t0\n0.140577109\t0.10978959\t27.89538097\t0\n0.159536634\t0.107970183\t26.69097178\t0\n0.172590692\t0.106150776\t25.88803232\t0\n0.182536671\t0.10433137\t25.25715132\t0\n0.192482739\t0.102511963\t24.5689175\t0\n0.20305028\t0.100692556\t23.93803649\t0\n0.214861124\t0.09887315\t23.19244985\t0\n0.227293664\t0.097053743\t22.36083398\t0\n0.239415201\t0.095234336\t21.67260016\t0\n0.25153696\t0.093414933\t20.84098429\t0\n0.264591196\t0.0934138\t19.92333919\t0\n0.27609148\t0.093412667\t19.03437051\t0\n0.286348329\t0.093411533\t18.34613668\t0\n0.297848614\t0.0934104\t17.457168\t0\n0.309659147\t0.093409267\t16.91231622\t0\n0.322713117\t0.093408133\t16.16672958\t0\n0.334834565\t0.093407\t15.53584858\t0\n0.345091281\t0.093405867\t14.93364398\t0\n0.356591344\t0.093404733\t14.18805734\t0\n0.367158885\t0.0934036\t13.55717634\t0\n0.375240265\t0.093402467\t12.86894251\t0\n0.385497114\t0.093401333\t12.18070869\t0\n0.396375525\t0.0934002\t11.49247487\t0\n0.406632108\t0.093399067\t10.9762995\t0\n0.419063938\t0.093397933\t10.60350618\t0\n0.436468714\t0.0933968\t9.94394877\t0\n0.450765676\t0.093395667\t9.28439136\t0\n0.465373463\t0.093394533\t8.59615753\t0\n0.476873349\t0.0933934\t7.96527653\t0\n0.489927141\t0.093392267\t7.33439553\t0\n0.497075821\t0.093391133\t6.87557298\t0\n0.511683032\t0.09339\t6.56013248\t0\n0.529087542\t0.093388867\t6.07263352\t0\n0.544627496\t0.093387733\t5.49910533\t0\n0.557680933\t0.0933866\t5.0976356\t0\n0.569491245\t0.093385467\t4.69616587\t0\n0.585652762\t0.093384333\t4.12263769\t0\n0.596841423\t0.0933832\t3.77852078\t0\n0.609273165\t0.093382067\t3.46308028\t0\n0.628853143\t0.093380933\t2.97558132\t0\n0.664905287\t0.0933798\t2.0005834\t0\n0.686349777\t0.093378667\t1.62779008\t0\n0.69940317\t0.093377533\t1.25499676\t0\n0.711213304\t0.0933764\t0.96823267\t0\n0.726753081\t0.093375267\t0.50941012\t0\n0.745400849\t0.093374133 -0.064118065 0\n0.762805314\t0.093373 -0.522940614 0\n0.797303462\t0.093371867\t-1.44058571 0\n0.842057794\t0.093370733 -2.61631849 0\n0.877177195\t0.0933696\t-3.333228722 0\n0.91385068\t0.093368467\t-4.164844591 0\n0.936227735\t0.093367333\t-4.681019957 0\n0.957361443\t0.0933662 -5.053813278 0\n0.977873766\t0.093365067 -5.541312235 0\n0.989683856\t0.093363933 -5.799399919 0\n1\t0.0933634\t-6.1\t0\n! URDuct\n 1.0000", - "file_path": "xrotorTest.xrotor", - "type_name": "XRotorFile" - }, - "length_unit": { - "units": "m", - "value": 1 - }, - "n_loading_nodes": 3, - "name": "BET11222", - "number_of_blades": 3, - "omega": { - "units": "rad/s", - "value": 10 - }, - "rotation_direction_rule": "leftHand", - "tip_gap": "inf" - }, - "rotation_direction_rule": "leftHand", - "tip_gap": "inf", - "type": "BETDisk", - "type_name": "BETDisk" - }, - { - "_id": "f929834a-0adb-4b42-a880-3d034edce883", - "entities": { - "stored_entities": [ - { - "axis": [ - 0, - 0, - 1 - ], - "center": { - "units": "cm", - "value": [ - 10, - 0, - 0 - ] - }, - "height": { - "units": "cm", - "value": 1 - }, - "inner_radius": { - "units": "m", - "value": 0 - }, - "name": "ad1", - "outer_radius": { - "units": "cm", - "value": 1 - }, - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_id": "c007c4ff-65af-41d9-847b-e0058f31ae51" - } - ] - }, - "force_per_area": { - "circumferential": { - "units": "N/m**2", - "value": [ - 0, - 20, - 1 - ] - }, - "radius": { - "units": "m", - "value": [ - 0, - 1, - 10 - ] - }, - "thrust": { - "units": "N/m**2", - "value": [ - 1, - 2, - 1 - ] - } - }, - "name": "Actuator disk1", - "private_attribute_id": "f929834a-0adb-4b42-a880-3d034edce883", - "type": "ActuatorDisk" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 3.06 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "private_attribute_constructor": "from_mach", - "private_attribute_input_cache": { - "alpha": { - "units": "degree", - "value": 3.06 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "mach": 0.84, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 288.15 - }, - "reference_viscosity": { - "units": "kg/(m*s)", - "value": 1.9328492090409794e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 288.15 - }, - "reference_viscosity": { - "units": "kg/(m*s)", - "value": 1.9328492090409794e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": { - "type_name": "number", - "units": "m/s", - "value": 285.84696487889875 - } - }, - "outputs": [ - { - "_id": "84906625-9279-4cb4-8812-dafb831b2cfa", - "frequency": -1, - "frequency_offset": 0, - "name": "Volume output", - "output_fields": { - "items": [ - "primitiveVars", - "residualNavierStokes", - "residualTurbulence", - "Mach", - "Sidewash", - "Upwash", - "Helicity" - ] - }, - "output_format": "paraview", - "output_type": "VolumeOutput", - "private_attribute_id": "84906625-9279-4cb4-8812-dafb831b2cfa" - }, - { - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - -0.026642, - 0.56614, - 0.0 - ] - }, - "name": "Point_1", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "b4f78cfe-f42d-47c9-94f5-d7afdb616a06" - } - ] - }, - "moving_statistic": { - "method": "mean", - "moving_window_size": 200, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "point_legacy1", - "output_fields": { - "items": [ - { - "name": "Helicity_user", - "type_name": "UserVariable" - } - ] - }, - "output_type": "ProbeOutput", - "private_attribute_id": "b0d034e3-87ce-4b79-8c5a-d22b7386000c" - }, - { - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - -0.026642, - 0.56614, - 0.0 - ] - }, - "name": "Point_1", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "5d0433c0-b202-4c14-bdde-e8e993b47f9e" - } - ] - }, - "moving_statistic": { - "method": "standard_deviation", - "moving_window_size": 100, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "point_legacy2", - "output_fields": { - "items": [ - { - "name": "Mach_SI", - "type_name": "UserVariable" - } - ] - }, - "output_type": "ProbeOutput", - "private_attribute_id": "9c72b148-84ff-4e78-82d7-8d4c5d11ebd3" - }, - { - "models": [ - "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c" - ], - "moving_statistic": { - "method": "mean", - "moving_window_size": 100, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "forceOutput2", - "output_fields": { - "items": [ - "CL", - "CFx", - "CFySkinFriction" - ] - }, - "output_type": "ForceOutput", - "private_attribute_id": "61863d9a-baf6-499b-87d3-509a2cea2b56" - }, - { - "models": [ - "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "42a99183-65eb-45eb-956a-7b41cae69efd" - ], - "name": "forceOutput", - "output_fields": { - "items": [ - "CL", - "CFx", - "CFySkinFriction" - ] - }, - "output_type": "ForceOutput", - "private_attribute_id": "61863d9a-baf6-499b-87d3-509a2cea2b51" - }, - { - "models": [ - "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "111" - ], - "name": "forceOutput", - "output_fields": { - "items": [ - "CL", - "CFx", - "CFySkinFriction" - ] - }, - "output_type": "ForceOutput", - "private_attribute_id": "61863d9a-baf6-499b-87d3-509a2cea2b51" - }, - { - "models": [ - "639cd8f5-79c3-4f08-a88f-b44ff8c8f43c", - "f929834a-0adb-4b42-a880-3d034edce883", - "38c82a7f-b0cf-4b38-a93f-31fd1561a946" - ], - "name": "forceOutput", - "output_fields": { - "items": [ - "CL", - "CFx" - ] - }, - "output_type": "ForceOutput", - "private_attribute_id": "61863d9a-baf6-499b-87d3-509a2cea2b51" - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "boundaries": [ - { - "name": "3", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "3", - "private_attribute_id": "3", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - }, - { - "name": "2", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "2", - "private_attribute_id": "2", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - }, - { - "name": "1", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": "1", - "private_attribute_id": "1", - "private_attribute_is_interface": false, - "private_attribute_sub_components": [] - } - ], - "draft_entities": [ - { - "location": { - "units": "m", - "value": [ - 0.0, - 1.0, - 0.04 - ] - }, - "name": "point_streamline", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "37083fc7-2aef-4d8a-aa63-e47491f334c3" - }, - { - "location": { - "units": "m", - "value": [ - -0.026642, - 0.56614, - 0.0 - ] - }, - "name": "Point_1", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "b4f78cfe-f42d-47c9-94f5-d7afdb616a06" - }, - { - "end": { - "units": "m", - "value": [ - 0.0, - 1.0, - 0.2 - ] - }, - "name": "pointarray_streamline", - "number_of_points": 20, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "36662ed5-ce40-4456-8f91-bb8372169ce8", - "start": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.2 - ] - } - }, - { - "name": "pointarray2d_streamline", - "origin": { - "units": "m", - "value": [ - 0.0, - 0.0, - -0.2 - ] - }, - "private_attribute_entity_type_name": "PointArray2D", - "private_attribute_id": "1d5db652-4fb8-4bcf-938e-ac49638e3a41", - "u_axis_vector": { - "units": "m", - "value": [ - 0.0, - 1.4, - 0.0 - ] - }, - "u_number_of_points": 10, - "v_axis_vector": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.4 - ] - }, - "v_number_of_points": 10 - }, - { - "name": "sliceName_1", - "normal": [ - 0.0, - 1.0, - 0.0 - ], - "origin": { - "units": "m", - "value": [ - 0.0, - 0.56413, - 0.0 - ] - }, - "private_attribute_entity_type_name": "Slice", - "private_attribute_id": "2553b0de-97cc-481e-b9a7-05d39e57f7d8" - }, - { - "angle_of_rotation": { - "units": "rad", - "value": -2.0943951023931953 - }, - "axis_of_rotation": [ - -0.5773502691896256, - -0.5773502691896256, - -0.577350269189626 - ], - "center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "name": "box", - "private_attribute_constructor": "from_principal_axes", - "private_attribute_entity_type_name": "Box", - "private_attribute_id": "07c017de-b078-48c6-bd65-f6bc11b321a2", - "private_attribute_input_cache": { - "axes": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "name": "box", - "size": { - "units": "m", - "value": [ - 0.2, - 0.3, - 2.0 - ] - } - }, - "private_attribute_zone_boundary_names": { - "items": [] - }, - "size": { - "units": "m", - "value": [ - 0.2, - 0.3, - 2.0 - ] - }, - "type_name": "Box" - } - ], - "ghost_entities": [], - "type_name": "VolumeMeshEntityInfo", - "zones": [ - { - "name": "1", - "private_attribute_entity_type_name": "GenericVolume", - "private_attribute_full_name": "1", - "private_attribute_id": "1", - "private_attribute_zone_boundary_names": { - "items": [ - "1", - "2", - "3" - ] - } - } - ] - }, - "project_length_unit": { - "units": "m", - "value": 0.8059 - }, - "use_geometry_AI": false, - "use_inhouse_mesher": false, - "variable_context": [ - { - "name": "Helicity_user", - "post_processing": true, - "value": { - "expression": "solution.velocity[0] * solution.vorticity[0] + solution.velocity[1] * solution.vorticity[1] + solution.velocity[2] * solution.vorticity[2]", - "type_name": "expression" - } - }, - { - "name": "Mach_SI", - "post_processing": true, - "value": { - "expression": "solution.Mach", - "type_name": "expression" - } - }, - { - "name": "Cp_SI", - "post_processing": true, - "value": { - "expression": "solution.Cp", - "type_name": "expression" - } - }, - { - "name": "velocity_SI", - "post_processing": true, - "value": { - "expression": "solution.velocity", - "type_name": "expression" - } - } - ] - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 0.748844455929999 - }, - "moment_center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "moment_length": { - "units": "m", - "value": 0.6460682372650963 - } - }, - "run_control": { - "stopping_criteria": [ - { - "monitor_field": { - "name": "Helicity_user", - "type_name": "UserVariable" - }, - "monitor_output": "b0d034e3-87ce-4b79-8c5a-d22b7386000c", - "name": "Criterion_Helicity", - "tolerance": { - "type_name": "number", - "units": "cm/s**2", - "value": 0.005 - }, - "tolerance_window_size": 3, - "type_name": "StoppingCriterion" - }, - { - "monitor_field": { - "name": "Mach_SI", - "type_name": "UserVariable" - }, - "monitor_output": "9c72b148-84ff-4e78-82d7-8d4c5d11ebd3", - "name": "Criterion_Mach", - "tolerance": { - "type_name": "number", - "value": 1e-05 - }, - "type_name": "StoppingCriterion" - }, - { - "monitor_field": "CL", - "monitor_output": "61863d9a-baf6-499b-87d3-509a2cea2b56", - "name": "Criterion_ForceOutput", - "tolerance": { - "type_name": "number", - "value": 0.265 - }, - "type_name": "StoppingCriterion" - } - ], - "type_name": "RunControl" - }, - "time_stepping": { - "CFL": { - "final": 200.0, - "initial": 5.0, - "ramp_steps": 40, - "type": "ramp" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [ - { - "expression": "Sidewash = atan(primitiveVars[1]/abs(primitiveVars[0]))", - "name": "Sidewash", - "type_name": "UserDefinedField" - }, - { - "expression": "Upwash = atan(primitiveVars[2]/abs(primitiveVars[0]))", - "name": "Upwash", - "type_name": "UserDefinedField" - }, - { - "expression": "double vorticity[3];vorticity[0] = gradPrimitive[3][1] - gradPrimitive[2][2];vorticity[1] = gradPrimitive[1][2] - gradPrimitive[3][0];vorticity[2] = gradPrimitive[2][0] - gradPrimitive[1][1];double velocity[3];velocity[0] = primitiveVars[1];velocity[1] = primitiveVars[2];velocity[2] = primitiveVars[3];Helicity = dot(velocity, vorticity);", - "name": "Helicity", - "type_name": "UserDefinedField" - } - ], - "version": "25.7.6b0" -} diff --git a/tests/simulation/params/data/simulation_stopping_criterion_webui.json b/tests/simulation/params/data/simulation_stopping_criterion_webui.json deleted file mode 100644 index 74bd9465d..000000000 --- a/tests/simulation/params/data/simulation_stopping_criterion_webui.json +++ /dev/null @@ -1,1171 +0,0 @@ -{ - "meshing": { - "defaults": { - "boundary_layer_first_layer_thickness": { - "units": "m", - "value": 1e-06 - }, - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12 - }, - "planar_face_tolerance": 1e-06, - "surface_edge_growth_rate": 1.2, - "surface_max_edge_length": { - "units": "m", - "value": 0.15 - } - }, - "gap_treatment_strength": 0, - "refinement_factor": 1, - "volume_zones": [ - { - "_id": "e4c4828d-0d4c-4a55-b973-7fede4b5554a", - "method": "auto", - "name": "Farfield", - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "_id": "1296ad9c-6678-4195-817f-d6e9781fc6a3", - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "low_mach_preconditioner_threshold": null, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1, - "order_of_accuracy": 2, - "relative_tolerance": 0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2, - "absolute_tolerance": 1e-05, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8, - "C_min_rd": 10, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3 - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - }, - { - "_id": "908d2d51-c73d-4a07-82cd-3ac84272ad7c", - "entities": { - "stored_entities": [ - { - "name": "body00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId" - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0 - } - }, - "name": "Wall", - "roughness_height": { - "units": "m", - "value": 0 - }, - "type": "Wall", - "use_wall_function": false - }, - { - "_id": "c4daabf6-5af4-4dbb-a110-4d1723adf353", - "entities": { - "stored_entities": [ - { - "_id": "8ae37a4b-6970-5d88-aef5-43a1abcc845e", - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - } - ] - }, - "name": "Freestream", - "type": "Freestream" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0 - }, - "beta": { - "units": "degree", - "value": 0 - }, - "private_attribute_constructor": "default", - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "private_attribute_constructor": "default", - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": { - "type_name": "number", - "units": "m/s", - "value": 20 - } - }, - "outputs": [ - { - "_id": "a6cd480b-f5c8-4516-8188-8506ab42469b", - "entities": { - "stored_entities": [ - { - "name": "body00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId" - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "private_attribute_id": "a6cd480b-f5c8-4516-8188-8506ab42469b", - "write_single_file": false - }, - { - "_id": "8b6c81a9-a409-44a1-9a85-4866f596a36d", - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - }, - { - "end": { - "units": "m", - "value": [ - 1, - 0, - 0 - ] - }, - "name": "Point array", - "number_of_points": 10, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "91cbc3d3-807d-4efe-a41a-8ea5f45e80fb", - "start": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - } - } - ] - }, - "moving_statistic": { - "method": "max", - "moving_window_size": 10, - "start_step": 20, - "type_name": "MovingStatistic" - }, - "name": "Probe output", - "output_fields": { - "items": [ - "Mach" - ] - }, - "output_type": "ProbeOutput", - "private_attribute_id": "8b6c81a9-a409-44a1-9a85-4866f596a36d" - }, - { - "_id": "a0fd1488-73b9-404d-a6ab-ec8427f7483f", - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - }, - { - "end": { - "units": "m", - "value": [ - 1, - 0, - 0 - ] - }, - "name": "Point array", - "number_of_points": 10, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "91cbc3d3-807d-4efe-a41a-8ea5f45e80fb", - "start": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - } - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "moving_statistic": { - "method": "mean", - "moving_window_size": 10, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "Time-averaging probe output", - "output_fields": { - "items": [ - { - "name": "velocity_with_units", - "type_name": "UserVariable" - }, - "Cp" - ] - }, - "output_type": "TimeAverageProbeOutput", - "private_attribute_id": "a0fd1488-73b9-404d-a6ab-ec8427f7483f" - }, - { - "_id": "ad089c5d-f357-45e7-bbb9-c11297eea170", - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - } - ] - }, - "moving_statistic": { - "method": "min", - "moving_window_size": 10, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "Probe output", - "output_fields": { - "items": [ - { - "name": "velocity_magnitude_with_units", - "type_name": "UserVariable" - } - ] - }, - "output_type": "ProbeOutput", - "private_attribute_id": "ad089c5d-f357-45e7-bbb9-c11297eea170" - }, - { - "_id": "b76839cf-d46d-494e-a5cb-a1fa69d4e608", - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - }, - { - "end": { - "units": "m", - "value": [ - 1, - 0, - 0 - ] - }, - "name": "Point array", - "number_of_points": 10, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "91cbc3d3-807d-4efe-a41a-8ea5f45e80fb", - "start": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - } - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "moving_statistic": { - "method": "standard_deviation", - "moving_window_size": 10, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "Time-averaging probe output", - "output_fields": { - "items": [ - { - "name": "velocity_magnitude_with_units", - "type_name": "UserVariable" - }, - "Cp", - "Cpt", - "mut", - "solutionNavierStokes", - "residualTransition" - ] - }, - "output_type": "TimeAverageProbeOutput", - "private_attribute_id": "b76839cf-d46d-494e-a5cb-a1fa69d4e608", - "start_step": 1 - }, - { - "_id": "d68e6448-9862-435a-8b89-8d9cb3638df9", - "entities": { - "stored_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - }, - { - "end": { - "units": "m", - "value": [ - 1, - 0, - 0 - ] - }, - "name": "Point array", - "number_of_points": 10, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "91cbc3d3-807d-4efe-a41a-8ea5f45e80fb", - "start": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - } - } - ] - }, - "moving_statistic": { - "method": "range", - "moving_window_size": 10, - "start_step": 0, - "type_name": "MovingStatistic" - }, - "name": "Surface probe output", - "output_fields": { - "items": [ - "Mach", - { - "name": "velocity_with_units", - "type_name": "UserVariable" - }, - { - "name": "pressure_with_units", - "type_name": "UserVariable" - }, - "Cp", - "Cpt" - ] - }, - "output_type": "SurfaceProbeOutput", - "private_attribute_id": "d68e6448-9862-435a-8b89-8d9cb3638df9", - "target_surfaces": { - "stored_entities": [ - { - "name": "body00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId" - } - ] - } - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "body00001" - ], - "draft_entities": [ - { - "location": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "name": "Point", - "private_attribute_entity_type_name": "Point", - "private_attribute_id": "3b6432ec-0b16-4626-a75f-fdef7f93e2af" - }, - { - "end": { - "units": "m", - "value": [ - 1, - 0, - 0 - ] - }, - "name": "Point array", - "number_of_points": 10, - "private_attribute_entity_type_name": "PointArray", - "private_attribute_id": "91cbc3d3-807d-4efe-a41a-8ea5f45e80fb", - "start": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - } - } - ], - "edge_attribute_names": [ - "edgeId" - ], - "edge_group_tag": "edgeId", - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012" - ], - "face_attribute_names": [ - "groupByBodyId", - "faceId" - ], - "face_group_tag": "groupByBodyId", - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 5.000010000000002, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_full_name": null, - "private_attribute_id": "farfield", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - }, - { - "center": [ - 0, - -0.010000100000000005, - 0 - ], - "max_radius": 0.10000020000000005, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_full_name": null, - "private_attribute_id": "symmetric-1", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - }, - { - "center": [ - 0, - 0.010000100000000005, - 0 - ], - "max_radius": 0.10000020000000005, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_full_name": null, - "private_attribute_id": "symmetric-2", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - }, - { - "center": [ - 0, - 0.010000100000000005, - 0 - ], - "max_radius": 0.10000020000000005, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_full_name": null, - "private_attribute_id": "symmetric", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - } - ], - "global_bounding_box": [ - [ - -0.050000100000000026, - -0.010000100000000005, - -0.050000100000000026 - ], - [ - 0.050000100000000026, - 0.010000100000000005, - 0.050000100000000026 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "body00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "body00001", - "private_attribute_registry_bucket_name": "GeometryBodyGroupEntityType", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "bodyId", - "transformation": { - "angle_of_rotation": { - "units": "degree", - "value": 0 - }, - "axis_of_rotation": [ - 1, - 0, - 0 - ], - "origin": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "scale": [ - 1, - 1, - 1 - ], - "translation": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "type_name": "BodyGroupTransformation" - } - } - ], - [ - { - "mesh_exterior": true, - "name": "wheel.step", - "private_attribute_color": null, - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "wheel.step", - "private_attribute_registry_bucket_name": "GeometryBodyGroupEntityType", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "groupByFile", - "transformation": { - "angle_of_rotation": { - "units": "degree", - "value": 0 - }, - "axis_of_rotation": [ - 1, - 0, - 0 - ], - "origin": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "scale": [ - 1, - 1, - 1 - ], - "translation": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "type_name": "BodyGroupTransformation" - } - } - ] - ], - "grouped_edges": [ - [ - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00001", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00002", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00003", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00004", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00005", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00006", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00007", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00008", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00009", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00010", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00011", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "body00001_edge00012", - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "body00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId" - } - ], - [ - { - "name": "body00001_face00001", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00001", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body00001_face00002", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00002", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body00001_face00003", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00003", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body00001_face00004", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00004", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body00001_face00005", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00005", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body00001_face00006", - "private_attribute_color": null, - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": "body00001_face00006", - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "faceId" - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": { - "units": "m", - "value": 1 - }, - "use_geometry_AI": false, - "use_inhouse_mesher": false, - "variable_context": [ - { - "name": "velocity_with_units", - "value": { - "expression": "solution.velocity", - "output_units": "SI_unit_system", - "type_name": "expression" - } - }, - { - "name": "velocity_magnitude_with_units", - "value": { - "expression": "math.magnitude(solution.velocity)", - "output_units": "SI_unit_system", - "type_name": "expression" - } - }, - { - "name": "pressure_with_units", - "value": { - "expression": "solution.pressure", - "output_units": "SI_unit_system", - "type_name": "expression" - } - }, - { - "name": "wall_shear_stress_magnitude_with_units", - "value": { - "expression": "solution.wall_shear_stress_magnitude", - "output_units": "SI_unit_system", - "type_name": "expression" - } - } - ] - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1 - }, - "moment_center": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1, - 1, - 1 - ] - } - }, - "run_control": { - "stopping_criteria": [ - { - "monitor_field": "Mach", - "monitor_output": "8b6c81a9-a409-44a1-9a85-4866f596a36d", - "name": "StoppingCriterion 1", - "tolerance": 0.2, - "tolerance_window_size": 10, - "type_name": "StoppingCriterion" - }, - { - "monitor_field": "Cp", - "monitor_output": "ad089c5d-f357-45e7-bbb9-c11297eea170", - "name": "StoppingCriterion 2", - "tolerance": 0.2, - "tolerance_window_size": 10, - "type_name": "StoppingCriterion" - }, - { - "monitor_field": { - "name": "velocity_magnitude_with_units", - "type_name": "UserVariable" - }, - "monitor_output": "ad089c5d-f357-45e7-bbb9-c11297eea170", - "name": "StoppingCriterion 3", - "tolerance": { - "type_name": "number", - "units": "m", - "value": 18.66 - }, - "tolerance_window_size": 10, - "type_name": "StoppingCriterion" - }, - { - "monitor_field": { - "name": "velocity_magnitude_with_units", - "type_name": "UserVariable" - }, - "monitor_output": "1234", - "name": "StoppingCriterion 4", - "tolerance": { - "type_name": "number", - "units": "m/s", - "value": 18.66 - }, - "tolerance_window_size": 10, - "type_name": "StoppingCriterion" - } - ], - "type_name": "RunControl" - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 1, - "max": 10000, - "max_relative_change": 50, - "min": 0.1, - "type": "adaptive" - }, - "max_pseudo_steps": 20, - "order_of_accuracy": 2, - "step_size": { - "type_name": "number", - "units": "s", - "value": 0.0001 - }, - "steps": 200, - "type_name": "Unsteady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_dynamics": null, - "version": "25.7.1b1" -} diff --git a/tests/simulation/params/meshing_validation/test_meshing_param_validation.py b/tests/simulation/params/meshing_validation/test_meshing_param_validation.py deleted file mode 100644 index 834fe1efe..000000000 --- a/tests/simulation/params/meshing_validation/test_meshing_param_validation.py +++ /dev/null @@ -1,441 +0,0 @@ -from flow360 import u -from flow360.component.simulation.framework.param_utils import AssetCache -from flow360.component.simulation.meshing_param import snappy -from flow360.component.simulation.meshing_param.face_params import GeometryRefinement -from flow360.component.simulation.meshing_param.meshing_specs import ( - MeshingDefaults, - VolumeMeshingDefaults, -) -from flow360.component.simulation.meshing_param.params import ( - MeshingParams, - ModularMeshingWorkflow, - VolumeMeshingParams, -) -from flow360.component.simulation.meshing_param.volume_params import ( - AutomatedFarfield, - CustomZones, - UniformRefinement, - UserDefinedFarfield, -) -from flow360.component.simulation.primitives import Box, CustomVolume, Surface -from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.unit_system import SI_unit_system - - -def test_uniform_project_only_with_snappy(): - refinement = UniformRefinement( - entities=[Box(center=(0, 0, 0) * u.m, size=(1, 1, 1) * u.m, name="box")], - spacing=0.1 * u.m, - project_to_surface=True, - ) - with SI_unit_system: - params_snappy = SimulationParams( - meshing=ModularMeshingWorkflow( - surface_meshing=snappy.SurfaceMeshingParams( - defaults=snappy.SurfaceMeshingDefaults( - min_spacing=1 * u.mm, - max_spacing=2 * u.mm, - gap_resolution=1 * u.mm, - ) - ), - volume_meshing=VolumeMeshingParams( - defaults=VolumeMeshingDefaults(boundary_layer_first_layer_thickness=1 * u.mm), - refinements=[refinement], - ), - zones=[AutomatedFarfield()], - ) - ) - - _, errors, _ = validate_model( - params_as_dict=params_snappy.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - assert errors is None - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - volume_zones=[AutomatedFarfield()], - refinements=[refinement], - defaults=MeshingDefaults( - curvature_resolution_angle=12 * u.deg, - boundary_layer_growth_rate=1.1, - boundary_layer_first_layer_thickness=1e-5 * u.m, - ), - ) - ) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="SurfaceMesh", - validation_level="VolumeMesh", - ) - - assert len(errors) == 1 - assert errors[0]["msg"] == ( - "Value error, project_to_surface is supported only for snappyHexMesh." - ) - assert errors[0]["loc"] == ("meshing", "refinements", 0, "UniformRefinement") - - -def test_per_face_min_passage_size_warning_without_remove_hidden_geometry(): - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=False, - ), - refinements=[ - GeometryRefinement( - geometry_accuracy=0.01 * u.m, - min_passage_size=0.05 * u.m, - faces=[Surface(name="face1")], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert len(warnings) == 1 - assert "min_passage_size" in warnings[0]["msg"] - assert "remove_hidden_geometry" in warnings[0]["msg"] - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - refinements=[ - GeometryRefinement( - geometry_accuracy=0.01 * u.m, - min_passage_size=0.05 * u.m, - faces=[Surface(name="face1")], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=False, - ), - refinements=[ - GeometryRefinement( - geometry_accuracy=0.01 * u.m, - faces=[Surface(name="face1")], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] - - -def test_multi_zone_remove_hidden_geometry_warning(): - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[ - AutomatedFarfield(enclosed_entities=[Surface(name="face1")]), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ) - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert len(warnings) == 1 - assert ( - "removal of hidden geometry for multi-zone cases is not fully supported" - in warnings[0]["msg"].lower() - ) - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[AutomatedFarfield()], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=False, - ), - volume_zones=[ - AutomatedFarfield(enclosed_entities=[Surface(name="face1")]), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ) - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[ - UserDefinedFarfield(), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ), - CustomVolume( - name="zone2", - bounding_entities=[Surface(name="face3"), Surface(name="face4")], - ), - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert len(warnings) == 1 - assert ( - "removal of hidden geometry for multi-zone cases is not fully supported" - in warnings[0]["msg"].lower() - ) - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[ - UserDefinedFarfield(), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ) - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[ - UserDefinedFarfield(), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ), - CustomVolume( - name="zone2", - bounding_entities=[Surface(name="face3"), Surface(name="face4")], - ), - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert len(warnings) == 1 - assert ( - "removal of hidden geometry for multi-zone cases is not fully supported" - in warnings[0]["msg"].lower() - ) - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - geometry_accuracy=0.01 * u.m, - surface_max_edge_length=0.1 * u.m, - remove_hidden_geometry=True, - ), - volume_zones=[ - UserDefinedFarfield(), - CustomZones( - name="custom_zones", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ) - ], - ), - ], - ), - private_attribute_asset_cache=AssetCache( - use_geometry_AI=True, - use_inhouse_mesher=True, - project_length_unit=1 * u.m, - ), - ) - _, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="SurfaceMesh", - ) - assert errors is None - assert warnings == [] diff --git a/tests/simulation/params/meshing_validation/test_refinements_validation.py b/tests/simulation/params/meshing_validation/test_refinements_validation.py deleted file mode 100644 index f3f2da8fd..000000000 --- a/tests/simulation/params/meshing_validation/test_refinements_validation.py +++ /dev/null @@ -1,168 +0,0 @@ -import flow360.component.simulation.units as u -from flow360.component.simulation.meshing_param import snappy -from flow360.component.simulation.meshing_param.meshing_specs import ( - VolumeMeshingDefaults, -) -from flow360.component.simulation.meshing_param.params import ( - ModularMeshingWorkflow, - VolumeMeshingParams, -) -from flow360.component.simulation.meshing_param.volume_params import ( - AutomatedFarfield, - UniformRefinement, -) -from flow360.component.simulation.primitives import Box, Cylinder -from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.unit_system import SI_unit_system - - -def _make_snappy_params_with_volume_uniform_refinement(refinement): - with SI_unit_system: - return SimulationParams( - meshing=ModularMeshingWorkflow( - surface_meshing=snappy.SurfaceMeshingParams( - defaults=snappy.SurfaceMeshingDefaults( - min_spacing=1 * u.mm, - max_spacing=10 * u.mm, - gap_resolution=0.1 * u.mm, - ) - ), - volume_meshing=VolumeMeshingParams( - defaults=VolumeMeshingDefaults( - boundary_layer_first_layer_thickness=1 * u.mm, - ), - refinements=[refinement], - ), - zones=[AutomatedFarfield()], - ) - ) - - -def test_volume_uniform_refinement_rotated_box_project_to_surface(): - rotated_box = Box( - center=[0, 0, 0] * u.m, - size=[1, 1, 1] * u.m, - axis_of_rotation=[0, 0, 1], - angle_of_rotation=45 * u.deg, - name="rotated_box", - ) - refinement = UniformRefinement( - spacing=5 * u.mm, - entities=[rotated_box], - project_to_surface=True, - ) - params = _make_snappy_params_with_volume_uniform_refinement(refinement) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - - assert errors is not None - error_messages = [error["msg"] for error in errors] - assert any("angle_of_rotation" in msg or "axes aligned" in msg for msg in error_messages) - - -def test_volume_uniform_refinement_hollow_cylinder_project_to_surface(): - hollow_cylinder = Cylinder( - name="hollow_cyl", - inner_radius=3 * u.mm, - outer_radius=7 * u.mm, - axis=[0, 0, 1], - center=[0, 0, 0] * u.m, - height=10 * u.mm, - ) - refinement = UniformRefinement( - spacing=5 * u.mm, - entities=[hollow_cylinder], - project_to_surface=True, - ) - params = _make_snappy_params_with_volume_uniform_refinement(refinement) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - - assert errors is not None - error_messages = [error["msg"] for error in errors] - assert any("inner_radius" in msg or "full cylinders" in msg for msg in error_messages) - - -def test_volume_uniform_refinement_cylinder_none_inner_radius_project_to_surface(): - full_cylinder = Cylinder( - name="full_cyl_none", - inner_radius=None, - outer_radius=7 * u.mm, - axis=[0, 0, 1], - center=[0, 0, 0] * u.m, - height=10 * u.mm, - ) - refinement = UniformRefinement( - spacing=5 * u.mm, - entities=[full_cylinder], - project_to_surface=True, - ) - params = _make_snappy_params_with_volume_uniform_refinement(refinement) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - - assert errors is None - - -def test_volume_uniform_refinement_default_project_to_surface(): - rotated_box = Box( - center=[0, 0, 0] * u.m, - size=[1, 1, 1] * u.m, - axis_of_rotation=[0, 0, 1], - angle_of_rotation=90 * u.deg, - name="rotated_box_default", - ) - refinement = UniformRefinement(spacing=5 * u.mm, entities=[rotated_box]) - params = _make_snappy_params_with_volume_uniform_refinement(refinement) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - - assert errors is not None - error_messages = [error["msg"] for error in errors] - assert any("angle_of_rotation" in msg or "axes aligned" in msg for msg in error_messages) - - -def test_volume_uniform_refinement_project_to_surface_false_skips_validation(): - rotated_box = Box( - center=[0, 0, 0] * u.m, - size=[1, 1, 1] * u.m, - axis_of_rotation=[0, 0, 1], - angle_of_rotation=45 * u.deg, - name="rotated_box_no_project", - ) - refinement = UniformRefinement( - spacing=5 * u.mm, - entities=[rotated_box], - project_to_surface=False, - ) - params = _make_snappy_params_with_volume_uniform_refinement(refinement) - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="VolumeMesh", - ) - - assert errors is None, "No snappy validation error expected when project_to_surface=False" diff --git a/tests/simulation/params/test_farfield_enclosed_entities.py b/tests/simulation/params/test_farfield_enclosed_entities.py deleted file mode 100644 index 6694307b5..000000000 --- a/tests/simulation/params/test_farfield_enclosed_entities.py +++ /dev/null @@ -1,509 +0,0 @@ -"""Tests for farfield enclosed_entities validation across all farfield types.""" - -import pytest - -import flow360.component.simulation.units as u -from flow360.component.simulation.framework.param_utils import AssetCache -from flow360.component.simulation.meshing_param.meshing_specs import MeshingDefaults -from flow360.component.simulation.meshing_param.params import MeshingParams -from flow360.component.simulation.meshing_param.volume_params import ( - AutomatedFarfield, - CustomZones, - FullyMovingFloor, - RotationVolume, - UserDefinedFarfield, - WindTunnelFarfield, -) -from flow360.component.simulation.primitives import ( - CustomVolume, - Cylinder, - Sphere, - Surface, -) -from flow360.component.simulation.services import ( - ValidationCalledBy, - clear_context, - validate_model, -) -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.unit_system import SI_unit_system - - -@pytest.fixture(autouse=True) -def reset_context(): - clear_context() - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -FARFIELD_TYPES_WITH_ENCLOSED = [AutomatedFarfield, WindTunnelFarfield] - - -def _make_farfield(farfield_cls, **kwargs): - """Instantiate a farfield zone with type-specific defaults.""" - if farfield_cls is WindTunnelFarfield: - kwargs.setdefault("name", "wind tunnel") - kwargs.setdefault("floor_type", FullyMovingFloor()) - return farfield_cls(**kwargs) - - -def _make_defaults(farfield_cls): - """Return MeshingDefaults with type-specific extras (e.g. geometry_accuracy for WindTunnel).""" - kwargs = {"boundary_layer_first_layer_thickness": 1e-4} - if farfield_cls is WindTunnelFarfield: - kwargs["geometry_accuracy"] = 1e-4 - return MeshingDefaults(**kwargs) - - -def _make_asset_cache(farfield_cls, *, use_inhouse_mesher=True): - """Return AssetCache with type-specific extras (e.g. use_geometry_AI for WindTunnel).""" - kwargs = {"use_inhouse_mesher": use_inhouse_mesher} - if farfield_cls is WindTunnelFarfield: - kwargs["use_geometry_AI"] = True - return AssetCache(**kwargs) - - -def _validate(params): - """Run validation and return (warnings, errors, info).""" - return validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="SurfaceMesh", - validation_level="VolumeMesh", - ) - - -def _make_custom_zones_with_volume(): - """Standard CustomZones fixture used across many tests.""" - return CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), Surface(name="face2")], - ) - ], - ) - - -def _make_rotor_disk(): - return Cylinder( - name="rotor", - center=(0, 0, 0) * u.m, - axis=(0, 0, 1), - height=1 * u.m, - outer_radius=5 * u.m, - ) - - -# --------------------------------------------------------------------------- -# Group A: enclosed_entities + beta mesher = PASS -# --------------------------------------------------------------------------- - - -@pytest.mark.parametrize("farfield_cls", FARFIELD_TYPES_WITH_ENCLOSED, ids=lambda c: c.__name__) -def test_enclosed_entities_beta_mesher_positive(farfield_cls): - """enclosed_entities with beta mesher should pass validation.""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=_make_defaults(farfield_cls), - volume_zones=[ - _make_custom_zones_with_volume(), - _make_farfield( - farfield_cls, - enclosed_entities=[Surface(name="face1"), Surface(name="face2")], - ), - ], - ), - private_attribute_asset_cache=_make_asset_cache(farfield_cls), - ) - _, errors, _ = _validate(params) - assert errors is None - - -# --------------------------------------------------------------------------- -# Group B: enclosed_entities + legacy mesher = FAIL -# --------------------------------------------------------------------------- - - -@pytest.mark.parametrize("farfield_cls", FARFIELD_TYPES_WITH_ENCLOSED, ids=lambda c: c.__name__) -def test_enclosed_entities_beta_mesher_negative(farfield_cls): - """enclosed_entities with legacy mesher should fail validation.""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=_make_defaults(farfield_cls), - volume_zones=[ - _make_farfield(farfield_cls, enclosed_entities=[Surface(name="face1")]), - ], - ), - private_attribute_asset_cache=_make_asset_cache(farfield_cls, use_inhouse_mesher=False), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any( - "`enclosed_entities` is only supported with the beta mesher" in e["msg"] for e in errors - ) - - -# --------------------------------------------------------------------------- -# Group C: Cylinder without RotationVolume = FAIL -# --------------------------------------------------------------------------- - - -@pytest.mark.parametrize("farfield_cls", FARFIELD_TYPES_WITH_ENCLOSED, ids=lambda c: c.__name__) -def test_enclosed_entities_rotation_volume_association_negative(farfield_cls): - """Cylinder in enclosed_entities without a RotationVolume should fail.""" - rotor_disk = _make_rotor_disk() - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=_make_defaults(farfield_cls), - volume_zones=[ - CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1")], - ) - ], - ), - _make_farfield( - farfield_cls, - enclosed_entities=[Surface(name="face1"), rotor_disk], - ), - ], - ), - private_attribute_asset_cache=_make_asset_cache(farfield_cls), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any( - "`Cylinder` entity `rotor` in `enclosed_entities` must be associated with a `RotationVolume`" - in e["msg"] - for e in errors - ) - - -# --------------------------------------------------------------------------- -# Group D: Cylinder with RotationVolume = PASS -# --------------------------------------------------------------------------- - - -@pytest.mark.parametrize("farfield_cls", FARFIELD_TYPES_WITH_ENCLOSED, ids=lambda c: c.__name__) -def test_enclosed_entities_rotation_volume_association_positive(farfield_cls): - """Cylinder in enclosed_entities that is also in a RotationVolume should pass.""" - rotor_disk = _make_rotor_disk() - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=_make_defaults(farfield_cls), - volume_zones=[ - RotationVolume( - entities=[rotor_disk], - spacing_axial=0.5 * u.m, - spacing_radial=0.5 * u.m, - spacing_circumferential=0.3 * u.m, - ), - CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1")], - ) - ], - ), - _make_farfield( - farfield_cls, - enclosed_entities=[Surface(name="face1"), rotor_disk], - ), - ], - ), - private_attribute_asset_cache=_make_asset_cache(farfield_cls), - ) - _, errors, _ = _validate(params) - assert errors is None - - -# --------------------------------------------------------------------------- -# Group E: enclosed_entities without CustomZones = FAIL (WindTunnel only) -# --------------------------------------------------------------------------- - - -def test_enclosed_entities_requires_custom_zones(): - """WindTunnelFarfield enclosed_entities without CustomZones should fail.""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=_make_defaults(WindTunnelFarfield), - volume_zones=[ - _make_farfield(WindTunnelFarfield, enclosed_entities=[Surface(name="face1")]), - ], - ), - private_attribute_asset_cache=_make_asset_cache(WindTunnelFarfield), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any("only allowed when `CustomVolume` entities are present" in e["msg"] for e in errors) - - -# --------------------------------------------------------------------------- -# AutomatedFarfield-specific tests — has separate validator with additional checks -# --------------------------------------------------------------------------- - - -def test_enclosed_entities_none_with_legacy_mesher(): - """enclosed_entities=None with legacy mesher should pass (no error from this validator).""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[AutomatedFarfield()], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=False), - ) - _, errors, _ = _validate(params) - assert errors is None - - -def test_enclosed_entities_surfaces_only_no_rotation_volume_needed(): - """Only Surface entities in enclosed_entities should not require a RotationVolume.""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - _make_custom_zones_with_volume(), - AutomatedFarfield( - enclosed_entities=[Surface(name="face1"), Surface(name="face2")], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is None - - -# --------------------------------------------------------------------------- -# UserDefinedFarfield: no enclosed_entities support -# --------------------------------------------------------------------------- - - -def test_udf_rejects_enclosed_entities(): - """UserDefinedFarfield should not accept enclosed_entities.""" - import pydantic as pd - - with pytest.raises(pd.ValidationError, match="Extra inputs are not permitted"): - UserDefinedFarfield(enclosed_entities=[Surface(name="face1")]) - - -def test_udf_with_custom_volume_no_enclosed_entities(): - """UDF + CustomVolume without enclosed_entities should pass validation.""" - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - _make_custom_zones_with_volume(), - UserDefinedFarfield(), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is None - - -# --------------------------------------------------------------------------- -# CustomVolume bounding_entities + rotation association tests -# --------------------------------------------------------------------------- - - -def test_custom_volume_enclosed_entities_rotation_volume_association_positive(): - """CustomVolume with Cylinder in bounding_entities that is in a RotationVolume should pass.""" - rotor = _make_rotor_disk() - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - RotationVolume( - entities=[rotor], - spacing_axial=0.5 * u.m, - spacing_radial=0.5 * u.m, - spacing_circumferential=0.3 * u.m, - ), - CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), rotor], - ) - ], - ), - AutomatedFarfield( - enclosed_entities=[Surface(name="face1"), rotor], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is None - - -def test_custom_volume_enclosed_entities_rotation_volume_association_negative(): - """CustomVolume with Cylinder in bounding_entities without a RotationVolume should fail.""" - rotor = _make_rotor_disk() - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), rotor], - ) - ], - ), - AutomatedFarfield( - enclosed_entities=[Surface(name="face1")], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any("`Cylinder` entity `rotor` in `CustomVolume` `zone1`" in e["msg"] for e in errors) - - -def test_custom_volume_enclosed_entities_sphere_rotation_volume_negative(): - """CustomVolume with Sphere in bounding_entities without a RotationVolume should fail.""" - sph = Sphere( - name="sph", - center=(0, 0, 0) * u.m, - radius=5 * u.m, - ) - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - CustomZones( - name="interior", - entities=[ - CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), sph], - ) - ], - ), - AutomatedFarfield( - enclosed_entities=[Surface(name="face1")], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any("`Sphere` entity `sph` in `CustomVolume` `zone1`" in e["msg"] for e in errors) - - -def test_custom_volume_in_farfield_enclosed_entities_rotation_volume_negative(): - """CustomVolume inside farfield enclosed_entities with Cylinder not in RotationVolume should fail.""" - rotor = _make_rotor_disk() - with SI_unit_system: - cv = CustomVolume( - name="zone1", - bounding_entities=[Surface(name="face1"), rotor], - ) - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - CustomZones( - name="interior", - entities=[ - cv, - CustomVolume( - name="zone2", - bounding_entities=[Surface(name="face2")], - ), - ], - ), - AutomatedFarfield( - enclosed_entities=[Surface(name="face2"), cv], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any("`Cylinder` entity `rotor` in `CustomVolume` `zone1`" in e["msg"] for e in errors) - - -# --------------------------------------------------------------------------- -# Farfield + CustomVolume intersection tests -# --------------------------------------------------------------------------- - - -def test_farfield_custom_volume_no_intersection_positive(): - """CustomVolume in farfield enclosed_entities with disjoint entities should pass.""" - with SI_unit_system: - cv = CustomVolume( - name="inner_zone", - bounding_entities=[Surface(name="cv_face1"), Surface(name="cv_face2")], - ) - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - CustomZones(name="interior", entities=[cv]), - AutomatedFarfield( - enclosed_entities=[Surface(name="outer_face"), cv], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is None - - -def test_farfield_custom_volume_no_intersection_negative(): - """CustomVolume in farfield enclosed_entities sharing a surface with a sibling should fail.""" - shared_face = Surface(name="shared") - with SI_unit_system: - cv = CustomVolume( - name="inner_zone", - bounding_entities=[shared_face, Surface(name="cv_only")], - ) - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - volume_zones=[ - CustomZones(name="interior", entities=[cv]), - AutomatedFarfield( - enclosed_entities=[shared_face, cv], - ), - ], - ), - private_attribute_asset_cache=AssetCache(use_inhouse_mesher=True), - ) - _, errors, _ = _validate(params) - assert errors is not None - assert any("shares bounding entities" in e["msg"] for e in errors) - assert any("shared" in e["msg"] for e in errors) diff --git a/tests/simulation/params/test_simulation_params.py b/tests/simulation/params/test_simulation_params.py index 0a265fb8d..5daf1165f 100644 --- a/tests/simulation/params/test_simulation_params.py +++ b/tests/simulation/params/test_simulation_params.py @@ -4,10 +4,8 @@ import pytest -import flow360.component.simulation.units as u from flow360.component.project import create_draft from flow360.component.project_utils import set_up_params_for_uploading -from flow360.component.simulation import services from flow360.component.simulation.entity_info import GeometryEntityInfo from flow360.component.simulation.entity_operation import CoordinateSystem from flow360.component.simulation.migration.extra_operating_condition import ( @@ -194,20 +192,3 @@ def _get_selected_grouped_bodies(entity_info_dict: dict) -> list[dict]: 1.0, 0.0, ] - - -def test_default_params_for_local_test(): - with SI_unit_system: - param = SimulationParams() - - param = services._store_project_length_unit(1 * u.m, param) - param_as_dict = param.model_dump( - exclude_none=True, - exclude={ - "operating_condition": {"velocity_magnitude": True}, - "private_attribute_asset_cache": {"registry": True}, - }, - ) - - with SI_unit_system: - SimulationParams(**param_as_dict) diff --git a/tests/simulation/params/test_unit_conversions.py b/tests/simulation/params/test_unit_conversions.py deleted file mode 100644 index d1e87d744..000000000 --- a/tests/simulation/params/test_unit_conversions.py +++ /dev/null @@ -1,108 +0,0 @@ -import re -import unittest - -import pydantic as pd -import pytest - -import flow360 as fl -from flow360 import SI_unit_system, u -from flow360.component.simulation.operating_condition.operating_condition import ( - ThermalState, -) -from flow360.component.simulation.primitives import Surface - -assertions = unittest.TestCase("__init__") - - -@pytest.fixture(autouse=True) -def change_test_dir(request, monkeypatch): - monkeypatch.chdir(request.fspath.dirname) - - -# test_unit_conversions: REMOVED — tested convert_unit with flow360_*_unit (deleted in Phase 4) -# Tracked in plans/removed_tests.markdown for future migration to schema side. -def _removed_test_unit_conversions(): - pass - - -def test_temperature_offset(): - ThermalState.from_standard_atmosphere( - altitude=10 * u.m, temperature_offset=11.11 * u.delta_degC - ) - with pytest.raises(ValueError, match="Use delta units"): - ThermalState.from_standard_atmosphere(altitude=10 * u.m, temperature_offset=11.11 * u.degC) - - with fl.imperial_unit_system: - ts: ThermalState = ThermalState.from_standard_atmosphere( - altitude=10 * u.m, temperature_offset=11.11 - ) - assert ts.temperature_offset == 11.11 * u.delta_degF - - with fl.SI_unit_system: - ts: ThermalState = ThermalState.from_standard_atmosphere( - altitude=10 * u.m, temperature_offset=11.11 - ) - assert ts.temperature_offset == 11.11 * u.K - - with fl.CGS_unit_system: - ts: ThermalState = ThermalState.from_standard_atmosphere( - altitude=10 * u.m, temperature_offset=11.11 - ) - assert ts.temperature_offset == 11.11 * u.K - - -def test_operations_on_units(): - - with SI_unit_system: - far_field_zone = fl.AutomatedFarfield() - params = fl.SimulationParams( - meshing=fl.MeshingParams( - defaults=fl.MeshingDefaults( - boundary_layer_first_layer_thickness=0.001, - surface_max_edge_length=1, - ), - volume_zones=[far_field_zone], - ), - reference_geometry=fl.ReferenceGeometry(), - operating_condition=fl.AerospaceCondition( - velocity_magnitude=100 * fl.u.m / 3 / fl.u.s * 7 * fl.u.inch / fl.u.cm, - alpha=5 * u.deg, - ), - time_stepping=fl.Steady(max_steps=1000), - models=[ - fl.Wall( - surfaces=[Surface(name="surface")], - name="Wall", - ), - fl.Freestream( - surfaces=[far_field_zone.farfield], - name="Freestream", - ), - ], - ) - - replaced = params.operating_condition.velocity_magnitude * 3 - assertions.assertAlmostEqual(replaced.value, 70000) - assert str(replaced.units) == "inch/s" - - replaced = params.operating_condition.velocity_magnitude / (27.3 * fl.u.m / fl.u.s) - assertions.assertAlmostEqual(replaced.value, 21.70940170940171) - assert str(replaced.units) == "dimensionless" - - replaced = params.operating_condition.velocity_magnitude**5 - (1 / 50 * (fl.u.km / fl.u.s) ** 5) - assertions.assertAlmostEqual(replaced.value, 502472105493.3395, 3) - assert str(replaced.units) == "inch**5*m**5/(cm**5*s**5)" - - replaced = ( - params.operating_condition.thermal_state.temperature.to("degC") - 25 * fl.u.degC - ).to("K") - assertions.assertAlmostEqual(replaced.value, -10) - assert str(replaced.units) == "K" - - replaced = params.operating_condition.thermal_state.temperature.to("degC") - 25 * fl.u.degC - assertions.assertAlmostEqual(replaced.value, -10) - assert str(replaced.units.expr) == "delta_degC" # unyt 3.0+ - - replaced = params.operating_condition.thermal_state.density + 2 * fl.u.g / fl.u.cm**3 - assertions.assertAlmostEqual(replaced.value, 2001.2249999999997) - assert str(replaced.units) == "kg/m**3" diff --git a/tests/simulation/params/test_validators_bet_disk.py b/tests/simulation/params/test_validators_bet_disk.py deleted file mode 100644 index b6788c96d..000000000 --- a/tests/simulation/params/test_validators_bet_disk.py +++ /dev/null @@ -1,140 +0,0 @@ -import unittest - -import pytest - -import flow360.component.simulation.units as u -from flow360.component.simulation import services -from flow360.component.simulation.models.volume_models import BETDisk -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.time_stepping.time_stepping import Unsteady -from tests.simulation.translator.utils.xv15_bet_disk_helper import createBETDiskSteady -from tests.simulation.translator.utils.xv15BETDisk_param_generator import ( - _BET_cylinder, - _rpm_hover_mode, -) - -assertions = unittest.TestCase("__init__") - - -@pytest.fixture -def create_steady_bet_disk(): - bet_disk = createBETDiskSteady(_BET_cylinder, 10, _rpm_hover_mode) - return bet_disk - - -@pytest.fixture(autouse=True) -def change_test_dir(request, monkeypatch): - monkeypatch.chdir(request.fspath.dirname) - - -def test_bet_disk_blade_line_chord(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match="BETDisk with name 'BET disk': the blade_line_chord has to be positive since its initial_blade_direction is specified.", - ): - bet_disk.initial_blade_direction = (1, 0, 0) - - -def test_bet_disk_initial_blade_direction(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - BETDisk.model_validate(bet_disk) - - with pytest.raises( - ValueError, - match="BETDisk with name 'BET disk': the initial_blade_direction is required to specify since its blade_line_chord is non-zero", - ): - bet_disk_2 = bet_disk.model_copy(deep=True) - bet_disk_2.blade_line_chord = 0.1 * u.inch - - -def test_bet_disk_initial_blade_direction_with_bet_name(create_steady_bet_disk): - with pytest.raises( - ValueError, - match="BETDisk with name 'custom_bet_disk_name': the initial_blade_direction is required to specify since its blade_line_chord is non-zero", - ): - bet_disk = create_steady_bet_disk - bet_disk.name = "custom_bet_disk_name" - bet_disk.blade_line_chord = 0.1 * u.inch - - -def test_bet_disk_disorder_alphas(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match="BETDisk with name 'BET disk': the alphas are not in increasing order.", - ): - tmp = bet_disk.alphas[0] - bet_disk.alphas[0] = bet_disk.alphas[1] - bet_disk.alphas[1] = tmp - BETDisk.deserialize(bet_disk.model_dump()) - - -def test_bet_disk_duplicate_chords(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': it has duplicated radius at .+ in chords\.", - ): - bet_disk.name = "diskABC" - bet_disk.chords.append(bet_disk.chords[-1]) - BETDisk.deserialize(bet_disk.model_dump()) - - -def test_bet_disk_duplicate_twists(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': it has duplicated radius at .+ in twists\.", - ): - bet_disk.name = "diskABC" - bet_disk.twists.append(bet_disk.twists[-1]) - BETDisk.deserialize(bet_disk.model_dump()) - - -def test_bet_disk_nonequal_sectional_radiuses_and_polars(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': the length of sectional_radiuses \(7\) is not the same as that of sectional_polars \(6\).", - ): - bet_disk.name = "diskABC" - bet_disk_dict = bet_disk.model_dump() - bet_disk_dict["sectional_radiuses"] = bet_disk_dict["sectional_radiuses"] + [ - bet_disk_dict["sectional_radiuses"][-1], - ] - BETDisk.deserialize(bet_disk_dict) - - -def test_bet_disk_3d_coefficients_dimension_wrong_mach_numbers(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': \(cross section: 0\): number of mach_numbers = 2, but the first dimension of lift_coeffs is 1", - ): - bet_disk.name = "diskABC" - bet_disk.mach_numbers.append(bet_disk.mach_numbers[-1]) - BETDisk.model_validate(bet_disk) - - -def test_bet_disk_3d_coefficients_dimension_wrong_re_numbers(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': \(cross section: 0\) \(Mach index \(0-based\) 0\): number of Reynolds = 2, but the second dimension of lift_coeffs is 1", - ): - bet_disk.name = "diskABC" - bet_disk.reynolds_numbers.append(bet_disk.reynolds_numbers[-1]) - BETDisk.model_validate(bet_disk) - - -def test_bet_disk_3d_coefficients_dimension_wrong_alpha_numbers(create_steady_bet_disk): - bet_disk = create_steady_bet_disk - with pytest.raises( - ValueError, - match=r"BETDisk with name 'diskABC': \(cross section: 0\) \(Mach index \(0-based\) 0, Reynolds index \(0-based\) 0\): number of Alphas = 18, but the third dimension of lift_coeffs is 17.", - ): - bet_disk.name = "diskABC" - bet_disk_dict = bet_disk.model_dump() - bet_disk_dict["alphas"] = bet_disk_dict["alphas"] + [bet_disk_dict["alphas"][-1]] - BETDisk.deserialize(bet_disk_dict) diff --git a/tests/simulation/params/test_validators_criterion.py b/tests/simulation/params/test_validators_criterion.py deleted file mode 100644 index 76cc82b80..000000000 --- a/tests/simulation/params/test_validators_criterion.py +++ /dev/null @@ -1,52 +0,0 @@ -import json -import os - -from flow360.component.simulation.services import ValidationCalledBy, validate_model - - -def test_criterion_with_monitor_output_id(): - simulation_path = os.path.join( - os.path.dirname(__file__), - "data", - "simulation_stopping_criterion_webui.json", - ) - with open(simulation_path, "r") as file: - data = json.load(file) - - _, errors, _ = validate_model( - params_as_dict=data, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - expected_errors = [ - { - "type": "value_error", - "loc": ("run_control", "stopping_criteria", 0, "monitor_output"), - "msg": "Value error, For stopping criterion setup, only one single `Point` entity is allowed in `ProbeOutput`/`SurfaceProbeOutput`.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "type": "value_error", - "loc": ("run_control", "stopping_criteria", 1, "monitor_output"), - "msg": "Value error, The monitor field does not exist in the monitor output.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "type": "value_error", - "loc": ("run_control", "stopping_criteria", 2, "tolerance"), - "msg": "Value error, The dimensions of monitor field and tolerance do not match.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "type": "value_error", - "loc": ("run_control", "stopping_criteria", 3, "monitor_output"), - "msg": "Value error, The monitor output does not exist in the outputs list.", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - assert len(errors) == len(expected_errors) - for error, expected in zip(errors, expected_errors): - assert error["loc"] == expected["loc"] - assert error["type"] == expected["type"] - assert error["msg"] == expected["msg"] - assert error["ctx"]["relevant_for"] == expected["ctx"]["relevant_for"] diff --git a/tests/simulation/params/test_validators_output.py b/tests/simulation/params/test_validators_output.py deleted file mode 100644 index e0428aa40..000000000 --- a/tests/simulation/params/test_validators_output.py +++ /dev/null @@ -1,121 +0,0 @@ -import json -import os - -from flow360.component.simulation.framework.param_utils import AssetCache -from flow360.component.simulation.models.surface_models import Wall -from flow360.component.simulation.models.volume_models import Fluid -from flow360.component.simulation.outputs.outputs import SurfaceOutput, VolumeOutput -from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.time_stepping.time_stepping import Steady -from flow360.component.simulation.unit_system import imperial_unit_system -from flow360.component.volume_mesh import VolumeMeshV2 - - -def test_output_frequency_settings_in_steady_simulation(): - volume_mesh = VolumeMeshV2.from_local_storage( - mesh_id=None, - local_storage_path=os.path.join( - os.path.dirname(__file__), - "..", - "data", - "vm_entity_provider", - ), - ) - simulation_path = os.path.join( - os.path.dirname(__file__), - "..", - "data", - "vm_entity_provider", - "simulation.json", - ) - with open(simulation_path, "r") as file: - asset_cache_data = json.load(file).pop("private_attribute_asset_cache") - asset_cache = AssetCache.deserialize(asset_cache_data) - with imperial_unit_system: - params = SimulationParams( - models=[Wall(name="wall", entities=volume_mesh["*"])], - time_stepping=Steady(), - outputs=[ - VolumeOutput(output_fields=["Mach", "Cp"], frequency=2), - SurfaceOutput( - output_fields=["Cp"], - entities=volume_mesh["*"], - frequency_offset=10, - ), - ], - private_attribute_asset_cache=asset_cache, - ) - - params_as_dict = params.model_dump(exclude_none=True, mode="json") - _, errors, _ = validate_model( - params_as_dict=params_as_dict, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level="All", - ) - - expected_errors = [ - { - "loc": ("outputs", 0, "frequency"), - "type": "value_error", - "msg": "Value error, Output frequency cannot be specified in a steady simulation.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "loc": ("outputs", 1, "frequency_offset"), - "type": "value_error", - "msg": "Value error, Output frequency_offset cannot be specified in a steady simulation.", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - assert len(errors) == len(expected_errors) - for error, expected in zip(errors, expected_errors): - assert error["loc"] == expected["loc"] - assert error["type"] == expected["type"] - assert error["msg"] == expected["msg"] - assert error["ctx"]["relevant_for"] == expected["ctx"]["relevant_for"] - - -def test_force_output_with_model_id(): - simulation_path = os.path.join( - os.path.dirname(__file__), - "data", - "simulation_force_output_webui.json", - ) - with open(simulation_path, "r") as file: - data = json.load(file) - - _, errors, _ = validate_model( - params_as_dict=data, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - expected_errors = [ - { - "type": "value_error", - "loc": ("outputs", 3, "models"), - "msg": "Value error, Duplicate models are not allowed in the same `ForceOutput`.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "type": "value_error", - "loc": ("outputs", 4, "models"), - "msg": "Value error, When ActuatorDisk/BETDisk/PorousMedium is specified, " - "only CL, CD, CFx, CFy, CFz, CMx, CMy, CMz can be set as output_fields.", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "type": "value_error", - "loc": ("outputs", 5, "models"), - "msg": "Value error, The model does not exist in simulation params' models list.", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - - assert len(errors) == len(expected_errors) - for error, expected in zip(errors, expected_errors): - assert error["loc"] == expected["loc"] - assert error["type"] == expected["type"] - assert error["ctx"]["relevant_for"] == expected["ctx"]["relevant_for"] - assert error["msg"] == expected["msg"] diff --git a/tests/simulation/params/test_validators_params.py b/tests/simulation/params/test_validators_params.py index 2e8263214..94aafdc8a 100644 --- a/tests/simulation/params/test_validators_params.py +++ b/tests/simulation/params/test_validators_params.py @@ -866,157 +866,6 @@ def test_output_fields_with_user_defined_fields(): ) -def test_rotation_parent_volumes(mock_case_validation_context): - - c_1 = Cylinder( - name="inner_rotating_cylinder", - outer_radius=1 * u.cm, - height=1 * u.cm, - center=(0, 0, 0) * u.cm, - axis=(0, 0, 1), - ) - - c_2 = Cylinder( - name="outer_rotating_cylinder", - outer_radius=12 * u.cm, - height=12 * u.cm, - center=(0, 0, 0) * u.cm, - axis=(0, 0, 1), - ) - - c_3 = Cylinder( - name="stationary_cylinder", - outer_radius=12 * u.m, - height=13 * u.m, - center=(0, 0, 0) * u.m, - axis=(0, 1, 2), - ) - - my_wall = Surface(name="my_wall", private_attribute_is_interface=False) - - msg = "For model #1, the parent rotating volume (stationary_cylinder) is not " - "used in any other `Rotation` model's `volumes`." - with mock_case_validation_context, pytest.raises(ValueError, match=re.escape(msg)): - with SI_unit_system: - SimulationParams( - models=[ - Fluid(), - Rotation(entities=[c_1], spec=AngleExpression("1+2"), parent_volume=c_3), - ] - ) - - with ValidationContext(CASE): - with SI_unit_system: - SimulationParams( - models=[ - Fluid(), - Rotation(entities=[c_1], spec=AngleExpression("1+2"), parent_volume=c_2), - Rotation(entities=[c_2], spec=AngleExpression("1+5")), - Wall(entities=[my_wall]), - ], - private_attribute_asset_cache=AssetCache( - project_length_unit=1 * u.cm, - project_entity_info=VolumeMeshEntityInfo(boundaries=[my_wall]), - ), - ) - - -def test_meshing_validator_dual_context(): - errors = None - try: - with SI_unit_system: - with ValidationContext(VOLUME_MESH): - SimulationParams(meshing=None) - except pd.ValidationError as err: - errors = err.errors() - assert len(errors) == 1 - assert errors[0]["type"] == "missing" - assert errors[0]["ctx"] == {"relevant_for": ["SurfaceMesh", "VolumeMesh"]} - assert errors[0]["loc"] == ("meshing",) - - -def test_rotating_reference_frame_model_flag(): - - c_1 = Cylinder( - name="inner_rotating_cylinder", - outer_radius=1 * u.cm, - height=1 * u.cm, - center=(0, 0, 0) * u.cm, - axis=(0, 0, 1), - ) - - c_2 = Cylinder( - name="outer_rotating_cylinder", - outer_radius=12 * u.cm, - height=12 * u.cm, - center=(0, 0, 0) * u.cm, - axis=(0, 0, 1), - ) - - c_3 = Cylinder( - name="another_cylinder", - outer_radius=12 * u.m, - height=13 * u.m, - center=(0, 0, 0) * u.m, - axis=(0, 1, 2), - ) - - my_wall = Surface(name="my_wall", private_attribute_is_interface=False) - timestepping_unsteady = Unsteady(steps=12, step_size=0.1 * u.s) - timestepping_steady = Steady(max_steps=1000) - - msg = "For model #1, the rotating_reference_frame_model may not be set to False for " - "steady state simulations." - - with pytest.raises(ValueError, match=re.escape(msg)): - with ValidationContext(CASE): - with SI_unit_system: - SimulationParams( - models=[ - Fluid(), - Rotation( - entities=[c_1], - spec=AngleExpression("1+2"), - rotating_reference_frame_model=False, - ), - Wall(entities=[my_wall]), - ], - time_stepping=timestepping_steady, - private_attribute_asset_cache=AssetCache( - project_length_unit=1 * u.cm, - project_entity_info=VolumeMeshEntityInfo(boundaries=[my_wall]), - ), - ) - - with ValidationContext(CASE): - with SI_unit_system: - test_param = SimulationParams( - models=[ - Fluid(), - Rotation( - entities=[c_1], - spec=AngleExpression("1+2"), - parent_volume=c_2, - rotating_reference_frame_model=True, - ), - Rotation( - entities=[c_2], - spec=AngleExpression("1+5"), - rotating_reference_frame_model=False, - ), - Rotation(entities=[c_3], spec=AngleExpression("3+5")), - Wall(entities=[my_wall]), - ], - time_stepping=timestepping_unsteady, - private_attribute_asset_cache=AssetCache( - project_length_unit=1 * u.cm, - project_entity_info=VolumeMeshEntityInfo(boundaries=[my_wall]), - ), - ) - - assert test_param.models[3].rotating_reference_frame_model == False - - def test_output_fields_with_time_average_output(): # Valid simulation params @@ -1079,221 +928,6 @@ def test_output_fields_with_time_average_output(): params.time_stepping = Steady(max_steps=1000) -def test_wall_deserialization(): - # Wall->velocity accept discriminated AND non-discriminated unions. - # Need to check if all works when deserializing. - dummy_boundary = Surface(name="chameleon") - with DeserializationContext(): - simple_wall = Wall(**Wall(entities=dummy_boundary).model_dump(mode="json")) - assert simple_wall.velocity is None - - with DeserializationContext(): - const_vel_wall = Wall( - **Wall(entities=dummy_boundary, velocity=[1, 2, 3] * u.m / u.s).model_dump(mode="json") - ) - assert all(const_vel_wall.velocity == [1, 2, 3] * u.m / u.s) - - with DeserializationContext(): - slater_bleed_wall = Wall( - **Wall( - entities=dummy_boundary, - velocity=SlaterPorousBleed(porosity=0.2, static_pressure=0.1 * u.Pa), - ).model_dump(mode="json") - ) - assert slater_bleed_wall.velocity.porosity == 0.2 - assert slater_bleed_wall.velocity.static_pressure == 0.1 * u.Pa - - -def test_populate_validated_models_to_validation_context(mock_validation_context): - """Test that models are properly populated to validation context.""" - # Create models with private_attribute_id - fluid_model = Fluid() - wall_model = Wall( - name="wall_bc", - surfaces=[Surface(name="wall_surface")], - ) - - # Before validation, physics_model_dict should be None - assert mock_validation_context.info.physics_model_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams( - models=[fluid_model, wall_model], - ) - - # After validation, physics_model_dict should be populated - assert mock_validation_context.info.physics_model_dict is not None - assert isinstance(mock_validation_context.info.physics_model_dict, dict) - - # Check that models are in the dict with their IDs as keys - assert len(mock_validation_context.info.physics_model_dict) == 2 - assert fluid_model.private_attribute_id in mock_validation_context.info.physics_model_dict - assert wall_model.private_attribute_id in mock_validation_context.info.physics_model_dict - - # Verify the objects are the same - assert ( - mock_validation_context.info.physics_model_dict[fluid_model.private_attribute_id] - == fluid_model - ) - assert ( - mock_validation_context.info.physics_model_dict[wall_model.private_attribute_id] - == wall_model - ) - - -def test_populate_validated_outputs_to_validation_context(mock_validation_context): - """Test that outputs are properly populated to validation context.""" - # Create outputs with private_attribute_id - probe_output = ProbeOutput( - name="probe1", - output_fields=["Cp"], - probe_points=[Point(name="pt1", location=(1, 2, 3) * u.m)], - ) - - surface_output = SurfaceOutput( - name="surface1", - output_fields=["Cp"], - entities=[Surface(name="wall")], - ) - - volume_output = VolumeOutput( - name="volume1", - output_fields=["primitiveVars"], - ) - - # Before validation, output_dict should be None - assert mock_validation_context.info.output_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams( - outputs=[probe_output, surface_output, volume_output], - ) - - # After validation, output_dict should be populated - assert mock_validation_context.info.output_dict is not None - assert isinstance(mock_validation_context.info.output_dict, dict) - - # Check that outputs are in the dict with their IDs as keys - assert len(mock_validation_context.info.output_dict) == 3 - assert probe_output.private_attribute_id in mock_validation_context.info.output_dict - assert surface_output.private_attribute_id in mock_validation_context.info.output_dict - assert volume_output.private_attribute_id in mock_validation_context.info.output_dict - - # Verify the objects are the same - assert ( - mock_validation_context.info.output_dict[probe_output.private_attribute_id] == probe_output - ) - assert ( - mock_validation_context.info.output_dict[surface_output.private_attribute_id] - == surface_output - ) - assert ( - mock_validation_context.info.output_dict[volume_output.private_attribute_id] - == volume_output - ) - - -def test_populate_both_models_and_outputs_to_validation_context(mock_validation_context): - """Test that both models and outputs are properly populated to the same validation context.""" - # Create models and outputs - fluid_model = Fluid() - probe_output = ProbeOutput( - name="probe1", - output_fields=["Cp"], - probe_points=[Point(name="pt1", location=(1, 2, 3) * u.m)], - ) - - # Before validation, both should be None - assert mock_validation_context.info.physics_model_dict is None - assert mock_validation_context.info.output_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams( - models=[fluid_model], - outputs=[probe_output], - ) - - # After validation, both should be populated - assert mock_validation_context.info.physics_model_dict is not None - assert mock_validation_context.info.output_dict is not None - - # Verify both dicts are populated correctly - assert fluid_model.private_attribute_id in mock_validation_context.info.physics_model_dict - assert probe_output.private_attribute_id in mock_validation_context.info.output_dict - - assert ( - mock_validation_context.info.physics_model_dict[fluid_model.private_attribute_id] - == fluid_model - ) - assert ( - mock_validation_context.info.output_dict[probe_output.private_attribute_id] == probe_output - ) - - -def test_populate_outputs_none_sets_empty_dict(mock_validation_context): - """Test that output_dict is set to {} when outputs=None. - - This distinguishes successful validation with no outputs (output_dict={}) - from validation errors (output_dict=None). - """ - assert mock_validation_context.info.output_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams(outputs=None) - - # output_dict should be set to empty dict, not None - assert mock_validation_context.info.output_dict == {} - - -def test_populate_outputs_empty_list_sets_empty_dict(mock_validation_context): - """Test that output_dict is set to {} when outputs=[].""" - assert mock_validation_context.info.output_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams(outputs=[]) - - # output_dict should be set to empty dict - assert mock_validation_context.info.output_dict == {} - - -def test_populate_models_none_sets_dict_with_default(mock_validation_context): - """Test that physics_model_dict is populated when models=None. - - Note: SimulationParams automatically adds a default Fluid model when models=None, - so physics_model_dict will contain the default model, not be empty. - This still distinguishes successful validation from validation errors (physics_model_dict=None). - """ - assert mock_validation_context.info.physics_model_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams(models=None) - - # physics_model_dict should be populated with default Fluid model - assert mock_validation_context.info.physics_model_dict is not None - assert isinstance(mock_validation_context.info.physics_model_dict, dict) - # Should contain the default fluid model - assert len(mock_validation_context.info.physics_model_dict) == 1 - assert "__default_fluid" in mock_validation_context.info.physics_model_dict - - -def test_populate_models_empty_list_sets_dict_with_default(mock_validation_context): - """Test that physics_model_dict is populated when models=[]. - - Note: SimulationParams automatically adds a default Fluid model when models=[], - so physics_model_dict will contain the default model. - """ - assert mock_validation_context.info.physics_model_dict is None - - with SI_unit_system, mock_validation_context: - params = SimulationParams(models=[]) - - # physics_model_dict should be populated with default Fluid model - assert mock_validation_context.info.physics_model_dict is not None - assert isinstance(mock_validation_context.info.physics_model_dict, dict) - assert len(mock_validation_context.info.physics_model_dict) == 1 - assert "__default_fluid" in mock_validation_context.info.physics_model_dict - - @pytest.fixture(autouse=True) def change_test_dir(request, monkeypatch): monkeypatch.chdir(request.fspath.dirname) @@ -1978,30 +1612,6 @@ def test_beta_mesher_only_features(mock_validation_context): assert errors[0]["loc"] == () -def test_edge_split_layers_default_no_warning_for_dict_input(): - non_beta_context = ParamsValidationInfo({}, []) - non_beta_context.is_beta_mesher = False - non_beta_context.project_length_unit = 1 * u.m - - with SI_unit_system, ValidationContext(VOLUME_MESH, non_beta_context) as validation_context: - defaults = MeshingDefaults.model_validate({"boundary_layer_first_layer_thickness": 1e-4}) - - assert "edge_split_layers" not in defaults.model_fields_set - assert validation_context.validation_warnings == [] - - -def test_edge_split_layers_default_no_warning_for_constructor_input(): - non_beta_context = ParamsValidationInfo({}, []) - non_beta_context.is_beta_mesher = False - non_beta_context.project_length_unit = 1 * u.m - - with SI_unit_system, ValidationContext(VOLUME_MESH, non_beta_context) as validation_context: - defaults = MeshingDefaults(boundary_layer_first_layer_thickness=1e-4) - - assert "edge_split_layers" not in defaults.model_fields_set - assert validation_context.validation_warnings == [] - - def test_geometry_AI_only_features(): with SI_unit_system: params = SimulationParams( @@ -2569,97 +2179,6 @@ def test_deleted_surfaces_domain_type(): assert "Boundary `pos_surf` will likely be deleted" in errors[0]["msg"] -def test_unique_selector_names(): - """Test that duplicate selector names are detected and raise an error.""" - from flow360.component.simulation.framework.entity_selector import ( - SurfaceSelector, - collect_and_tokenize_selectors_in_place, - ) - from flow360.component.simulation.models.surface_models import Wall - from flow360.component.simulation.primitives import Surface - - # Create actual Surface entities to avoid selector expansion issues - surface1 = Surface(name="surface1") - surface2 = Surface(name="surface2") - - # Create selectors with duplicate names - selector1 = SurfaceSelector(name="duplicate_name").match("wing*") - selector2 = SurfaceSelector(name="duplicate_name").match("tail*") - - # Test duplicate selector names in different EntityLists (different Wall models) - with SI_unit_system: - params = SimulationParams( - models=[ - Wall(entities=[surface1, selector1]), - Wall(entities=[surface2, selector2]), - ], - ) - - # Tokenize selectors to populate used_selectors (simulating what happens in set_up_params_for_uploading) - params_dict = params.model_dump(mode="json", exclude_none=True) - params_dict = collect_and_tokenize_selectors_in_place(params_dict) - - # Now validate using validate_model which will materialize and validate - _, errors, _ = validate_model( - params_as_dict=params_dict, - validated_by=ValidationCalledBy.LOCAL, - root_item_type=None, - validation_level=None, - ) - - assert errors is not None - assert len(errors) == 1 - assert "Duplicate selector name 'duplicate_name'" in errors[0]["msg"] - - # Test duplicate selector names in the same EntityList - with SI_unit_system: - params2 = SimulationParams( - models=[ - Wall(entities=[surface1, selector1, selector2]), - ], - ) - - params_dict2 = params2.model_dump(mode="json", exclude_none=True) - params_dict2 = collect_and_tokenize_selectors_in_place(params_dict2) - - _, errors2, _ = validate_model( - params_as_dict=params_dict2, - validated_by=ValidationCalledBy.LOCAL, - root_item_type=None, - validation_level=None, - ) - - assert errors2 is not None - assert len(errors2) == 1 - assert "Duplicate selector name 'duplicate_name'" in errors2[0]["msg"] - - # Test that unique selector names work fine - selector3 = SurfaceSelector(name="unique_name_1").match("wing*") - selector4 = SurfaceSelector(name="unique_name_2").match("tail*") - - with SI_unit_system: - params3 = SimulationParams( - models=[ - Wall(entities=[surface1, selector3]), - Wall(entities=[surface2, selector4]), - ], - ) - - params_dict3 = params3.model_dump(mode="json", exclude_none=True) - params_dict3 = collect_and_tokenize_selectors_in_place(params_dict3) - - validated_params, errors3, _ = validate_model( - params_as_dict=params_dict3, - validated_by=ValidationCalledBy.LOCAL, - root_item_type=None, - validation_level=None, - ) - - # Should not have errors for unique names - assert errors3 is None or len(errors3) == 0 - assert validated_params is not None - - def test_coordinate_system_requires_geometry_ai(): """Test that CoordinateSystem is only supported when Geometry AI is enabled.""" # Create a CoordinateSystemStatus with assignments @@ -2938,97 +2457,6 @@ def test_domain_type_bbox_mismatch_downgraded_to_warning_when_transformed(): ), warnings -def test_incomplete_BC_with_geometry_AI(): - """Test that missing boundary conditions produce warnings (not errors) when using Geometry AI.""" - # Construct a dummy asset cache with GAI enabled - wall = Surface(name="wall", private_attribute_is_interface=False, private_attribute_id="wall") - no_bc = Surface( - name="no_bc", private_attribute_is_interface=False, private_attribute_id="no_bc" - ) - - asset_cache = AssetCache( - project_length_unit=1 * u.m, - project_entity_info=VolumeMeshEntityInfo(boundaries=[wall, no_bc]), - use_geometry_AI=True, # Enable GAI - ) - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - boundary_layer_first_layer_thickness=1e-10, - surface_max_edge_length=1e-10, - ) - ), - models=[ - Fluid(), - Wall(entities=[wall]), - # no_bc is intentionally missing - ], - private_attribute_asset_cache=asset_cache, - ) - - params, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level="All", - ) - - # Should not have errors, only warnings - assert errors is None or len(errors) == 0 - assert len(warnings) > 0 - assert any( - "no_bc" in w.get("msg", "") and "do not have a boundary condition" in w.get("msg", "") - for w in warnings - ), f"Expected warning about missing boundary condition for 'no_bc', got: {warnings}" - - -def test_incomplete_BC_without_geometry_AI(): - """Test that missing boundary conditions produce errors when NOT using Geometry AI.""" - # Construct a dummy asset cache without GAI - wall = Surface(name="wall", private_attribute_is_interface=False, private_attribute_id="wall") - no_bc = Surface( - name="no_bc", private_attribute_is_interface=False, private_attribute_id="no_bc" - ) - - asset_cache = AssetCache( - project_length_unit=1 * u.m, - project_entity_info=VolumeMeshEntityInfo(boundaries=[wall, no_bc]), - use_geometry_AI=False, # Disable GAI - ) - - with SI_unit_system: - params = SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - boundary_layer_first_layer_thickness=1e-10, - surface_max_edge_length=1e-10, - ) - ), - models=[ - Fluid(), - Wall(entities=[wall]), - # no_bc is intentionally missing - ], - private_attribute_asset_cache=asset_cache, - ) - - params, errors, warnings = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level="All", - ) - - # Should have errors - assert len(errors) == 1 - assert errors[0]["msg"] == ( - "Value error, The following boundaries do not have a boundary condition: no_bc. " - "Please add them to a boundary condition model in the `models` section." - ) - - def test_automated_farfield_with_custom_zones(): """AutomatedFarfield + CustomZones: enclosed_entities is required when CustomVolumes exist.""" diff --git a/tests/simulation/params/test_validators_solid.py b/tests/simulation/params/test_validators_solid.py deleted file mode 100644 index a0f959507..000000000 --- a/tests/simulation/params/test_validators_solid.py +++ /dev/null @@ -1,162 +0,0 @@ -import re - -import pytest - -import flow360.component.simulation.units as u -from flow360.component.simulation.entity_info import SurfaceMeshEntityInfo -from flow360.component.simulation.framework.param_utils import AssetCache -from flow360.component.simulation.meshing_param.meshing_specs import ( - VolumeMeshingDefaults, -) -from flow360.component.simulation.meshing_param.params import ( - MeshingDefaults, - MeshingParams, - ModularMeshingWorkflow, - VolumeMeshingParams, - snappy, -) -from flow360.component.simulation.meshing_param.volume_params import ( - CustomZones, - UserDefinedFarfield, -) -from flow360.component.simulation.models.material import aluminum -from flow360.component.simulation.models.volume_models import Solid -from flow360.component.simulation.primitives import ( - CustomVolume, - SeedpointVolume, - Surface, -) -from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.simulation_params import SimulationParams -from flow360.component.simulation.unit_system import SI_unit_system - - -def _build_params_with_custom_volume(element_type: str): - zone = CustomVolume(name="solid_zone", bounding_entities=[Surface(name="face1")]) - return SimulationParams( - meshing=MeshingParams( - defaults=MeshingDefaults( - boundary_layer_first_layer_thickness=1e-4, - planar_face_tolerance=1e-4, - ), - volume_zones=[ - CustomZones( - name="custom_zones", - entities=[zone], - element_type=element_type, - ), - UserDefinedFarfield(), - ], - ), - models=[ - Solid( - entities=[zone], - material=aluminum, - ) - ], - private_attribute_asset_cache=AssetCache( - use_inhouse_mesher=True, - project_entity_info=SurfaceMeshEntityInfo(boundaries=[Surface(name="face1")]), - ), - ) - - -def _build_params_with_seedpoint_volume(element_type: str): - zone = SeedpointVolume(name="solid_zone", point_in_mesh=(0, 0, 0) * u.mm) - return SimulationParams( - meshing=ModularMeshingWorkflow( - surface_meshing=snappy.SurfaceMeshingParams( - defaults=snappy.SurfaceMeshingDefaults( - min_spacing=2 * u.mm, max_spacing=4 * u.mm, gap_resolution=1 * u.mm - ) - ), - volume_meshing=VolumeMeshingParams( - defaults=VolumeMeshingDefaults(boundary_layer_first_layer_thickness=1e-4), - ), - zones=[ - CustomZones( - name="custom_zones", - entities=[zone], - element_type=element_type, - ), - ], - ), - models=[ - Solid( - entities=[zone], - material=aluminum, - ) - ], - private_attribute_asset_cache=AssetCache( - use_inhouse_mesher=True, - project_entity_info=SurfaceMeshEntityInfo(boundaries=[Surface(name="face1")]), - ), - ) - - -def test_solid_custom_volume_requires_tetrahedra_raises_on_mixed(): - with SI_unit_system: - params = _build_params_with_custom_volume(element_type="mixed") - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="SurfaceMesh", - validation_level="All", - ) - - assert errors is not None and len(errors) == 1 - assert errors[0]["msg"] == ( - "Value error, CustomVolume 'solid_zone' must be meshed with " - "tetrahedra-only elements. Please adjust setting in `CustomZones`." - ) - assert errors[0]["loc"][0] == "models" - assert errors[0]["loc"][2] == "entities" - - -def test_solid_custom_volume_allows_tetrahedra(): - with SI_unit_system: - params = _build_params_with_custom_volume(element_type="tetrahedra") - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="SurfaceMesh", - validation_level="All", - ) - - assert errors is None - - -def test_solid_seedpoint_volume_requires_tetrahedra_raises_on_mixed(): - with SI_unit_system: - params = _build_params_with_seedpoint_volume(element_type="mixed") - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="All", - ) - - assert errors is not None and len(errors) == 1 - assert errors[0]["msg"] == ( - "Value error, SeedpointVolume 'solid_zone' must be meshed with " - "tetrahedra-only elements. Please adjust setting in `CustomZones`." - ) - assert errors[0]["loc"][0] == "models" - assert errors[0]["loc"][2] == "entities" - - -def test_solid_seedpoint_volume_allows_tetrahedra(): - with SI_unit_system: - params = _build_params_with_seedpoint_volume(element_type="tetrahedra") - - _, errors, _ = validate_model( - params_as_dict=params.model_dump(mode="json"), - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level="All", - ) - - assert errors is None diff --git a/tests/simulation/service/data/dependency_geometry_sphere1_simulation.json b/tests/simulation/service/data/dependency_geometry_sphere1_simulation.json deleted file mode 100644 index c60744ae1..000000000 --- a/tests/simulation/service/data/dependency_geometry_sphere1_simulation.json +++ /dev/null @@ -1,746 +0,0 @@ -{ - "hash": "562ccb89a69df627df3a181b692b3467afdf05ae4e9586c828a98e86d765ce68", - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12.0 - }, - "planar_face_tolerance": 1e-06, - "preserve_thin_geometry": false, - "resolve_face_boundaries": false, - "sealing_size": { - "units": "m", - "value": 0.0 - }, - "sliding_interface_tolerance": 0.01, - "surface_edge_growth_rate": 1.2, - "surface_max_adaptation_iterations": 50, - "surface_max_aspect_ratio": 10.0 - }, - "outputs": [], - "refinement_factor": 1.0, - "refinements": [], - "type_name": "MeshingParams", - "volume_zones": [ - { - "method": "auto", - "name": "Farfield", - "relative_size": 50.0, - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0.0 - } - }, - "name": "Wall", - "private_attribute_id": "b7990356-c29b-44ee-aa5e-a163a18848d0", - "roughness_height": { - "units": "m", - "value": 0.0 - }, - "type": "Wall", - "use_wall_function": false - }, - { - "entities": { - "stored_entities": [ - { - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_id": "farfield" - } - ] - }, - "name": "Freestream", - "private_attribute_id": "a00c9458-066e-4207-94c7-56474e62fe60", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "private_attribute_id": "39c6e6c8-9756-401f-bb12-8d037d829908", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "bodies_face_edge_ids": { - "sphere1_body00001": { - "edge_ids": [ - "sphere1_body00001_edge00001", - "sphere1_body00001_edge00003" - ], - "face_ids": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ] - } - }, - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "sphere1_body00001" - ], - "default_geometry_accuracy": { - "units": "m", - "value": 0.0001 - }, - "draft_entities": [], - "edge_attribute_names": [ - "name", - "edgeId" - ], - "edge_group_tag": "name", - "edge_ids": [ - "sphere1_body00001_edge00001", - "sphere1_body00001_edge00003" - ], - "face_attribute_names": [ - "builtinName", - "groupByBodyId", - "name", - "faceId" - ], - "face_group_tag": "name", - "face_ids": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 200.0, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield" - }, - { - "center": [ - 0.0, - -2.0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-1" - }, - { - "center": [ - 0.0, - 2.0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-2" - }, - { - "center": [ - 0.0, - 0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric" - }, - { - "name": "windTunnelInlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelInlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelOutlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelOutlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelCeiling", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCeiling", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFloor", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFloor", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelLeft", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelLeft", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelRight", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRight", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFrictionPatch", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": [ - "StaticFloor" - ] - }, - { - "name": "windTunnelCentralBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": [ - "CentralBelt", - "WheelBelts" - ] - }, - { - "name": "windTunnelFrontWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": [ - "WheelBelts" - ] - }, - { - "name": "windTunnelRearWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": [ - "WheelBelts" - ] - } - ], - "global_bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "sphere1_body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "ddf34d3d-1354-46dd-9165-0c18f4010b31", - "private_attribute_sub_components": [ - "sphere1_body00001" - ], - "private_attribute_tag_key": "bodyId" - } - ], - [ - { - "mesh_exterior": true, - "name": "sphere_r2mm.step", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "442cc0e0-da72-4784-8036-fd5c1e643831", - "private_attribute_sub_components": [ - "sphere1_body00001" - ], - "private_attribute_tag_key": "groupByFile" - } - ] - ], - "grouped_edges": [ - [ - { - "name": "sphere1_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "9cbefe8c-82e0-486d-b805-6ee5ecd49c21", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere1_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "48869a6b-c99e-46fd-a816-2833aa16283c", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00003" - ], - "private_attribute_tag_key": "name" - } - ], - [ - { - "name": "sphere1_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "dc6dea8e-240d-4eb8-9c32-d4a42a0d99b7", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere1_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "adb4961e-0e43-400f-97a6-ffb07c16e472", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "e8473b81-9840-441d-a45d-534320f3b330", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere1_body00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3a150e35-76bc-4e47-84f1-238f9200d0ea", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere1_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "d5922440-36fc-4308-aac4-b040ee31d950", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "238489c6-b158-44bb-b5b4-d6cc17a69b51", - "private_attribute_sub_components": [ - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere1_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3d8cd3d8-4719-40db-9929-d683a504e670", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "a932d870-d169-49aa-83e1-be9fbffcbe2d", - "private_attribute_sub_components": [ - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": { - "units": "m", - "value": 1.0 - }, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1.0 - }, - "moment_center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1.0, - 1.0, - 1.0 - ] - } - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/simulation/service/data/dependency_geometry_sphere2_simulation.json b/tests/simulation/service/data/dependency_geometry_sphere2_simulation.json deleted file mode 100644 index e2344dca8..000000000 --- a/tests/simulation/service/data/dependency_geometry_sphere2_simulation.json +++ /dev/null @@ -1,746 +0,0 @@ -{ - "hash": "800de3ec2de57facdf30ae67b66bda611402446426f2fd2882541995e92cac65", - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12.0 - }, - "planar_face_tolerance": 1e-06, - "preserve_thin_geometry": false, - "resolve_face_boundaries": false, - "sealing_size": { - "units": "m", - "value": 0.0 - }, - "sliding_interface_tolerance": 0.01, - "surface_edge_growth_rate": 1.2, - "surface_max_adaptation_iterations": 50, - "surface_max_aspect_ratio": 10.0 - }, - "outputs": [], - "refinement_factor": 1.0, - "refinements": [], - "type_name": "MeshingParams", - "volume_zones": [ - { - "method": "auto", - "name": "Farfield", - "relative_size": 50.0, - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0.0 - } - }, - "name": "Wall", - "private_attribute_id": "b7990356-c29b-44ee-aa5e-a163a18848d0", - "roughness_height": { - "units": "m", - "value": 0.0 - }, - "type": "Wall", - "use_wall_function": false - }, - { - "entities": { - "stored_entities": [ - { - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_id": "farfield" - } - ] - }, - "name": "Freestream", - "private_attribute_id": "a00c9458-066e-4207-94c7-56474e62fe60", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "private_attribute_id": "39c6e6c8-9756-401f-bb12-8d037d829908", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "bodies_face_edge_ids": { - "sphere2_body00001": { - "edge_ids": [ - "sphere2_body00001_edge00001", - "sphere2_body00001_edge00003" - ], - "face_ids": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ] - } - }, - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "sphere2_body00001" - ], - "default_geometry_accuracy": { - "units": "m", - "value": 0.0001 - }, - "draft_entities": [], - "edge_attribute_names": [ - "name", - "edgeId" - ], - "edge_group_tag": "name", - "edge_ids": [ - "sphere2_body00001_edge00001", - "sphere2_body00001_edge00003" - ], - "face_attribute_names": [ - "builtinName", - "groupByBodyId", - "name", - "faceId" - ], - "face_group_tag": "name", - "face_ids": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 200.0, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield" - }, - { - "center": [ - 5.0, - -2.0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-1" - }, - { - "center": [ - 5.0, - 2.0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-2" - }, - { - "center": [ - 5.0, - 0, - 0.0 - ], - "max_radius": 200.0, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric" - }, - { - "name": "windTunnelInlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelInlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelOutlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelOutlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelCeiling", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCeiling", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFloor", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFloor", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelLeft", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelLeft", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelRight", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRight", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFrictionPatch", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": [ - "StaticFloor" - ] - }, - { - "name": "windTunnelCentralBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": [ - "CentralBelt", - "WheelBelts" - ] - }, - { - "name": "windTunnelFrontWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": [ - "WheelBelts" - ] - }, - { - "name": "windTunnelRearWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": [ - "WheelBelts" - ] - } - ], - "global_bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "sphere2_body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "fad554fd-2de9-4064-a5b3-8488a235812a", - "private_attribute_sub_components": [ - "sphere2_body00001" - ], - "private_attribute_tag_key": "bodyId" - } - ], - [ - { - "mesh_exterior": true, - "name": "sphere_r2mm_center_5_0_0.step", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "0fb73bec-f430-4efd-8dc5-4b9955df849e", - "private_attribute_sub_components": [ - "sphere2_body00001" - ], - "private_attribute_tag_key": "groupByFile" - } - ] - ], - "grouped_edges": [ - [ - { - "name": "sphere2_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "96b21c6a-21b5-4387-acd2-83ae71f17413", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere2_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "4b30a96b-b8c1-4de2-9a5f-f447bb42f4a9", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00003" - ], - "private_attribute_tag_key": "name" - } - ], - [ - { - "name": "sphere2_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "3193fbf3-6379-42de-ac63-5ad9401dcce2", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere2_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "ac831004-5a5e-4b8b-b66a-475b78308ab9", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "032d8c9b-9873-4557-b7c6-cde69f6507f7", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere2_body00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "6ce3c95d-1bd2-434c-be8b-d88151a099a0", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere2_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "ee6f39e2-15ed-4d3b-a77a-8383831bad15", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere2_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "ad2779dd-c479-4b20-b753-054a988f6fac", - "private_attribute_sub_components": [ - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere2_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "33dc2ccd-4b46-4444-b094-76e5fdd2249f", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere2_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "8c3e316d-fbd5-45ef-a79f-e60f764abcca", - "private_attribute_sub_components": [ - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": { - "units": "m", - "value": 1.0 - }, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1.0 - }, - "moment_center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1.0, - 1.0, - 1.0 - ] - } - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/simulation/service/data/result_merged_geometry_entity_info1.json b/tests/simulation/service/data/result_merged_geometry_entity_info1.json deleted file mode 100644 index b70a06379..000000000 --- a/tests/simulation/service/data/result_merged_geometry_entity_info1.json +++ /dev/null @@ -1,1048 +0,0 @@ -{ - "bodies_face_edge_ids": { - "body00001": { - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012" - ], - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ] - }, - "sphere1_body00001": { - "edge_ids": [ - "sphere1_body00001_edge00001", - "sphere1_body00001_edge00003" - ], - "face_ids": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ] - } - }, - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "body00001", - "sphere1_body00001" - ], - "default_geometry_accuracy": 0.0001, - "draft_entities": [], - "edge_attribute_names": [ - "name", - "edgeId" - ], - "edge_group_tag": "name", - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012", - "sphere1_body00001_edge00001", - "sphere1_body00001_edge00003" - ], - "face_attribute_names": [ - "builtinName", - "groupByBodyId", - "name", - "faceId" - ], - "face_group_tag": "groupByBodyId", - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006", - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 100.0, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield" - }, - { - "center": [ - 12.0, - -1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-1" - }, - { - "center": [ - 12.0, - 1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-2" - }, - { - "center": [ - 12.0, - 0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric" - }, - { - "name": "windTunnelInlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelInlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelOutlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelOutlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelCeiling", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCeiling", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFloor", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFloor", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelLeft", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelLeft", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelRight", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRight", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFrictionPatch", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": [ - "StaticFloor" - ] - }, - { - "name": "windTunnelCentralBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": [ - "CentralBelt", - "WheelBelts" - ] - }, - { - "name": "windTunnelFrontWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": [ - "WheelBelts" - ] - }, - { - "name": "windTunnelRearWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": [ - "WheelBelts" - ] - } - ], - "global_bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 13.0, - 2.0, - 2.0 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "b496086c-136d-4f01-998d-c9e1eea120ae", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "bodyId" - }, - { - "mesh_exterior": true, - "name": "sphere1_body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "ddf34d3d-1354-46dd-9165-0c18f4010b31", - "private_attribute_sub_components": [ - "sphere1_body00001" - ], - "private_attribute_tag_key": "bodyId" - } - ], - [ - { - "mesh_exterior": true, - "name": "sphere_r2mm.step", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "442cc0e0-da72-4784-8036-fd5c1e643831", - "private_attribute_sub_components": [ - "sphere1_body00001" - ], - "private_attribute_tag_key": "groupByFile" - }, - { - "mesh_exterior": false, - "name": "cube_2mm_center", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "7d2b9129-f5f4-4f92-b9b6-a554b420f162", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "groupByFile" - } - ] - ], - "grouped_edges": [ - [ - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "0dcf993b-6ac4-4089-b4d6-2fd2d3a94d29", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "1442e021-6026-4e98-a0a2-d45f14e017a5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2e7e546a-753e-4b80-9d46-281f13070365", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere1_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "48869a6b-c99e-46fd-a816-2833aa16283c", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00003" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "596a214f-3b47-448e-b18e-7e7b2999a845", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "67bf3b4f-b319-4cd2-a7b6-9c81281a7d2d", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "6e06acde-5ff1-475d-a327-ea330f44b267", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "75c1c7be-cbee-430e-9b0f-cf3fbf01ac61", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "791f24ba-efdd-4912-aa3c-66e5d6b667f9", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "99d61ea6-9f7e-4236-87c0-c6101dfb0ee0", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere1_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "9cbefe8c-82e0-486d-b805-6ee5ecd49c21", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a27906f8-10ff-4820-a32b-41fa6c6cfa3c", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "b60b9fa0-e08c-44f4-9869-0b80a92c3c7e", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "be4f9f1f-e938-492a-aa73-d90b089619f8", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "name" - } - ], - [ - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "05742309-f8f3-439b-a3d1-6a60570a35ed", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "177aac2c-d04b-4bd5-8e5f-758b472bf985", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2fe046d7-7d58-4b37-b4f5-b391335a520a", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "4978befb-352c-4879-a1d5-c4dc0dc83a07", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "5297031f-260c-4ff3-ba06-3e08018a51a4", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "599a9e71-3d9c-4ae6-962b-6bb34e8ee961", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "8e8d80ee-35ed-431a-bee6-460118ba75e9", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "93549028-dbcd-4dd3-87f5-745d269f8243", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a6462fd9-871c-4ee7-b33c-f36e5788a965", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere1_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "adb4961e-0e43-400f-97a6-ffb07c16e472", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere1_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "dc6dea8e-240d-4eb8-9c32-d4a42a0d99b7", - "private_attribute_sub_components": [ - "sphere1_body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e3c65004-eec0-469b-9dfe-bbd62705e412", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e5e5b6e3-2835-4c1b-a0ce-056617827745", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "f0839250-331b-4d76-8409-824679adb5f5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "359eeb96-86b5-4952-ac23-192dfd3a40ac", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "e8473b81-9840-441d-a45d-534320f3b330", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere1_body00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3a150e35-76bc-4e47-84f1-238f9200d0ea", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001", - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "cube_body", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "dc724906-9b8f-4e62-ac58-ec97e2a12c76", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "084ec7b0-6ff1-4a3f-993d-06128efa49f8", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "238489c6-b158-44bb-b5b4-d6cc17a69b51", - "private_attribute_sub_components": [ - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "59eda58d-0dac-4f77-b4c4-2fcdf4361378", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "8277de84-8306-4547-9cb0-687d178b14b1", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "900a49b1-6d7b-44df-89f9-2cf48ac243f8", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "b4ca0f33-0d8f-4fc1-be3a-30aa7b2d22da", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "d4efa00f-dfdd-4461-b317-25fc6a775d4e", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "d5922440-36fc-4308-aac4-b040ee31d950", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "346806f8-3946-4a48-8616-56b538605814", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3d8cd3d8-4719-40db-9929-d683a504e670", - "private_attribute_sub_components": [ - "sphere1_body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 2.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3db752a1-2925-4fc6-89fe-100a490d141b", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "a3c3b221-97e2-4368-ac13-addb3102b46c", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere1_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "a932d870-d169-49aa-83e1-be9fbffcbe2d", - "private_attribute_sub_components": [ - "sphere1_body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - -2.0, - -2.0, - -2.0 - ], - [ - 2.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c236edf3-4d79-4fbe-908d-0420dfdf53cc", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c89e0cf2-777a-413f-8e59-48f387f564ee", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "cb676b21-1ecd-4062-94f6-3eb5fb279c7e", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ] - ], - "type_name": "GeometryEntityInfo" -} diff --git a/tests/simulation/service/data/result_merged_geometry_entity_info2.json b/tests/simulation/service/data/result_merged_geometry_entity_info2.json deleted file mode 100644 index bcca5f01e..000000000 --- a/tests/simulation/service/data/result_merged_geometry_entity_info2.json +++ /dev/null @@ -1,1048 +0,0 @@ -{ - "bodies_face_edge_ids": { - "body00001": { - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012" - ], - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ] - }, - "sphere2_body00001": { - "edge_ids": [ - "sphere2_body00001_edge00001", - "sphere2_body00001_edge00003" - ], - "face_ids": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ] - } - }, - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "body00001", - "sphere2_body00001" - ], - "default_geometry_accuracy": 0.0001, - "draft_entities": [], - "edge_attribute_names": [ - "name", - "edgeId" - ], - "edge_group_tag": "name", - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012", - "sphere2_body00001_edge00001", - "sphere2_body00001_edge00003" - ], - "face_attribute_names": [ - "builtinName", - "groupByBodyId", - "name", - "faceId" - ], - "face_group_tag": "groupByBodyId", - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006", - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 100.0, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield" - }, - { - "center": [ - 12.0, - -1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-1" - }, - { - "center": [ - 12.0, - 1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-2" - }, - { - "center": [ - 12.0, - 0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric" - }, - { - "name": "windTunnelInlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelInlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelOutlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelOutlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelCeiling", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCeiling", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFloor", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFloor", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelLeft", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelLeft", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelRight", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRight", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFrictionPatch", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": [ - "StaticFloor" - ] - }, - { - "name": "windTunnelCentralBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": [ - "CentralBelt", - "WheelBelts" - ] - }, - { - "name": "windTunnelFrontWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": [ - "WheelBelts" - ] - }, - { - "name": "windTunnelRearWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": [ - "WheelBelts" - ] - } - ], - "global_bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 13.0, - 2.0, - 2.0 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "b496086c-136d-4f01-998d-c9e1eea120ae", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "bodyId" - }, - { - "mesh_exterior": true, - "name": "sphere2_body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "fad554fd-2de9-4064-a5b3-8488a235812a", - "private_attribute_sub_components": [ - "sphere2_body00001" - ], - "private_attribute_tag_key": "bodyId" - } - ], - [ - { - "mesh_exterior": true, - "name": "sphere_r2mm_center_5_0_0.step", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "0fb73bec-f430-4efd-8dc5-4b9955df849e", - "private_attribute_sub_components": [ - "sphere2_body00001" - ], - "private_attribute_tag_key": "groupByFile" - }, - { - "mesh_exterior": false, - "name": "cube_2mm_center", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "7d2b9129-f5f4-4f92-b9b6-a554b420f162", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "groupByFile" - } - ] - ], - "grouped_edges": [ - [ - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "0dcf993b-6ac4-4089-b4d6-2fd2d3a94d29", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "1442e021-6026-4e98-a0a2-d45f14e017a5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2e7e546a-753e-4b80-9d46-281f13070365", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere2_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "4b30a96b-b8c1-4de2-9a5f-f447bb42f4a9", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00003" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "596a214f-3b47-448e-b18e-7e7b2999a845", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "67bf3b4f-b319-4cd2-a7b6-9c81281a7d2d", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "6e06acde-5ff1-475d-a327-ea330f44b267", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "75c1c7be-cbee-430e-9b0f-cf3fbf01ac61", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "791f24ba-efdd-4912-aa3c-66e5d6b667f9", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "sphere2_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "96b21c6a-21b5-4387-acd2-83ae71f17413", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "99d61ea6-9f7e-4236-87c0-c6101dfb0ee0", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a27906f8-10ff-4820-a32b-41fa6c6cfa3c", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "b60b9fa0-e08c-44f4-9869-0b80a92c3c7e", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "be4f9f1f-e938-492a-aa73-d90b089619f8", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "name" - } - ], - [ - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "05742309-f8f3-439b-a3d1-6a60570a35ed", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "177aac2c-d04b-4bd5-8e5f-758b472bf985", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2fe046d7-7d58-4b37-b4f5-b391335a520a", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere2_body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "3193fbf3-6379-42de-ac63-5ad9401dcce2", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "4978befb-352c-4879-a1d5-c4dc0dc83a07", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "5297031f-260c-4ff3-ba06-3e08018a51a4", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "599a9e71-3d9c-4ae6-962b-6bb34e8ee961", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "8e8d80ee-35ed-431a-bee6-460118ba75e9", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "93549028-dbcd-4dd3-87f5-745d269f8243", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a6462fd9-871c-4ee7-b33c-f36e5788a965", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "sphere2_body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "ac831004-5a5e-4b8b-b66a-475b78308ab9", - "private_attribute_sub_components": [ - "sphere2_body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e3c65004-eec0-469b-9dfe-bbd62705e412", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e5e5b6e3-2835-4c1b-a0ce-056617827745", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "f0839250-331b-4d76-8409-824679adb5f5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "032d8c9b-9873-4557-b7c6-cde69f6507f7", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "359eeb96-86b5-4952-ac23-192dfd3a40ac", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere2_body00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "6ce3c95d-1bd2-434c-be8b-d88151a099a0", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001", - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "cube_body", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "dc724906-9b8f-4e62-ac58-ec97e2a12c76", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "084ec7b0-6ff1-4a3f-993d-06128efa49f8", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "59eda58d-0dac-4f77-b4c4-2fcdf4361378", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "8277de84-8306-4547-9cb0-687d178b14b1", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "900a49b1-6d7b-44df-89f9-2cf48ac243f8", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere2_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "ad2779dd-c479-4b20-b753-054a988f6fac", - "private_attribute_sub_components": [ - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "b4ca0f33-0d8f-4fc1-be3a-30aa7b2d22da", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "d4efa00f-dfdd-4461-b317-25fc6a775d4e", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere2_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "ee6f39e2-15ed-4d3b-a77a-8383831bad15", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "sphere2_body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "33dc2ccd-4b46-4444-b094-76e5fdd2249f", - "private_attribute_sub_components": [ - "sphere2_body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -4.499279347985573e-32, - -2.0 - ], - [ - 7.0, - 2.0, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "346806f8-3946-4a48-8616-56b538605814", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3db752a1-2925-4fc6-89fe-100a490d141b", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "sphere2_body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "8c3e316d-fbd5-45ef-a79f-e60f764abcca", - "private_attribute_sub_components": [ - "sphere2_body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 3.0, - -2.0, - -2.0 - ], - [ - 7.0, - 2.4492935982947064e-16, - 2.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "a3c3b221-97e2-4368-ac13-addb3102b46c", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c236edf3-4d79-4fbe-908d-0420dfdf53cc", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c89e0cf2-777a-413f-8e59-48f387f564ee", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "cb676b21-1ecd-4062-94f6-3eb5fb279c7e", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ] - ], - "type_name": "GeometryEntityInfo" -} diff --git a/tests/simulation/service/data/root_geometry_cube_simulation.json b/tests/simulation/service/data/root_geometry_cube_simulation.json deleted file mode 100644 index 0e3c8d0f4..000000000 --- a/tests/simulation/service/data/root_geometry_cube_simulation.json +++ /dev/null @@ -1,1154 +0,0 @@ -{ - "hash": "4da4256d0f07d14933d36243edede09ade1cf4894b99c3eeb7145146f6b32752", - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12.0 - }, - "planar_face_tolerance": 1e-06, - "preserve_thin_geometry": false, - "resolve_face_boundaries": false, - "sealing_size": { - "units": "m", - "value": 0.0 - }, - "sliding_interface_tolerance": 0.01, - "surface_edge_growth_rate": 1.2, - "surface_max_adaptation_iterations": 50, - "surface_max_aspect_ratio": 10.0 - }, - "outputs": [], - "refinement_factor": 1.0, - "refinements": [], - "type_name": "MeshingParams", - "volume_zones": [ - { - "method": "auto", - "name": "Farfield", - "relative_size": 50.0, - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "W/m**2", - "value": 0.0 - } - }, - "name": "Wall", - "private_attribute_id": "b7990356-c29b-44ee-aa5e-a163a18848d0", - "roughness_height": { - "units": "m", - "value": 0.0 - }, - "type": "Wall", - "use_wall_function": false - }, - { - "entities": { - "stored_entities": [ - { - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_id": "farfield" - } - ] - }, - "name": "Freestream", - "private_attribute_id": "a00c9458-066e-4207-94c7-56474e62fe60", - "type": "Freestream" - }, - { - "initial_condition": { - "p": "p", - "rho": "rho", - "type_name": "NavierStokesInitialCondition", - "u": "u", - "v": "v", - "w": "w" - }, - "interface_interpolation_tolerance": 0.2, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1.0, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1.0, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1.0, - "order_of_accuracy": 2, - "relative_tolerance": 0.0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "private_attribute_id": "__default_fluid", - "transition_model_solver": { - "type_name": "None" - }, - "turbulence_model_solver": { - "CFL_multiplier": 2.0, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "low_reynolds_correction": false, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_cb1": 0.1355, - "C_cb2": 0.622, - "C_d": 8.0, - "C_min_rd": 10.0, - "C_sigma": 0.6666666666666666, - "C_t3": 1.2, - "C_t4": 0.5, - "C_v1": 7.1, - "C_vonKarman": 0.41, - "C_w2": 0.3, - "C_w4": 0.21, - "C_w5": 1.5, - "type_name": "SpalartAllmarasConsts" - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0.0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "alpha": { - "units": "degree", - "value": 0.0 - }, - "beta": { - "units": "degree", - "value": 0.0 - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - } - }, - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition" - }, - "outputs": [ - { - "entities": { - "stored_entities": [ - { - "name": "*", - "private_attribute_entity_type_name": "Surface", - "private_attribute_sub_components": [] - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "private_attribute_id": "39c6e6c8-9756-401f-bb12-8d037d829908", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "bodies_face_edge_ids": { - "body00001": { - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012" - ], - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ] - } - }, - "body_attribute_names": [ - "bodyId", - "groupByFile" - ], - "body_group_tag": "groupByFile", - "body_ids": [ - "body00001" - ], - "default_geometry_accuracy": { - "units": "m", - "value": 0.0001 - }, - "draft_entities": [], - "edge_attribute_names": [ - "name", - "edgeId" - ], - "edge_group_tag": "name", - "edge_ids": [ - "body00001_edge00001", - "body00001_edge00002", - "body00001_edge00003", - "body00001_edge00004", - "body00001_edge00005", - "body00001_edge00006", - "body00001_edge00007", - "body00001_edge00008", - "body00001_edge00009", - "body00001_edge00010", - "body00001_edge00011", - "body00001_edge00012" - ], - "face_attribute_names": [ - "builtinName", - "groupByBodyId", - "name", - "faceId" - ], - "face_group_tag": "groupByBodyId", - "face_ids": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 100.0, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_id": "farfield" - }, - { - "center": [ - 12.0, - -1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-1", - "normal_axis": [ - 0, - -1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-1" - }, - { - "center": [ - 12.0, - 1.0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric-2" - }, - { - "center": [ - 12.0, - 0, - 0.0 - ], - "max_radius": 100.0, - "name": "symmetric", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_id": "symmetric" - }, - { - "name": "windTunnelInlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelInlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelOutlet", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelOutlet", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelCeiling", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCeiling", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFloor", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFloor", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelLeft", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelLeft", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelRight", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRight", - "used_by": [ - "all" - ] - }, - { - "name": "windTunnelFrictionPatch", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrictionPatch", - "used_by": [ - "StaticFloor" - ] - }, - { - "name": "windTunnelCentralBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelCentralBelt", - "used_by": [ - "CentralBelt", - "WheelBelts" - ] - }, - { - "name": "windTunnelFrontWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelFrontWheelBelt", - "used_by": [ - "WheelBelts" - ] - }, - { - "name": "windTunnelRearWheelBelt", - "private_attribute_entity_type_name": "WindTunnelGhostSurface", - "private_attribute_id": "windTunnelRearWheelBelt", - "used_by": [ - "WheelBelts" - ] - } - ], - "global_bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "grouped_bodies": [ - [ - { - "mesh_exterior": true, - "name": "body00001", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "b496086c-136d-4f01-998d-c9e1eea120ae", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "bodyId" - } - ], - [ - { - "mesh_exterior": false, - "name": "cube_2mm_center", - "private_attribute_entity_type_name": "GeometryBodyGroup", - "private_attribute_id": "7d2b9129-f5f4-4f92-b9b6-a554b420f162", - "private_attribute_sub_components": [ - "body00001" - ], - "private_attribute_tag_key": "groupByFile" - } - ] - ], - "grouped_edges": [ - [ - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "99d61ea6-9f7e-4236-87c0-c6101dfb0ee0", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "67bf3b4f-b319-4cd2-a7b6-9c81281a7d2d", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a27906f8-10ff-4820-a32b-41fa6c6cfa3c", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "be4f9f1f-e938-492a-aa73-d90b089619f8", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "0dcf993b-6ac4-4089-b4d6-2fd2d3a94d29", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2e7e546a-753e-4b80-9d46-281f13070365", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "596a214f-3b47-448e-b18e-7e7b2999a845", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "75c1c7be-cbee-430e-9b0f-cf3fbf01ac61", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "1442e021-6026-4e98-a0a2-d45f14e017a5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "b60b9fa0-e08c-44f4-9869-0b80a92c3c7e", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "6e06acde-5ff1-475d-a327-ea330f44b267", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "name" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "791f24ba-efdd-4912-aa3c-66e5d6b667f9", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "name" - } - ], - [ - { - "name": "body00001_edge00001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "05742309-f8f3-439b-a3d1-6a60570a35ed", - "private_attribute_sub_components": [ - "body00001_edge00001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "5297031f-260c-4ff3-ba06-3e08018a51a4", - "private_attribute_sub_components": [ - "body00001_edge00002" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "a6462fd9-871c-4ee7-b33c-f36e5788a965", - "private_attribute_sub_components": [ - "body00001_edge00003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "8e8d80ee-35ed-431a-bee6-460118ba75e9", - "private_attribute_sub_components": [ - "body00001_edge00004" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e5e5b6e3-2835-4c1b-a0ce-056617827745", - "private_attribute_sub_components": [ - "body00001_edge00005" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "2fe046d7-7d58-4b37-b4f5-b391335a520a", - "private_attribute_sub_components": [ - "body00001_edge00006" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "93549028-dbcd-4dd3-87f5-745d269f8243", - "private_attribute_sub_components": [ - "body00001_edge00007" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "4978befb-352c-4879-a1d5-c4dc0dc83a07", - "private_attribute_sub_components": [ - "body00001_edge00008" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "f0839250-331b-4d76-8409-824679adb5f5", - "private_attribute_sub_components": [ - "body00001_edge00009" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "177aac2c-d04b-4bd5-8e5f-758b472bf985", - "private_attribute_sub_components": [ - "body00001_edge00010" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "599a9e71-3d9c-4ae6-962b-6bb34e8ee961", - "private_attribute_sub_components": [ - "body00001_edge00011" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body00001_edge00012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": "e3c65004-eec0-469b-9dfe-bbd62705e412", - "private_attribute_sub_components": [ - "body00001_edge00012" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "No Name", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "359eeb96-86b5-4952-ac23-192dfd3a40ac", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "builtinName", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "cube_body", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "dc724906-9b8f-4e62-ac58-ec97e2a12c76", - "private_attribute_sub_components": [ - "body00001_face00001", - "body00001_face00002", - "body00001_face00003", - "body00001_face00004", - "body00001_face00005", - "body00001_face00006" - ], - "private_attribute_tag_key": "groupByBodyId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "900a49b1-6d7b-44df-89f9-2cf48ac243f8", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "084ec7b0-6ff1-4a3f-993d-06128efa49f8", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "59eda58d-0dac-4f77-b4c4-2fcdf4361378", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "b4ca0f33-0d8f-4fc1-be3a-30aa7b2d22da", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "8277de84-8306-4547-9cb0-687d178b14b1", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "d4efa00f-dfdd-4461-b317-25fc6a775d4e", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "name", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ], - [ - { - "name": "body00001_face00001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "a3c3b221-97e2-4368-ac13-addb3102b46c", - "private_attribute_sub_components": [ - "body00001_face00001" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 11.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c89e0cf2-777a-413f-8e59-48f387f564ee", - "private_attribute_sub_components": [ - "body00001_face00002" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - -1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "3db752a1-2925-4fc6-89fe-100a490d141b", - "private_attribute_sub_components": [ - "body00001_face00003" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 13.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "cb676b21-1ecd-4062-94f6-3eb5fb279c7e", - "private_attribute_sub_components": [ - "body00001_face00004" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - 1.0, - -1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "c236edf3-4d79-4fbe-908d-0420dfdf53cc", - "private_attribute_sub_components": [ - "body00001_face00005" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - -1.0 - ], - [ - 13.0, - 1.0, - -1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - }, - { - "name": "body00001_face00006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "346806f8-3946-4a48-8616-56b538605814", - "private_attribute_sub_components": [ - "body00001_face00006" - ], - "private_attribute_tag_key": "faceId", - "private_attributes": { - "bounding_box": [ - [ - 11.0, - -1.0, - 1.0 - ], - [ - 13.0, - 1.0, - 1.0 - ] - ], - "type_name": "SurfacePrivateAttributes" - } - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": { - "units": "m", - "value": 1.0 - }, - "use_geometry_AI": false, - "use_inhouse_mesher": false - }, - "reference_geometry": { - "area": { - "type_name": "number", - "units": "m**2", - "value": 1.0 - }, - "moment_center": { - "units": "m", - "value": [ - 0.0, - 0.0, - 0.0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1.0, - 1.0, - 1.0 - ] - } - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000.0, - "max_relative_change": 1.0, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_fields": [] -} diff --git a/tests/simulation/service/ref/updater_to_25_2_2.json b/tests/simulation/service/ref/updater_to_25_2_2.json deleted file mode 100644 index 1577551ff..000000000 --- a/tests/simulation/service/ref/updater_to_25_2_2.json +++ /dev/null @@ -1,705 +0,0 @@ -{ - "meshing": { - "defaults": { - "boundary_layer_growth_rate": 1.2, - "curvature_resolution_angle": { - "units": "degree", - "value": 12 - }, - "surface_edge_growth_rate": 1.2 - }, - "gap_treatment_strength": 0, - "refinement_factor": 1, - "volume_zones": [ - { - "_id": "565a2873-27f6-4459-bfe3-d39d86a79a30", - "method": "auto", - "name": "Farfield", - "type": "AutomatedFarfield" - } - ] - }, - "models": [ - { - "_id": "c470609f-54ce-4ea3-a357-47c94005728c", - "initial_condition": { - "p": "p", - "rho": "rho", - "type": "expression", - "u": "u", - "v": "v", - "w": "w" - }, - "material": { - "dynamic_viscosity": { - "effective_temperature": { - "units": "K", - "value": 110.4 - }, - "reference_temperature": { - "units": "K", - "value": 273.15 - }, - "reference_viscosity": { - "units": "Pa*s", - "value": 1.716e-05 - } - }, - "name": "air", - "type": "air" - }, - "navier_stokes_solver": { - "CFL_multiplier": 1, - "absolute_tolerance": 1e-10, - "equation_evaluation_frequency": 1, - "kappa_MUSCL": -1, - "limit_pressure_density": false, - "limit_velocity": false, - "linear_solver": { - "max_iterations": 30 - }, - "low_mach_preconditioner": false, - "low_mach_preconditioner_threshold": null, - "max_force_jac_update_physical_steps": 0, - "numerical_dissipation_factor": 1, - "order_of_accuracy": 2, - "relative_tolerance": 0, - "type_name": "Compressible", - "update_jacobian_frequency": 4 - }, - "transition_model_solver": { - "N_crit": 8.15, - "absolute_tolerance": 1e-07, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "max_force_jac_update_physical_steps": 0, - "order_of_accuracy": 2, - "relative_tolerance": 0, - "turbulence_intensity_percent": 1, - "type_name": "AmplificationFactorTransport", - "update_jacobian_frequency": 4 - }, - "turbulence_model_solver": { - "CFL_multiplier": 2, - "absolute_tolerance": 1e-08, - "equation_evaluation_frequency": 4, - "linear_solver": { - "max_iterations": 20 - }, - "max_force_jac_update_physical_steps": 0, - "modeling_constants": { - "C_DES": 0.72, - "C_d": 8 - }, - "order_of_accuracy": 2, - "quadratic_constitutive_relation": false, - "reconstruction_gradient_limiter": 0.5, - "relative_tolerance": 0, - "rotation_correction": false, - "type_name": "SpalartAllmaras", - "update_jacobian_frequency": 4 - }, - "type": "Fluid" - }, - { - "_id": "3c37e273-0785-4025-be10-c099bf03e402", - "entities": { - "stored_entities": [ - { - "_id": "body0001_face0001", - "name": "body0001_face0001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0001" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0002", - "name": "body0001_face0002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0002" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0003", - "name": "body0001_face0003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0003" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0004", - "name": "body0001_face0004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0004" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0005", - "name": "body0001_face0005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0005" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0006", - "name": "body0001_face0006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0006" - ], - "private_attribute_tag_key": "faceId" - } - ] - }, - "heat_spec": { - "type_name": "HeatFlux", - "value": { - "units": "kg/s**3", - "value": 0 - } - }, - "name": "Wall", - "type": "Wall", - "use_wall_function": false - }, - { - "_id": "bca1513a-511b-4353-b3f4-904e68373277", - "entities": { - "stored_entities": [ - { - "_id": "8ae37a4b-6970-5d88-aef5-43a1abcc845e", - "name": "farfield", - "private_attribute_entity_type_name": "GhostSurface", - "private_attribute_registry_bucket_name": "SurfaceEntityType" - } - ] - }, - "name": "Freestream1", - "type": "Freestream" - } - ], - "operating_condition": { - "alpha": { - "units": "degree", - "value": 0 - }, - "beta": { - "units": "degree", - "value": 0 - }, - "private_attribute_constructor": "default", - "thermal_state": { - "density": { - "units": "kg/m**3", - "value": 1.225 - }, - "private_attribute_constructor": "default", - "private_attribute_input_cache": { - "altitude": { - "units": "m", - "value": 0 - }, - "temperature_offset": { - "units": "K", - "value": 0 - } - }, - "temperature": { - "units": "K", - "value": 288.15 - }, - "type_name": "ThermalState" - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": { - "units": "m/s", - "value": 1 - } - }, - "outputs": [ - { - "_id": "4a34d924-294f-448e-ba22-7e8789d7d7de", - "entities": { - "stored_entities": [ - { - "_id": "body0001_face0001", - "name": "body0001_face0001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0001" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0002", - "name": "body0001_face0002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0002" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0003", - "name": "body0001_face0003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0003" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0004", - "name": "body0001_face0004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0004" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0005", - "name": "body0001_face0005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0005" - ], - "private_attribute_tag_key": "faceId" - }, - { - "_id": "body0001_face0006", - "name": "body0001_face0006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0006" - ], - "private_attribute_tag_key": "faceId" - } - ] - }, - "frequency": -1, - "frequency_offset": 0, - "name": "Surface output", - "output_fields": { - "items": [ - "Cp", - "yPlus", - "Cf", - "CfVec" - ] - }, - "output_format": "paraview", - "output_type": "SurfaceOutput", - "write_single_file": false - } - ], - "private_attribute_asset_cache": { - "project_entity_info": { - "draft_entities": [ - { - "name": "Slice", - "normal": [ - 0, - 0, - 1 - ], - "origin": { - "units": "m", - "value": [ - 1, - 1, - 1 - ] - }, - "private_attribute_entity_type_name": "Slice", - "private_attribute_id": "afea6db5-6e61-4c5c-8628-8c3ee399f0ad" - } - ], - "edge_attribute_names": [ - "edgeId" - ], - "edge_group_tag": "edgeId", - "edge_ids": [ - "body0001_edge0001", - "body0001_edge0002", - "body0001_edge0003", - "body0001_edge0004", - "body0001_edge0005", - "body0001_edge0006", - "body0001_edge0007", - "body0001_edge0008", - "body0001_edge0009", - "body0001_edge0010", - "body0001_edge0011", - "body0001_edge0012" - ], - "face_attribute_names": [ - "faceId" - ], - "face_group_tag": "faceId", - "face_ids": [ - "body0001_face0001", - "body0001_face0002", - "body0001_face0003", - "body0001_face0004", - "body0001_face0005", - "body0001_face0006" - ], - "ghost_entities": [ - { - "center": [ - 0, - 0, - 0 - ], - "max_radius": 5.000000000000003, - "name": "farfield", - "private_attribute_entity_type_name": "GhostSphere", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType" - }, - { - "center": [ - 0, - -0.010000000000000005, - 0 - ], - "max_radius": 0.10000000000000005, - "name": "symmetry-1", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType" - }, - { - "center": [ - 0, - 0.010000000000000005, - 0 - ], - "max_radius": 0.10000000000000005, - "name": "symmetry-2", - "normal_axis": [ - 0, - 1, - 0 - ], - "private_attribute_entity_type_name": "GhostCircularPlane", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType" - } - ], - "grouped_edges": [ - [ - { - "name": "body0001_edge0001", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0001" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0002", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0002" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0003", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0003" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0004", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0004" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0005", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0005" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0006", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0006" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0007", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0007" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0008", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0008" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0009", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0009" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0010", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0010" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0011", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0011" - ], - "private_attribute_tag_key": "edgeId" - }, - { - "name": "body0001_edge0012", - "private_attribute_entity_type_name": "Edge", - "private_attribute_id": null, - "private_attribute_registry_bucket_name": "EdgeEntityType", - "private_attribute_sub_components": [ - "body0001_edge0012" - ], - "private_attribute_tag_key": "edgeId" - } - ] - ], - "grouped_faces": [ - [ - { - "name": "body0001_face0001", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0001" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body0001_face0002", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0002" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body0001_face0003", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0003" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body0001_face0004", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0004" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body0001_face0005", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0005" - ], - "private_attribute_tag_key": "faceId" - }, - { - "name": "body0001_face0006", - "private_attribute_entity_type_name": "Surface", - "private_attribute_full_name": null, - "private_attribute_id": null, - "private_attribute_is_interface": null, - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_sub_components": [ - "body0001_face0006" - ], - "private_attribute_tag_key": "faceId" - } - ] - ], - "type_name": "GeometryEntityInfo" - }, - "project_length_unit": { - "units": "m", - "value": 1 - } - }, - "reference_geometry": { - "area": { - "units": "m**2", - "value": 11 - }, - "moment_center": { - "units": "m", - "value": [ - 0, - 0, - 0 - ] - }, - "moment_length": { - "units": "m", - "value": [ - 1, - 1, - 1 - ] - } - }, - "time_stepping": { - "CFL": { - "convergence_limiting_factor": 0.25, - "max": 10000, - "max_relative_change": 1, - "min": 0.1, - "type": "adaptive" - }, - "max_steps": 2000, - "order_of_accuracy": 2, - "type_name": "Steady" - }, - "unit_system": { - "name": "SI" - }, - "user_defined_dynamics": null, - "version": "25.2.2" -} diff --git a/tests/simulation/service/test_apply_simulation_setting.py b/tests/simulation/service/test_apply_simulation_setting.py deleted file mode 100644 index b3ab979e5..000000000 --- a/tests/simulation/service/test_apply_simulation_setting.py +++ /dev/null @@ -1,488 +0,0 @@ -"""Tests for apply_simulation_setting_to_entity_info service function.""" - -import copy - -import pytest - -from flow360.component.simulation import services - - -@pytest.fixture(autouse=True) -def change_test_dir(request, monkeypatch): - monkeypatch.chdir(request.fspath.dirname) - - -def _create_base_simulation_dict(entity_info_type="VolumeMeshEntityInfo", surfaces=None): - """Helper to create a base simulation dict with configurable entity info.""" - if surfaces is None: - surfaces = [] - - entity_info = { - "draft_entities": [], - "ghost_entities": [], - "type_name": entity_info_type, - } - - if entity_info_type == "VolumeMeshEntityInfo": - entity_info["zones"] = [] - entity_info["boundaries"] = surfaces - elif entity_info_type == "SurfaceMeshEntityInfo": - entity_info["boundaries"] = surfaces - elif entity_info_type == "GeometryEntityInfo": - entity_info["grouped_faces"] = [surfaces] if surfaces else [[]] - entity_info["grouped_edges"] = [[]] - entity_info["grouped_bodies"] = [[]] - entity_info["face_attribute_names"] = ["default"] - entity_info["edge_attribute_names"] = ["default"] - entity_info["body_attribute_names"] = ["default"] - entity_info["face_group_tag"] = "default" - entity_info["edge_group_tag"] = "default" - entity_info["body_group_tag"] = "default" - entity_info["body_ids"] = [] - entity_info["face_ids"] = [] - entity_info["edge_ids"] = [] - - return { - "meshing": { - "refinement_factor": 1.0, - "gap_treatment_strength": 0.2, - "defaults": { - "surface_edge_growth_rate": 1.5, - "boundary_layer_first_layer_thickness": {"value": 1, "units": "m"}, - "surface_max_edge_length": {"value": 1, "units": "m"}, - }, - "refinements": [], - "volume_zones": [], - }, - "reference_geometry": { - "moment_center": {"value": [0, 0, 0], "units": "m"}, - "moment_length": {"value": 1.0, "units": "m"}, - "area": {"value": 1.0, "units": "m**2"}, - }, - "time_stepping": { - "type_name": "Steady", - "max_steps": 10, - "CFL": {"type": "ramp", "initial": 1.5, "final": 1.5, "ramp_steps": 5}, - }, - "models": [], - "outputs": [], - "user_defined_dynamics": [], - "unit_system": {"name": "SI"}, - "version": "24.11.0", - "private_attribute_asset_cache": { - "project_length_unit": None, - "project_entity_info": entity_info, - "use_inhouse_mesher": True, - "use_geometry_AI": False, - }, - } - - -def _create_surface_entity(name, private_attribute_id=None): - """Helper to create a surface entity dict.""" - return { - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_entity_type_name": "Surface", - "name": name, - "private_attribute_id": private_attribute_id or name, - "private_attribute_is_interface": False, - "private_attribute_sub_components": [], - } - - -def _create_box_entity(name, center=None): - """Helper to create a box (draft) entity dict.""" - return { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "Box", - "type_name": "Box", - "name": name, - "center": center or {"value": [0, 0, 0], "units": "m"}, - "size": {"value": [1, 1, 1], "units": "m"}, - "axis_of_rotation": [0, 0, 1], - "angle_of_rotation": {"value": 0, "units": "degree"}, - } - - -class TestApplySimulationSettingBasic: - """Basic tests for apply_simulation_setting_to_entity_info.""" - - def test_basic_entity_replacement(self): - """Test that entities are correctly replaced when names match.""" - # Source simulation with settings and entity "wing" - source_surface = _create_surface_entity("wing", "source_wing_id") - source_dict = _create_base_simulation_dict(surfaces=[source_surface]) - source_dict["models"] = [ - { - "type": "Wall", - "entities": {"stored_entities": [_create_surface_entity("wing", "source_wing_id")]}, - "use_wall_function": False, - } - ] - - # Target simulation with different entity info (same name "wing" but different id) - target_surface = _create_surface_entity("wing", "target_wing_id") - target_dict = _create_base_simulation_dict(surfaces=[target_surface]) - - # Apply settings from source to target's entity info - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: entity in models should now reference target's entity - stored_entity = result_dict["models"][0]["entities"]["stored_entities"][0] - assert stored_entity["private_attribute_id"] == "target_wing_id" - assert stored_entity["name"] == "wing" - - # Verify: project_entity_info should be from target - boundary = result_dict["private_attribute_asset_cache"]["project_entity_info"][ - "boundaries" - ][0] - assert boundary["private_attribute_id"] == "target_wing_id" - - -class TestApplySimulationSettingUnmatchedEntity: - """Tests for unmatched entity handling.""" - - def test_unmatched_entity_generates_warning(self): - """Test that unmatched entities are skipped and generate warnings.""" - # Source has entity "wing" and "fuselage" - source_surfaces = [ - _create_surface_entity("wing", "wing_id"), - _create_surface_entity("fuselage", "fuselage_id"), - ] - source_dict = _create_base_simulation_dict(surfaces=source_surfaces) - source_dict["models"] = [ - { - "type": "Wall", - "entities": { - "stored_entities": [ - _create_surface_entity("wing", "wing_id"), - _create_surface_entity("fuselage", "fuselage_id"), - ] - }, - "use_wall_function": False, - } - ] - - # Target only has "wing", no "fuselage" - target_surfaces = [_create_surface_entity("wing", "target_wing_id")] - target_dict = _create_base_simulation_dict(surfaces=target_surfaces) - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: only "wing" should remain in stored_entities - stored = result_dict["models"][0]["entities"]["stored_entities"] - assert len(stored) == 1 - assert stored[0]["name"] == "wing" - - # Verify: warning generated for "fuselage" - entity_warnings = [w for w in warnings if w.get("type") == "entity_not_found"] - assert len(entity_warnings) == 1 - assert "fuselage" in entity_warnings[0]["msg"] - - -class TestApplySimulationSettingPreserveDraftEntities: - """Tests for draft/ghost entity preservation.""" - - def test_draft_entities_preserved_in_entity_info(self): - """Test that draft_entities from source are preserved in result.""" - # Source has a box in draft_entities - source_dict = _create_base_simulation_dict() - source_dict["private_attribute_asset_cache"]["project_entity_info"]["draft_entities"] = [ - _create_box_entity("refinement_box") - ] - - # Target has no draft entities - target_dict = _create_base_simulation_dict() - target_dict["private_attribute_asset_cache"]["project_entity_info"]["draft_entities"] = [] - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: draft_entities from source should be preserved - draft_entities = result_dict["private_attribute_asset_cache"]["project_entity_info"][ - "draft_entities" - ] - assert len(draft_entities) == 1 - assert draft_entities[0]["name"] == "refinement_box" - - def test_draft_entities_in_stored_entities_preserved(self): - """Test that draft entities in stored_entities are preserved without matching.""" - # Source with a Box entity in stored_entities (used in refinement) - source_dict = _create_base_simulation_dict() - source_dict["meshing"]["refinements"] = [ - { - "type": "UniformRefinement", - "entities": {"stored_entities": [_create_box_entity("my_box")]}, - "spacing": {"value": 0.1, "units": "m"}, - } - ] - - # Target with different entity info - target_dict = _create_base_simulation_dict() - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: Box entity should be preserved (not matched/removed) - stored = result_dict["meshing"]["refinements"][0]["entities"]["stored_entities"] - assert len(stored) == 1 - assert stored[0]["name"] == "my_box" - assert stored[0]["private_attribute_entity_type_name"] == "Box" - - # Verify: no warning for Box entity - entity_warnings = [w for w in warnings if w.get("type") == "entity_not_found"] - assert len(entity_warnings) == 0 - - -class TestApplySimulationSettingCrossEntityInfoType: - """Tests for applying settings across different entity info types.""" - - def test_volume_mesh_to_volume_mesh(self): - """Test applying settings from one VolumeMesh project to another.""" - source_surface = _create_surface_entity("inlet", "source_inlet_id") - source_dict = _create_base_simulation_dict(surfaces=[source_surface]) - source_dict["models"] = [ - { - "type": "Freestream", - "entities": { - "stored_entities": [_create_surface_entity("inlet", "source_inlet_id")] - }, - } - ] - - target_surface = _create_surface_entity("inlet", "target_inlet_id") - target_dict = _create_base_simulation_dict(surfaces=[target_surface]) - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: entity replaced with target's - stored = result_dict["models"][0]["entities"]["stored_entities"] - assert stored[0]["private_attribute_id"] == "target_inlet_id" - - def test_geometry_to_volume_mesh_no_grouping_tags(self): - """Test that grouping tags from Geometry source don't leak into VolumeMesh target.""" - # Source is GeometryEntityInfo with grouping tags - source_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "some_grouping" - - # Target is VolumeMeshEntityInfo (no grouping tags) - target_surface = _create_surface_entity("wall", "target_wall_id") - target_dict = _create_base_simulation_dict( - entity_info_type="VolumeMeshEntityInfo", surfaces=[target_surface] - ) - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: no grouping tags should be in result entity_info - result_entity_info = result_dict["private_attribute_asset_cache"]["project_entity_info"] - assert "face_group_tag" not in result_entity_info - assert "body_group_tag" not in result_entity_info - assert "edge_group_tag" not in result_entity_info - - # Verify: result type should still be VolumeMeshEntityInfo - assert result_entity_info["type_name"] == "VolumeMeshEntityInfo" - - -class TestApplySimulationSettingGroupingTags: - """Tests for grouping tag inheritance from source.""" - - def test_grouping_tags_inherited_from_source_when_available_in_target(self): - """Test that grouping tags are inherited from source when they exist in target's attribute_names.""" - # Source uses "groupA" for all groupings - source_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupA" - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "body_group_tag" - ] = "groupA" - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "edge_group_tag" - ] = "groupA" - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = ["groupA", "groupB"] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "body_attribute_names" - ] = ["groupA", "groupB"] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "edge_attribute_names" - ] = ["groupA", "groupB"] - - # Target has both groupA and groupB, but uses groupB by default - target_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupB" - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "body_group_tag" - ] = "groupB" - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "edge_group_tag" - ] = "groupB" - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = [ - "groupA", - "groupB", - ] # Target has groupA available - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "body_attribute_names" - ] = ["groupA", "groupB"] - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "edge_attribute_names" - ] = ["groupA", "groupB"] - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: grouping tags should be from source since "groupA" exists in target's attribute_names - result_entity_info = result_dict["private_attribute_asset_cache"]["project_entity_info"] - assert result_entity_info["face_group_tag"] == "groupA" - assert result_entity_info["body_group_tag"] == "groupA" - assert result_entity_info["edge_group_tag"] == "groupA" - - def test_grouping_tags_use_target_when_source_is_none(self): - """Test that target's grouping tags are used when source has None.""" - # Source with None grouping tags - source_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - source_dict["private_attribute_asset_cache"]["project_entity_info"]["face_group_tag"] = None - - # Target with specific grouping tag - target_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "target_face_grouping" - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: face_group_tag should remain from target since source is None - result_entity_info = result_dict["private_attribute_asset_cache"]["project_entity_info"] - assert result_entity_info["face_group_tag"] == "target_face_grouping" - - def test_geometry_entities_matched_with_source_grouping(self): - """Test that entities are matched using source's grouping selection.""" - # Create surfaces for two different groupings - wing_surface_group_a = _create_surface_entity("wing", "wing_group_a_id") - wing_surface_group_b = _create_surface_entity("wing", "wing_group_b_id") - - # Source uses "groupA" for face grouping - source_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - source_dict["private_attribute_asset_cache"]["project_entity_info"]["grouped_faces"] = [ - [wing_surface_group_a], # groupA surfaces - [], # groupB surfaces (empty in source) - ] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = ["groupA", "groupB"] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupA" - source_dict["models"] = [ - { - "type": "Wall", - "entities": { - "stored_entities": [_create_surface_entity("wing", "wing_group_a_id")] - }, - "use_wall_function": False, - } - ] - - # Target has surfaces in both groupings - target_wing_group_a = _create_surface_entity("wing", "target_wing_group_a_id") - target_wing_group_b = _create_surface_entity("wing", "target_wing_group_b_id") - target_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - target_dict["private_attribute_asset_cache"]["project_entity_info"]["grouped_faces"] = [ - [target_wing_group_a], # groupA surfaces - [target_wing_group_b], # groupB surfaces - ] - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = ["groupA", "groupB"] - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupB" # Target originally uses groupB - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: result should use source's grouping (groupA), so entity should match groupA's wing - stored = result_dict["models"][0]["entities"]["stored_entities"] - assert len(stored) == 1 - assert stored[0]["private_attribute_id"] == "target_wing_group_a_id" - - # Verify: face_group_tag in result should be from source - result_entity_info = result_dict["private_attribute_asset_cache"]["project_entity_info"] - assert result_entity_info["face_group_tag"] == "groupA" - - def test_source_grouping_tag_not_in_target_falls_back_to_target_tag(self): - """Test that when source's grouping tag doesn't exist in target, target's tag is used.""" - # Source uses "groupA" which target doesn't have - source_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - source_dict["private_attribute_asset_cache"]["project_entity_info"]["grouped_faces"] = [ - [_create_surface_entity("wing", "source_wing_id")], - ] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = ["groupA"] - source_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupA" - source_dict["models"] = [ - { - "type": "Wall", - "entities": {"stored_entities": [_create_surface_entity("wing", "source_wing_id")]}, - "use_wall_function": False, - } - ] - - # Target only has "groupB" (no "groupA") - target_dict = _create_base_simulation_dict(entity_info_type="GeometryEntityInfo") - target_dict["private_attribute_asset_cache"]["project_entity_info"]["grouped_faces"] = [ - [_create_surface_entity("wing", "target_wing_id")], - ] - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_attribute_names" - ] = ["groupB"] - target_dict["private_attribute_asset_cache"]["project_entity_info"][ - "face_group_tag" - ] = "groupB" - - result_dict, errors, warnings = services.apply_simulation_setting_to_entity_info( - simulation_setting_dict=copy.deepcopy(source_dict), - entity_info_dict=copy.deepcopy(target_dict), - ) - - # Verify: face_group_tag should fall back to target's "groupB" since "groupA" doesn't exist - result_entity_info = result_dict["private_attribute_asset_cache"]["project_entity_info"] - assert result_entity_info["face_group_tag"] == "groupB" - - # Verify: entity should still be matched using target's grouping - stored = result_dict["models"][0]["entities"]["stored_entities"] - assert len(stored) == 1 - assert stored[0]["private_attribute_id"] == "target_wing_id" diff --git a/tests/simulation/service/test_services_v2.py b/tests/simulation/service/test_services_v2.py index ab95072af..9ac9780ab 100644 --- a/tests/simulation/service/test_services_v2.py +++ b/tests/simulation/service/test_services_v2.py @@ -4,954 +4,22 @@ from typing import get_args import pytest -from flow360_schema.framework.expression import UserVariable from unyt import Unit import flow360.component.simulation.units as u from flow360.component.simulation import services -from flow360.component.simulation.entity_info import GeometryEntityInfo from flow360.component.simulation.exposed_units import supported_units_by_front_end from flow360.component.simulation.framework.updater_utils import compare_values from flow360.component.simulation.services_report import get_default_report_config from flow360.component.simulation.unit_system import DimensionedTypes from flow360.component.simulation.validation.validation_context import ( CASE, - SURFACE_MESH, - VOLUME_MESH, - get_validation_info, ) from flow360.version import __version__ -from tests.utils import compare_dict_to_ref - - @pytest.fixture(autouse=True) def change_test_dir(request, monkeypatch): monkeypatch.chdir(request.fspath.dirname) - -def test_validate_service(): - - params_data_from_vm = { - "meshing": { - "refinement_factor": 1.0, - "gap_treatment_strength": 0.2, - "defaults": {"surface_edge_growth_rate": 1.5}, - "refinements": [], - "volume_zones": [ - { - "method": "auto", - "type": "AutomatedFarfield", - "private_attribute_entity": { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "GenericVolume", - "name": "automated_farfield_entity", - "private_attribute_zone_boundary_names": {"items": []}, - }, - "_id": "137854c4-dea1-47a4-b352-b545ffb0b85c", - } - ], - }, - "reference_geometry": { - "moment_center": {"value": [0, 0, 0], "units": "m"}, - "moment_length": {"value": 1.0, "units": "m"}, - "area": {"value": 1.0, "units": "m**2"}, - }, - "time_stepping": { - "type_name": "Steady", - "max_steps": 10, - "CFL": {"type": "ramp", "initial": 1.5, "final": 1.5, "ramp_steps": 5}, - }, - "models": [ - { - "_id": "09435427-c2dd-4535-935c-b131ab7d1a5b", - "type": "Wall", - "entities": { - "stored_entities": [ - { - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_entity_type_name": "Surface", - "name": "Mysurface", - "private_attribute_is_interface": False, - "private_attribute_sub_components": [], - "_id": "Mysurface", - } - ] - }, - "use_wall_function": False, - } - ], - "user_defined_dynamics": [], - "unit_system": {"name": "SI"}, - "private_attribute_asset_cache": { - "project_length_unit": None, - "project_entity_info": { - "draft_entities": [], - "type_name": "VolumeMeshEntityInfo", - "zones": [], - "boundaries": [ - { - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_entity_type_name": "Surface", - "name": "Mysurface", - "private_attribute_full_name": None, - "private_attribute_is_interface": False, - "private_attribute_tag_key": None, - "private_attribute_sub_components": [], - "_id": "Mysurface", - } - ], - }, - }, - } - - params_data_from_geo = params_data_from_vm - params_data_from_geo["meshing"]["defaults"] = { - "surface_edge_growth_rate": 1.5, - "boundary_layer_first_layer_thickness": {"value": 1, "units": "m"}, - "surface_max_edge_length": {"value": 1, "units": "m"}, - } - params_data_from_geo["version"] = "24.11.0" - - params_data_op_from_mach_reynolds = params_data_from_vm.copy() - params_data_op_from_mach_reynolds["private_attribute_asset_cache"]["project_length_unit"] = { - "value": 0.8059, - "units": "m", - } - params_data_op_from_mach_reynolds["operating_condition"] = { - "type_name": "AerospaceCondition", - "private_attribute_constructor": "from_mach_reynolds", - "private_attribute_input_cache": { - "mach": 0.84, - "reynolds_mesh_unit": 10.0, - "alpha": {"value": 3.06, "units": "degree"}, - "beta": {"value": 0.0, "units": "degree"}, - "temperature": {"value": 288.15, "units": "K"}, - }, - "alpha": {"value": 3.06, "units": "degree"}, - "beta": {"value": 0.0, "units": "degree"}, - "velocity_magnitude": { - "type_name": "number", - "value": 285.84696487889875, - "units": "m/s", - }, - "thermal_state": { - "type_name": "ThermalState", - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "temperature": {"value": 288.15, "units": "K"}, - "density": {"value": 7.767260032496146e-07, "units": "Pa*s**2/m**2"}, - "material": { - "type": "air", - "name": "air", - "dynamic_viscosity": { - "reference_viscosity": {"value": 1.716e-05, "units": "Pa*s"}, - "reference_temperature": {"value": 273.15, "units": "K"}, - "effective_temperature": {"value": 110.4, "units": "K"}, - }, - }, - }, - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data_from_geo, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - - assert errors is None - - _, errors, _ = services.validate_model( - params_as_dict=params_data_from_vm, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level=CASE, - ) - - assert errors is None - - _, errors, _ = services.validate_model( - params_as_dict=params_data_op_from_mach_reynolds, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level=CASE, - ) - - assert errors is None - - -def test_validate_error(): - params_data = { - "meshing": { - "farfield": "invalid", - "refinement_factor": 1.0, - "gap_treatment_strength": 0.2, - "defaults": {"surface_edge_growth_rate": 1.5}, - "refinements": [], - "volume_zones": [ - { - "method": "auto", - "type": "AutomatedFarfield", - "private_attribute_entity": { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "GenericVolume", - "name": "automated_farfield_entity", - "private_attribute_zone_boundary_names": {"items": []}, - }, - } - ], - }, - "reference_geometry": { - "moment_center": {"value": [0, 0, 0], "units": "m"}, - "moment_length": {"value": 1.0, "units": "m"}, - "area": {"value": 1.0, "units": "m**2", "type_name": "number"}, - }, - "time_stepping": { - "type_name": "Steady", - "max_steps": 10, - "CFL": {"type": "ramp", "initial": 1.5, "final": 1.5, "ramp_steps": 5}, - }, - "user_defined_dynamics": [], - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - - expected_errors = [ - { - "loc": ("meshing", "defaults", "boundary_layer_first_layer_thickness"), - "type": "missing", - "ctx": {"relevant_for": ["VolumeMesh"]}, - }, - { - "loc": ("meshing", "defaults", "surface_max_edge_length"), - "type": "missing", - "ctx": {"relevant_for": ["SurfaceMesh"]}, - }, - { - "loc": ("meshing", "farfield"), - "type": "extra_forbidden", - "ctx": {"relevant_for": ["SurfaceMesh", "VolumeMesh"]}, - }, - ] - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["ctx"]["relevant_for"] == exp_err["ctx"]["relevant_for"] - - -def test_validate_multiple_errors(): - params_data = { - "meshing": { - "farfield": "invalid", - "refinement_factor": 1.0, - "gap_treatment_strength": 0.2, - "defaults": { - "surface_edge_growth_rate": 1.5, - "boundary_layer_first_layer_thickness": {"value": 1, "units": "m"}, - "surface_max_edge_length": {"value": 1, "units": "s"}, - }, - "refinements": [], - "volume_zones": [ - { - "method": "auto", - "type": "AutomatedFarfield", - "private_attribute_entity": { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "GenericVolume", - "name": "automated_farfield_entity", - "private_attribute_zone_boundary_names": {"items": []}, - }, - } - ], - }, - "reference_geometry": { - "moment_center": {"value": [0, 0, 0], "units": "m"}, - "moment_length": {"value": 1.0, "units": "m"}, - "area": {"value": -10.0, "units": "m**2"}, - }, - "time_stepping": { - "type_name": "Steady", - "max_steps": 10, - "CFL": {"type": "ramp", "initial": 1.5, "final": 1.5, "ramp_steps": 5}, - }, - "user_defined_dynamics": [], - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - - expected_errors = [ - { - "loc": ("meshing", "defaults", "surface_max_edge_length"), - "type": "value_error", - "ctx": {"relevant_for": ["SurfaceMesh"]}, - }, - { - "loc": ("meshing", "farfield"), - "type": "extra_forbidden", - "ctx": {"relevant_for": ["SurfaceMesh", "VolumeMesh"]}, - }, - { - "loc": ("reference_geometry", "area", "value"), - "type": "value_error", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["ctx"]["relevant_for"] == exp_err["ctx"]["relevant_for"] - - -def test_validate_error_from_initialize_variable_space(): - with open("../translator/data/simulation_isosurface.json", "r") as fp: - param_dict = json.load(fp) - - UserVariable(name="my_time_stepping_var", value=0.6 * u.s) - _, errors, _ = services.validate_model( - params_as_dict=param_dict, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - expected_errors = [ - { - "type": "value_error", - "loc": ["unknown"], - "msg": "Loading user variable 'my_time_stepping_var' from simulation.json " - "which is already defined in local context. Please change your local user variable definition.", - } - ] - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["msg"] == exp_err["msg"] - - services.clear_context() - _ = UserVariable(name="my_time_stepping_var", value=0.6 * u.s) - _, errors, _ = services.validate_model( - params_as_dict=param_dict, - validated_by=services.ValidationCalledBy.SERVICE, - root_item_type="VolumeMesh", - ) - assert errors is None - - -def test_validate_error_from_multi_constructor(): - - def _compare_validation_errors(err, exp_err): - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - for key in exp_err.keys(): - assert err[key] == exp_err[key] - - # test from_mach() with two validation errors within private_attribute_input_cache - params_data = { - "operating_condition": { - "private_attribute_constructor": "from_mach", - "type_name": "AerospaceCondition", - "private_attribute_input_cache": { - "mach": -1, - "alpha": {"value": 0, "units": "degree"}, - "beta": {"value": 0, "units": "degree"}, - "thermal_state": { - "type_name": "ThermalState", - "private_attribute_constructor": "default", - "density": {"value": -2, "units": "kg/m**3"}, - "temperature": {"value": 288.15, "units": "K"}, - }, - }, - }, - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - - expected_errors = [ - { - "loc": ("operating_condition", "private_attribute_input_cache", "mach"), - "type": "greater_than_equal", - "msg": "Input should be greater than or equal to 0", - "input": -1, - "ctx": {"ge": "0.0"}, - }, - { - "loc": ( - "operating_condition", - "private_attribute_input_cache", - "thermal_state", - "density", - ), - "type": "value_error", - "msg": "Value error, Value must be positive (>0), got -2.0", - }, - ] - _compare_validation_errors(errors, expected_errors) - - # test BETDisk.from_dfdc() with: - # 1. one validation error within private_attribute_input_cache - # 2. a missing BETDiskCache argument for the dfdc constructor - # 3. one validation error outside the input_cache - params_data = { - "models": [ - { - "name": "BET disk", - "private_attribute_constructor": "from_dfdc", - "private_attribute_input_cache": { - "angle_unit": {"units": "degree", "value": 1.0}, - "blade_line_chord": {"units": "m", "value": 5.0}, - "chord_ref": {"units": "m", "value": -14.0}, - "entities": { - "stored_entities": [ - { - "axis": [0.0, 0.0, 1.0], - "center": {"units": "m", "value": [0.0, 0.0, 0.0]}, - "height": {"units": "m", "value": -15.0}, - "inner_radius": {"units": "m", "value": 0.0}, - "name": "BET_cylinder", - "outer_radius": {"units": "m", "value": 3.81}, - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_full_name": None, - "private_attribute_id": "ca0d3a3f-49cb-4637-a789-744c643ce955", - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": {"items": []}, - } - ] - }, - "file": { - "content": "DFDC Version 0.70E+03\nvb block 1 c 25 HP SLS\n\nOPER\n! Vinf Vref RPM1\n 0.000 10.000 15.0\n! Rho Vso Rmu Alt\n 1.0 342.0 0.17791E-04 0.30000E-01\n! XDwake Nwake\n 1.0000 20\n! Lwkrlx\n F\nENDOPER\n\nAERO\n! #sections\n 5\n! Xisection\n 0.09\n ! A0deg dCLdA CLmax CLmin\n -6.5 4.000 1.2500 -0.0000\n ! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n ! CDmin CLCDmin dCDdCL^2\n 0.075000E-01 0.00000 0.40000E-02\n ! REref REexp\n 0.30000E+06 -0.70000\n 0.17\n ! A0deg dCLdA CLmax CLmin\n -6.0 6.0 1.300 -0.55000\n ! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n ! CDmin CLCDmin dCDdCL^2\n 0.075000E-01 0.10000 0.40000E-02\n ! REref REexp\n 0.30000E+06 -0.70000\n 0.51\n ! A0deg dCLdA CLmax CLmin\n -1.0 6.00 1.400 -1.4000\n ! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n ! CDmin CLCDmin dCDdCL^2\n 0.05000E-01 0.10000 0.40000E-02\n ! REref REexp\n 0.30000E+06 -0.70000\n 0.8\n ! A0deg dCLdA CLmax CLmin\n -1.0 6.0 1.600 -1.500\n ! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n ! CDmin CLCDmin dCDdCL^2\n 0.03000E-01 0.10000 0.40000E-02\n ! REref REexp\n 0.30000E+06 -0.70000\n 1.0\n ! A0deg dCLdA CLmax CLmin\n -1 6.0 1.0 -1.8000\n ! dCLdAstall dCLstall Cmconst Mcrit\n 0.10000 0.10000 -0.10000 0.75000\n ! CDmin CLCDmin dCDdCL^2\n 0.04000E-01 0.10000 0.40000E-02\n ! REref REexp\n 0.30000E+06 -0.70000\nENDAERO\n\nROTOR\n! Xdisk Nblds NRsta\n 150 3 63\n! #stations\n 63\n! r C Beta0deg\n0.087645023\t0.432162215\t33.27048712\n0.149032825\t0.432162215\t32.37853609\n0.230063394\t0.432162215\t31.42712165\n0.31845882\t0.432162215\t30.65409742\n0.354421836\t0.432162215\t30.13214089\n0.412445831\t0.432162215\t29.41523066\n0.465733177\t0.425230275\t28.75567325\n0.535598785\t0.418298338\t27.89538097\n0.607834576\t0.411366397\t26.69097178\n0.657570537\t0.404434457\t25.88803232\n0.695464717\t0.39750252\t25.25715132\n0.733359236\t0.390570579\t24.5689175\n0.773621567\t0.383638638\t23.93803649\n0.818620882\t0.376706702\t23.19244985\n0.86598886\t0.369774761\t22.36083398\n0.912171916\t0.36284282\t21.67260016\n0.958355818\t0.355910895\t20.84098429\n1.008092457\t0.355906578\t19.92333919\n1.051908539\t0.355902261\t19.03437051\n1.090987133\t0.355897941\t18.34613668\n1.134803219\t0.355893624\t17.457168\n1.17980135\t0.355889307\t16.91231622\n1.229536976\t0.355884987\t16.16672958\n1.275719693\t0.35588067\t15.53584858\n1.314797781\t0.355876353\t14.93364398\n1.358613021\t0.355872033\t14.18805734\n1.398875352\t0.355867716\t13.55717634\n1.42966541\t0.355863399\t12.86894251\n1.468744004\t0.355859079\t12.18070869\n1.51019075\t0.355854762\t11.49247487\n1.549268331\t0.355850445\t10.9762995\n1.596633604\t0.355846125\t10.60350618\n1.6629458\t0.355841808\t9.94394877\n1.717417226\t0.355837491\t9.28439136\n1.773072894\t0.355833171\t8.59615753\n1.81688746\t0.355828854\t7.96527653\n1.866622407\t0.355824537\t7.33439553\n1.893858878\t0.355820217\t6.87557298\n1.949512352\t0.3558159\t6.56013248\n2.015823535\t0.355811583\t6.07263352\n2.07503076\t0.355807263\t5.49910533\n2.124764355\t0.355802946\t5.0976356\n2.169761643\t0.355798629\t4.69616587\n2.231337023\t0.355794309\t4.12263769\n2.273965822\t0.355789992\t3.77852078\n2.321330759\t0.355785675\t3.46308028\n2.395930475\t0.355781355\t2.97558132\n2.533289143\t0.355777038\t2.0005834\n2.61499265\t0.355772721\t1.62779008\n2.664726078\t0.355768401\t1.25499676\n2.709722688\t0.355764084\t0.96823267\n2.768929239\t0.355759767\t0.50941012\n2.839977235\t0.355755447\t-0.064118065\n2.906288246\t0.35575113\t-0.522940614\n3.03772619\t0.355746813\t-1.44058571\n3.208240195\t0.355742493\t-2.61631849\n3.342045113\t0.355738176\t-3.333228722\n3.481771091\t0.355733859\t-4.164844591\n3.56702767\t0.355729539\t-4.681019957\n3.647547098\t0.355725222\t-5.053813278\n3.725699048\t0.355720905\t-5.541312235\n3.770695491\t0.355716585\t-5.799399919\n3.81\t0.355714554\t-6.1\nENDROTOR\n\nGEOM\n /IGNORED BELOW THIS POINT\n", - "file_path": "aba", - "type_name": "DFDCFile", - }, - "initial_blade_direction": [1.0, 0.0, 0.0], - "length_unit": {"units": "m", "value": 1.0}, - "omega": {"units": "degree/s", "value": 0.0046}, - "rotation_direction_rule": "leftHand", - "number_of_blades": 2, - }, - "type": "BETDisk", - "type_name": "BETDisk", - }, - { - "entities": {"stored_entities": []}, - "heat_spec": {"type_name": "HeatFlux", "value": {"units": "W/m**2", "value": 0.0}}, - "name": "Wall", - "roughness_height": {"units": "m", "value": -10.0}, - "type": "Wall", - "use_wall_function": False, - "velocity": None, - }, - ], - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - - expected_errors = [ - { - "loc": ("models", 0, "private_attribute_input_cache", "chord_ref"), - "type": "value_error", - "msg": "Value error, Value must be positive (>0), got -14.0", - }, - { - "type": "missing_argument", - "loc": ("models", 0, "private_attribute_input_cache", "n_loading_nodes"), - "msg": "Missing required argument", - "ctx": {}, - }, - { - "loc": ( - "models", - 0, - "private_attribute_input_cache", - "entities", - "stored_entities", - 0, - "height", - ), - "type": "value_error", - "msg": "Value error, Value must be positive (>0), got -15.0", - }, - ] - - _compare_validation_errors(errors, expected_errors) - - # test Box.from_principal_axes() with one validation error within private_attribute_input_cache - # the multiconstructor call is within a default constructor call - params_data = { - "models": [ - { - "darcy_coefficient": {"units": "m**(-2)", "value": [1000000.0, 0.0, 0.0]}, - "entities": { - "stored_entities": [ - { - "angle_of_rotation": {"units": "rad", "value": -2.0943951023931953}, - "axis_of_rotation": [ - -0.5773502691896257, - -0.5773502691896257, - -0.5773502691896261, - ], - "center": {"units": "m", "value": [0, 0, 0]}, - "name": "porous_zone", - "private_attribute_constructor": "from_principal_axes", - "private_attribute_entity_type_name": "Box", - "private_attribute_full_name": None, - "private_attribute_id": "69751367-210b-4df3-b4cd-1f2adbd866ed", - "private_attribute_input_cache": { - "axes": [[0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], - "center": {"units": "m", "value": [0, 0, 0]}, - "name": "porous_zone", - "size": {"units": "m", "value": [0.2, 0.3, -2.0]}, - }, - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_zone_boundary_names": {"items": []}, - "size": {"units": "m", "value": [0.2, 0.3, 2.0]}, - "type_name": "Box", - } - ] - }, - "forchheimer_coefficient": {"units": "1/m", "value": [1, 0, 0]}, - "name": "Porous medium", - "type": "PorousMedium", - "volumetric_heat_source": {"units": "W/m**3", "value": 1.0}, - } - ], - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - expected_errors = [ - { - "type": "value_error", - "loc": ( - "models", - 0, - "entities", - "stored_entities", - 0, - "private_attribute_input_cache", - "size", - ), - "msg": "Value error, All vector components must be positive (>0), got -2.0", - } - ] - _compare_validation_errors(errors, expected_errors) - - # test ThermalState.from_standard_atmosphere() with one validation error within private_attribute_input_cache - # the multiconstructor call is nested in another multiconstructor call - params_data = { - "operating_condition": { - "alpha": {"units": "degree", "value": 0.0}, - "beta": {"units": "degree", "value": 0.0}, - "private_attribute_constructor": "from_mach", - "private_attribute_input_cache": { - "alpha": {"units": "degree", "value": 0.0}, - "beta": {"units": "degree", "value": 0.0}, - "mach": -1, - "reference_mach": None, - "thermal_state": { - "density": {"units": "kg/m**3", "value": 1.1724995324950298}, - "material": { - "dynamic_viscosity": { - "effective_temperature": {"units": "K", "value": 110.4}, - "reference_temperature": {"units": "K", "value": 273.15}, - "reference_viscosity": {"units": "Pa*s", "value": 1.716e-05}, - }, - "name": "air", - "type": "air", - }, - "private_attribute_constructor": "from_standard_atmosphere", - "private_attribute_input_cache": { - "altitude": {"units": "m", "value": 100.0}, - "temperature_offset": {"units": "K", "value": 10.0}, - }, - "temperature": {"units": "K", "value": 297.5000102251644}, - "type_name": "ThermalState", - }, - }, - "reference_velocity_magnitude": None, - "thermal_state": { - "density": {"units": "kg/m**3", "value": 1.1724995324950298}, - "material": { - "dynamic_viscosity": { - "effective_temperature": {"units": "K", "value": 110.4}, - "reference_temperature": {"units": "K", "value": 273.15}, - "reference_viscosity": {"units": "Pa*s", "value": 1.716e-05}, - }, - "name": "air", - "type": "air", - }, - "private_attribute_constructor": "from_standard_atmosphere", - "private_attribute_input_cache": { - "altitude": {"units": "K", "value": 100.0}, - "temperature_offset": {"units": "K", "value": 10.0}, - }, - "temperature": {"units": "K", "value": 297.5000102251644}, - "type_name": "ThermalState", - }, - "type_name": "AerospaceCondition", - "velocity_magnitude": {"units": "m/s", "value": 34.57709313392731}, - }, - "unit_system": {"name": "SI"}, - "version": "24.11.5", - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - - expected_errors = [ - { - "type": "value_error", - "loc": ( - "operating_condition", - "thermal_state", - "private_attribute_input_cache", - "altitude", - ), - "msg": "Value error, Dimension mismatch: expected length (meter), got (temperature)", - "input": {"units": "K", "value": 100.0}, - "ctx": {"error": "Dimension mismatch: expected length (meter), got (temperature)"}, - } - ] - _compare_validation_errors(errors, expected_errors) - - -def test_init(): - def remove_model_and_output_id_in_default_dict(data): - data["outputs"][0].pop("private_attribute_id", None) - data["models"][0].pop("private_attribute_id", None) - data["models"][1].pop("private_attribute_id", None) - - ##1: test default values for geometry starting point - data = services.get_default_params( - unit_system_name="SI", length_unit="m", root_item_type="Geometry" - ) - assert data["operating_condition"]["alpha"] == 0 - assert "velocity_magnitude" not in data["operating_condition"].keys() - remove_model_and_output_id_in_default_dict(data) - # to convert tuples to lists: - data = json.loads(json.dumps(data)) - - compare_dict_to_ref(data, "../../ref/simulation/service_init_geometry.json") - - ##2: test default values for volume mesh starting point - data = services.get_default_params( - unit_system_name="SI", length_unit="m", root_item_type="VolumeMesh" - ) - assert "meshing" not in data - remove_model_and_output_id_in_default_dict(data) - # to convert tuples to lists: - data = json.loads(json.dumps(data)) - compare_dict_to_ref(data, "../../ref/simulation/service_init_volume_mesh.json") - - ##3: test default values for surface mesh starting point - data = services.get_default_params( - unit_system_name="SI", length_unit="cm", root_item_type="SurfaceMesh" - ) - assert data["reference_geometry"]["area"]["units"] == "cm**2" - # New schema types serialize moment_center/moment_length as bare SI values - assert data["reference_geometry"]["moment_center"] == [0.0, 0.0, 0.0] - assert data["reference_geometry"]["moment_length"] == [0.01, 0.01, 0.01] - assert data["private_attribute_asset_cache"]["project_length_unit"] == 0.01 - - # roughness_height now serializes as bare SI float (new dimension types) - assert data["models"][0]["roughness_height"] == 0.0 - remove_model_and_output_id_in_default_dict(data) - # to convert tuples to lists: - data = json.loads(json.dumps(data)) - compare_dict_to_ref(data, "../../ref/simulation/service_init_surface_mesh.json") - - -def test_validate_init_data_errors(): - - data = services.get_default_params( - unit_system_name="SI", length_unit="m", root_item_type="Geometry" - ) - _, errors, _ = services.validate_model( - params_as_dict=data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - - expected_errors = [ - { - "loc": ("meshing", "defaults", "boundary_layer_first_layer_thickness"), - "type": "missing", - "ctx": {"relevant_for": ["VolumeMesh"]}, - }, - { - "loc": ("meshing", "defaults", "surface_max_edge_length"), - "type": "missing", - "ctx": {"relevant_for": ["SurfaceMesh"]}, - }, - { - "loc": ("operating_condition", "velocity_magnitude"), - "type": "missing", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["ctx"]["relevant_for"] == exp_err["ctx"]["relevant_for"] - - -def test_validate_init_data_for_sm_and_vm_errors(): - - data = services.get_default_params( - unit_system_name="SI", length_unit="m", root_item_type="Geometry" - ) - _, errors, _ = services.validate_model( - params_as_dict=data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - validation_level=[SURFACE_MESH, VOLUME_MESH], - ) - - expected_errors = [ - { - "loc": ("meshing", "defaults", "boundary_layer_first_layer_thickness"), - "type": "missing", - "ctx": {"relevant_for": ["VolumeMesh"]}, - }, - { - "loc": ("meshing", "defaults", "surface_max_edge_length"), - "type": "missing", - "ctx": {"relevant_for": ["SurfaceMesh"]}, - }, - ] - - assert len(errors) == len(expected_errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["ctx"]["relevant_for"] == exp_err["ctx"]["relevant_for"] - - -def test_validate_init_data_vm_workflow_errors(): - - data = services.get_default_params( - unit_system_name="SI", length_unit="m", root_item_type="VolumeMesh" - ) - _, errors, _ = services.validate_model( - params_as_dict=data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - validation_level=CASE, - ) - - expected_errors = [ - { - "loc": ("operating_condition", "velocity_magnitude"), - "type": "missing", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "loc": ("models", 0, "entities"), - "type": "value_error", - "ctx": {"relevant_for": ["Case"]}, - }, - { - "loc": ("models", 1, "entities"), - "type": "value_error", - "ctx": {"relevant_for": ["Case"]}, - }, - ] - - assert len(errors) == len(expected_errors), print(">>> errors:", errors) - for err, exp_err in zip(errors, expected_errors): - assert err["loc"] == exp_err["loc"] - assert err["type"] == exp_err["type"] - assert err["ctx"]["relevant_for"] == exp_err["ctx"]["relevant_for"] - - -def test_front_end_JSON_with_multi_constructor(): - params_data = { - "meshing": { - "defaults": { - "boundary_layer_first_layer_thickness": {"value": 1, "units": "m"}, - "surface_max_edge_length": {"value": 1, "units": "m"}, - }, - "refinement_factor": 1.45, - "refinements": [ - { - "entities": { - "stored_entities": [ - { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "Box", - "private_attribute_id": "hardcoded_id-1", - "name": "my_box_default", - "private_attribute_zone_boundary_names": {"items": []}, - "type_name": "Box", - "private_attribute_constructor": "default", - "private_attribute_input_cache": {}, - "center": {"value": [1.0, 2.0, 3.0], "units": "m"}, - "size": {"value": [2.0, 2.0, 3.0], "units": "m"}, - "axis_of_rotation": [1.0, 0.0, 0.0], - "angle_of_rotation": {"value": 20.0, "units": "degree"}, - }, - { - "type_name": "Box", - "private_attribute_id": "hardcoded_id-2", - "private_attribute_constructor": "from_principal_axes", - "private_attribute_input_cache": { - "axes": [[0.6, 0.8, 0.0], [0.8, -0.6, 0.0]], - "center": {"value": [7.0, 1.0, 2.0], "units": "m"}, - "size": {"value": [2.0, 2.0, 3.0], "units": "m"}, - "name": "my_box_from", - }, - }, - { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "Cylinder", - "private_attribute_id": "hardcoded_id-3", - "name": "my_cylinder_default", - "private_attribute_zone_boundary_names": {"items": []}, - "axis": [0.0, 1.0, 0.0], - "center": {"value": [1.0, 2.0, 3.0], "units": "m"}, - "height": {"value": 3.0, "units": "m"}, - "outer_radius": {"value": 2.0, "units": "m"}, - }, - ] - }, - "refinement_type": "UniformRefinement", - "spacing": {"units": "cm", "value": 7.5}, - } - ], - "volume_zones": [ - { - "method": "auto", - "type": "AutomatedFarfield", - "private_attribute_entity": { - "private_attribute_registry_bucket_name": "VolumetricEntityType", - "private_attribute_entity_type_name": "GenericVolume", - "private_attribute_id": "hardcoded_id-4", - "name": "automated_farfield_entity", - "private_attribute_zone_boundary_names": {"items": []}, - }, - } - ], - }, - "unit_system": {"name": "SI"}, - "version": "24.2.0", - "private_attribute_asset_cache": { - "project_length_unit": 1.0, - "project_entity_info": { - "type_name": "GeometryEntityInfo", - "face_ids": ["face_x_1", "face_x_2", "face_x_3"], - "face_group_tag": "some_tag", - "face_attribute_names": ["some_tag"], - "grouped_faces": [ - [ - { - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_entity_type_name": "Surface", - "name": "surface_x", - "private_attribute_is_interface": False, - "private_attribute_sub_components": [ - "face_x_1", - "face_x_2", - "face_x_3", - ], - } - ] - ], - }, - }, - "models": [ - { - "type": "Wall", - "entities": { - "stored_entities": [ - { - "private_attribute_registry_bucket_name": "SurfaceEntityType", - "private_attribute_entity_type_name": "Surface", - "name": "surface_x", - "private_attribute_is_interface": False, - "private_attribute_sub_components": [ - "face_x_1", - "face_x_2", - "face_x_3", - ], - } - ] - }, - "use_wall_function": False, - "private_attribute_id": "wall1", - } - ], - "operating_condition": { - "type_name": "AerospaceCondition", - "private_attribute_constructor": "from_mach", - "private_attribute_input_cache": { - "alpha": {"value": 5.0, "units": "degree"}, - "beta": {"value": 0.0, "units": "degree"}, - "thermal_state": { - "type_name": "ThermalState", - "private_attribute_constructor": "from_standard_atmosphere", - "private_attribute_input_cache": { - "altitude": {"value": 1000.0, "units": "m"}, - "temperature_offset": {"value": 0.0, "units": "K"}, - }, - }, - "mach": 0.8, - }, - }, - } - - simulation_param, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="Geometry", - ) - assert errors is None - with open("../../ref/simulation/simulation_json_with_multi_constructor_used.json", "r") as f: - ref_data = json.load(f) - ref_param, err, _ = services.validate_model( - params_as_dict=ref_data, - root_item_type="Geometry", - validated_by=services.ValidationCalledBy.LOCAL, - ) - assert err is None - - param_dict = simulation_param.model_dump(exclude_none=True) - ref_param_dict = ref_param.model_dump(exclude_none=True) - assert compare_values(ref_param_dict, param_dict) - - def test_generate_process_json(): params_data = { "meshing": { @@ -1139,38 +207,6 @@ def test_generate_process_json_skips_case_validation_for_meshing(): assert res2 is None assert res3 is None - -def test_default_validation_contest(): - "Ensure that the default validation context is None which is the escaper for many validators" - assert get_validation_info() is None - - -def test_validation_level_intersection(): - def get_validation_levels_to_use(root_item_type, requested_levels): - available_levels = services._determine_validation_level( - up_to="Case", root_item_type=root_item_type - ) - return services._intersect_validation_levels(requested_levels, available_levels) - - assert get_validation_levels_to_use("Geometry", "All") == ["SurfaceMesh", "VolumeMesh", "Case"] - - assert get_validation_levels_to_use("SurfaceMesh", "All") == ["VolumeMesh", "Case"] - - assert get_validation_levels_to_use("VolumeMesh", "All") == [ - "Case", - ] - - assert get_validation_levels_to_use("SurfaceMesh", ["Case", "VolumeMesh", "SurfaceMesh"]) == [ - "Case", - "VolumeMesh", - ] - - # When validation_level=None, all context-aware validators should be skipped - assert get_validation_levels_to_use("Geometry", None) == [] - assert get_validation_levels_to_use("SurfaceMesh", None) == [] - assert get_validation_levels_to_use("VolumeMesh", None) == [] - - def test_forward_compatibility_error(): from flow360.version import __version__ @@ -1371,30 +407,6 @@ def test_unchanged_BETDisk_length_unit(): } -def test_updater_service(): - with open("data/updater_should_pass.json", "r") as fp: - dict_to_update = json.load(fp) - updated_params_as_dict, errors = services.update_simulation_json( - params_as_dict=dict_to_update, target_python_api_version="25.2.2" - ) - - with open("ref/updater_to_25_2_2.json", "r") as fp: - ref_dict = json.load(fp) - assert compare_values(updated_params_as_dict, ref_dict) - assert not errors - - # ============# - dict_to_update["version"] = "999.999.999" - updated_params_as_dict, errors = services.update_simulation_json( - params_as_dict=dict_to_update, target_python_api_version="25.2.2" - ) - assert len(errors) == 1 - assert ( - errors[0] - == "[Internal] API misuse. Input version (999.999.999) is higher than requested target version (25.2.2)." - ) - - def test_unit_conversion_front_end_compatibility(): ##### 1. Ensure that the units are valid in `supported_units_by_front_end` @@ -1435,320 +447,6 @@ def test_get_default_report_config_json(): ref_dict = json.load(fp) assert compare_values(report_config_dict, ref_dict, ignore_keys=["formatter"]) - -def test_merge_geometry_entity_info(): - """ - Test the merge_geometry_entity_info function to ensure proper merging of geometry entity information. - - Test scenarios: - 1. Merge root geometry with one dependency geometry, should preserve mesh_exterior and name settings - of geometryBodyGroup in root geometry. - 2. Start from result of (1), replace the dependency with another dependency geometry, should check: - a. the preservation of mesh_exterior and name settings of geometryBodyGroup in new_draft_param_as_dict - b. the new dependency geometry should have replaced the old dependency geometry in the new_draft_param_as_dict - """ - import copy - - def check_setting_preserved( - result_entity_info: GeometryEntityInfo, - reference_entity_infos: list[GeometryEntityInfo], - entity_type: str, - setting_name: str, - ): - """ - Check that a specific setting is preserved from reference entity infos. - - Args: - result_entity_info: The merged entity info to verify - reference_entity_infos: List of reference entity infos to check against - entity_type: Either "body" or "face" - setting_name: The setting to check (e.g., "mesh_exterior", "name") - """ - if entity_type == "body": - group_tag = result_entity_info.body_group_tag - attribute_names = result_entity_info.body_attribute_names - grouped_entities = result_entity_info.grouped_bodies - elif entity_type == "face": - group_tag = result_entity_info.face_group_tag - attribute_names = result_entity_info.face_attribute_names - grouped_entities = result_entity_info.grouped_faces - else: - raise ValueError(f"Invalid entity_type: {entity_type}") - - group_index_result = attribute_names.index(group_tag) - - for entity in grouped_entities[group_index_result]: - found = False - for reference_info in reference_entity_infos: - if entity_type == "body": - ref_attribute_names = reference_info.body_attribute_names - ref_grouped_entities = reference_info.grouped_bodies - else: # face - ref_attribute_names = reference_info.face_attribute_names - ref_grouped_entities = reference_info.grouped_faces - - group_index_ref = ref_attribute_names.index(group_tag) - - for ref_entity in ref_grouped_entities[group_index_ref]: - if entity.private_attribute_id == ref_entity.private_attribute_id: - result_value = getattr(entity, setting_name) - ref_value = getattr(ref_entity, setting_name) - assert result_value == ref_value, ( - f"{setting_name} mismatch for {entity_type} " - f"'{entity.name}' (id: {entity.private_attribute_id}): " - f"expected {ref_value}, got {result_value}" - ) - found = True - break - if found: - break - assert found, ( - f"{entity_type.capitalize()} '{entity.name}' (id: {entity.private_attribute_id}) " - f"not found in any reference entity info" - ) - - # Load test data - with open("data/root_geometry_cube_simulation.json", "r") as f: - root_cube_simulation_dict = json.load(f) - root_cube_entity_info = GeometryEntityInfo.deserialize( - root_cube_simulation_dict["private_attribute_asset_cache"]["project_entity_info"] - ) - with open("data/dependency_geometry_sphere1_simulation.json", "r") as f: - dependency_sphere1_simulation_dict = json.load(f) - dependency_sphere1_entity_info = GeometryEntityInfo.deserialize( - dependency_sphere1_simulation_dict["private_attribute_asset_cache"][ - "project_entity_info" - ] - ) - with open("data/dependency_geometry_sphere2_simulation.json", "r") as f: - dependency_sphere2_simulation_dict = json.load(f) - dependency_sphere2_entity_info = GeometryEntityInfo.deserialize( - dependency_sphere2_simulation_dict["private_attribute_asset_cache"][ - "project_entity_info" - ] - ) - - # Test 1: Merge root geometry and one dependency geometry - # Should preserve mesh_exterior and name settings of geometryBodyGroup in root geometry - result_entity_info_dict1 = services.merge_geometry_entity_info( - draft_param_as_dict=root_cube_simulation_dict, - geometry_dependencies_param_as_dict=[ - root_cube_simulation_dict, - dependency_sphere1_simulation_dict, - ], - ) - result_entity_info1 = GeometryEntityInfo.deserialize(result_entity_info_dict1) - - # Load expected result for test 1 - with open("data/result_merged_geometry_entity_info1.json", "r") as f: - expected_result1 = json.load(f) - - # Compare results - assert compare_values( - result_entity_info_dict1, expected_result1 - ), "Test 1 failed: Merged entity info does not match expected result" - - # Verify key properties are preserved using helper function - check_setting_preserved( - result_entity_info1, - [root_cube_entity_info, dependency_sphere1_entity_info], - entity_type="body", - setting_name="mesh_exterior", - ) - check_setting_preserved( - result_entity_info1, - [root_cube_entity_info, dependency_sphere1_entity_info], - entity_type="body", - setting_name="name", - ) - check_setting_preserved( - result_entity_info1, - [root_cube_entity_info, dependency_sphere1_entity_info], - entity_type="face", - setting_name="name", - ) - - # Test 2: Start from result of (1), replace the dependency with another dependency geometry - # Should check: - # a. the preservation of mesh_exterior and name settings of geometryBodyGroup in new_draft_param_as_dict - # b. the new dependency geometry should have replaced the old dependency geometry - new_draft_param_as_dict = copy.deepcopy(root_cube_simulation_dict) - new_draft_param_as_dict["private_attribute_asset_cache"]["project_entity_info"] = copy.deepcopy( - result_entity_info_dict1 - ) - - result_entity_info_dict2 = services.merge_geometry_entity_info( - draft_param_as_dict=new_draft_param_as_dict, - geometry_dependencies_param_as_dict=[ - root_cube_simulation_dict, - dependency_sphere2_simulation_dict, - ], - ) - - # Load expected result for test 2 - with open("data/result_merged_geometry_entity_info2.json", "r") as f: - expected_result2 = json.load(f) - - # Compare results - assert compare_values( - result_entity_info_dict2, expected_result2 - ), "Test 2 failed: Merged entity info with replaced dependency does not match expected result" - - result_entity_info2 = GeometryEntityInfo.deserialize(result_entity_info_dict2) - - # Verify key properties are preserved using helper function - check_setting_preserved( - result_entity_info2, - [root_cube_entity_info, dependency_sphere2_entity_info], - entity_type="body", - setting_name="mesh_exterior", - ) - check_setting_preserved( - result_entity_info2, - [root_cube_entity_info, dependency_sphere2_entity_info], - entity_type="body", - setting_name="name", - ) - check_setting_preserved( - result_entity_info2, - [root_cube_entity_info, dependency_sphere2_entity_info], - entity_type="face", - setting_name="name", - ) - - -def test_sanitize_stack_trace(): - """Test that _sanitize_stack_trace properly sanitizes file paths and removes traceback prefix.""" - from flow360.component.simulation.services import _sanitize_stack_trace - - # Test case 1: Full stack trace with traceback prefix and absolute paths - input_stack = """Traceback (most recent call last): - File "/disk2/ben/Flow360-R2/flow360/component/simulation/services.py", line 553, in validate_model - validation_info = ParamsValidationInfo( - File "/disk2/ben/Flow360-R2/flow360/component/simulation/validation/validation_context.py", line 437, in __init__ - self.farfield_method = self._get_farfield_method_(param_as_dict=param_as_dict) - File "/disk2/ben/Flow360-R2/flow360/component/simulation/validation/validation_context.py", line 162, in _get_farfield_method_ - if meshing["type_name"] == "MeshingParams": -KeyError: 'type_name'""" - - expected_output = """File "flow360/component/simulation/services.py", line 553, in validate_model - validation_info = ParamsValidationInfo( - File "flow360/component/simulation/validation/validation_context.py", line 437, in __init__ - self.farfield_method = self._get_farfield_method_(param_as_dict=param_as_dict) - File "flow360/component/simulation/validation/validation_context.py", line 162, in _get_farfield_method_ - if meshing["type_name"] == "MeshingParams": -KeyError: 'type_name'""" - - result = _sanitize_stack_trace(input_stack) - assert result == expected_output - - # Test case 2: Stack trace without traceback prefix (already sanitized prefix) - input_stack_no_prefix = """File "/home/user/projects/flow360/component/simulation/services.py", line 100, in some_function - some_code()""" - - expected_no_prefix = """File "flow360/component/simulation/services.py", line 100, in some_function - some_code()""" - - result_no_prefix = _sanitize_stack_trace(input_stack_no_prefix) - assert result_no_prefix == expected_no_prefix - - # Test case 3: Stack trace with non-flow360 paths should remain unchanged for those paths - input_mixed = """Traceback (most recent call last): - File "/usr/lib/python3.10/site-packages/pydantic/main.py", line 100, in validate - return cls.model_validate(obj) - File "/disk2/ben/Flow360-R2/flow360/component/simulation/services.py", line 50, in my_func - do_something()""" - - expected_mixed = """File "/usr/lib/python3.10/site-packages/pydantic/main.py", line 100, in validate - return cls.model_validate(obj) - File "flow360/component/simulation/services.py", line 50, in my_func - do_something()""" - - result_mixed = _sanitize_stack_trace(input_mixed) - assert result_mixed == expected_mixed - - # Test case 4: Empty string should return empty string - assert _sanitize_stack_trace("") == "" - - # Test case 5: String with no file paths should remain unchanged (except traceback prefix) - input_no_paths = "Some error message without file paths" - assert _sanitize_stack_trace(input_no_paths) == input_no_paths - - # Test case 6: Windows-style paths - input_windows = """Traceback (most recent call last): - File "C:\\Users\\dev\\Flow360-R2\\flow360\\component\\simulation\\services.py", line 100, in func - code()""" - - expected_windows = """File "flow360\\component\\simulation\\services.py", line 100, in func - code()""" - - result_windows = _sanitize_stack_trace(input_windows) - assert result_windows == expected_windows - - -def test_validate_error_location_with_selector(): - """ - Test that validation error locations are correctly preserved when errors occur - within EntitySelector's children field. - - This test verifies the fix for the bug where error locations were incorrectly - reduced to just ("children",) instead of the full path like - ("models", 0, "entities", "selectors", 0, "children", 0, "value"). - - The bug was in _traverse_error_location which used `current.get(field)` instead - of `field in current`, causing fields with falsy values (empty list, 0, etc.) - to be incorrectly filtered out. - """ - params_data = { - "models": [ - { - "type": "Wall", - "name": "Wall with selector", - "entities": { - "stored_entities": [], - "selectors": ["test-selector-id"], - }, - "use_wall_function": False, - } - ], - "unit_system": {"name": "SI"}, - "version": __version__, - "private_attribute_asset_cache": { - "project_entity_info": { - "type_name": "VolumeMeshEntityInfo", - "draft_entities": [], - "zones": [], - "boundaries": [], - }, - "used_selectors": [ - { - "name": "test_selector", - "target_class": "Surface", - "logic": "AND", - "selector_id": "test-selector-id", - } - ], - }, - } - - _, errors, _ = services.validate_model( - params_as_dict=params_data, - validated_by=services.ValidationCalledBy.LOCAL, - root_item_type="VolumeMesh", - ) - - assert errors is not None, "Expected validation errors but got None" - assert len(errors) == 1, f"Expected 1 error, got {len(errors)}" - - # Verify the location contains the full path, not just "children" - loc = errors[0]["loc"] - assert loc == ("private_attribute_asset_cache", "used_selectors", 0, "children"), print( - "Wrong localtion: ", loc - ) - - # Verify key path components are present for tokenized selectors in used_selectors - - @pytest.mark.parametrize("unit_system_name", ["SI", "Imperial", "CGS"]) def test_validate_model_preserves_unit_system(unit_system_name): """validate_model must not mutate the unit_system entry in the input dict.""" diff --git a/tests/simulation/services/test_entity_processing_service.py b/tests/simulation/services/test_entity_processing_service.py index 45a502bf8..be1331be1 100644 --- a/tests/simulation/services/test_entity_processing_service.py +++ b/tests/simulation/services/test_entity_processing_service.py @@ -1,5 +1,4 @@ import copy -import json import os import pytest @@ -18,9 +17,6 @@ from flow360.component.simulation.models.surface_models import Wall from flow360.component.simulation.primitives import MirroredSurface, Surface from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.services_utils import ( - strip_selector_matches_and_broken_entities_inplace, -) from flow360.component.volume_mesh import VolumeMeshMetaV2, VolumeMeshV2 @@ -46,14 +42,6 @@ def _load_local_vm(): ), ) - -def _load_json(path_from_tests_dir: str) -> dict: - """Helper to load a JSON file from the tests/simulation directory.""" - base = os.path.dirname(os.path.abspath(__file__)) - with open(os.path.join(base, "..", path_from_tests_dir), "r", encoding="utf-8") as file: - return json.load(file) - - def test_validate_model_keeps_selectors_unexpanded(): """ Test: End-to-end validation with delayed selector expansion. @@ -123,140 +111,6 @@ def test_validate_model_keeps_selectors_unexpanded(): validated.model_dump(mode="json"), validated_again.model_dump(mode="json") ) - -def test_validate_model_materializes_dict_and_preserves_selectors(): - """ - Test: `validate_model` correctly materializes explicit entity dicts into objects - while preserving the original selectors from a raw dictionary input. - - With delayed expansion, selectors are NOT expanded into stored_entities during - validation. Expansion happens later during translation. - """ - params = _load_json("data/geometry_grouped_by_file/simulation.json") - - # Inject a selector into the params dict and assign all entities to a Wall - # to satisfy the boundary condition validation. - selector_dict = { - "target_class": "Surface", - "name": "some_selector_name", - "logic": "AND", - "selector_id": "some_selector_id", - "children": [{"attribute": "name", "operator": "matches", "value": "*"}], - } - outputs = params.get("outputs") or [] - entities = outputs[0].get("entities") or {} - entities["selectors"] = [selector_dict] - entities["stored_entities"] = [] # Start with no materialized entities - - # Assign all boundaries to a default wall to pass validation - all_boundaries_selector = { - "target_class": "Surface", - "name": "all_boundaries", - "children": [ - {"attribute": "name", "operator": "matches", "value": "*"}, - {"attribute": "name", "operator": "not_matches", "value": "farfield"}, - {"attribute": "name", "operator": "not_matches", "value": "symmetric"}, - ], - } - params["models"].append( - { - "type": "Wall", - "name": "DefaultWall", - "entities": {"selectors": [all_boundaries_selector]}, - } - ) - - validated, errors, _ = validate_model( - params_as_dict=params, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Case", - ) - assert not errors, f"Unexpected validation errors: {errors}" - - # With delayed expansion, stored_entities should remain empty since only selectors were specified - stored_entities = validated.outputs[0].entities.stored_entities - assert len(stored_entities) == 0, "stored_entities should be empty with delayed expansion" - - # Verify selectors are preserved - preserved_selectors = validated.outputs[0].entities.selectors - assert len(preserved_selectors) == 1 - assert preserved_selectors[0].model_dump(exclude_none=True) == selector_dict - - -def test_validate_model_deduplicates_non_point_entities(): - """ - Test: `validate_model` deduplicates non-Point entities based on (type, id). - """ - params = { - "version": "25.7.6b0", - "operating_condition": { - "type_name": "AerospaceCondition", - "velocity_magnitude": {"units": "m/s", "value": 10}, - }, - "outputs": [ - { - "output_type": "SurfaceOutput", - "name": "o1", - "output_fields": ["Cp"], - "entities": { - "stored_entities": [ - { - "name": "wing", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "s-1", - }, - { - "name": "wing", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "s-1", - }, - ] - }, - } - ], - "private_attribute_asset_cache": { - "project_entity_info": {"type_name": "SurfaceMeshEntityInfo", "boundaries": []} - }, - "unit_system": {"name": "SI"}, - } - - validated, errors, _ = validate_model( - params_as_dict=params, validated_by=ValidationCalledBy.LOCAL, root_item_type="Case" - ) - assert not errors - final_entities = validated.outputs[0].entities.stored_entities - assert len(final_entities) == 1 - assert final_entities[0].name == "wing" - - -def test_strip_selector_matches_removes_selector_overlap(): - """Ensure selector-overlap entities are dropped prior to upload.""" - with fl.SI_unit_system: - params = fl.SimulationParams( - outputs=[ - fl.SurfaceOutput( - name="surface_output", - output_fields=[fl.UserVariable(name="var", value=1)], - entities=[ - Surface(name="front", private_attribute_id="s-1"), - Surface(name="rear", private_attribute_id="s-2"), - SurfaceSelector(name="front_selector").any_of(["front"]), - ], - ) - ], - private_attribute_asset_cache=AssetCache( - project_entity_info=SurfaceMeshEntityInfo( - boundaries=[ - Surface(name="front", private_attribute_id="s-1"), - Surface(name="rear", private_attribute_id="s-2"), - ] - ) - ), - ) - strip_selector_matches_and_broken_entities_inplace(params) - assert [entity.name for entity in params.outputs[0].entities.stored_entities] == ["rear"] - - def test_expand_entity_list_in_context_includes_mirrored_entities_from_mirror_status(): """Ensure selector expansion can see mirrored entities registered from mirror_status.""" mirror_plane = MirrorPlane( @@ -311,269 +165,3 @@ def test_expand_entity_list_in_context_includes_mirrored_entities_from_mirror_st expanded_type_names = {entity.private_attribute_entity_type_name for entity in expanded} assert "Surface" in expanded_type_names assert "MirroredSurface" in expanded_type_names - - -def test_strip_broken_and_foreign_mirror_entities_from_stored_entities(): - """Ensure stored_entities drops mirrored entities that are not valid for the current params registry.""" - mirror_plane = MirrorPlane( - name="plane", - normal=(1, 0, 0), - center=(0, 0, 0) * fl.u.m, - private_attribute_id="mp-1", - ) - - valid_mirrored_surface = MirroredSurface( - name="front_", - surface_id="s-1", - mirror_plane_id="mp-1", - private_attribute_id="ms-valid", - ) - broken_mirrored_surface = MirroredSurface( - name="broken_", - surface_id="s-missing", - mirror_plane_id="mp-1", - private_attribute_id="ms-broken", - ) - foreign_mirrored_surface = MirroredSurface( - name="front_", - surface_id="s-1", - mirror_plane_id="mp-1", - private_attribute_id="ms-foreign", - ) - - with fl.SI_unit_system: - params = fl.SimulationParams( - outputs=[ - fl.SurfaceOutput( - name="surface_output", - output_fields=[fl.UserVariable(name="var", value=1)], - entities=[ - Surface(name="front", private_attribute_id="s-1"), - Surface(name="stale", private_attribute_id="s-stale"), - valid_mirrored_surface, - broken_mirrored_surface, - foreign_mirrored_surface, - ], - ) - ], - private_attribute_asset_cache=AssetCache( - project_entity_info=SurfaceMeshEntityInfo( - boundaries=[Surface(name="front", private_attribute_id="s-1")] - ), - mirror_status=MirrorStatus( - mirror_planes=[mirror_plane], - mirrored_geometry_body_groups=[], - mirrored_surfaces=[valid_mirrored_surface], - ), - ), - ) - - strip_selector_matches_and_broken_entities_inplace(params) - remaining_names = [entity.name for entity in params.outputs[0].entities.stored_entities] - assert remaining_names == ["front", "stale", "front_"] - - -def test_validate_model_does_not_deduplicate_point_entities(): - """ - Test: `validate_model` preserves duplicate Point entities. - """ - params = { - "version": "25.7.6b0", - "operating_condition": { - "type_name": "AerospaceCondition", - "velocity_magnitude": {"value": 10, "units": "m/s"}, - }, - "outputs": [ - { - "output_type": "StreamlineOutput", - "name": "o2", - "entities": { - "stored_entities": [ - { - "name": "p1", - "private_attribute_entity_type_name": "Point", - "location": {"value": [0, 0, 0], "units": "m"}, - }, - { - "name": "p1", - "private_attribute_entity_type_name": "Point", - "location": {"value": [0, 0, 0], "units": "m"}, - }, - ] - }, - } - ], - "private_attribute_asset_cache": { - "project_entity_info": {"type_name": "SurfaceMeshEntityInfo", "boundaries": []} - }, - "unit_system": {"name": "SI"}, - } - - validated, errors, _ = validate_model( - params_as_dict=params, validated_by=ValidationCalledBy.LOCAL, root_item_type="Case" - ) - assert not errors - final_entities = validated.outputs[0].entities.stored_entities - assert len(final_entities) == 2 - assert all(e.name == "p1" for e in final_entities) - - -def test_validate_model_shares_entity_instances_across_lists(): - """ - Test: `validate_model` uses a global cache to share entity instances, - ensuring that an entity with the same ID is the same Python object everywhere. - """ - entity_dict = { - "name": "s", - "private_attribute_entity_type_name": "Surface", - "private_attribute_id": "s-1", - } - params = { - "version": "25.7.6b0", - "unit_system": {"name": "SI"}, - "operating_condition": { - "type_name": "AerospaceCondition", - "velocity_magnitude": {"value": 10, "units": "m/s"}, - }, - "models": [ - {"type": "Wall", "name": "Wall", "entities": {"stored_entities": [entity_dict]}} - ], - "outputs": [ - { - "output_type": "SurfaceOutput", - "name": "o3", - "output_fields": ["Cp"], - "entities": {"stored_entities": [entity_dict]}, - } - ], - "private_attribute_asset_cache": { - "project_entity_info": {"type_name": "SurfaceMeshEntityInfo", "boundaries": []} - }, - } - - validated, errors, _ = validate_model( - params_as_dict=params, validated_by=ValidationCalledBy.LOCAL, root_item_type="Case" - ) - assert not errors - entity_in_model = validated.models[0].entities.stored_entities[0] - entity_in_output = validated.outputs[0].entities.stored_entities[0] - assert entity_in_model is entity_in_output - - -def test_delayed_expansion_round_trip_preserves_semantics(): - """ - simulation.json -> validate -> round-trip -> compare - Ensures delayed expansion maintains consistency across round-trips. - - With delayed expansion, selectors are NOT expanded into stored_entities during - validation. This test verifies: - - Explicit entities remain in stored_entities - - Selectors are preserved - - Round-trip maintains consistency - """ - # Use a large, real geometry with many faces - params = _load_json("../data/geo-fcbe1113-a70b-43b9-a4f3-bbeb122d64fb/simulation.json") - - # Set face grouping tag so selector operates on faceId groups - pei = params["private_attribute_asset_cache"]["project_entity_info"] - pei["face_group_tag"] = "faceId" - # Remove obsolete/unknown meshing defaults to avoid validation noise in Case-level - params.get("meshing", {}).get("defaults", {}).pop("geometry_tolerance", None) - - # Build mixed EntityList with overlap under outputs[0].entities - outputs = params.get("outputs") or [] - assert outputs, "Test fixture lacks outputs" - entities = outputs[0].get("entities") or {} - entities["stored_entities"] = [ - { - "private_attribute_entity_type_name": "Surface", - "name": "body00001_face00001", - "private_attribute_id": "body00001_face00001", - }, - { - "private_attribute_entity_type_name": "Surface", - "name": "body00001_face00014", - "private_attribute_id": "body00001_face00014", - }, - ] - entities["selectors"] = [ - { - "target_class": "Surface", - "name": "some_overlap", - "children": [ - { - "attribute": "name", - "operator": "any_of", - "value": ["body00001_face00001", "body00001_face00002"], - } - ], - } - ] - outputs[0]["entities"] = entities - params["outputs"] = outputs - - # Ensure models contain a DefaultWall that matches all to satisfy BC validation - all_boundaries_selector = { - "target_class": "Surface", - "name": "all_boundaries", - "children": [ - {"attribute": "name", "operator": "matches", "value": "*"}, - {"attribute": "name", "operator": "not_matches", "value": "farfield"}, - ], - } - params.setdefault("models", []).append( - { - "type": "Wall", - "name": "DefaultWall", - "entities": {"selectors": [all_boundaries_selector]}, - } - ) - - # Baseline validation (with delayed expansion) - validated, errors, _ = validate_model( - params_as_dict=params, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Case", - ) - assert not errors, f"Unexpected validation errors: {errors}" - - # With delayed expansion, stored_entities should only contain explicit entities - baseline_entities = validated.outputs[0].entities.stored_entities # type: ignore[index] - baseline_names = sorted( - [f"{e.private_attribute_entity_type_name}:{e.name}" for e in baseline_entities] - ) - # Only explicitly specified entities should be present (NOT selector matches) - expected_explicit = ["Surface:body00001_face00001", "Surface:body00001_face00014"] - assert baseline_names == expected_explicit, ( - f"Expected only explicit entities in stored_entities\n" - f"Got: {baseline_names}\n" - f"Expected: {expected_explicit}" - ) - - # Verify selectors are preserved - baseline_selectors = validated.outputs[0].entities.selectors - assert len(baseline_selectors) == 1 - assert baseline_selectors[0].name == "some_overlap" - - # Round-trip: serialize and re-validate - round_trip_dict = validated.model_dump(mode="json", exclude_none=True) - validated2, errors2, _ = validate_model( - params_as_dict=round_trip_dict, - validated_by=ValidationCalledBy.LOCAL, - root_item_type="Case", - ) - assert not errors2, f"Unexpected validation errors on round-trip: {errors2}" - - # Verify round-trip consistency - post_entities = validated2.outputs[0].entities.stored_entities # type: ignore[index] - post_names = sorted([f"{e.private_attribute_entity_type_name}:{e.name}" for e in post_entities]) - assert baseline_names == post_names, ( - "Entity list mismatch after round-trip\n" - + f"Baseline: {baseline_names}\n" - + f"Post : {post_names}\n" - ) - - # Verify selectors are still preserved after round-trip - post_selectors = validated2.outputs[0].entities.selectors - assert len(post_selectors) == 1 - assert post_selectors[0].name == "some_overlap" diff --git a/tests/simulation/services/test_services_utils.py b/tests/simulation/services/test_services_utils.py index a874b9877..0b860d18f 100644 --- a/tests/simulation/services/test_services_utils.py +++ b/tests/simulation/services/test_services_utils.py @@ -1,21 +1,12 @@ import json -from types import SimpleNamespace import flow360 as fl import flow360.component.simulation.units as u from flow360.component.project_utils import validate_params_with_context from flow360.component.simulation.framework.param_utils import AssetCache -from flow360.component.simulation.meshing_param.meshing_specs import MeshingDefaults -from flow360.component.simulation.services_utils import ( - strip_implicit_edge_split_layers_inplace, -) from flow360.component.simulation.web.draft import Draft -def _build_dummy_params(defaults: MeshingDefaults): - return SimpleNamespace(meshing=SimpleNamespace(defaults=defaults)) - - def _build_simulation_params(*, edge_split_layers=None): defaults_kwargs = dict( boundary_layer_first_layer_thickness=1e-4, @@ -35,51 +26,6 @@ def _build_simulation_params(*, edge_split_layers=None): ), ) - -def test_strip_implicit_edge_split_layers_removes_default_injected_field(): - with fl.SI_unit_system: - defaults = MeshingDefaults(boundary_layer_first_layer_thickness=1e-4) - - params = _build_dummy_params(defaults) - params_dict = { - "meshing": {"defaults": {"edge_split_layers": 1, "surface_edge_growth_rate": 1.2}} - } - - out = strip_implicit_edge_split_layers_inplace(params, params_dict) - - assert out is params_dict - assert "edge_split_layers" not in out["meshing"]["defaults"] - assert out["meshing"]["defaults"]["surface_edge_growth_rate"] == 1.2 - - -def test_strip_implicit_edge_split_layers_keeps_explicit_default_value(): - with fl.SI_unit_system: - defaults = MeshingDefaults(boundary_layer_first_layer_thickness=1e-4, edge_split_layers=1) - - params = _build_dummy_params(defaults) - params_dict = { - "meshing": {"defaults": {"edge_split_layers": 1, "surface_edge_growth_rate": 1.2}} - } - - out = strip_implicit_edge_split_layers_inplace(params, params_dict) - - assert out["meshing"]["defaults"]["edge_split_layers"] == 1 - - -def test_strip_implicit_edge_split_layers_keeps_explicit_non_default_value(): - with fl.SI_unit_system: - defaults = MeshingDefaults(boundary_layer_first_layer_thickness=1e-4, edge_split_layers=3) - - params = _build_dummy_params(defaults) - params_dict = { - "meshing": {"defaults": {"edge_split_layers": 3, "surface_edge_growth_rate": 1.2}} - } - - out = strip_implicit_edge_split_layers_inplace(params, params_dict) - - assert out["meshing"]["defaults"]["edge_split_layers"] == 3 - - def test_validate_params_with_context_no_warning_for_implicit_default(): params = _build_simulation_params() diff --git a/tests/simulation/test_updater.py b/tests/simulation/test_updater.py index 5c1e0bf94..db631735c 100644 --- a/tests/simulation/test_updater.py +++ b/tests/simulation/test_updater.py @@ -1,4 +1,3 @@ -import json import os import re @@ -7,8 +6,6 @@ from flow360.component.simulation.framework.updater import VERSION_MILESTONES from flow360.component.simulation.framework.updater_utils import Flow360Version -from flow360.component.simulation.services import ValidationCalledBy, validate_model -from flow360.component.simulation.validation.validation_context import ALL from flow360.version import __solver_version__, __version__ @@ -48,16 +45,3 @@ def test_version_greater_than_highest_updater_version(): assert ( current_python_version >= VERSION_MILESTONES[-1][0] ), "Highest version updater can handle is higher than Python client version. This is not allowed." - - -def test_deserialization_with_updater(): - simulation_path = os.path.join("..", "data", "simulation", "simulation_24_11_0.json") - with open(simulation_path, "r") as file: - params = json.load(file) - - validate_model( - params_as_dict=params, - root_item_type="VolumeMesh", - validated_by=ValidationCalledBy.LOCAL, - validation_level=ALL, - ) From a27a49bf660388fff9ed6f32df25e523bde577c3 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Fri, 17 Apr 2026 15:19:19 -0400 Subject: [PATCH 2/6] Fix pylint unused-import warnings in schema relay files Add `# pylint: disable=unused-import` to relay-only files whose re-exported symbols are consumed by compute pipeline scripts. Remove genuinely unused `materialize_entities_and_selectors_in_place` import from services.py. Co-Authored-By: Claude Sonnet 4.6 --- flow360/component/simulation/conversion.py | 1 + .../component/simulation/framework/updater.py | 1 + .../simulation/framework/updater_functions.py | 1 + .../simulation/framework/updater_utils.py | 1 + flow360/component/simulation/services.py | 28 ++++++------------- .../component/simulation/services_utils.py | 1 + flow360/component/simulation/utils.py | 1 + tests/simulation/service/test_services_v2.py | 9 ++++-- .../test_entity_processing_service.py | 2 ++ .../services/test_services_utils.py | 1 + 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/flow360/component/simulation/conversion.py b/flow360/component/simulation/conversion.py index bf30495ec..edb4e5a05 100644 --- a/flow360/component/simulation/conversion.py +++ b/flow360/component/simulation/conversion.py @@ -1,5 +1,6 @@ """Relay schema-owned conversion helpers for migrated simulation modules.""" +# pylint: disable=unused-import from flow360_schema.models.simulation.conversion import ( LIQUID_IMAGINARY_FREESTREAM_MACH, RestrictedUnitSystem, diff --git a/flow360/component/simulation/framework/updater.py b/flow360/component/simulation/framework/updater.py index 5b2ffc9bd..d64dc3b7c 100644 --- a/flow360/component/simulation/framework/updater.py +++ b/flow360/component/simulation/framework/updater.py @@ -1,5 +1,6 @@ """Relay schema-owned updater orchestration for simulation models.""" +# pylint: disable=unused-import from flow360_schema.models.simulation.framework.updater import ( DEFAULT_PLANAR_FACE_TOLERANCE, DEFAULT_SLIDING_INTERFACE_TOLERANCE, diff --git a/flow360/component/simulation/framework/updater_functions.py b/flow360/component/simulation/framework/updater_functions.py index fec914eb0..6ca26261e 100644 --- a/flow360/component/simulation/framework/updater_functions.py +++ b/flow360/component/simulation/framework/updater_functions.py @@ -1,5 +1,6 @@ """Relay schema-owned updater helper functions for simulation models.""" +# pylint: disable=unused-import from flow360_schema.models.simulation.framework.updater_functions import ( fix_ghost_sphere_schema, is_entity_dict, diff --git a/flow360/component/simulation/framework/updater_utils.py b/flow360/component/simulation/framework/updater_utils.py index 147709cac..8ca1d82f4 100644 --- a/flow360/component/simulation/framework/updater_utils.py +++ b/flow360/component/simulation/framework/updater_utils.py @@ -1,5 +1,6 @@ """Relay schema-owned updater utilities for simulation models.""" +# pylint: disable=unused-import from flow360_schema.models.simulation.framework.updater_utils import ( FLOW360_SCHEMA_DEFAULT_VERSION, PYTHON_API_VERSION_REGEXP, diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 158f00aa7..44f039217 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -2,23 +2,14 @@ import json import os -from typing import ( - Any, - Collection, - Dict, - List, - Literal, - Optional, - Tuple, - Union, -) +from typing import Any, Collection, Dict, List, Literal, Optional, Tuple, Union import pydantic as pd from flow360_schema.framework.physical_dimensions import Angle, Length -from flow360_schema.models.simulation.services import ( # pylint: disable=unused-import +from flow360_schema.models.simulation.services import ( ValidationCalledBy, - _get_default_reference_geometry, _determine_validation_level, + _get_default_reference_geometry, _insert_forward_compatibility_notice, _intersect_validation_levels, _normalize_union_branch_error_location, @@ -37,14 +28,13 @@ merge_geometry_entity_info, update_simulation_json, validate_error_locations, - validate_model as _schema_validate_model, +) +from flow360_schema.models.simulation.services import ( + validate_model as _schema_validate_model, # pylint: disable=unused-import ) from pydantic import TypeAdapter from flow360.component.simulation.exposed_units import supported_units_by_front_end -from flow360.component.simulation.framework.entity_materializer import ( - materialize_entities_and_selectors_in_place, -) from flow360.component.simulation.models.bet.bet_translator_interface import ( generate_polar_file_name_list, translate_xfoil_c81_to_bet_dict, @@ -75,12 +65,10 @@ ) from flow360.component.simulation.unit_system import _dimensioned_type_serializer, u from flow360.component.simulation.validation.validation_context import ALL -from flow360.exceptions import ( - Flow360TranslationError, - Flow360ValueError, -) +from flow360.exceptions import Flow360TranslationError, Flow360ValueError from flow360.version import __version__ + def validate_model( # pylint: disable=too-many-locals *, params_as_dict, diff --git a/flow360/component/simulation/services_utils.py b/flow360/component/simulation/services_utils.py index 44d41c422..f9f91e96a 100644 --- a/flow360/component/simulation/services_utils.py +++ b/flow360/component/simulation/services_utils.py @@ -1,5 +1,6 @@ """Utility functions for the simulation services.""" +# pylint: disable=unused-import from flow360_schema.models.simulation.services_utils import ( strip_implicit_edge_split_layers_inplace, strip_selector_matches_and_broken_entities_inplace, diff --git a/flow360/component/simulation/utils.py b/flow360/component/simulation/utils.py index 0560af2b1..65736ba82 100644 --- a/flow360/component/simulation/utils.py +++ b/flow360/component/simulation/utils.py @@ -1,5 +1,6 @@ """Relay schema-owned utility functions for the simulation component.""" +# pylint: disable=unused-import from flow360_schema.framework.bounding_box import BoundingBox, BoundingBoxType from flow360_schema.models.simulation.utils import ( get_combined_subclasses, diff --git a/tests/simulation/service/test_services_v2.py b/tests/simulation/service/test_services_v2.py index 9ac9780ab..62463fff8 100644 --- a/tests/simulation/service/test_services_v2.py +++ b/tests/simulation/service/test_services_v2.py @@ -12,14 +12,15 @@ from flow360.component.simulation.framework.updater_utils import compare_values from flow360.component.simulation.services_report import get_default_report_config from flow360.component.simulation.unit_system import DimensionedTypes -from flow360.component.simulation.validation.validation_context import ( - CASE, -) +from flow360.component.simulation.validation.validation_context import CASE from flow360.version import __version__ + + @pytest.fixture(autouse=True) def change_test_dir(request, monkeypatch): monkeypatch.chdir(request.fspath.dirname) + def test_generate_process_json(): params_data = { "meshing": { @@ -207,6 +208,7 @@ def test_generate_process_json_skips_case_validation_for_meshing(): assert res2 is None assert res3 is None + def test_forward_compatibility_error(): from flow360.version import __version__ @@ -447,6 +449,7 @@ def test_get_default_report_config_json(): ref_dict = json.load(fp) assert compare_values(report_config_dict, ref_dict, ignore_keys=["formatter"]) + @pytest.mark.parametrize("unit_system_name", ["SI", "Imperial", "CGS"]) def test_validate_model_preserves_unit_system(unit_system_name): """validate_model must not mutate the unit_system entry in the input dict.""" diff --git a/tests/simulation/services/test_entity_processing_service.py b/tests/simulation/services/test_entity_processing_service.py index be1331be1..ab321bd5b 100644 --- a/tests/simulation/services/test_entity_processing_service.py +++ b/tests/simulation/services/test_entity_processing_service.py @@ -42,6 +42,7 @@ def _load_local_vm(): ), ) + def test_validate_model_keeps_selectors_unexpanded(): """ Test: End-to-end validation with delayed selector expansion. @@ -111,6 +112,7 @@ def test_validate_model_keeps_selectors_unexpanded(): validated.model_dump(mode="json"), validated_again.model_dump(mode="json") ) + def test_expand_entity_list_in_context_includes_mirrored_entities_from_mirror_status(): """Ensure selector expansion can see mirrored entities registered from mirror_status.""" mirror_plane = MirrorPlane( diff --git a/tests/simulation/services/test_services_utils.py b/tests/simulation/services/test_services_utils.py index 0b860d18f..2da0f2f84 100644 --- a/tests/simulation/services/test_services_utils.py +++ b/tests/simulation/services/test_services_utils.py @@ -26,6 +26,7 @@ def _build_simulation_params(*, edge_split_layers=None): ), ) + def test_validate_params_with_context_no_warning_for_implicit_default(): params = _build_simulation_params() From 323c272aef15fcff3a9fb3a4d6886189334599aa Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Fri, 17 Apr 2026 15:25:38 -0400 Subject: [PATCH 3/6] Remove unused relay imports from services.py Keep only relay exports consumed by external compute scripts (_parse_root_item_type_from_simulation_json, apply_simulation_setting_to_entity_info, get_default_params, merge_geometry_entity_info, update_simulation_json). Remove 15 symbols with no internal or external callers. Co-Authored-By: Claude Sonnet 4.6 --- flow360/component/simulation/services.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 44f039217..24b252844 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -8,30 +8,18 @@ from flow360_schema.framework.physical_dimensions import Angle, Length from flow360_schema.models.simulation.services import ( ValidationCalledBy, - _determine_validation_level, - _get_default_reference_geometry, - _insert_forward_compatibility_notice, - _intersect_validation_levels, - _normalize_union_branch_error_location, + validate_model as _schema_validate_model, +) + +# pylint: disable=unused-import # relay exports consumed by compute pipeline scripts +from flow360_schema.models.simulation.services import ( _parse_root_item_type_from_simulation_json, - _populate_error_context, - _sanitize_stack_trace, - _store_project_length_unit, - _traverse_error_location, apply_simulation_setting_to_entity_info, - clean_unrelated_setting_from_params_dict, - clear_context, get_default_params, - handle_generic_exception, - init_unit_system, - initialize_variable_space, merge_geometry_entity_info, update_simulation_json, - validate_error_locations, -) -from flow360_schema.models.simulation.services import ( - validate_model as _schema_validate_model, # pylint: disable=unused-import ) +# pylint: enable=unused-import from pydantic import TypeAdapter from flow360.component.simulation.exposed_units import supported_units_by_front_end From 4ffd57ba776109493fbeeeafc5320d64801ebd49 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Fri, 17 Apr 2026 15:30:09 -0400 Subject: [PATCH 4/6] Fix linter --- flow360/component/simulation/services.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 24b252844..6f44ab519 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -6,19 +6,20 @@ import pydantic as pd from flow360_schema.framework.physical_dimensions import Angle, Length -from flow360_schema.models.simulation.services import ( - ValidationCalledBy, - validate_model as _schema_validate_model, -) # pylint: disable=unused-import # relay exports consumed by compute pipeline scripts from flow360_schema.models.simulation.services import ( + ValidationCalledBy, _parse_root_item_type_from_simulation_json, apply_simulation_setting_to_entity_info, get_default_params, merge_geometry_entity_info, update_simulation_json, ) +from flow360_schema.models.simulation.services import ( + validate_model as _schema_validate_model, +) + # pylint: enable=unused-import from pydantic import TypeAdapter From 355d0ef00330102d151543741dc6d30ed5550869 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Fri, 17 Apr 2026 15:34:02 -0400 Subject: [PATCH 5/6] Fix linter --- flow360/component/simulation/services.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 6f44ab519..b23da4052 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -10,6 +10,8 @@ # pylint: disable=unused-import # relay exports consumed by compute pipeline scripts from flow360_schema.models.simulation.services import ( ValidationCalledBy, + _determine_validation_level, + _get_default_reference_geometry, _parse_root_item_type_from_simulation_json, apply_simulation_setting_to_entity_info, get_default_params, From 06d41107a20ddfd0a8ba82ece2d910fc35e178a5 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Sat, 18 Apr 2026 12:07:00 -0400 Subject: [PATCH 6/6] Get to the latest --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 41725bdbe..621fde08a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1468,14 +1468,14 @@ files = [ [[package]] name = "flow360-schema" -version = "25.10.1b1" +version = "25.10.2b1" description = "Pure Pydantic schemas for Flow360 - Single Source of Truth" optional = false python-versions = ">=3.10,<4.0" groups = ["main"] files = [ - {file = "flow360_schema-25.10.1b1-py3-none-any.whl", hash = "sha256:2229974c4003138b56c2bb392d1ec09a578cfc0bb73c3a31d63f91febd2eefa6"}, - {file = "flow360_schema-25.10.1b1.tar.gz", hash = "sha256:41a6440f4295ad93c6591320e461264965a6a69cef8c0280d84abbea4f4e8be0"}, + {file = "flow360_schema-25.10.2b1-py3-none-any.whl", hash = "sha256:52e0ffd6e5a4c20fb23155b68fc1eadeebcb1f4236bab20c4d1b83043649e34c"}, + {file = "flow360_schema-25.10.2b1.tar.gz", hash = "sha256:4f9f5b94635dc60a4862d90e5465cadcad32ec0a0fb65541347a556b1ea36503"}, ] [package.dependencies] @@ -6526,4 +6526,4 @@ docs = ["autodoc_pydantic", "cairosvg", "ipython", "jinja2", "jupyter", "myst-pa [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "78042dd058873ceb2f115cddf761b19a995fc4da0e532d0b5991c0b9449236b7" +content-hash = "6c2dbbccc52682232b6182a17d80c78822b01557fc1620c5d3553e97c9e84147" diff --git a/pyproject.toml b/pyproject.toml index 33a5f16c7..f40dcfdaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ pydantic = ">=2.8,<2.12" # -- Local dev (editable install, schema changes take effect immediately): # flow360-schema = { path = "../../../../flex/share/flow360-schema", develop = true } # -- CI / release (install from CodeArtifact, swap comments before pushing): -flow360-schema = { version = "= 25.10.1b1", source = "codeartifact" } +flow360-schema = { version = "= 25.10.2b1", source = "codeartifact" } pytest = "^7.1.2" click = "^8.1.3" toml = "^0.10.2"