Skip to main content

Granta MI Scripting Toolkit 4.2

Create Functional Data

Last update: 16.07.2025

Populate a functional attribute with data fitted using the Python numpy library.

Import libraries and define a polynomial fit function

This example populates a functional attribute for Ultimate Tensile Strength vs Temperature in one table from a polynomial fit of the individual attributes in another table.

from datetime import datetime
import numpy as np
from GRANTA_MIScriptingToolkit import granta as mpy

def My4degPolyFitFunc(x, a, b, c, d, e):
    return a*np.power(x, 4) + b*np.power(x, 3) + c*np.power(x, 2) + d*x + e

Specify database and table

The source data will come from the Tensile Statistical Data table.

mi = mpy.connect("http://my.server.name/mi_servicelayer", autologon=True)

db = mi.get_db(db_key="MI_Training")
db.unit_system ="Metric"
db.absolute_temperatures = True

table = db.get_table("Tensile Statistical Data")

Export test data

Find High Alloy Steel > AMS 6520 > Plate records in which both the Ultimate Tensile Strength and Test Temperature attributes are populated.

records = table.get_records_from_path(
    starting_node=None,
    tree_path=["High Alloy Steel", "AMS 6520", "Plate"],
)

Extract the attribute values from the returned records into x and y values.

table.bulk_fetch(records, attributes=["Test Temperature", "Ultimate Tensile Strength"])
populated_records = [
    r for r in records
    if not r.attributes["Test Temperature"].is_empty()
    and not r.attributes["Ultimate Tensile Strength"].is_empty()
]

x_values = [r.attributes["Test Temperature"].value for r in populated_records]
y_values = [r.attributes["Ultimate Tensile Strength"].value for r in populated_records]

Fit the test data

Fit a fourth-order polynomial to your x and y data.

coeffs = np.polyfit(x_values, y_values, 4)

Generate x and y values for the fitted equation, using the function you defined at the start.

x_fit = np.linspace(np.amin(x_values), np.amax(x_values), 20)
y_fit = My4degPolyFitFunc(x_fit, *coeffs)

Create a record to store the data in

The resulting functional data will be written into the Metals subset of the Design Data table, using the same unit system.

design_data = db.get_table("Design Data")
design_data.subsets.clear()
design_data.subsets.add("Metals")

Create a new record to store your functional data.

now = datetime.now().strftime("%c")
record_name = f"Scripting Toolkit Example 8:{now}"
record = design_data.create_record(record_name)
record.color = mpy.RecordColor.Green

Access the (empty) functional attribute, and view its column headers.

func = record.attributes["Tens. Ult. Stress (L-dir) with Temp."]
func.column_headers

Previous cell output:

['Y min (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
 'Y max (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
 'Temperature [K]',
 'Time [hr]',
 'Other []',
 'Data Type Lab []',
 'Estimated point?']

Populate the functional attribute

Add the test data to the functional attribute point-by-point, then view the attribute data. Column headers can be omitted if they aren't required to represent the data.

for x, y in zip(x_values, y_values):
    point = {"Temperature": x, "y": y, "Data Type Lab": "Test Data"}
    func.add_point(point)
func.value

Previous cell output:

[['Y min (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
  'Y max (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
  'Temperature [K]',
  'Time [hr]',
  'Other []',
  'Data Type Lab []',
  'Estimated point?'],
 [1263.0048828125,
  1263.0048828125,
  810.9284057617188,
  None,
  None,
  'Test Data',
  False],
 [2399.146240234375,
  2399.146240234375,
  194.2612762451172,
  None,
  None,
  'Test Data',
  False],
 [2078.31, 2078.31, 422.0389938964844, None, None, 'Test Data', False],
 [1848.140014648438,
  1848.140014648438,
  588.7060546875,
  None,
  None,
  'Test Data',
  False],
 [1734.37646484375,
  1734.37646484375,
  699.8172607421875,
  None,
  None,
  'Test Data',
  False],
 [2189.89, 2189.89, 294.2613938964844, None, None, 'Test Data', False]]

