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


Material phase#

This example shows how to explore the material 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)

Materials phase#

The environmental contribution from the material phase is summarized in the material_details property. The results are aggregated: each item in material_details represents the total environmental impact of a material summed from all its occurrences in the BoM. Listed materials contribute more than 2% of the total impact for the material phase. Materials that do not contribute at least 2% of the total are aggregated under the Other item.

[2]:
sustainability_summary.material_details
[2]:
[<MaterialSummaryResult('stainless-astm-cn-7ms-cast', EE%=45.864330109954146, CC%=37.36950817938181)>,
 <MaterialSummaryResult('beryllium-beralcast191-cast', EE%=35.276841577106666, CC%=48.52278822564834)>,
 <MaterialSummaryResult('steel-1010-annealed', EE%=18.85882831293918, CC%=14.107703594969825)>]
[3]:
import pandas as pd

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

materials_df = pd.DataFrame.from_records(
    [
        {
            "Name": item.identity,
            "EE%": item.embodied_energy_percentage,
            EE_HEADER: item.embodied_energy.value,
            "CC%": item.climate_change_percentage,
            CC_HEADER: item.climate_change.value,
            f"Mass before processing [{MASS_UNIT}]": item.mass_before_processing.value,
            f"Mass after processing [{MASS_UNIT}]": item.mass_after_processing.value,
        }
        for item in sustainability_summary.material_details
    ]
)
materials_df
[3]:
Name EE% EE [MJ] CC% CC [kg] Mass before processing [kg] Mass after processing [kg]
0 stainless-astm-cn-7ms-cast 45.864330 153.040336 37.369508 11.963111 1.54595 1.450
1 beryllium-beralcast191-cast 35.276842 117.711949 48.522788 15.533614 0.02700 0.024
2 steel-1010-annealed 18.858828 62.928237 14.107704 4.516303 2.74574 2.640

Plot a pair of pie charts which show the “Embodied Energy” and “Climate Change CO2 equivalent” impacts respectively.

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


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

Mass before and mass after secondary processing can help determine if the material mass removed during processing contributes a significant fraction of the impact of the overall material phase.

Plot the aggregated material masses as a bar chart.

[5]:
fig = go.Figure(
    data=[
        go.Bar(
            name="Mass before secondary processing",
            x=materials_df["Name"],
            y=materials_df[f"Mass before processing [{MASS_UNIT}]"],
        ),
        go.Bar(
            name="Mass after secondary processing",
            x=materials_df["Name"],
            y=materials_df[f"Mass after processing [{MASS_UNIT}]"],
        ),
    ],
    layout=go.Layout(
        xaxis=go.layout.XAxis(title="Materials"),
        yaxis=go.layout.YAxis(title=f"Mass [{MASS_UNIT}]"),
        legend=dict(orientation="h")
    ),
)
fig.show()