From 1527306001790fd15f78ecdad6e9a7446cbae890 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Fri, 23 Feb 2024 12:59:47 +0100 Subject: [PATCH 01/16] added open_file to all the methods which requires open --- pyaedt/application/Analysis.py | 2 +- pyaedt/application/Design.py | 3 +- pyaedt/desktop.py | 14 +++++----- pyaedt/generic/com_parameters.py | 5 ++-- pyaedt/generic/configurations.py | 3 +- pyaedt/generic/general_methods.py | 44 ++++++++++++++++++++---------- pyaedt/generic/ibis_reader.py | 19 ++++--------- pyaedt/generic/pdf.py | 3 +- pyaedt/generic/spisim.py | 15 +++++----- pyaedt/maxwell.py | 5 ++-- pyaedt/modeler/cad/Primitives3D.py | 2 +- pyaedt/modeler/modeler3d.py | 9 +++--- pyaedt/modules/CableModeling.py | 3 +- pyaedt/modules/DesignXPloration.py | 3 +- pyaedt/modules/PostProcessor.py | 15 ++++------ pyaedt/modules/solutions.py | 10 ++++--- pyaedt/rpc/rpyc_services.py | 10 +++++++ pyaedt/twinbuilder.py | 3 +- 18 files changed, 97 insertions(+), 71 deletions(-) diff --git a/pyaedt/application/Analysis.py b/pyaedt/application/Analysis.py index 8a0aac7d8fc..8d2fd6904bc 100644 --- a/pyaedt/application/Analysis.py +++ b/pyaedt/application/Analysis.py @@ -1999,7 +1999,7 @@ def solve_in_batch( if machine == "localhost": while not os.path.exists(queue_file): time.sleep(0.5) - with open(queue_file, "r") as f: + with open_file(queue_file, "r") as f: lines = f.readlines() for line in lines: if "JobID" in line: diff --git a/pyaedt/application/Design.py b/pyaedt/application/Design.py index 1b132cb061d..98b2f86c36e 100644 --- a/pyaedt/application/Design.py +++ b/pyaedt/application/Design.py @@ -534,8 +534,7 @@ def project_properties(self): and settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists(self.project_file) ): - local_path = os.path.join(settings.remote_rpc_session_temp_folder, os.path.split(self.project_file)[-1]) - file_path = check_and_download_file(local_path, self.project_file) + file_path = check_and_download_file(self.project_file) try: settings._project_properties[os.path.normpath(self.project_file)] = load_entire_aedt_file(file_path) except: diff --git a/pyaedt/desktop.py b/pyaedt/desktop.py index 82096093206..fb604b4bea0 100644 --- a/pyaedt/desktop.py +++ b/pyaedt/desktop.py @@ -1632,7 +1632,7 @@ def change_registry_from_file(self, registry_file, make_active=True): try: self._main.oDesktop.SetRegistryFromFile(registry_file) if make_active: - with open(registry_file, "r") as f: + with open_file(registry_file, "r") as f: for line in f: stripped_line = line.strip() if "ConfigName" in stripped_line: @@ -1780,8 +1780,8 @@ def add_script_to_menu( dst = os.path.join(tool_dir, file_name.replace("_", " ") + ".py") if not os.path.isfile(src): raise FileNotFoundError("File not found: {}".format(src)) - with open(src, "r") as build_file: - with open(dst, "w") as out_file: + with open_file(src, "r") as build_file: + with open_file(dst, "w") as out_file: self.logger.info("Building to " + dst) build_file_data = build_file.read() build_file_data = ( @@ -2084,10 +2084,10 @@ def get_ansyscloud_job_info(self, job_id=None, job_name=None): # pragma: no cov elif job_id: command = [command, "jobinfo", "-i", job_id] cloud_info = os.path.join(tempfile.gettempdir(), generate_unique_name("job_info")) - with open(cloud_info, "w") as outfile: + with open_file(cloud_info, "w") as outfile: subprocess.Popen(" ".join(command), stdout=outfile).wait() out = {} - with open(cloud_info, "r") as infile: + with open_file(cloud_info, "r") as infile: lines = infile.readlines() for i in lines: if ":" in i.strip(): @@ -2190,11 +2190,11 @@ def get_available_cloud_config(self, region="westeurope"): # pragma: no cover ver = self.aedt_version_id.replace(".", "R") command = [command, "getQueues", "-p", "AEDT", "-v", ver, "--details"] cloud_info = os.path.join(tempfile.gettempdir(), generate_unique_name("cloud_info")) - with open(cloud_info, "w") as outfile: + with open_file(cloud_info, "w") as outfile: subprocess.Popen(" ".join(command), stdout=outfile).wait() dict_out = {} - with open(cloud_info, "r") as infile: + with open_file(cloud_info, "r") as infile: lines = infile.readlines() for i in range(len(lines)): line = lines[i].strip() diff --git a/pyaedt/generic/com_parameters.py b/pyaedt/generic/com_parameters.py index 91d65d2601c..29ffa4443f7 100644 --- a/pyaedt/generic/com_parameters.py +++ b/pyaedt/generic/com_parameters.py @@ -2,6 +2,7 @@ from pyaedt import pyaedt_function_handler from pyaedt import settings +from pyaedt.generic.general_methods import open_file logger = settings.logger @@ -50,7 +51,7 @@ def load(self, file_path): bool """ self._standard = "custom" - with open(file_path, "r") as fp: + with open_file(file_path, "r") as fp: lines = fp.readlines() for line in lines: if not line.startswith("#") and "=" in line: @@ -72,7 +73,7 @@ def export(self, file_path): ------- bool """ - with open(file_path, "w") as fp: + with open_file(file_path, "w") as fp: fp.write("################################################################################\n") fp.write("# MODULE: COM\n") fp.write("# GENERATED ON\n") diff --git a/pyaedt/generic/configurations.py b/pyaedt/generic/configurations.py index c4be7a23379..0be1f3099f7 100644 --- a/pyaedt/generic/configurations.py +++ b/pyaedt/generic/configurations.py @@ -15,6 +15,7 @@ from pyaedt.generic.DataHandlers import _arg2dict from pyaedt.generic.LoadAEDTFile import load_keyword_in_aedt_file from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_configuration_file from pyaedt.generic.general_methods import write_configuration_file @@ -1213,7 +1214,7 @@ def _export_general(self, dict_out): if list(self._app.output_variables): oo_out = os.path.join(tempfile.gettempdir(), generate_unique_name("oo") + ".txt") self._app.ooutput_variable.ExportOutputVariables(oo_out) - with open(oo_out, "r") as f: + with open_file(oo_out, "r") as f: lines = f.readlines() for line in lines: line_split = line.split(" ") diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index 547b118c354..55281a2c470 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -283,13 +283,16 @@ def check_numeric_equivalence(a, b, relative_tolerance=1e-7): @pyaedt_function_handler() -def check_and_download_file(local_path, remote_path, overwrite=True): +def _check_path(path_to_check): + return path_to_check.replace("\\", "/") if path_to_check[0] != "\\" else path_to_check + + +@pyaedt_function_handler() +def check_and_download_file(remote_path, overwrite=True): """Check if a file is remote and either download it or return the path. Parameters ---------- - local_path : str - Local path to save the file to. remote_path : str Path to the remote file. overwrite : bool, optional @@ -301,9 +304,11 @@ def check_and_download_file(local_path, remote_path, overwrite=True): str """ if settings.remote_rpc_session: - remote_path = remote_path.replace("\\", "/") if remote_path[0] != "\\" else remote_path - settings.remote_rpc_session.filemanager.download_file(remote_path, local_path, overwrite=overwrite) - return local_path + remote_path = _check_path(remote_path) + local_path = os.path.join(settings.remote_rpc_session_temp_folder, os.path.split(remote_path)[-1]) + if settings.remote_rpc_session.filemanager.pathexists(remote_path): + settings.remote_rpc_session.filemanager.download_file(remote_path, local_path, overwrite=overwrite) + return local_path return remote_path @@ -423,7 +428,7 @@ def read_json(fn): dict """ json_data = {} - with open(fn) as json_file: + with open_file(fn) as json_file: try: json_data = json.load(json_file) except json.JSONDecodeError as e: # pragma: no cover @@ -841,6 +846,11 @@ def is_project_locked(project_path): bool ``True`` when successful, ``False`` when failed. """ + if settings.remote_rpc_session: + if settings.remote_rpc_session.filemanager.pathexists(project_path + ".lock"): + return True + else: + return False return check_if_path_exists(project_path + ".lock") @@ -861,6 +871,9 @@ def remove_project_lock(project_path): bool ``True`` when successful, ``False`` when failed. """ + if settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists(project_path + ".lock"): + settings.remote_rpc_session.filemanager.unlink(project_path + ".lock") + return True if os.path.exists(project_path + ".lock"): os.remove(project_path + ".lock") return True @@ -882,6 +895,7 @@ def read_csv(filename, encoding="utf-8"): list """ + filename = check_and_download_file(filename) lines = [] with codecs.open(filename, "rb", encoding) as csvfile: @@ -907,6 +921,7 @@ def read_csv_pandas(filename, encoding="utf-8"): :class:`pandas.DataFrame` """ + filename = check_and_download_file(filename) try: import pandas as pd @@ -949,6 +964,7 @@ def read_xlsx(filename): list """ + filename = check_and_download_file(filename) try: import pandas as pd @@ -1113,17 +1129,17 @@ def _create_json_file(json_dict, full_json_path): if not os.path.exists(os.path.dirname(full_json_path)): os.makedirs(os.path.dirname(full_json_path)) if not is_ironpython: - with open(full_json_path, "w") as fp: + with open_file(full_json_path, "w") as fp: json.dump(json_dict, fp, indent=4) else: temp_path = full_json_path.replace(".json", "_temp.json") - with open(temp_path, "w") as fp: + with open_file(temp_path, "w") as fp: json.dump(json_dict, fp, indent=4) - with open(temp_path, "r") as file: + with open_file(temp_path, "r") as file: filedata = file.read() filedata = filedata.replace("True", "true") filedata = filedata.replace("False", "false") - with open(full_json_path, "w") as file: + with open_file(full_json_path, "w") as file: file.write(filedata) os.remove(temp_path) return True @@ -1611,7 +1627,7 @@ def tech_to_control_file(tech_path, unit="nm", control_path=None): Out xml file. """ result = [] - with open(tech_path) as f: + with open_file(tech_path) as f: vals = list(CSS4_COLORS.values()) id_layer = 0 for line in f: @@ -1632,7 +1648,7 @@ def tech_to_control_file(tech_path, unit="nm", control_path=None): unit = line_split[1] if not control_path: control_path = os.path.splitext(tech_path)[0] + ".xml" - with open(control_path, "w") as f: + with open_file(control_path, "w") as f: f.write('\n') f.write(' \n') f.write("\n") @@ -1939,7 +1955,7 @@ def _check_installed_version(install_path, long_version): product_list_path = os.path.join(install_path, "config", "ProductList.txt") if os.path.isfile(product_list_path): try: - with open(product_list_path, "r") as f: + with open_file(product_list_path, "r") as f: install_version = f.readline().strip()[-6:] if install_version == long_version: return True diff --git a/pyaedt/generic/ibis_reader.py b/pyaedt/generic/ibis_reader.py index 36c7130a99f..5a7cde33e33 100644 --- a/pyaedt/generic/ibis_reader.py +++ b/pyaedt/generic/ibis_reader.py @@ -7,7 +7,7 @@ from pyaedt.aedt_logger import pyaedt_logger as logger from pyaedt.generic.general_methods import check_and_download_file from pyaedt.generic.general_methods import check_if_path_exists -from pyaedt.generic.settings import settings +from pyaedt.generic.general_methods import open_file class Component: @@ -620,11 +620,8 @@ def parse_ibis_file(self): ibis_name = pyaedt.generic.general_methods.get_filename_without_extension(self._filename) ibis = Ibis(ibis_name, self._circuit) - if settings.remote_rpc_session_temp_folder: - local_path = os.path.join(settings.remote_rpc_session_temp_folder, os.path.split(self._filename)[-1]) - file_to_open = check_and_download_file(local_path, self._filename) - else: - file_to_open = self._filename + + file_to_open = check_and_download_file(self._filename) # Read *.ibis file. ibis_info = ibis_parsing(self._filename) @@ -983,11 +980,7 @@ def parse_ibis_file(self): ami_name = pyaedt.generic.general_methods.get_filename_without_extension(self._filename) ibis = AMI(ami_name, self._circuit) - if settings.remote_rpc_session_temp_folder: - local_path = os.path.join(settings.remote_rpc_session_temp_folder, os.path.split(self._filename)[-1]) - file_to_open = check_and_download_file(local_path, self._filename) - else: - file_to_open = self._filename + file_to_open = check_and_download_file(self._filename) # Read *.ibis file. ibis_info = ibis_parsing(self._filename) @@ -1100,10 +1093,10 @@ def ibis_parsing(file): """ ibis = {} # OPEN AND READ IBIS FILE - with open(file, "r") as fp: + with open_file(file, "r") as fp: ibis_data = list(enumerate(fp)) - with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "ibis_v7.json"), "r") as f: + with open_file(os.path.join(os.path.dirname(os.path.abspath(__file__)), "ibis_v7.json"), "r") as f: ibis_ref = json.load(f) ibis_ref = lowercase_json(ibis_ref) diff --git a/pyaedt/generic/pdf.py b/pyaedt/generic/pdf.py index 9c067177a3b..fdf8b76bfb4 100644 --- a/pyaedt/generic/pdf.py +++ b/pyaedt/generic/pdf.py @@ -8,6 +8,7 @@ from pyaedt import __version__ from pyaedt.generic.constants import unit_converter +from pyaedt.generic.general_methods import open_file @dataclass @@ -77,7 +78,7 @@ def read_template(self, template_file): if template_file: self.report_specs.template_name = template_file if os.path.exists(self.report_specs.template_name): - with open(self.report_specs.template_name, "r") as f: + with open_file(self.report_specs.template_name, "r") as f: tdata = json.load(f) self.report_specs = ReportSpec(**tdata) diff --git a/pyaedt/generic/spisim.py b/pyaedt/generic/spisim.py index 81749b36c3e..70b00c904f3 100644 --- a/pyaedt/generic/spisim.py +++ b/pyaedt/generic/spisim.py @@ -15,6 +15,7 @@ from pyaedt import settings from pyaedt.generic.com_parameters import COMParameters from pyaedt.generic.general_methods import env_value +from pyaedt.generic.general_methods import open_file from pyaedt.misc import current_version @@ -68,10 +69,10 @@ def _compute_spisim(self, parameter, out_file="", touchstone_file="", config_fil my_env.update(settings.aedt_environment_variables) if is_linux: # pragma: no cover command.append("&") - with open(out_processing, "w") as outfile: + with open_file(out_processing, "w") as outfile: subprocess.Popen(command, env=my_env, stdout=outfile, stderr=outfile).wait() # nosec else: - with open(out_processing, "w") as outfile: + with open_file(out_processing, "w") as outfile: subprocess.Popen(" ".join(command), env=my_env, stdout=outfile, stderr=outfile).wait() # nosec return out_processing @@ -79,7 +80,7 @@ def _compute_spisim(self, parameter, out_file="", touchstone_file="", config_fil def _get_output_parameter_from_result(self, out_file, parameter_name): if parameter_name == "ERL": try: - with open(out_file, "r") as infile: + with open_file(out_file, "r") as infile: lines = infile.read() parmDat = lines.split("[ParmDat]:", 1)[1] for keyValu in parmDat.split(","): @@ -95,7 +96,7 @@ def _get_output_parameter_from_result(self, out_file, parameter_name): return False elif parameter_name == "COM": try: - with open(out_file, "r") as infile: + with open_file(out_file, "r") as infile: txt = infile.read() com_case_0 = re.search(r"Case 0: Calculated COM = (.*?),", txt).groups()[0] com_case_1 = re.search(r"Case 1: Calculated COM = (.*?),", txt).groups()[0] @@ -186,7 +187,7 @@ def compute_erl( "NCYCLES": 1000, } if config_file: - with open(config_file, "r") as fp: + with open_file(config_file, "r") as fp: lines = fp.readlines() for line in lines: if not line.startswith("#") and "=" in line: @@ -228,7 +229,7 @@ def compute_erl( cfg_dict["NCYCLES"] = reflections_length if reflections_length is not None else cfg_dict["NCYCLES"] new_cfg_file = os.path.join(self.working_directory, "spisim_erl.cfg").replace("\\", "/") - with open(new_cfg_file, "w") as fp: + with open_file(new_cfg_file, "w") as fp: for k, v in cfg_dict.items(): fp.write("# {}: {}\n".format(k, k)) fp.write("{} = {}\n".format(k, v)) @@ -354,7 +355,7 @@ def detect_encoding(file_path, expected_pattern="", re_flags=0): """Check encoding of a file.""" for encoding in ("utf-8", "utf_16_le", "cp1252", "cp1250", "shift_jis"): try: - with open(file_path, "r", encoding=encoding) as f: + with open_file(file_path, "r", encoding=encoding) as f: lines = f.read() f.seek(0) except UnicodeDecodeError: diff --git a/pyaedt/maxwell.py b/pyaedt/maxwell.py index 625d3e12535..77074ea0d78 100644 --- a/pyaedt/maxwell.py +++ b/pyaedt/maxwell.py @@ -11,6 +11,7 @@ from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import SOLUTIONS from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_configuration_file from pyaedt.generic.general_methods import write_configuration_file @@ -460,9 +461,9 @@ def setup_ctrlprog( source_dir = self.pyaedt_dir if os.path.exists(ctl_file_path) and keep_modifications: - with open(ctl_file_path, "r") as fi: + with open_file(ctl_file_path, "r") as fi: existing_data = fi.readlines() - with open(ctl_file_path, "w") as fo: + with open_file(ctl_file_path, "w") as fo: first_line = True for line in existing_data: if first_line: diff --git a/pyaedt/modeler/cad/Primitives3D.py b/pyaedt/modeler/cad/Primitives3D.py index e5a1b782ab0..ecbd8960d11 100644 --- a/pyaedt/modeler/cad/Primitives3D.py +++ b/pyaedt/modeler/cad/Primitives3D.py @@ -1517,7 +1517,7 @@ def insert_3d_component( self._app.configurations.options.import_native_components = True self._app.configurations.options.import_monitor = True temp_dict_file = os.path.join(self._app.toolkit_directory, generate_unique_name("tempdict_")) - with open(temp_dict_file, "w") as f: + with open_file(temp_dict_file, "w") as f: json.dump(temp_dict, f) exclude_set = set([obj.name for _, obj in self._app.modeler.objects.items()]) old_udm = set(list(self._app.modeler.user_defined_components)) diff --git a/pyaedt/modeler/modeler3d.py b/pyaedt/modeler/modeler3d.py index 51998af0d7e..951a98fb73e 100644 --- a/pyaedt/modeler/modeler3d.py +++ b/pyaedt/modeler/modeler3d.py @@ -9,6 +9,7 @@ from pyaedt.application.Variables import generate_validation_errors from pyaedt.generic.general_methods import GrpcApiError from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.Primitives3D import Primitives3D from pyaedt.modeler.geometry_operators import GeometryOperators @@ -332,7 +333,7 @@ def create_3dcomponent( datasets.update(self._app.design_datasets) if native_components is None: native_components = self._app.native_components - with open(configfile) as f: + with open_file(configfile) as f: config_dict = json.load(f) out_dict = {} if monitor_objects: @@ -372,7 +373,7 @@ def create_3dcomponent( for cs in list(out_dict["coordinatesystems"]): if cs not in cs_set: del out_dict["coordinatesystems"][cs] - with open(auxiliary_dict, "w") as outfile: + with open_file(auxiliary_dict, "w") as outfile: json.dump(out_dict, outfile) if not os.path.isdir(os.path.dirname(component_file)): self.logger.warning("Folder '" + os.path.dirname(component_file) + "' doesn't exist.") @@ -902,7 +903,7 @@ def import_nastran(self, file_path, import_lines=True, lines_thickness=0, import self.logger.reset_timer() self.logger.info("Loading file") - with open(file_path, "r") as f: + with open_file(file_path, "r") as f: lines = f.read().splitlines() id = 0 for lk in range(len(lines)): @@ -1242,7 +1243,7 @@ def import_from_openstreet_map( "parts": parts_dict, } - with open(json_path, "w", encoding="utf-8") as f: + with open_file(json_path, "w", encoding="utf-8") as f: json.dump(scene, f, indent=4) self.logger.info("Done...") diff --git a/pyaedt/modules/CableModeling.py b/pyaedt/modules/CableModeling.py index 9ed69a2ae1a..5d8cb3f1ab4 100644 --- a/pyaedt/modules/CableModeling.py +++ b/pyaedt/modules/CableModeling.py @@ -5,6 +5,7 @@ from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import read_configuration_file @@ -1409,6 +1410,6 @@ def _cable_properties_parser(self, omodule, working_dir): omodule.ExportCableLibrary(file_path_export) file_path_export_as_json = os.path.join(working_dir, "export_cable_library_as_json_test.json") data = load_entire_aedt_file(file_path_export) - with open(file_path_export_as_json, "w") as f: + with open_file(file_path_export_as_json, "w") as f: json.dump(data, f) return data diff --git a/pyaedt/modules/DesignXPloration.py b/pyaedt/modules/DesignXPloration.py index 86036445c82..5c7ae6c1e85 100644 --- a/pyaedt/modules/DesignXPloration.py +++ b/pyaedt/modules/DesignXPloration.py @@ -6,6 +6,7 @@ from pyaedt.generic.DataHandlers import _dict2arg from pyaedt.generic.general_methods import PropsManager from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modules.OptimetricsTemplates import defaultdoeSetup from pyaedt.modules.OptimetricsTemplates import defaultdxSetup @@ -1218,7 +1219,7 @@ def add_from_file(self, filename, parametricname=None): setup = SetupParam(self._app, parametricname, optim_type="OptiParametric") setup.auto_update = False setup.props["Sim. Setups"] = [setup_defined.name for setup_defined in self._app.setups] - with open(filename, "r") as csvfile: + with open_file(filename, "r") as csvfile: csvreader = csv.DictReader(csvfile) first_data_line = next(csvreader) setup.props["Sweeps"] = {"SweepDefinition": OrderedDict()} diff --git a/pyaedt/modules/PostProcessor.py b/pyaedt/modules/PostProcessor.py index 78cb34f82f0..97a3e270bf4 100644 --- a/pyaedt/modules/PostProcessor.py +++ b/pyaedt/modules/PostProcessor.py @@ -2810,10 +2810,8 @@ def export_field_plot(self, plotname, filepath, filename="", file_format="aedtpl self.ofieldsreporter.ExportFieldPlot(plotname, False, file_path) else: # pragma: no cover self.ofieldsreporter.ExportFieldPlot(plotname, False, file_path) - if settings.remote_rpc_session_temp_folder: - local_path = os.path.join(settings.remote_rpc_session_temp_folder, filename + "." + file_format) - file_path = check_and_download_file(local_path, file_path) - return file_path + + return check_and_download_file(file_path) @pyaedt_function_handler() def change_field_plot_scale(self, plot_name, minimum_value, maximum_value, is_log=False, is_db=False): @@ -3718,9 +3716,8 @@ def export_model_obj(self, obj_list=None, export_path=None, export_as_single_obj for el in obj_list: fname = os.path.join(export_path, "{}.obj".format(el)) self._app.modeler.oeditor.ExportModelMeshToFile(fname, [el]) - if settings.remote_rpc_session_temp_folder: - local_path = "{}/{}".format(settings.remote_rpc_session_temp_folder, "{}.obj".format(el)) - fname = check_and_download_file(local_path, fname) + + fname = check_and_download_file(fname) if not self._app.modeler[el].display_wireframe: transp = 0.6 @@ -4994,7 +4991,7 @@ def get_field_summary_data(self, sweep_name=None, design_variation={}, intrinsic with tempfile.NamedTemporaryFile(mode="w+", delete=False) as temp_file: temp_file.close() self.export_csv(temp_file.name, sweep_name, design_variation, intrinsic_value) - with open(temp_file.name, "r") as f: + with open_file(temp_file.name, "r") as f: for _ in range(4): _ = next(f) reader = csv.DictReader(f) @@ -5124,7 +5121,7 @@ def get_fans_operating_point(self, export_file=None, setup_name=None, timestep=N timestep, ] ) - with open(export_file, "r") as f: + with open_file(export_file, "r") as f: reader = csv.reader(f) for line in reader: if "Fan Instances" in line: diff --git a/pyaedt/modules/solutions.py b/pyaedt/modules/solutions.py index e718206d0d1..4fea7a6eddf 100644 --- a/pyaedt/modules/solutions.py +++ b/pyaedt/modules/solutions.py @@ -15,6 +15,7 @@ from pyaedt.generic.constants import db10 from pyaedt.generic.constants import db20 from pyaedt.generic.constants import unit_converter +from pyaedt.generic.general_methods import check_and_download_file from pyaedt.generic.general_methods import check_and_download_folder from pyaedt.generic.general_methods import conversion_function from pyaedt.generic.general_methods import open_file @@ -1158,7 +1159,7 @@ def __init__( for eep in eep_files: metadata_file = os.path.join(os.path.dirname(eep), "eep.json") if os.path.exists(metadata_file): - with open(metadata_file) as f: + with open_file(metadata_file) as f: # Load JSON data from file metadata = json.load(f) self.model_info.append(metadata["model_info"]) @@ -2108,7 +2109,7 @@ def _init_ffd(self, eep_file_info): valid_ffd = True if os.path.exists(eep_file_info[all_ports[0]][0]): - with open(eep_file_info[all_ports[0]][0], "r") as reader: + with open_file(eep_file_info[all_ports[0]][0], "r") as reader: theta = [int(i) for i in reader.readline().split()] phi = [int(i) for i in reader.readline().split()] reader.close() @@ -2202,7 +2203,7 @@ def _read_eep_files(self, eep_path): """ self._eep_file_info_list.append({}) if os.path.exists(eep_path): - with open(eep_path, "r") as reader: + with open_file(eep_path, "r") as reader: lines = [line.split(None) for line in reader] lines = lines[1:] # remove header for pattern in lines: @@ -2529,7 +2530,7 @@ def _export_all_ffd(self): ] items["lattice_vector"] = component_array.lattice_vector() - with open(metadata_file_name, "w") as f: + with open_file(metadata_file_name, "w") as f: json.dump(items, f, indent=2) elapsed_time = time.time() - time_before self._app.logger.info("Exporting embedded element patterns.... Done: %s seconds", elapsed_time) @@ -3264,6 +3265,7 @@ def export_image(self, full_path=None, width=1920, height=1080, orientation="iso height=height, display_wireframe=display_wireframe, ) + full_path = check_and_download_file(full_path) if status: return full_path else: diff --git a/pyaedt/rpc/rpyc_services.py b/pyaedt/rpc/rpyc_services.py index c48d3932972..80d9e1319bf 100644 --- a/pyaedt/rpc/rpyc_services.py +++ b/pyaedt/rpc/rpyc_services.py @@ -172,6 +172,10 @@ def pathexists(self, remotepath): if self.client.root.pathexists(remotepath): return True return False + def unlink(self, remotepath): + if self.client.root.unlink(remotepath): + return True + return False def normpath(self, remotepath): return self.client.root.normpath(remotepath) def isdir(self, remotepath): @@ -1055,6 +1059,12 @@ def exposed_pathexists(remotepath): return True return False + @staticmethod + def exposed_unlink(remotepath): + if os.unlink(remotepath): + return True + return False + @staticmethod def exposed_isdir(remotepath): return os.path.isdir(remotepath) diff --git a/pyaedt/twinbuilder.py b/pyaedt/twinbuilder.py index c91471da399..bb52a3085f5 100644 --- a/pyaedt/twinbuilder.py +++ b/pyaedt/twinbuilder.py @@ -10,6 +10,7 @@ from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.general_methods import generate_unique_name from pyaedt.generic.general_methods import is_number +from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler @@ -154,7 +155,7 @@ def create_schematic_from_netlist(self, file_to_import): ypos = 0 delta = 0.0508 use_instance = True - with open(file_to_import, "r") as f: + with open_file(file_to_import, "r") as f: for line in f: mycomp = None fields = line.split(" ") From 1c66915d5ebd232bb8339cf6175868febd76ef98 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Fri, 23 Feb 2024 13:30:08 +0100 Subject: [PATCH 02/16] Fix Codacy --- pyaedt/generic/general_methods.py | 12 ++++++++---- pyaedt/generic/ibis_reader.py | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index 55281a2c470..a4c22f7dfd8 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -354,7 +354,7 @@ def check_and_download_folder(local_path, remote_path, overwrite=True): return remote_path -def open_file(file_path, file_options="r"): +def open_file(file_path, file_options="r", encoding=None): """Open a file and return the object. Parameters @@ -363,6 +363,10 @@ def open_file(file_path, file_options="r"): Full absolute path to the file (either local or remote). file_options : str, optional Options for opening the file. + encoding : str, optional + Name of the encoding used to decode or encode the file. + The default used is platform dependent, but any encoding supported by Python can be + passed. Returns ------- @@ -373,15 +377,15 @@ def open_file(file_path, file_options="r"): dir_name = os.path.dirname(file_path) if "r" in file_options: if os.path.exists(file_path): - return open(file_path, file_options) + return open(file_path, file_options, encoding) elif settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists( file_path ): # pragma: no cover local_file = os.path.join(tempfile.gettempdir(), os.path.split(file_path)[-1]) settings.remote_rpc_session.filemanager.download_file(file_path, local_file) - return open(local_file, file_options) + return open(local_file, file_options, encoding) elif os.path.exists(dir_name): - return open(file_path, file_options) + return open(file_path, file_options, encoding) elif settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists(dir_name): return settings.remote_rpc_session.open_file(file_path, file_options) else: diff --git a/pyaedt/generic/ibis_reader.py b/pyaedt/generic/ibis_reader.py index 5a7cde33e33..f557cb9713a 100644 --- a/pyaedt/generic/ibis_reader.py +++ b/pyaedt/generic/ibis_reader.py @@ -621,7 +621,7 @@ def parse_ibis_file(self): ibis_name = pyaedt.generic.general_methods.get_filename_without_extension(self._filename) ibis = Ibis(ibis_name, self._circuit) - file_to_open = check_and_download_file(self._filename) + check_and_download_file(self._filename) # Read *.ibis file. ibis_info = ibis_parsing(self._filename) @@ -980,7 +980,7 @@ def parse_ibis_file(self): ami_name = pyaedt.generic.general_methods.get_filename_without_extension(self._filename) ibis = AMI(ami_name, self._circuit) - file_to_open = check_and_download_file(self._filename) + check_and_download_file(self._filename) # Read *.ibis file. ibis_info = ibis_parsing(self._filename) From bcff48b3394b50eb0402dc86bc7c9343075ea599 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Fri, 23 Feb 2024 15:08:27 +0100 Subject: [PATCH 03/16] added encoding option to open_file method --- pyaedt/generic/general_methods.py | 17 ++++++++++++----- pyaedt/rpc/rpyc_services.py | 18 +++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index a4c22f7dfd8..91abc29dacd 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -354,7 +354,7 @@ def check_and_download_folder(local_path, remote_path, overwrite=True): return remote_path -def open_file(file_path, file_options="r", encoding=None): +def open_file(file_path, file_options="r", encoding=None, override_existing=True): """Open a file and return the object. Parameters @@ -367,6 +367,8 @@ def open_file(file_path, file_options="r", encoding=None): Name of the encoding used to decode or encode the file. The default used is platform dependent, but any encoding supported by Python can be passed. + override_existing : bool, optional + Whether if override existing file in case of open file in write mode on remote machine. Returns ------- @@ -377,17 +379,22 @@ def open_file(file_path, file_options="r", encoding=None): dir_name = os.path.dirname(file_path) if "r" in file_options: if os.path.exists(file_path): - return open(file_path, file_options, encoding) + return open(file_path, file_options, encoding=encoding) elif settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists( file_path ): # pragma: no cover local_file = os.path.join(tempfile.gettempdir(), os.path.split(file_path)[-1]) settings.remote_rpc_session.filemanager.download_file(file_path, local_file) - return open(local_file, file_options, encoding) + return open(local_file, file_options, encoding=encoding) elif os.path.exists(dir_name): - return open(file_path, file_options, encoding) + return open(file_path, file_options, encoding=encoding) elif settings.remote_rpc_session and settings.remote_rpc_session.filemanager.pathexists(dir_name): - return settings.remote_rpc_session.open_file(file_path, file_options) + if "w" in file_options: + return settings.remote_rpc_session.create_file( + file_path, file_options, encoding=encoding, override=override_existing + ) + else: + return settings.remote_rpc_session.open_file(file_path, file_options, encoding=encoding) else: settings.logger.error("The file or folder %s does not exist", dir_name) diff --git a/pyaedt/rpc/rpyc_services.py b/pyaedt/rpc/rpyc_services.py index 80d9e1319bf..de92c7c33dc 100644 --- a/pyaedt/rpc/rpyc_services.py +++ b/pyaedt/rpc/rpyc_services.py @@ -147,11 +147,11 @@ def _download_dir(self, remotepath, localpath, overwrite=True): i += 1 logger.info("Directory %s downloaded. %s files copied", localpath, i) - def open_file(self, remote_file, open_options="r"): - return self.client.root.open(remote_file, open_options=open_options) + def open_file(self, remote_file, open_options="r", encoding=None): + return self.client.root.open(remote_file, open_options=open_options, encoding=encoding) - def create_file(self, remote_file, create_options="w"): - return self.client.root.open(remote_file, open_options=create_options) + def create_file(self, remote_file, create_options="w", encoding=None, override=True): + return self.client.root.create(remote_file, open_options=create_options, encoding=encoding, override=override) def makedirs(self, remotepath): if self.client.root.pathexists(remotepath): @@ -1029,15 +1029,15 @@ def edb(edbpath=None, use_ppe=use_ppe, ) @staticmethod - def exposed_open(filename, open_options="rb"): - f = open(filename, open_options) + def exposed_open(filename, open_options="rb", encoding=None): + f = open(filename, open_options, encoding=encoding) return rpyc.restricted(f, ["read", "readlines", "close"], []) @staticmethod - def exposed_create(filename,create_options="wb"): - if os.path.exists(filename): + def exposed_create(filename,create_options="wb", encoding=None, override=True): + if os.path.exists(filename) and not override: return "File already exists" - f = open(filename, create_options) + f = open(filename, create_options, encoding=encoding) return rpyc.restricted(f, ["read", "readlines", "write", "writelines", "close"], []) @staticmethod From fa98a8a0d65dc66fc8f9fed77a9fe06c5ae7e40c Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Fri, 23 Feb 2024 15:55:54 +0100 Subject: [PATCH 04/16] added encoding option to open_file method --- pyaedt/common_rpc.py | 11 +++++++---- pyaedt/generic/general_methods.py | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index 0c33c06f684..7d8c1212571 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -120,7 +120,9 @@ def pyaedt_service_manager(port=17878, aedt_version=None, student_version=False): - """Starts an RPyC server on CPython and listens on a specified port. + """Starts PyAEDT service manager using RPyC server on CPython and listens on a specified port. + This method is used as a service on the server machine to listen on a dedicated port for inbound requests + to launch new server connection and launch Ansys Electronics Desktop. This method must run on a server machine. @@ -253,7 +255,7 @@ def launch_server(port=18000, ansysem_path=None, non_graphical=False, threaded=T def create_session(server_name, client_port=None, launch_aedt_on_server=False, aedt_port=None, non_graphical=True): """ - Connect to an existing AEDT server session. + Connect to an existing AEDT server session and connect to it. Parameters ---------- @@ -267,9 +269,10 @@ def create_session(server_name, client_port=None, launch_aedt_on_server=False, a Aedt Grpc port on server. non_graphical : bool, optional Aedt Non Graphical Flag. + Returns ------- - RPyC object. + RPyC client object. """ try: client = rpyc.connect( @@ -315,7 +318,7 @@ def connect(server_name, aedt_client_port): Returns ------- - RPyC object. + RPyC client object. """ try: client = rpyc.connect( diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index 91abc29dacd..2c315ef75ef 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -375,7 +375,9 @@ def open_file(file_path, file_options="r", encoding=None, override_existing=True object Opened file. """ + file_path = str(file_path) file_path = file_path.replace("\\", "/") if file_path[0] != "\\" else file_path + dir_name = os.path.dirname(file_path) if "r" in file_options: if os.path.exists(file_path): From b9af30a0d572e0caba2a2f41c7086306daf1cd03 Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:27:02 +0100 Subject: [PATCH 05/16] Update pyaedt/common_rpc.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/common_rpc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index 7d8c1212571..6c483fbf8b2 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -121,10 +121,10 @@ def pyaedt_service_manager(port=17878, aedt_version=None, student_version=False): """Starts PyAEDT service manager using RPyC server on CPython and listens on a specified port. - This method is used as a service on the server machine to listen on a dedicated port for inbound requests - to launch new server connection and launch Ansys Electronics Desktop. - - This method must run on a server machine. + + This method, which must run on a server machine, is used as a service on the + server machine to listen on a dedicated port for inbound requests to launch + a new server connection and launch AEDT. Parameters ---------- From 3337dd4f4540ef3d134efb4f09c3939e5b5a34cb Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:27:08 +0100 Subject: [PATCH 06/16] Update pyaedt/generic/general_methods.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/generic/general_methods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index 2c315ef75ef..e56c6bbe703 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -365,8 +365,8 @@ def open_file(file_path, file_options="r", encoding=None, override_existing=True Options for opening the file. encoding : str, optional Name of the encoding used to decode or encode the file. - The default used is platform dependent, but any encoding supported by Python can be - passed. + The default is ``None``, which means a platform-dependent encoding is used. You can + specify any encoding supported by Python. override_existing : bool, optional Whether if override existing file in case of open file in write mode on remote machine. From 7a5245e65da20cc3751576a9dd00e19d3b5f3dfe Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:27:14 +0100 Subject: [PATCH 07/16] Update pyaedt/generic/general_methods.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/generic/general_methods.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index e56c6bbe703..2e025529f09 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -368,7 +368,8 @@ def open_file(file_path, file_options="r", encoding=None, override_existing=True The default is ``None``, which means a platform-dependent encoding is used. You can specify any encoding supported by Python. override_existing : bool, optional - Whether if override existing file in case of open file in write mode on remote machine. + Whether to override an existing file if opening a file in write mode on a remote + machine. The default is ``True``. Returns ------- From b296a1ceaac5db4438d761c0b709272e3aebd912 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 06:34:02 +0000 Subject: [PATCH 08/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyaedt/common_rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index 575ef398810..a3338d4c8c9 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -120,7 +120,7 @@ def pyaedt_service_manager(port=17878, aedt_version=None, student_version=False): """Starts PyAEDT service manager using RPyC server on CPython and listens on a specified port. - + This method, which must run on a server machine, is used as a service on the server machine to listen on a dedicated port for inbound requests to launch a new server connection and launch AEDT. From 31261b328a86ae526365205fadb0add57f933726 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 28 Mar 2024 07:35:50 +0100 Subject: [PATCH 09/16] moved IcepakPostProcessor --- pyaedt/modules/AdvancedPostProcessing.py | 34 +-- pyaedt/modules/PostProcessor.py | 331 ----------------------- 2 files changed, 11 insertions(+), 354 deletions(-) diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index 17c51454c4c..46ac80a5445 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -1026,7 +1026,7 @@ def plot_scene( class IcepakPostProcessor(PostProcessor, object): def __init__(self, app): - PostProcessor.__init__(self, app) + PostProcessorCommon.__init__(self, app) @pyaedt_function_handler() def create_field_summary(self): @@ -1108,7 +1108,7 @@ def get_fans_operating_point(self, export_file=None, setup_name=None, timestep=N timestep, ] ) - with open(export_file, "r") as f: + with open_file(export_file, "r") as f: reader = csv.reader(f) for line in reader: if "Fan Instances" in line: @@ -1120,7 +1120,7 @@ def get_fans_operating_point(self, export_file=None, setup_name=None, timestep=N @pyaedt_function_handler def _parse_field_summary_content(self, fs, setup_name, design_variation, quantity_name): - content = fs.get_field_summary_data(setup_name=setup_name, design_variation=design_variation) + content = fs.get_field_summary_data(sweep_name=setup_name, design_variation=design_variation) pattern = r"\[([^]]*)\]" match = re.search(pattern, content["Quantity"][0]) if match: @@ -1139,7 +1139,7 @@ def evaluate_faces_quantity( quantity_name, side="Default", setup_name=None, - design_variation=None, + design_variation={}, ref_temperature="", ): """Export the field surface output. @@ -1175,17 +1175,11 @@ def evaluate_faces_quantity( >>> oModule.ExportFieldsSummary """ - if design_variation is None: - design_variation = {} - facelist_name = generate_unique_name(quantity_name) - self._app.modeler.create_face_list(faces_list, facelist_name) + name = generate_unique_name(quantity_name) + self._app.modeler.create_face_list(faces_list, name) fs = self.create_field_summary() - fs.add_calculation( - "Object", "Surface", facelist_name, quantity_name, side=side, ref_temperature=ref_temperature - ) - out = self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) - self._app.oeditor.Delete(["NAME:Selections", "Selections:=", facelist_name]) - return out + fs.add_calculation("Object", "Surface", name, quantity_name, side=side, ref_temperature=ref_temperature) + return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) @pyaedt_function_handler() def evaluate_boundary_quantity( @@ -1195,7 +1189,7 @@ def evaluate_boundary_quantity( side="Default", volume=False, setup_name=None, - design_variation=None, + design_variation={}, ref_temperature="", ): """Export the field output on a boundary. @@ -1234,8 +1228,6 @@ def evaluate_boundary_quantity( >>> oModule.ExportFieldsSummary """ - if design_variation is None: - design_variation = {} fs = self.create_field_summary() fs.add_calculation( "Boundary", @@ -1254,7 +1246,7 @@ def evaluate_monitor_quantity( quantity_name, side="Default", setup_name=None, - design_variation=None, + design_variation={}, ref_temperature="", ): """Export monitor field output. @@ -1290,8 +1282,6 @@ def evaluate_monitor_quantity( >>> oModule.ExportFieldsSummary """ - if design_variation is None: - design_variation = {} if settings.aedt_version < "2024.1": raise NotImplementedError("Monitors are not supported in field summary in versions earlier than 2024 R1.") else: # pragma: no cover @@ -1315,7 +1305,7 @@ def evaluate_object_quantity( side="Default", volume=False, setup_name=None, - design_variation=None, + design_variation={}, ref_temperature="", ): """Export the field output on or in an object. @@ -1353,8 +1343,6 @@ def evaluate_object_quantity( >>> oModule.ExportFieldsSummary """ - if design_variation is None: - design_variation = {} fs = self.create_field_summary() fs.add_calculation( "Boundary", diff --git a/pyaedt/modules/PostProcessor.py b/pyaedt/modules/PostProcessor.py index f402b871066..8ca06cb0e2d 100644 --- a/pyaedt/modules/PostProcessor.py +++ b/pyaedt/modules/PostProcessor.py @@ -5213,334 +5213,3 @@ def _create_field_summary(self, setup, variation): arg.append("Calculation:=") arg.append(i) self._app.osolution.EditFieldsSummarySetting(arg) - - -class IcepakPostProcessor(PostProcessor, object): - def __init__(self, app): - PostProcessorCommon.__init__(self, app) - - @pyaedt_function_handler() - def create_field_summary(self): - return FieldSummary(self._app) - - @pyaedt_function_handler() - def get_fans_operating_point(self, export_file=None, setup_name=None, timestep=None, design_variation=None): - """ - Get the operating point of the fans in the design. - - Parameters - ---------- - export_file : str, optional - Name of the file to save the operating point of the fans to. The default is - ``None``, in which case the filename is automatically generated. - setup_name : str, optional - Setup name to determine the operating point of the fans. The default is - ``None``, in which case the first available setup is used. - timestep : str, optional - Time, with units, at which to determine the operating point of the fans. The default - is ``None``, in which case the first available timestep is used. This parameter is - only relevant in transient simulations. - design_variation : str, optional - Design variation to determine the operating point of the fans from. The default is - ``None``, in which case the nominal variation is used. - - Returns - ------- - list - First element of the list is the CSV filename. The second and third elements - are the quantities with units describing the operating point of the fans. - The fourth element is a dictionary with the names of the fan instances - as keys and lists with volumetric flow rates and pressure rise floats associated - with the operating point as values. - - References - ---------- - - >>> oModule.ExportFanOperatingPoint - - Examples - -------- - >>> from pyaedt import Icepak - >>> ipk = Icepak() - >>> ipk.create_fan() - >>> filename, vol_flow_name, p_rise_name, op_dict= ipk.get_fans_operating_point() - """ - - if export_file is None: - path = self._app.temp_directory - base_name = "{}_{}_FanOpPoint".format(self._app.project_name, self._app.design_name) - export_file = os.path.join(path, base_name + ".csv") - while os.path.exists(export_file): - file_name = generate_unique_name(base_name) - export_file = os.path.join(path, file_name + ".csv") - if setup_name is None: - setup_name = "{} : {}".format(self._app.get_setups()[0], self._app.solution_type) - if timestep is None: - timestep = "" - if self._app.solution_type == "Transient": - self._app.logger.warning("No timestep is specified. First timestep is exported.") - else: - if not self._app.solution_type == "Transient": - self._app.logger.warning("Simulation is steady-state. Timestep argument is ignored.") - timestep = "" - if design_variation is None: - design_variation = "" - self._app.osolution.ExportFanOperatingPoint( - [ - "SolutionName:=", - setup_name, - "DesignVariationKey:=", - design_variation, - "ExportFilePath:=", - export_file, - "Overwrite:=", - True, - "TimeStep:=", - timestep, - ] - ) - with open_file(export_file, "r") as f: - reader = csv.reader(f) - for line in reader: - if "Fan Instances" in line: - vol_flow = line[1] - p_rise = line[2] - break - var = {line[0]: [float(line[1]), float(line[2])] for line in reader} - return [export_file, vol_flow, p_rise, var] - - @pyaedt_function_handler - def _parse_field_summary_content(self, fs, setup_name, design_variation, quantity_name): - content = fs.get_field_summary_data(sweep_name=setup_name, design_variation=design_variation) - pattern = r"\[([^]]*)\]" - match = re.search(pattern, content["Quantity"][0]) - if match: - content["Unit"] = [match.group(1)] - else: # pragma: no cover - content["Unit"] = [None] - - if quantity_name in TOTAL_QUANTITIES: - return {i: content[i][0] for i in ["Total", "Unit"]} - return {i: content[i][0] for i in ["Min", "Max", "Mean", "Stdev", "Unit"]} - - @pyaedt_function_handler() - def evaluate_faces_quantity( - self, - faces_list, - quantity_name, - side="Default", - setup_name=None, - design_variation={}, - ref_temperature="", - ): - """Export the field surface output. - - Parameters - ---------- - faces_list : list - List of faces to apply. - quantity_name : str - Name of the quantity to export. - side : str, optional - Which side of the mesh face to use. The default is ``Default``. - Options are ``"Adjacent"``, ``"Combined"``, and ``"Default"``. - setup_name : str, optional - Name of the setup and name of the sweep. For example, ``"IcepakSetup1 : SteatyState"``. - The default is ``None``, in which case the active setup and active sweep are used. - design_variation : dict, optional - Dictionary of parameters defined for the specific setup with values. The default is ``{}``. - ref_temperature: str, optional - Reference temperature to use for heat transfer coefficient computation. The default is ``""``. - - Returns - ------- - dict - Output dictionary, which depending on the quantity chosen, contains one - of these sets of keys: - - - ``"Min"``, ``"Max"``, ``"Mean"``, ``"Stdev"``, and ``"Unit"`` - - ``"Total"`` and ``"Unit"`` - - References - ---------- - - >>> oModule.ExportFieldsSummary - """ - name = generate_unique_name(quantity_name) - self._app.modeler.create_face_list(faces_list, name) - fs = self.create_field_summary() - fs.add_calculation("Object", "Surface", name, quantity_name, side=side, ref_temperature=ref_temperature) - return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) - - @pyaedt_function_handler() - def evaluate_boundary_quantity( - self, - boundary_name, - quantity_name, - side="Default", - volume=False, - setup_name=None, - design_variation={}, - ref_temperature="", - ): - """Export the field output on a boundary. - - Parameters - ---------- - boundary_name : str - Name of boundary to perform the computation on. - quantity_name : str - Name of the quantity to export. - side : str, optional - Side of the mesh face to use. The default is ``"Default"``. - Options are ``"Adjacent"``, ``"Combined"``, and ``"Default"``. - volume : bool, optional - Whether to compute the quantity on the volume or on the surface. - The default is ``False``, in which case the quantity will be evaluated - only on the surface . - setup_name : str, optional - Name of the setup and name of the sweep. For example, ``"IcepakSetup1 : SteatyState"``. - The default is ``None``, in which case the active setup and active sweep are used. - design_variation : dict, optional - Dictionary of parameters defined for the specific setup with values. The default is ``{}``. - ref_temperature: str, optional - Reference temperature to use for heat transfer coefficient computation. The default is ``""``. - - Returns - ------- - dict - Output dictionary, which depending on the quantity chosen, contains one - of these sets of keys: - - ``"Min"``, ``"Max"``, ``"Mean"``, ``"Stdev"``, and ``"Unit"`` - - ``"Total"`` and ``"Unit"`` - - References - ---------- - - >>> oModule.ExportFieldsSummary - """ - fs = self.create_field_summary() - fs.add_calculation( - "Boundary", - ["Surface", "Volume"][int(volume)], - boundary_name, - quantity_name, - side=side, - ref_temperature=ref_temperature, - ) - return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) - - @pyaedt_function_handler() - def evaluate_monitor_quantity( - self, - monitor_name, - quantity_name, - side="Default", - setup_name=None, - design_variation={}, - ref_temperature="", - ): - """Export monitor field output. - - Parameters - ---------- - monitor_name : str - Name of monitor to perform the computation on. - quantity_name : str - Name of the quantity to export. - side : str, optional - Side of the mesh face to use. The default is ``"Default"``. - Options are ``"Adjacent"``, ``"Combined"``, and ``"Default"``. - setup_name : str, optional - Name of the setup and name of the sweep. For example, ``"IcepakSetup1 : SteatyState"``. - The default is ``None``, in which case the active setup and active sweep are used. - design_variation : dict, optional - Dictionary of parameters defined for the specific setup with values. The default is ``{}``. - ref_temperature: str, optional - Reference temperature to use for heat transfer coefficient computation. The default is ``""``. - - Returns - ------- - dict - Output dictionary, which depending on the quantity chosen, contains one - of these sets of keys: - - - ``"Min"``, ``"Max"``, ``"Mean"``, ``"Stdev"``, and ``"Unit"`` - - ``"Total"`` and ``"Unit"`` - - References - ---------- - - >>> oModule.ExportFieldsSummary - """ - if settings.aedt_version < "2024.1": - raise NotImplementedError("Monitors are not supported in field summary in versions earlier than 2024 R1.") - else: # pragma: no cover - if self._app.monitor.face_monitors.get(monitor_name, None): - field_type = "Surface" - elif self._app.monitor.point_monitors.get(monitor_name, None): - field_type = "Volume" - else: - raise AttributeError("Monitor {} is not found in the design.".format(monitor_name)) - fs = self.create_field_summary() - fs.add_calculation( - "Monitor", field_type, monitor_name, quantity_name, side=side, ref_temperature=ref_temperature - ) - return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) - - @pyaedt_function_handler() - def evaluate_object_quantity( - self, - object_name, - quantity_name, - side="Default", - volume=False, - setup_name=None, - design_variation={}, - ref_temperature="", - ): - """Export the field output on or in an object. - - Parameters - ---------- - object_name : str - Name of object to perform the computation on. - quantity_name : str - Name of the quantity to export. - side : str, optional - Side of the mesh face to use. The default is ``"Default"``. - Options are ``"Adjacent"``, ``"Combined"``, and ``"Default"``. - volume : bool, optional - Whether to compute the quantity on the volume or on the surface. The default is ``False``. - setup_name : str, optional - Name of the setup and name of the sweep. For example, ``"IcepakSetup1 : SteatyState"``. - The default is ``None``, in which case the active setup and active sweep are used. - design_variation : dict, optional - Dictionary of parameters defined for the specific setup with values. The default is ``{}``. - ref_temperature: str, optional - Reference temperature to use for heat transfer coefficient computation. The default is ``""``. - - Returns - ------- - dict - Output dictionary, which depending on the quantity chosen, contains one - of these sets of keys: - - - ``"Min"``, ``"Max"``, ``"Mean"``, ``"Stdev"``, and ``"Unit"`` - - ``"Total"`` and ``"Unit"`` - - References - ---------- - - >>> oModule.ExportFieldsSummary - """ - fs = self.create_field_summary() - fs.add_calculation( - "Boundary", - ["Surface", "Volume"][int(volume)], - object_name, - quantity_name, - side=side, - ref_temperature=ref_temperature, - ) - return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) From 2419637303bb340bfa1f730c48f06dd0bb2a81c6 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 4 Apr 2024 13:56:29 +0200 Subject: [PATCH 10/16] fixed test --- pyaedt/modules/AdvancedPostProcessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index 46ac80a5445..9584b22475a 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -1026,7 +1026,7 @@ def plot_scene( class IcepakPostProcessor(PostProcessor, object): def __init__(self, app): - PostProcessorCommon.__init__(self, app) + PostProcessor.__init__(self, app) @pyaedt_function_handler() def create_field_summary(self): From 4bab53c0d06c90b52bc3d84e1bbb7f0e438adc06 Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:57:10 +0200 Subject: [PATCH 11/16] Update pyaedt/common_rpc.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/common_rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index a3338d4c8c9..daf613fab46 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -119,7 +119,7 @@ def pyaedt_service_manager(port=17878, aedt_version=None, student_version=False): - """Starts PyAEDT service manager using RPyC server on CPython and listens on a specified port. + """Starts the PyAEDT service manager using RPyC server on CPython. This method, which must run on a server machine, is used as a service on the server machine to listen on a dedicated port for inbound requests to launch From 76cadc797da12546a507cf6efa03389d884c9bbf Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 4 Apr 2024 13:58:01 +0200 Subject: [PATCH 12/16] fixed test --- pyaedt/common_rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index a3338d4c8c9..8f3c74e93c0 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -254,7 +254,7 @@ def launch_server(port=18000, ansysem_path=None, non_graphical=False, threaded=T def create_session(server_name, client_port=None, launch_aedt_on_server=False, aedt_port=None, non_graphical=True): """ - Connect to an existing AEDT server session and connect to it. + Connect to an existing AEDT server session and create a new client session from it.. Parameters ---------- From 442499f9c1f0e4c13e9a8831ebd57c8b45141312 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 4 Apr 2024 13:59:21 +0200 Subject: [PATCH 13/16] fixed test --- pyaedt/generic/general_methods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index abd29a4869d..bfb2d0037c7 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -294,7 +294,7 @@ def check_and_download_file(remote_path, overwrite=True): remote_path : str Path to the remote file. overwrite : bool, optional - Whether to overwrite the file if it already exits locally. + Whether to overwrite the file if it already exists locally. The default is ``True``. Returns @@ -338,7 +338,7 @@ def check_and_download_folder(local_path, remote_path, overwrite=True): remote_path : str Path to the remote folder. overwrite : bool, optional - Whether to overwrite the folder if it already exits locally. + Whether to overwrite the folder if it already exists locally. The default is ``True``. Returns From 486eacdd8733bc764d41dfb06b4d104d1e4b36e6 Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 4 Apr 2024 17:25:14 +0200 Subject: [PATCH 14/16] fixed typo --- pyaedt/modules/AdvancedPostProcessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index 9584b22475a..2d696e9a4bf 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -1120,7 +1120,7 @@ def get_fans_operating_point(self, export_file=None, setup_name=None, timestep=N @pyaedt_function_handler def _parse_field_summary_content(self, fs, setup_name, design_variation, quantity_name): - content = fs.get_field_summary_data(sweep_name=setup_name, design_variation=design_variation) + content = fs.get_field_summary_data(setup_name=setup_name, design_variation=design_variation) pattern = r"\[([^]]*)\]" match = re.search(pattern, content["Quantity"][0]) if match: From 73e2323db1454ba74094780b7c4c881df8dcbc5e Mon Sep 17 00:00:00 2001 From: maxcapodi78 Date: Thu, 4 Apr 2024 17:30:21 +0200 Subject: [PATCH 15/16] fixed typo --- pyaedt/modules/AdvancedPostProcessing.py | 28 +++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index 2d696e9a4bf..aaae24b25f5 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -1139,7 +1139,7 @@ def evaluate_faces_quantity( quantity_name, side="Default", setup_name=None, - design_variation={}, + design_variation=None, ref_temperature="", ): """Export the field surface output. @@ -1175,11 +1175,17 @@ def evaluate_faces_quantity( >>> oModule.ExportFieldsSummary """ - name = generate_unique_name(quantity_name) - self._app.modeler.create_face_list(faces_list, name) + if design_variation is None: + design_variation = {} + facelist_name = generate_unique_name(quantity_name) + self._app.modeler.create_face_list(faces_list, facelist_name) fs = self.create_field_summary() - fs.add_calculation("Object", "Surface", name, quantity_name, side=side, ref_temperature=ref_temperature) - return self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) + fs.add_calculation( + "Object", "Surface", facelist_name, quantity_name, side=side, ref_temperature=ref_temperature + ) + out = self._parse_field_summary_content(fs, setup_name, design_variation, quantity_name) + self._app.oeditor.Delete(["NAME:Selections", "Selections:=", facelist_name]) + return out @pyaedt_function_handler() def evaluate_boundary_quantity( @@ -1189,7 +1195,7 @@ def evaluate_boundary_quantity( side="Default", volume=False, setup_name=None, - design_variation={}, + design_variation=None, ref_temperature="", ): """Export the field output on a boundary. @@ -1228,6 +1234,8 @@ def evaluate_boundary_quantity( >>> oModule.ExportFieldsSummary """ + if design_variation is None: + design_variation = {} fs = self.create_field_summary() fs.add_calculation( "Boundary", @@ -1246,7 +1254,7 @@ def evaluate_monitor_quantity( quantity_name, side="Default", setup_name=None, - design_variation={}, + design_variation=None, ref_temperature="", ): """Export monitor field output. @@ -1282,6 +1290,8 @@ def evaluate_monitor_quantity( >>> oModule.ExportFieldsSummary """ + if design_variation is None: + design_variation = {} if settings.aedt_version < "2024.1": raise NotImplementedError("Monitors are not supported in field summary in versions earlier than 2024 R1.") else: # pragma: no cover @@ -1305,7 +1315,7 @@ def evaluate_object_quantity( side="Default", volume=False, setup_name=None, - design_variation={}, + design_variation=None, ref_temperature="", ): """Export the field output on or in an object. @@ -1343,6 +1353,8 @@ def evaluate_object_quantity( >>> oModule.ExportFieldsSummary """ + if design_variation is None: + design_variation = {} fs = self.create_field_summary() fs.add_calculation( "Boundary", From 1edd08949349202c6860f5d4534bbe79677549fa Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:57:45 +0200 Subject: [PATCH 16/16] Update pyaedt/common_rpc.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/common_rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index a0c5092e63d..b53a519c420 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -254,7 +254,7 @@ def launch_server(port=18000, ansysem_path=None, non_graphical=False, threaded=T def create_session(server_name, client_port=None, launch_aedt_on_server=False, aedt_port=None, non_graphical=True): """ - Connect to an existing AEDT server session and create a new client session from it.. + Connect to an existing AEDT server session and create a new client session from it. Parameters ----------