Basic preprocessing with IndenToolbox

This notebook walks through turning raw nanoindentation exports into a structured batch ready for analysis with IndenToolbox. You will load raw files, define the indenter tip and test protocol, complete essential metadata, and export the result for downstream processing.

What you’ll do:

  • Select and parse raw test files (CLI or widget UI).

  • Define the indenter tip and test protocol.

  • Fill metadata: date, operators, sample, device.

  • Build a Batch and export FusedQuartz_batch.toml and FusedQuartz_batch.csv.

Notes:

  • Example data targets Hysitron TI‑950 files; CSM is also supported.

  • Make sure ipywidgets is enabled (%matplotlib widget) for the UI.

  • If your acquisition differs, adjust protocol and file encoding accordingly.

Run the notebook top‑to‑bottom. At the file selection step, choose either the command‑line path list or the interactive widgets, then proceed to create and dump the batch.

%matplotlib widget
import indentoolbox as itb
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import datetime
import os
setup = {}

Tip

An indentation tip must be defined to allow interpretation of the tests.

In our experiments, we performed nanoindentation using a Berkovich diamond tip. However, for post-processing and modeling purposes, we approximate the indenter geometry as a spherocone. This simplified geometry, defined by its half angle and truncated length, facilitates the interpretation of the mechanical response while retaining key features of the contact mechanics.

Have a look at the documentation on step classes.

setup["tip"] = itb.core.SpheroConicalTip(angle = 70.3, 
                                         htrunc = 15.e-9, 
                                         young_modulus=1141.0e9, 
                                         poisson_coefficient=0.14)

Test protocol

In IndenToolbox, a batch is made up of several tests, which are themselves made up of steps. The test protocol defines the structure of these steps. It defines their nature and sequence. All tests in the same batch share the same structure.

Have a look at the documentation on step classes.

#protocol = None # If left to None, the test protocol will be inferred by the parser.
protocol = 3 * [None] + ["ConicalLoadingStep", "Step", "UnloadingStep"] # Use your own protocol: None ignores a step and otherwise a class name is provided
protocol
[None, None, None, 'ConicalLoadingStep', 'Step', 'UnloadingStep']

Select test txt files

There are two possible options here: define file paths directly on the command line, or use the graphical interface.

Option 1 : command line

folder = "datasets/Hysitron_TI950/2011-06-28_Hysitron_TI950_Fused_Quartz/"
pathes = sorted([f for f in os.listdir(folder) if f.endswith(".txt")])
pathes
['2011-06-28_Hysitron_TI950_Fused_Quartz_001.txt',
 '2011-06-28_Hysitron_TI950_Fused_Quartz_002.txt',
 '2011-06-28_Hysitron_TI950_Fused_Quartz_003.txt',
 '2011-06-28_Hysitron_TI950_Fused_Quartz_004.txt']
file_format = "hysitron nano"
encoding = "ISO-8859-1"

tests = []
for path in pathes:
    data = open(f"{folder}{path}", "rb").read().decode(encoding)
    test = itb.core.Test.from_txt(
                content=data, protocol=protocol, file_format=file_format)
    display(test.data)
    tests.append(test)
setup["tests"] = tests
tests
time disp force step
0 3.97437 2.476870e-10 0.000003 0
1 3.97937 5.780340e-10 0.000004 0
2 3.98437 1.063623e-09 0.000006 0
3 3.98937 1.633712e-09 0.000008 0
4 3.99437 2.344546e-09 0.000011 0
... ... ... ... ...
1994 43.94437 1.231350e-07 0.000022 2
1995 43.94937 1.229267e-07 0.000017 2
1996 43.95437 1.226304e-07 0.000012 2
1997 43.95937 1.221842e-07 0.000008 2
1998 43.96437 1.220285e-07 0.000004 2

7999 rows × 4 columns

