Skip to content

A solid's stress from its strain, live

Hooke's law in one dimension, σ = E ε, a solid's stress from its strain (the change in length over the length, positive stretched) and its Young's modulus E, with whether it fails beside it: where the stress passes its tensile strength stretched, or its compressive strength squeezed. Below, a brittle solid, concrete's modulus of 30 GPa and its strengths of 3 MPa stretched and 30 MPa squeezed, is taken from a strain of −0.0015 to +0.0015, 0.000025 a step, twenty steps a second, and at each the library's law (lusine.laws.elastic, with lusine.laws.fails) gives its stress and its verdict on your GPU as you read.

This page runs the program on your GPU through WebGPU, so it needs a browser with WebGPU (a recent Chrome, Edge, Safari or Firefox). Without it the program does not run and nothing is drawn below.

What it shows

  • The strip above the controls is green while every check holds, and turns red for good once one fails.
  • The solid: the first chart draws the stress against the strain, a point a step over one whole sweep, and beside it the stress at the opposite strain, negated: the two lie one over the other, a straight line through zero. Below it, the strain, the stress and the stress at twice the strain. The second chart draws where the solid fails (1) and where it holds (0): it holds from a strain of −0.001 (30 MPa squeezed) to 0.0001 (3 MPa stretched), and fails past either, a brittle solid's ten times weaker stretched than squeezed.
  • The checks, each held at every step: odd, the opposite strain giving exactly the opposite stress, bit for bit; linear, twice the strain giving exactly twice the stress; unstrained, no strain giving no stress; brittle, the solid failing at 4 MPa stretched, holding at 4 MPa squeezed and failing at 40 MPa squeezed.

Every number here is computed by the program on the GPU; the page only reads the values back and draws them. The modulus, the strengths and the sweep are the program's settings, which the host may write; this page offers no control to change them yet.

The program

The sweep, the law's answers and the checks, the panels the page draws, and the one procedure, main, run each step: the sweep moves on, the law is asked at the strain and its variants, and the checks are taken.

// Hooke's law's live page: a brittle solid's strain swept from squeezed to stretched, the library's stress at each and
// whether the solid fails there, beside the same law at the opposite strain and at twice the strain, with the page's
// checks computed here on the GPU and shown by the panels the program declares.

namespace elastic;

lusine.version version = { { number = 1 } };

// The reader's settings: the solid's Young's modulus and its strengths, tensile and compressive (concrete's), and the
// sweep: the strain it starts at and how far each step moves it.
host struct {
  float<Pa> modulus = 30000000000.0 Pa; float<Pa> tensile = 3000000.0 Pa; float<Pa> compressive = 30000000.0 Pa;
  float lowest = -0.0015; float stride = 0.000025;
} settings;

// The sweep: the step it is at, from 0 to 120 and round again, starting from the middle, and the strain there.
struct { integer step = 59; float strain; } sweep;

// The stress at the strain; the same law at the opposite strain, negated; at twice the strain; and whether the solid
// fails at the stress, 1 where it does and 0 where it holds.
struct { float<Pa> stress; float<Pa> mirrored; float<Pa> doubled; float broken; } law;

// The checks: the opposite strain giving exactly the opposite stress; twice the strain exactly twice the stress; no
// strain, no stress; and the brittle solid failing stretched at 4 MPa, holding squeezed at 4 MPa, and failing squeezed
// at 40 MPa.
struct { bool odd = true; bool linear = true; bool unstrained = true; bool brittle = true; } checks;

// A strip of lamps the page draws, lit green while every check holds and red once one fails.
struct lamp { vector<float, 4> colour; };
lattice<lamp, 2> lamps(spacing = 1 m, boundary = wall);

vector<float, 4> lamp_colour(bool holds)
{
  return holds ? vector<float, 4>(0.15, 0.6, 0.3, 1.0) : vector<float, 4>(0.75, 0.15, 0.15, 1.0);
}

output table<lusine.widget> panels = {
  lusine.series { { panel = "the solid", chart = "stress", quantity = law.stress, steps = 121, against = sweep.strain,
                    label = "sigma" } },
  lusine.series { { panel = "the solid", chart = "stress", quantity = law.mirrored, steps = 121,
                    against = sweep.strain, label = "mirrored, negated" } },
  lusine.value { { panel = "the solid", quantity = sweep.strain, label = "strain" } },
  lusine.value { { panel = "the solid", quantity = law.stress, label = "stress" } },
  lusine.value { { panel = "the solid", quantity = law.doubled, label = "at twice the strain" } },
  lusine.series { { panel = "the solid", chart = "fails (1) or holds (0)", quantity = law.broken, steps = 121,
                    against = sweep.strain, label = "fails" } },
  lusine.value { { panel = "the checks", quantity = checks.odd, label = "odd" } },
  lusine.value { { panel = "the checks", quantity = checks.linear, label = "linear" } },
  lusine.value { { panel = "the checks", quantity = checks.unstrained, label = "unstrained" } },
  lusine.value { { panel = "the checks", quantity = checks.brittle, label = "brittle" } },
};

void main()
{
  sweep.step = sweep.step >= 120 ? 0 : sweep.step + 1;
  sweep.strain = settings.lowest + float(sweep.step) * settings.stride;
  law.stress = lusine.laws.elastic(settings.modulus, sweep.strain);
  law.mirrored = -lusine.laws.elastic(settings.modulus, strain = -sweep.strain);
  law.doubled = lusine.laws.elastic(settings.modulus, strain = 2.0 * sweep.strain);
  law.broken = lusine.laws.fails(law.stress, settings.tensile, settings.compressive) ? 1.0 : 0.0;
  checks.odd = checks.odd && law.mirrored == law.stress;
  checks.linear = checks.linear && law.doubled == 2.0 * law.stress;
  checks.unstrained = checks.unstrained && lusine.laws.elastic(settings.modulus, strain = 0.0) == 0.0 Pa;
  checks.brittle = checks.brittle
                   && lusine.laws.fails(stress = 4000000.0 Pa, settings.tensile, settings.compressive)
                   && !lusine.laws.fails(stress = -4000000.0 Pa, settings.tensile, settings.compressive)
                   && lusine.laws.fails(stress = -40000000.0 Pa, settings.tensile, settings.compressive);
  lamps.colour = lamp_colour(holds = checks.odd && checks.linear && checks.unstrained && checks.brittle);
}

The law's other proof (the stress against a reference over metals and stone) is on its proof page.