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


Messages and phase summary#

This example shows how to run a sustainability summary query and how to explore the phases summary result. It also shows how to review any messages generated by the server during the analysis.

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#

First, connect to Granta MI.

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

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

Next, create a sustainability summary query. The query accepts a single BoM as argument and an optional configuration for units. If a unit is not specified, the default unit is used. Default units for the analysis are MJ for energy, kg for mass, and km for distance.

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

from ansys.grantami.bomanalytics import queries

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

sustainability_summary_query = (
    queries.BomSustainabilitySummaryQuery()
    .with_bom(bom)
    .with_units(mass=MASS_UNIT, energy=ENERGY_UNIT, distance=DISTANCE_UNIT)
)
[3]:
sustainability_summary = cxn.run(sustainability_summary_query)
sustainability_summary
[3]:
<BomSustainabilitySummaryQueryResult>

Messages#

The BomSustainabilitySummaryQueryResult object that is returned implements a messages property and properties showing the environmental impact of the items included in the BoM. Log messages are sorted by decreasing severity. The same messages are available in the MI Service Layer log file and are logged using the standard logging module.

If there are no messages, an empty list is returned. This means there were no unexpected events during BoM analysis.

[4]:
sustainability_summary.messages
[4]:
[]

Phases summary#

The phases_summary property summarizes the environmental impact contributions by lifecycle phase: materials, processes, and transport phases. The results for each phase include their absolute and relative contributions to the product as a whole.

[5]:
sustainability_summary.phases_summary
[5]:
[<SustainabilityPhaseSummaryResult('Material', EE%=56.26497924826154, CC%=66.68484815955397)>,
 <SustainabilityPhaseSummaryResult('Processes', EE%=26.8904676648199, CC%=18.802258197322264)>,
 <SustainabilityPhaseSummaryResult('Transport', EE%=16.844553086918566, CC%=14.512893643123762)>]

Use the pandas and plotly libraries to visualize the results. First, the data is translated from the BoM Analytics BomSustainabilitySummaryQueryResult to a pandas Dataframe object.

[6]:
import pandas as pd

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

phases_df = pd.DataFrame.from_records(
    [
        {
            "Name": item.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.phases_summary
    ]
)
phases_df
[6]:
Name EE% EE [MJ] CC% CC [kg]
0 Material 56.264979 333.680522 66.684848 32.013029
1 Processes 26.890468 159.474427 18.802258 9.026297
2 Transport 16.844553 99.896940 14.512894 6.967125

Next, the dataframe is visualized as a pair of pie charts.

[7]:
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=phases_df["Name"], values=phases_df[EE_HEADER], name=ENERGY_UNIT), 1, 1)
fig.add_trace(go.Pie(labels=phases_df["Name"], values=phases_df[CC_HEADER], name=MASS_UNIT), 1, 2)
fig.update_layout(title_text="BoM sustainability summary - By phase", legend=dict(orientation="h"))
fig.update_traces(textposition="inside", textinfo="percent+label", hoverinfo="value+name")
fig.show()