Skip to content

Instantly share code, notes, and snippets.

@pineapplemachine
Created April 4, 2018 14:54
Show Gist options
  • Select an option

  • Save pineapplemachine/8bd11c7ad219c413b83df9d53ff83b31 to your computer and use it in GitHub Desktop.

Select an option

Save pineapplemachine/8bd11c7ad219c413b83df9d53ff83b31 to your computer and use it in GitHub Desktop.
// Draws an approximated phase diagram given a substance's triple point and critical point.
// Goto line 104 to use different inputs from the hydrogen example
class Material{
constructor(name, abbreviation, properties){
this.name = name;
this.abbreviation = abbreviation;
this.properties = properties;
this.triplePointKelvin = properties.triplePointKelvin;
this.triplePointPascals = properties.triplePointPascals;
this.criticalPointKelvin = properties.criticalPointKelvin;
this.criticalPointPascals = properties.criticalPointPascals;
}
phase(K, Pa){
// Get whether the material should be a solid, liquid, gas, etc. at a
// given temperature (Kelvins) and pressure (pascals).
// This is an extremely rough approximation!
if(Pa <= this.triplePointPascals){
// Below triple point Pa, is either solid (low K) or gas (high K)
const sublimationKelvin = this.triplePointKelvin * (
(Pa / this.triplePointPascals) ** 0.046875 // = 3/64
);
if(K >= sublimationKelvin){
return Phase.Gas;
}else{
return Phase.Solid;
}
}else if(K <= this.triplePointKelvin){
// Pa above triple point but K below triple point implies solid
return Phase.Solid;
}else if(Pa <= this.criticalPointPascals){
// Is either liquid (low K) or gas (high K)
const deltaKelvin = this.criticalPointKelvin - this.triplePointKelvin;
const deltaPascals = this.criticalPointPascals - this.triplePointPascals;
const saturationKelvin = this.triplePointKelvin + deltaKelvin * (
((Pa - this.triplePointPascals) / deltaPascals) ** 0.375 // = 3/8
);
if(K <= saturationKelvin){
return Phase.Liquid;
}else{
return Phase.Gas;
}
}else{
// Pa above critical point implies solid, liquid, or supercritical
const meltingKelvin = this.triplePointKelvin + (
(Pa - this.criticalPointPascals) * 1.1920928955078125e-07 // 2^-23
);
// console.log(K, "K", Pa, "Pa", meltingKelvin);
if(K <= meltingKelvin){
// Low K relative to melting curve implies solid
return Phase.Solid;
}else if(Pa >= this.criticalPointPascals){
// Not melting, but K and Pa both in supercritical region
if(K >= this.criticalPointKelvin){
return Phase.Supercritical;
// Not melting, with Pa above critical point but not K
}else{
return Phase.Liquid;
}
}
}
}
}
// Phases to be output
class Phase{
constructor(name, describe){
this.name = name;
this.describe = describe;
}
}
Phase.Solid = new Phase("solid", i => `solid ${i}`);
Phase.Liquid = new Phase("liquid", i => `liquid ${i}`);
Phase.Gas = new Phase("gas", i => `${i} gas`);
Phase.Supercritical = new Phase("supercritical", i => `supercritical ${i}`);
// Unit helpers
// Kelvin => Kelvin
const kelvin = K => K;
// Celsius => Kelvin
const celsius = C => 273.15 + C;
// pascals => pascals
const pascals = Pa => Pa;
// kilopascals => pascals
const kilopascals = kPa => 1000 * kPa;
// megapascals => pascals
const megapascals = MPa => 1000000 * MPa;
// Examples of elements with triple and critical points
const hydrogen = new Material("hydrogen", "H2", {
triplePointKelvin: kelvin(13.8033),
triplePointPascals: kilopascals(7.041),
criticalPointKelvin: kelvin(32.938),
criticalPointPascals: megapascals(1.2858),
});
const oxygen = new Material("oxygen", "O2", {
triplePointKelvin: kelvin(54.361),
triplePointPascals: kilopascals(0.1463),
criticalPointKelvin: kelvin(154.581),
criticalPointPascals: megapascals(5.043),
});
// Diagram inputs
const element = hydrogen;
const Pamax = 3;
const Pamin = -4;
const Kmax = 100;
const Kinc = 2.5;
// const element = oxygen;
// const Pamax = 2;
// const Pamin = -5;
// const Kmax = 400;
// const Kinc = 10;
// ¯\_(ツ)_/¯
function leftPad(value, length){
let text = String(value);
while(text.length < length){
text = " " + text;
}
return text;
}
function rightPad(value, length){
let text = String(value);
while(text.length < length){
text = text + " ";
}
return text;
}
// Write the diagram
console.log(`Approximate phase diagram for ${element.name}:\n`);
// Output a graph one horizontal slice at a time
for(let PaExp = Pamax; PaExp >= Pamin; PaExp -= 0.5){
const MPa = 10 ** PaExp; // Megapascals
let line = "";
for(let K = 0; K < Kmax; K += Kinc){
const phase = element.phase(K, MPa * 1000000);
if(phase === Phase.Solid){
line += "X";
}else if(phase === Phase.Liquid){
line += "l";
}else if(phase === Phase.Gas){
line += "~";
}else if(phase === Phase.Supercritical){
line += "*";
}else if(phase === Phase.None){
line += " ";
}else{
line += "?";
}
}
let yLabel = " ";
if(PaExp % 1 === 0){
yLabel = leftPad(`10^${PaExp} MPa`, yLabel.length);
}
console.log(yLabel + " " + line);
}
// Label the X axis
let xLabelLine = " ";
for(let K = 0; K < Kmax; K += Kinc){
if(K % (Kinc * 4) === 0){
xLabelLine += rightPad(K, 4);
}
}
console.log(xLabelLine + "K\n");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment