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