Download of output files

This example shows how to download the output files of design points. We assume you have already completed the Creating A Project tutorial and have the MAPDL Motorbike Frame project at hand.

To begin with, we connect to a DCS server running on the localhost with default username and password and specify the local path where the files are going to be saved.

Warning

Before executing the code, make sure to adjust the download_path variable.

import os
from ansys.dcs.client.dps import Client

# Connect to the DCS server and query the project
client = Client(dcs_url="https://127.0.0.1/dcs", username="dcadmin", password="dcadmin")
proj = client.get_project(id="mapdl_motorbike_frame")

# Specify the base path where to download files
download_path = #e.g. 'C:\\Users\\your_username\\Documents\\mapdl_motorbike_frame\\download'
if not os.path.exists(download_path):
    os.makedirs(download_path)

Log files

We first show how to download the log files. To this end, let’s first get all evaluated and failed design points. Note that we specify the fields query parameter to restrict the returned fields to the ones we actually need for this example.

dps = proj.get_design_points(fields=["id", "files", "eval_status"], eval_status=["evaluated", "failed"])

Also note that each design point holds a list of file IDs linked to it.

print(dps[0].file_ids)
#Output (numbers could be different)
#[6, 7, 8, 36, 1]

For each design point, we now download the content of its file.out log file (which contains the APDL output) and save it to disk.

for dp in dps:

    print(f"Downloading log file of design point {dp.id} ...")
    f = proj.get_files(id=dp.file_ids, evaluation_path="file.out", content=True)[0]

    # If some content is found (it's not the case if the design point fails
    # even before starting the simulation) we save it to disk.
    if f.content:
        path = os.path.join(download_path, f"{f.name}_dp{dp.id}.txt")
        print(f"Saving {f.name} to {path}")
        with open(path, "w") as tf:
            tf.write(f.content.decode('utf-8'))

Note

With the id and evaluation path query parameters in the get_files function we specify that we are only interested in the file.out produced by the current design point. Moreover, by setting content=True we effectively download the file content and not only its metadata.

Images

Similarly, we can download the images associated to the design points. In this example, for each design point we download and save all JPEG images.

for dp in dps:

    print(f"Downloading image files of design point {dp.id} ... ")
    files = proj.get_files(id=dp.file_ids, type="image/jpeg", content=True)

    for f in files:
        if f.content:
            path = os.path.join(download_path, f"{f.name}_dp{dp.id}.jpg")
            print(f"Saving {f.name} to {path}")
            with open(path, "wb") as bf:
                bf.write(f.content)

Parsing of log files

The possibility to download and parse log files can be particularly useful when design point failures need to be investigated. Consider for instance the case where design points are submitted to DPS from a Workbench project. Suppose that unexpected failures are observed for different reasons. For instance, some might be due to parameter values resulting in invalid configurations, others could be related to non-convergence of some intermediate steps, some others could instead be caused by hardware failure.

To systematically investigate such cases, one could for instance download the log files of failed design points and parse the content looking for specific failure indicators.

Downloading the log files goes along the lines of the examples above. Note however the different query parameters used in the get_files function.

import os
from ansys.dcs.client.dps import Client

# Connect to the DCS server and query the project
client = Client(dcs_url="https://127.0.0.1/dcs", username="dcadmin", password="dcadmin")
proj = client.get_project(id="project_id")

# Specify the base path where to download files
download_path = #e.g. 'C:\\Users\\your_username\\Documents\\project_id\\download'
if not os.path.exists(download_path):
    os.makedirs(download_path)

# Get all failed design points
failed_dps = proj.get_design_points(eval_status=['failed'])
print("%d failed design points" % len(failed_dps))

# for each design point, download its workbench log file
for dp in failed_dps:

    print("Downloading log file of design point %d ... " % dp.id)

    query_params = {"id": dp.file_ids, "name.contains": "log_Workbench_Project"}
    f = proj.get_files(**query_params, content=True)[0]

    if f.content:
        path = os.path.join(download_path, f"{f.name}_dp{dp.id}.txt")
        print(f"Saving {f.name} to {path}")
        with open(path, "w") as tf:
            tf.write(f.content.decode('utf-8'))

The actual parsing of the log files could be done for instance by first defining a dictionary of failure strings to look for. These could have been identified by prior knowledge of possible failure reasons or by manually inspecting some of the log files.

failure_dict = [
    {
        "failure_string": "Could not find file",
        "label": "Missing file"
    },
    {
        "failure_string": "no longer available in the geometry",
        "label": "Missing geometry"
    },
    {
        "failure_string": "Can't initialize Addin",
        "label": "Installation"
    },
    {
        "failure_string": "One or more entities failed to mesh",
        "label": "Meshing failure"
    },
    {
        "failure_string": "license",
        "label": "No License"
    }
]

For each design point, we then open the corresponding log file and test whether it contains any failure strings. The results are collected in a pandas dataframe object which can be easily queried or exported in csv or xlsx format.

import pandas
df = pandas.DataFrame(columns=["Id", "Name", "Eval Status", "Elapsed Time", "Failures"])

for dp in failed_dps:
    log_file_path = os.path.join(download_path, "log_Workbench_Project_dp%d.txt" % dp.id)

    errors = set()

    if os.path.exists(log_file_path):
        with open(log_file_path, 'r') as lf:
            content = lf.read()

        errors = set()
        for row in failure_dict:
            if row["failure_string"] in content:
                errors.add(row["label"])

        if not errors:
            errors.add("Unknown")
    else:
        errors.add("Missing Log File")

    df = df.append({
         "Id": dp.id,
         "Name":  dp.name,
         "Eval Status":  dp.eval_status,
         "Elapsed Time":  dp.elapsed_time,
         "Failures": '; '.join(errors)
        }, ignore_index=True)


# Example export to Excel or CSV
df.to_excel(os.path.join(download_path, "failures.xlsx"), index=False) # requires the openpyxl package to be available
df.to_csv(os.path.join(download_path, "failures.csv"), index=False)

The dataframe will look like this

   Id Name Eval Status  Elapsed Time          Failures
0   6    8      failed    137.543538  Missing geometry
1   7    9      failed     86.561933           Unknown
2  10   12      failed    112.935375  Missing geometry; Missing file
3  11   13      failed    138.019429           License
4  18   20      failed    133.204345  Missing geometry
...

By suitably querying the dataframe, one could then easily e.g. set to pending all design points which failed because of a specific reason.

from ansys.dcs.client.dps import DesignPoint

# get the ID of design points which failed because of license issues
ids = df[df["Failures"].str.contains("License")]["Id"].to_list()

dps_of_interest = [DesignPoint(id=id, eval_status="pending") for id in ids]
dps_of_interest = proj.update_design_points(dps_of_interest)