Practical work — Tensile test data analysis (4h)#

In this lab you will analyze tensile-test data exported as CSV files. The method is always the same:

  1. Get your code working on one file.

  2. Generalize to a batch of files.

Learning goals#

  • Load and clean experimental data from CSV exports.

  • Plot true stress–true strain curves.

  • Compute key mechanical properties:

    • Ultimate tensile strength Rm

    • Young’s modulus E

    • 0.2% offset yield strength Re0.2

  • Build a summary table and rank materials.

Dataset#

  • The CSV files are located in _data_trac/.

  • The columns of interest are (French labels in the export):

    • Déformation réelle (true strain)

    • Contrainte réelle (true stress)

Session plan (suggested)#

  • Part A : understand the format + load one file.

  • Part B : batch loading + plot all curves.

  • Part C : parse metadata.

  • Part D : compute Rm, E, Re0.2.

  • Part E : summary table + ranking.

You will fill in the TODO sections in the code cells.

# Setup
from pathlib import Path
import glob
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

%matplotlib widget

Part A — Work on ONE file first#

Q1 — Inspect the header#

Many test machines export metadata before the table. Inspect the first lines to decide:

  • the separator (often ;)

  • the encoding (Windows “ANSI” is often cp1252)

  • which rows to skip (skiprows=[...])

# use the glob methode to list all csv files in the data directory
# example : csv_files = glob.glob('xxx/*.csv')


# Pick a single file for development/debug
# csv_path = csv_files[0]
# csv_path
# Inspect the first lines of the file
# TODO: try: 'cp1252', 'latin1', or 'utf-8'.

# Sugested code :
# ENCODING = "cp1252"

# with open(csv_path, encoding=ENCODING) as f:
#     for i in range(12):
#         line = f.readline()
#         print(f"{i:02d}: {line.rstrip()}")

Q2 — Load and clean the data table#

Implement load_trac_csv(path).

Constraints (adapt if your inspection shows differences)

  • Use sep='...'

  • Use skiprows=[0,1,2,...]

  • Keep only the two columns of interest

  • rename columns to STRAIN_COL and STRESS_COL to avoid encoding issues

Tip: if your column names look like Déformation réelle, your encoding is wrong.

def load_trac_csv(path):
    """Load one tensile CSV and return a clean dataframe with (strain, stress)."""
    # TODO: read CSV
    data = 0.0

    # TODO: keep only the two columns

    return data


# test the function on the first file
df = load_trac_csv("path_to a file")

Q3 — Plot the curve (one file)#

Plot Contrainte réelle vs Déformation réelle.

Checklist:

  • labels, title, grid

  • curve is continuous (no non-numeric values)

# plot 'strain' vs 'stress'

Part B — Batch processing#

Q4 — Load all files + plot all curves#

Create a dictionary data_by_file:

  • key: filename stem (without extension)

  • value: cleaned DataFrame

Then plot all curves in one figure.

Part C — Metadata#

Q5 — Parse metadata from the header#

Read the first 5 lines of the CSV file. Each line is separated by ; and looks like:

Key;Value;Unit

Implement read_metadata(path) and test it on one file.

def read_metadata(path: Path):
    metadata = {}

    return metadata


metadata = read_metadata("path_to a file")
metadata
{}

Part D — Mechanical properties#

Q6 — Compute Rm#

Rm is the maximum stress on the curve.

Q7 — Estimate E#

Estimate E as the Young’s modulus.

Q8 — Compute Re0.2 (0.2% offset)#

Re0.2 is the stress at the intersection with the experimental curve.

Hint: find where stress - sigma_offset changes sign, where sigma_offset = 0.002 * E.

Part E — Summary + ranking#

Q9 — Build a summary datafram (one row per file)#

For each file, compute Rm, E, and Re0.2. Optionally add othe file name.

Q10 — Display material properties#

Make a look like hasby diagrmam with Rm, E, Re0.2.

Optional (if time) — Wrap everything in a class#

Create a class TensileTest that stores:

  • .metadata

  • .data And exposes:

  • .Rm, .E, .Re02

  • .plot()

class TensileTest:
    def __init__(self, path: Path):
        self.path = Path(path)
        # TODO
        # self.metadata = read_metadata(self.path)
        # self.data = load_trac_csv(self.path)

    @property
    def Rm(self):
        # TODO
        raise NotImplementedError

    @property
    def E(self):
        # TODO
        raise NotImplementedError

    @property
    def Re02(self):
        # TODO
        raise NotImplementedError

    def plot(self):
        # TODO
        raise NotImplementedError

    def __repr__(self):
        return f"TensileTest({self.path.name})"


# Example (after implementation)
# test = TensileTest(csv_path)
# test.plot()
# test.Rm, test.E, test.Re02