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")