Quick Start

We are familiar with stress-strain plots. These are usually "Engineering" or "Cauchy" values, calculated directly from the force/strain data from our machines. We should, but generally don't, plot the True (or "Hencky", a term used in the food industry) values. Here we explore the differences.


I first came across this in a wonderful YouTube video by the Efficient Engineer: Understanding True Stress & True Strain.

Engineering & True Stress-Strain

Modulus E
Yield Stress
Ultimate Strength
Fracture Strength
Necking Factor
All curves
//One universal basic required here to get things going once loaded
window.onload = function () {
    //restoreDefaultValues(); //Un-comment this if you want to start with defaults

//Main() is hard wired as THE place to start calculating when inputs change
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
    //Save settings every time you calculate, so they're always ready on a reload

    //Send all the inputs as a structured object
    //If you need to convert to, say, SI units, do it here!
    const inputs = {
        E: sliders.SlideE.value*100,
        Y: sliders.SlideY.value,
        U: sliders.SlideU.value,
        F: sliders.SlideF.value,
        NF: sliders.SlideNF.value,

    //Send inputs off to CalcIt where the names are instantly available
    //Get all the resonses as an object, result
    const result = CalcIt(inputs);

      //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //plotIt is part of the app infrastructure in
    if (result.plots) {
        for (let i = 0; i < result.plots.length; i++) {
            plotIt(result.plots[i], result.canvas[i]);

    //You might have some other stuff to do here, but for most apps that's it for Main!

//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ E,Y,U,F,All,NF }) {

    let EEPts = [], ETPts = [], TEPts = [], TTPts=[]
    let se=0,st=0,et=0
    const ey=Y/E, eu=2*U/E, eyu=(0.2*eu+0.8*ey), offs=Math.exp(-Math.pow((eyu-eu)/(eu-ey),2))*(U-Y)
    for (let ee=0;ee<=0.1;ee+=0.01){
        if (ee > ey) se=Y
        if (ee > eyu) se=Y+Math.exp(-Math.pow((ee-eu)/(eu-ey),2))*(U-Y)-offs
        if (ee > eu && se < F) break
        if (ee > eu) st=se*(1+Math.pow(ee/eu,NF)*ee)
    //Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot
    let PD=[],LL=[]
    if (All){
       LL=["Engineering σ-Engineering ε","True σ-True ε", "Engineering σ-True ε", "True σ-Engineering ε"]
    }else {
        LL=["Engineering σ-Engineering ε", "True σ-True ε"]
    const prmap = {
        plotData: PD, //An array of 1 or more datasets
        lineLabels: LL, //An array of labels for each dataset
        xLabel: 'ε& ', //Label for the x axis, with an & to separate the units
        yLabel: 'σ& ', //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [,0.1], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'P3', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'P3', //F for Fixed, P for Precision, E for exponential

    return {
        plots: [prmap],
        canvas: ['canvas'],


We all know that a curve of stress σ versus strain ε tends to have a linear part from which we get the modulus E:


At some point the sample yields, becoming non-linear, at the yield stress, then we reach a maximum at the ultimate tensile stress and then a fall-off before the sample breaks at the fracture strength. In fact the fall-off is an artefact of the fact that we define stress as `σ=F/A_0` and `ε="Δl"/l_0` where F is the applied force, Δl is the increase in length, A0 is the original cross-sectional area and l0 is the original length. The standard plot is of Engineering (or Cauchy) stress and strain, i.e. the ones we calculate simply from the data from our machine.

The true stress is `σ=F/A_l`, the force divided by the current cross-sectional area (which decreases, and can be calculated using the assumption of constant volume). So for the current length l, we get:


Via simple arithmetic we can calculate the true stress σt from the engineering stress (the one we typically show), σe directly from the engineering strain (again, the one we typically show) εe via:


True strain is always the increase of length Δl divided by the current length l. When you do the integration of all these sub-steps involving `1/l` you get a log term and find that the true stress εt is given by:


Thus we can plot True (or Hencky) stress and strain to know what's really going on.


To get a feel for what this means, enter some parameters for a simulated (engineering) stress-strain curve, one that looks familiar to you. You get that plot plus true stress versus true strain. If you select All curves you also get engineering stress versus true strain and true stress versus engineering strain - each of which can be found in the literature.


  • Units are unspecified as we are interested in the general principles.
  • Calculations after necking are inaccurate because the constant volume assumption breaks down, the Necking Factor simulates greater necking which increases the true strain value.