Created
April 4, 2018 14:54
-
-
Save pineapplemachine/8bd11c7ad219c413b83df9d53ff83b31 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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