Download this example as a Jupyter notebook or a Python script.


Process phase#

This example shows how to explore the process phase results of a sustainability summary query.

The following supporting files are required for this example:

For help on constructing an XML BoM, see BoM examples.

Info:

This example uses an input file that is in the 24/12 XML BoM format. This structure requires Granta MI Restricted Substances and Sustainability Reports 2025 R2 or later.

To run this example with an older version of the reports bundle, use sustainability-bom-2301.xml instead. Some sections of this example will produce different results from the published example when this BoM is used.

Run a sustainability summary query#

[1]:
from ansys.grantami.bomanalytics import Connection, queries

MASS_UNIT = "kg"
ENERGY_UNIT = "MJ"
DISTANCE_UNIT = "km"

server_url = "http://my_grantami_server/mi_servicelayer"
cxn = Connection(server_url).with_credentials("user_name", "password").connect()

xml_file_path = "../supporting-files/sustainability-bom-2412.xml"
with open(xml_file_path) as f:
    bom = f.read()

sustainability_summary_query = (
    queries.BomSustainabilitySummaryQuery()
    .with_bom(bom)
    .with_units(mass=MASS_UNIT, energy=ENERGY_UNIT, distance=DISTANCE_UNIT)
)
sustainability_summary = cxn.run(sustainability_summary_query)

Process phase#

The environmental contributions from primary and secondary processing (applied to materials) and the joining and finishing processes (applied to parts) are summarized in the primary_processes_details, secondary_processes_details, and joining_and_finishing_processes_details properties respectively. Each of these properties lists the unique process-material pairs (for primary and secondary processing) or individual processes (for joining and finishing) that contribute at least 5% of the total impact for that category of process. The percentage contributions are relative to the total contribution of all processes from the same category. Processes that do not meet the contribution threshold are aggregated under the Other item, with the material set to None.

Primary processing#

[2]:
sustainability_summary.primary_processes_details
[2]:
[<ProcessSummaryResult(process='Primary processing, Casting', material='stainless-astm-cn-7ms-cast', EE%=49.003635167126944, CC%=51.95611124961991)>,
 <ProcessSummaryResult(process='Primary processing, Casting', material='steel-1010-annealed', EE%=33.53096586378645, CC%=28.699639137870474)>,
 <ProcessSummaryResult(process='Primary processing, Metal extrusion, hot', material='steel-1010-annealed', EE%=17.027930635795315, CC%=19.088533058623412)>,
 <ProcessSummaryResult(process='Other', material='None', EE%=0.4374683332912844, CC%=0.2557165538862139)>]
[3]:
import pandas as pd

EE_HEADER = f"EE [{ENERGY_UNIT}]"
CC_HEADER = f"CC [{MASS_UNIT}]"

primary_process_df = pd.DataFrame.from_records(
    [
        {
            "Process name": item.process_name,
            "Material name": item.material_identity,
            "EE%": item.embodied_energy_percentage,
            EE_HEADER: item.embodied_energy.value,
            "CC%": item.climate_change_percentage,
            CC_HEADER: item.climate_change.value,
        }
        for item in sustainability_summary.primary_processes_details
    ]
)
primary_process_df
[3]:
Process name Material name EE% EE [MJ] CC% CC [kg]
0 Primary processing, Casting stainless-astm-cn-7ms-cast 49.003635 74.662587 51.956111 4.505396
1 Primary processing, Casting steel-1010-annealed 33.530966 51.088224 28.699639 2.488701
2 Primary processing, Metal extrusion, hot steel-1010-annealed 17.027931 25.943981 19.088533 1.655270
3 Other None 0.437468 0.666533 0.255717 0.022175

Add a Name to each item that represents the process-material pair name.

[4]:
primary_process_df["Name"] = primary_process_df.apply(
    lambda row: f"{row['Process name']} - {row['Material name']}", axis=1
)
primary_process_df
[4]:
Process name Material name EE% EE [MJ] CC% CC [kg] Name
0 Primary processing, Casting stainless-astm-cn-7ms-cast 49.003635 74.662587 51.956111 4.505396 Primary processing, Casting - stainless-astm-c...
1 Primary processing, Casting steel-1010-annealed 33.530966 51.088224 28.699639 2.488701 Primary processing, Casting - steel-1010-annealed
2 Primary processing, Metal extrusion, hot steel-1010-annealed 17.027931 25.943981 19.088533 1.655270 Primary processing, Metal extrusion, hot - ste...
3 Other None 0.437468 0.666533 0.255717 0.022175 Other - None