time disp force step
0 4.024354 4.506540e-10 0.000003 0
1 4.029354 7.972240e-10 0.000004 0
2 4.034354 1.285238e-09 0.000006 0
3 4.039354 1.799397e-09 0.000008 0
4 4.044354 2.504955e-09 0.000011 0
... ... ... ... ...
1994 43.994354 1.242191e-07 0.000022 2
1995 43.999354 1.237960e-07 0.000017 2
1996 44.004354 1.235869e-07 0.000012 2
1997 44.009354 1.231864e-07 0.000008 2
1998 44.014354 1.229150e-07 0.000004 2

7999 rows × 4 columns

time disp force step
0 4.00436 3.257470e-10 0.000003 0
1 4.00936 6.418070e-10 0.000004 0
2 4.01436 9.967910e-10 0.000006 0
3 4.01936 1.763823e-09 0.000008 0
4 4.02436 2.461305e-09 0.000011 0
... ... ... ... ...
1995 43.97436 1.220879e-07 0.000022 2
1996 43.97936 1.218535e-07 0.000017 2
1997 43.98436 1.215346e-07 0.000012 2
1998 43.98936 1.211864e-07 0.000007 2
1999 43.99436 1.208849e-07 0.000004 2

7999 rows × 4 columns

time disp force step
0 3.97437 2.391390e-10 0.000003 0
1 3.97937 6.097460e-10 0.000004 0
2 3.98437 1.099288e-09 0.000006 0
3 3.98937 1.327693e-09 0.000008 0
4 3.99437 1.882111e-09 0.000011 0
... ... ... ... ...
1994 43.94437 1.230221e-07 0.000022 2
1995 43.94937 1.227381e-07 0.000017 2
1996 43.95437 1.223665e-07 0.000012 2
1997 43.95937 1.219799e-07 0.000008 2
1998 43.96437 1.215279e-07 0.000004 2

7999 rows × 4 columns

[Test(3 steps), Test(3 steps), Test(3 steps), Test(3 steps)]

Options 2 : graphical interface

#itb.gui.file_processing_widgets(setup, protocol)
setup
{'tip': SpheroConicalTip(radius=2.413e-07, htrunc=1.50e-08, hcrit=1.41e-08),
 'tests': [Test(3 steps), Test(3 steps), Test(3 steps), Test(3 steps)]}

Date

#itb.gui.date_selection_widget(setup)

Operators

operators = [
    itb.core.Operator(name = "Ludovic Charleux", institute= "Institut de Physique de Rennes"),
    itb.core.Operator(name = "Mariette Nivard", institute= "Institut de Physique de Rennes")]
setup["operators"] = operators
operators
[Operator(name='Ludovic Charleux', institute='Institut de Physique de Rennes'),
 Operator(name='Mariette Nivard', institute='Institut de Physique de Rennes')]

Sample

sample = itb.core.Sample(name = "Fused Quartz", provider = "Hysitron")
setup["sample"] = sample
sample
Sample(name='Fused Quartz', provider='Hysitron')

Device

device = itb.core.Device(name = "TI-950", institute = "Institut de Physique de Rennes", compliance = 0., provider = "Hysitron")
setup["device"] = device
device
Device(name='TI-950', institute='Institut de Physique de Rennes', compliance=0.0, provider='Hysitron')
setup
{'tip': SpheroConicalTip(radius=2.413e-07, htrunc=1.50e-08, hcrit=1.41e-08),
 'tests': [Test(3 steps), Test(3 steps), Test(3 steps), Test(3 steps)],
 'operators': [Operator(name='Ludovic Charleux', institute='Institut de Physique de Rennes'),
  Operator(name='Mariette Nivard', institute='Institut de Physique de Rennes')],
 'sample': Sample(name='Fused Quartz', provider='Hysitron'),
 'device': Device(name='TI-950', institute='Institut de Physique de Rennes', compliance=0.0, provider='Hysitron')}

Batch creation and dumping

batch = itb.core.Batch(**setup)
batch
Batch(4 tests)
batch.dump("FusedQuartz_batch")