Then add the fitted data to the functional attribute point-by-point, and view the attribute data with series number as an extra column.

for x, y in zip(x_fit, y_fit):
    point = {"Temperature": x, "y": y, "Data Type Lab": "Fitted Data"}
    func.add_point(point)
func.data_with_series_number

Previous cell output:

[['Y min (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
  'Y max (Tens. Ult. Stress (L-dir) with Temp. [MPa])',
  'Temperature [K]',
  'Time [hr]',
  'Other []',
  'Data Type Lab []',
  'Estimated point?',
  'Series number'],
 [1263.0048828125,
  1263.0048828125,
  810.9284057617188,
  None,
  None,
  'Test Data',
  False,
  1],
 [2399.146240234375,
  2399.146240234375,
  194.2612762451172,
  None,
  None,
  'Test Data',
  False,
  1],
 [2078.31, 2078.31, 422.0389938964844, None, None, 'Test Data', False, 1],
 [1848.140014648438,
  1848.140014648438,
  588.7060546875,
  None,
  None,
  'Test Data',
  False,
  1],
 [1734.37646484375,
  1734.37646484375,
  699.8172607421875,
  None,
  None,
  'Test Data',
  False,
  1],
 [2189.89, 2189.89, 294.2613938964844, None, None, 'Test Data', False, 1],
 [np.float64(2392.1796767662518),
  np.float64(2392.1796767662518),
  np.float64(194.2612762451172),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2333.081679240432),
  np.float64(2333.081679240432),
  np.float64(226.71744095651727),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2274.74066356839),
  np.float64(2274.74066356839),
  np.float64(259.17360566791734),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2219.0030335134543),
  np.float64(2219.0030335134543),
  np.float64(291.62977037931745),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2167.2202125230733),
  np.float64(2167.2202125230733),
  np.float64(324.0859350907175),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2120.248643728818),
  np.float64(2120.248643728818),
  np.float64(356.5420998021176),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2078.4497899463804),
  np.float64(2078.4497899463804),
  np.float64(388.9982645135177),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2041.6901336755727),
  np.float64(2041.6901336755727),
  np.float64(421.4544292249178),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(2009.3411771003305),
  np.float64(2009.3411771003305),
  np.float64(453.91059393631787),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1980.2794420887074),
  np.float64(1980.2794420887074),
  np.float64(486.366758647718),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1952.8864701928812),
  np.float64(1952.8864701928812),
  np.float64(518.822923359118),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1925.0488226491502),
  np.float64(1925.0488226491502),
  np.float64(551.2790880705181),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1894.1580803779325),
  np.float64(1894.1580803779325),
  np.float64(583.7352527819182),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1857.1108439837685),
  np.float64(1857.1108439837685),
  np.float64(616.1914174933183),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1810.3087337553218),
  np.float64(1810.3087337553218),
  np.float64(648.6475822047184),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1749.6583896653735),
  np.float64(1749.6583896653735),
  np.float64(681.1037469161184),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1670.571471370828),
  np.float64(1670.571471370828),
  np.float64(713.5599116275185),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1567.9646582127116),
  np.float64(1567.9646582127116),
  np.float64(746.0160763389187),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1436.2596492161715),
  np.float64(1436.2596492161715),
  np.float64(778.4722410503188),
  None,
  None,
  'Fitted Data',
  False,
  2],
 [np.float64(1269.3831630904717),
  np.float64(1269.3831630904717),
  np.float64(810.9284057617188),
  None,
  None,
  'Fitted Data',
  False,
  2]]

Adjust the series linestyles (series_linestyles is a dictionary, indexed with integers).

func.series_linestyles[1] = "Markers"
func.series_linestyles[2] = "Lines"
func.series_linestyles

Previous cell output:

{1: 'Markers', 2: 'Lines'}

Write your changes to MI

Set the attributes you've modified to update, and write the new record to the server.

record.set_attributes([func])
mi.update([record])

Previous cell output:

[<record long name: scripting toolkit example may>]

Connect with Ansys