diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index dffebf5e5f..da9bc2c7f9 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -17,7 +17,7 @@ on: env: DOCKER_IMAGE_NAME: ghcr.io/ansys/prime - DOCKER_IMAGE_TAG: '26.1.2.dev0' + DOCKER_IMAGE_TAG: '26.1.3' MAIN_PYTHON_VERSION: '3.14' PACKAGE_NAME: 'ansys-meshing-prime' PACKAGE_NAMESPACE: 'ansys.meshing.prime' diff --git a/doc/changelog.d/1298.maintenance.md b/doc/changelog.d/1298.maintenance.md new file mode 100644 index 0000000000..a06cf14bc7 --- /dev/null +++ b/doc/changelog.d/1298.maintenance.md @@ -0,0 +1 @@ +Ado sync for 26r1sp02 diff --git a/pyproject.toml b/pyproject.toml index 5e2eb878dc..6ea7bf5d2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi" [project] name = "ansys-meshing-prime" -version = "0.10.3" +version = "0.10.4" description = "PyPrimeMesh is a Python client to Ansys Prime Server, which delivers core Ansys meshing technology." readme = "README.md" requires-python = ">=3.10,<4" @@ -116,13 +116,13 @@ title_format = "## [{version}](https://github.com/ansys/pyprimemesh/releases/tag issue_format = "[#{issue}](https://github.com/ansys/pyprimemesh/pull/{issue})" [[tool.towncrier.type]] -directory = "added" -name = "Added" +directory = "breaking" +name = "Breaking" showcontent = true [[tool.towncrier.type]] -directory = "changed" -name = "Changed" +directory = "added" +name = "Added" showcontent = true [[tool.towncrier.type]] @@ -131,27 +131,32 @@ name = "Fixed" showcontent = true [[tool.towncrier.type]] -directory = "dependencies" -name = "Dependencies" +directory = "documentation" +name = "Documentation" showcontent = true [[tool.towncrier.type]] -directory = "miscellaneous" -name = "Miscellaneous" +directory = "dependencies" +name = "Dependencies" showcontent = true - [[tool.towncrier.type]] -directory = "documentation" -name = "Documentation" +directory = "maintenance" +name = "Maintenance" showcontent = true [[tool.towncrier.type]] -directory = "maintenance" -name = "Maintenance" +directory = "miscellaneous" +name = "Miscellaneous" showcontent = true [[tool.towncrier.type]] directory = "test" name = "Test" showcontent = true + +[[tool.towncrier.type]] +directory = "changed" +name = "Changed" +showcontent = true + diff --git a/src/ansys/meshing/prime/core/fileio.py b/src/ansys/meshing/prime/core/fileio.py index c64d27110a..18ede9c4bb 100644 --- a/src/ansys/meshing/prime/core/fileio.py +++ b/src/ansys/meshing/prime/core/fileio.py @@ -328,9 +328,6 @@ def export_mapdl_cdb( """ params = copy.copy(params) with utils.file_write_context(self._model, file_name) as temp_file_name: - # part_id = 1 - # if len(self._model.parts) > 0: - # part_id = self._model.parts[0].id args = {"partId": 0} command_name = "PrimeMesh::FileIO/GetAbaqusSimulationData" sim_data_str = self._comm.serve(self._model, command_name, self._object_id, args=args) @@ -338,24 +335,26 @@ def export_mapdl_cdb( params.config_settings = '' generate_mapdl_commands_error = None generate_mapdl_commands_traceback = None - try: - all_mat_cmds, analysis_settings = mapdlcdbexportutils.generate_mapdl_commands( - self._model, sim_data_str, params - ) - except Exception as e: - generate_mapdl_commands_error = e - generate_mapdl_commands_traceback = traceback.format_exc() + with utils.capture_log_records(self._model.python_logger) as collected_logs: all_mat_cmds, analysis_settings = "", "" + try: + all_mat_cmds, analysis_settings = mapdlcdbexportutils.generate_mapdl_commands( + self._model, sim_data_str, params + ) + except Exception as e: + generate_mapdl_commands_error = e + generate_mapdl_commands_traceback = traceback.format_exc() + if generate_mapdl_commands_error is not None: + self._model.python_logger.warning( + "Failed to generate MAPDL material/analysis commands. " + "Export proceeded with empty settings. \nError: %s\n%s", + generate_mapdl_commands_error, + generate_mapdl_commands_traceback, + ) params.material_properties = all_mat_cmds + params.material_properties params.analysis_settings = analysis_settings + params._custom_params["client_log_messages"] = json.dumps(collected_logs) result = super().export_mapdl_cdb(temp_file_name, params) - if generate_mapdl_commands_error is not None: - self._model.python_logger.warning( - "Failed to generate MAPDL material/analysis commands. " - "Export proceeded with empty settings. \nError: %s\n%s", - generate_mapdl_commands_error, - generate_mapdl_commands_traceback, - ) return result def initialize_cdb_export_params( @@ -587,9 +586,6 @@ def export_lsdyna_keyword_file( """ params = copy.copy(params) with utils.file_write_context(self._model, file_name) as temp_file_name: - # part_id = 1 - # if len(self._model.parts) > 0: - # part_id = self._model.parts[0].id args = {"partId": 0} command_name = "PrimeMesh::FileIO/GetAbaqusSimulationData" sim_data_str = self._comm.serve(self._model, command_name, self._object_id, args=args) @@ -597,10 +593,26 @@ def export_lsdyna_keyword_file( sim_data = None else: sim_data = json.loads(sim_data_str) - if sim_data is not None: - mp = dynaexportutils.MaterialProcessor(self._model, sim_data) - all_mat_cmds = mp.get_all_material_commands() - params.material_properties = all_mat_cmds + params.material_properties + generate_lsdyna_commands_error = None + generate_lsdyna_commands_traceback = None + with utils.capture_log_records(self._model.python_logger) as collected_logs: + all_mat_cmds = "" + try: + if sim_data is not None: + mp = dynaexportutils.MaterialProcessor(self._model, sim_data) + all_mat_cmds = mp.get_all_material_commands() + except Exception as e: + generate_lsdyna_commands_error = e + generate_lsdyna_commands_traceback = traceback.format_exc() + if generate_lsdyna_commands_error is not None: + self._model.python_logger.warning( + "Failed to generate LS-DYNA material commands. " + "Export proceeded with empty settings. \nError: %s\n%s", + generate_lsdyna_commands_error, + generate_lsdyna_commands_traceback, + ) + params.material_properties = all_mat_cmds + params.material_properties + params._custom_params["client_log_messages"] = json.dumps(collected_logs) result = super().export_lsdyna_keyword_file(temp_file_name, params) return result diff --git a/src/ansys/meshing/prime/core/mapdlcdbexportutils.py b/src/ansys/meshing/prime/core/mapdlcdbexportutils.py index 88201ba30e..01f61d31e3 100644 --- a/src/ansys/meshing/prime/core/mapdlcdbexportutils.py +++ b/src/ansys/meshing/prime/core/mapdlcdbexportutils.py @@ -4267,10 +4267,12 @@ def get_output_analysis_data(self, output_data): else: ninterval = int(parameters['NUMBER INTERVAL']) nfreq = None - if 'Parameters' in output: - parameters = output['Parameters'] - if 'FREQUENCY' in parameters: - nfreq = parameters['FREQUENCY'] + if 'Parameters' in output and 'FREQUENCY' in output['Parameters']: + if 'Frequency' in self._curr_step: + # Abaqus ignores *OUTPUT FREQUENCY in a *FREQUENCY step and forces it to 1. + nfreq = 1 + else: + nfreq = output['Parameters']['FREQUENCY'] time_interval = None if 'Parameters' in output: parameters = output['Parameters'] diff --git a/src/ansys/meshing/prime/internals/utils.py b/src/ansys/meshing/prime/internals/utils.py index 1da69aa421..b0544ccc60 100644 --- a/src/ansys/meshing/prime/internals/utils.py +++ b/src/ansys/meshing/prime/internals/utils.py @@ -223,6 +223,40 @@ def print_beta_api_warning(logger: logging.Logger, command: str): ) +@contextmanager +def capture_log_records(logger): + """Context manager that tracks log records from the given logger. + + Records are captured passively via a filter and do not interfere + with existing handlers. On exit the collected list is available + through the value yielded. + + Parameters + ---------- + logger : logging.Logger + Logger to attach the collecting filter to. + + Yields + ------ + list[dict] + List of ``{'level': str, 'message': str}`` dicts, populated + in-place as log records pass through. + """ + collected = [] + + def _collect(record): + collected.append({'level': record.levelname, 'message': record.getMessage()}) + return True + + log_filter = logging.Filter() + log_filter.filter = _collect + logger.addFilter(log_filter) + try: + yield collected + finally: + logger.removeFilter(log_filter) + + def launch_prime_github_container( mount_host: str = defaults.get_user_data_path(), mount_image: str = defaults.get_user_data_path_for_containers(),