This example produces multiple plots which all consist of a pair of pie charts representing the “Embodied Energy” and “Climate Change CO2 equivalent” impacts respectively. Define a helper function to create these plots.

[5]:
import plotly.graph_objects as go
from plotly.subplots import make_subplots


def plot_impact(df, title):
    fig = make_subplots(
        rows=1,
        cols=2,
        specs=[[{"type": "domain"}, {"type": "domain"}]],
        subplot_titles=["Embodied Energy", "Climate Change"],
    )
    fig.add_trace(go.Pie(labels=df["Name"], values=df[EE_HEADER], name=ENERGY_UNIT), 1, 1)
    fig.add_trace(go.Pie(labels=df["Name"], values=df[CC_HEADER], name=MASS_UNIT), 1, 2)
    fig.update_layout(title_text=title, legend=dict(orientation="h"))
    fig.update_traces(textposition="inside", textinfo="percent", hoverinfo="value+name+label")
    fig.show()
[6]:
plot_impact(primary_process_df, "Aggregated primary processes impact")

Secondary processing#

[7]:
sustainability_summary.secondary_processes_details
[7]:
[<ProcessSummaryResult(process='Secondary processing, Grinding', material='steel-1010-annealed', EE%=44.54415461216754, CC%=41.27956869646294)>,
 <ProcessSummaryResult(process='Secondary processing, Machining, coarse', material='stainless-astm-cn-7ms-cast', EE%=30.788425634110617, CC%=28.53198005630229)>,
 <ProcessSummaryResult(process='Machining, fine', material='steel-1010-annealed', EE%=15.02826066688355, CC%=13.926858057768948)>,
 <ProcessSummaryResult(process='Secondary processing, Machining, fine', material='stainless-astm-cn-7ms-cast', EE%=7.789400344621524, CC%=14.54740097421245)>,
 <ProcessSummaryResult(process='Other', material='None', EE%=1.8497587422167667, CC%=1.7141922152533655)>]
[8]:
secondary_process_df = pd.DataFrame.from_records(
    [
        {
            "Process name": item.process_name,
            "Material name": item.material_identity,
            "EE%": item.embodied_energy_percentage,
            EE_HEADER: item.embodied_energy.value,
            "CC%": item.climate_change_percentage,
            CC_HEADER: item.climate_change.value,
        }
        for item in sustainability_summary.secondary_processes_details
    ]
)
secondary_process_df
[8]:
Process name Material name EE% EE [MJ] CC% CC [kg]
0 Secondary processing, Grinding steel-1010-annealed 44.544155 1.758458 41.279569 0.058501
1 Secondary processing, Machining, coarse stainless-astm-cn-7ms-cast 30.788426 1.215427 28.531980 0.040435
2 Machining, fine steel-1010-annealed 15.028261 0.593267 13.926858 0.019737
3 Secondary processing, Machining, fine stainless-astm-cn-7ms-cast 7.789400 0.307500 14.547401 0.020617
4 Other None 1.849759 0.073022 1.714192 0.002429

Add a Name to each item that represents the process-material pair name.

[9]:
secondary_process_df["Name"] = secondary_process_df.apply(
    lambda row: f"{row['Process name']} - {row['Material name']}", axis=1
)
plot_impact(secondary_process_df, "Aggregated secondary processes impact")

Joining and finishing#

Joining and finishing processes apply to parts or assemblies and therefore don’t include a material identity.

[10]:
sustainability_summary.joining_and_finishing_processes_details
[10]:
[<ProcessSummaryResult(process='Joining and finishing, Welding, electric', material='None', EE%=100.0, CC%=100.0)>]
[11]:
joining_and_finishing_processes_df = pd.DataFrame.from_records(
    [
        {
            "Name": item.process_name,
            "EE%": item.embodied_energy_percentage,
            EE_HEADER: item.embodied_energy.value,
            "CC%": item.climate_change_percentage,
            CC_HEADER: item.climate_change.value,
        }
        for item in sustainability_summary.joining_and_finishing_processes_details
    ]
)
joining_and_finishing_processes_df
[11]:
Name EE% EE [MJ] CC% CC [kg]
0 Joining and finishing, Welding, electric 100.0 3.165429 100.0 0.213035
[12]:
plot_impact(joining_and_finishing_processes_df, "Aggregated joining and finishing processes impact")