public void add_heat_constant_v(double j) { try { double new_u = internalenergy + j; double new_t = ThermoMath.iterate_t_given_v_verify_u(temperature, volume, new_u); //at this point, we have enough internal state to derive the rest internalenergy = new_u; temperature = new_t; pressure = ThermoMath.p_given_vt(volume, temperature); enthalpy = ThermoMath.h_given_vt(volume, temperature); entropy = ThermoMath.s_given_vt(volume, temperature); region = ThermoMath.region_given_pvt(pressure, volume, temperature); switch (region) { case 0: quality = 0; break; //subcooled liquid case 1: quality = ThermoMath.x_given_pv(pressure, volume); break; //two-phase region case 2: quality = 1; break; //superheated vapor } } catch (Exception e) {} clamp_state(); visualize_state(); }
void SetChallengeBall() { double volume = ThermoMath.v_given_percent(Random.Range(0.1f, 0.9f)); double temperature = ThermoMath.t_given_percent(Random.Range(0.1f, 0.9f)); double pressure = ThermoMath.p_given_vt(volume, temperature); challenge_dot.transform.localPosition = thermo.plot(pressure, volume, temperature); }
//assume starting/ending point consistent for whole API! public void add_heat_constant_p(double j) { try { double new_h = enthalpy + j; switch (region) { case 1: double new_x = ThermoMath.x_given_ph(pressure, new_h); //at this point, we have enough internal state to derive the rest enthalpy = new_h; quality = new_x; volume = ThermoMath.v_given_px(pressure, new_x); temperature = ThermoMath.tsat_given_p(pressure); entropy = ThermoMath.s_given_px(pressure, new_x); internalenergy = ThermoMath.u_given_px(pressure, new_x); break; case 0: case 2: //at this point, we have enough internal state to derive the rest enthalpy = new_h; volume = ThermoMath.v_given_ph(pressure, new_h); temperature = ThermoMath.t_given_ph(pressure, new_h); entropy = ThermoMath.s_given_vt(volume, temperature); internalenergy = ThermoMath.u_given_vt(volume, temperature); break; } region = ThermoMath.region_given_pvt(pressure, volume, temperature); switch (region) { case 0: quality = 0; break; //subcooled liquid case 1: quality = ThermoMath.x_given_pv(pressure, volume); break; //two-phase region case 2: quality = 1; break; //superheated vapor } } catch (Exception e) {} if (debug_write) { debug_file.WriteLine("add_heat_constant_p({0})", j); debug_deltas(); } clamp_state(); visualize_state(); }
public void add_pressure_insulated(double p) { try { double new_p = pressure + p; switch (region) { case 0: //subcooled liquid case 1: //two-phase region { //AVOID THESE SCENARIOS } break; case 2: //superheated vapor { //default guess double new_t = temperature; double new_u = internalenergy; double new_v = volume; double k = 1.27; new_v = volume * Math.Pow(pressure / new_p, 1.0 / k); new_u = internalenergy - ((new_p * new_v - pressure * volume) / (1 - k)); new_t = ThermoMath.iterate_t_given_p_verify_u(temperature, pressure, new_u); //at this point, we have enough internal state to derive the rest pressure = new_p; volume = new_v; temperature = new_t; internalenergy = new_u; enthalpy = ThermoMath.h_given_vt(volume, temperature); entropy = ThermoMath.s_given_vt(volume, temperature); region = ThermoMath.region_given_pvt(pressure, volume, temperature); } break; } } catch (Exception e) {} clamp_state(); visualize_state(); }
public void add_pressure_uninsulated(double p) { try { double new_p = pressure + p; switch (region) { case 0: //subcooled liquid case 1: //two-phase region { //AVOID THESE SCENARIOS return; } break; case 2: //superheated vapor { //default guess double new_u = internalenergy; double new_v = volume; //already done! new_v = ThermoMath.v_given_pt(new_p, temperature); new_u = ThermoMath.u_given_pt(new_p, temperature); //at this point, we have enough internal state to derive the rest pressure = new_p; volume = new_v; internalenergy = new_u; enthalpy = ThermoMath.h_given_vt(volume, temperature); entropy = ThermoMath.s_given_vt(volume, temperature); region = ThermoMath.region_given_pvt(pressure, volume, temperature); } break; } } catch (Exception e) {} clamp_state(); visualize_state(); }
void reset_state() { //ensure consistent state pressure = ThermoMath.p_neutral; temperature = ThermoMath.t_neutral; //from this point, the rest should be derived! volume = ThermoMath.v_given_pt(pressure, temperature); internalenergy = ThermoMath.u_given_pt(pressure, temperature); enthalpy = ThermoMath.h_given_vt(volume, temperature); entropy = ThermoMath.s_given_vt(volume, temperature); quality = ThermoMath.x_neutral; region = ThermoMath.region_given_pvt(pressure, volume, temperature); prev_pressure = -1; prev_temperature = -1; prev_volume = -1; prev_internalenergy = -1; prev_entropy = -1; prev_enthalpy = -1; prev_quality = -1; prev_region = -1; }
public ThermoPoint(double t, double v, double p, double u, double h, double s, ThermoMath.area a, int i) { T = t; V = v; P = p; U = u; H = h; S = s; area = a; index = i; }
//generates points from thermomath api, and stitches them together into a mesh //the "only reason" this is complex is: // we generate a "biased", "zoomed" grid of the mesh looked at from one axis ("looking at yz graph"). // then we stitch this uniform (uniform other than bias/zoom, which can be "ignored") graph together. // however, there is a region of the generated graph ("the vapor dome") which is "constant z" (so invisible to this perspective). // so we detect triangles that span this "invisible" region, and cut them out of the stitching. // we then generate the vapor dome points _independently_, and create a very nice mesh of the region across the "xy" plane, which by design fits right into the cutaway stitching. // the final step then, is to "zip" together the two meshes. // this is done by walking the sorted list of "orphaned" points (<- I could have come up with a better name for that...), which corresponds to the list of points disconnected by the cutting of the grid mesh // and simultaneously walking the sorted list of the vapor dome region points, zig-zagging triangles to fill the space //the good news: any complexity from the generation of the mesh is pretty well isolated to this one function // NOTE: Phil didn't really say *what* this mesh is, just "a mesh". This function generates the graph object's mesh. void genMesh() { GameObject old_gm = GameObject.Find("graph_mesh"); if (old_gm != null) { Destroy(old_gm); } int n_pts = samples * samples; int n_pts_per_group = 1000; int n_groups = (int)Mathf.Ceil(n_pts / n_pts_per_group); Vector3[] pt_positions; //gen positions pt_positions = new Vector3[n_pts]; for (int y = 0; y < samples; y++) { double pt = ((double)y / (samples - 1)); for (int z = 0; z < samples; z++) { double tt = ((double)z / (samples - 1)); double pst = sample(pt); double tst = sample(tt); double p = ThermoMath.p_given_percent(pst); double t = ThermoMath.t_given_percent(tst); double v = ThermoMath.v_given_pt(p, t); //pvt in Pa, M^3/Kg, K //Debug.LogFormat("p:{0}Pa, v:{1}M^3/Kg, t:{2}K",p,v,t); int i = samples * y + z; pt_positions[i] = plot(p, v, t); } } //MESH List <Vector3> mesh_positions; List <Vector3> mesh_normals; List <int> mesh_triangles; mesh_positions = new List <Vector3>(pt_positions); int vi = 0; int ni = 0; mesh_triangles = new List <int>((samples - 1) * (samples - 1) * 6); for (int y = 0; y < samples - 1; y++) { for (int z = 0; z < samples - 1; z++) { vi = samples * y + z; mesh_triangles.Add(vi + 0); ni++; mesh_triangles.Add(vi + samples + 0); ni++; mesh_triangles.Add(vi + samples + 1); ni++; mesh_triangles.Add(vi + 0); ni++; mesh_triangles.Add(vi + samples + 1); ni++; mesh_triangles.Add(vi + 1); ni++; } } int concentrated_samples = samples * 2; int position_dome_region = mesh_positions.Count; float highest_y = 0f; int highest_y_i = 0; for (int y = 0; y < concentrated_samples; y++) { double pt = ((double)y / (concentrated_samples - 1)); double pst = sample(pt); double p = ThermoMath.psat_given_percent(pst); double t = ThermoMath.tsat_given_p(p); //pvt in Pa, M^3/Kg, K //Debug.LogFormat("p:{0}Pa, v:{1}M^3/Kg, t:{2}K",p,v,t); float pplot = plot_dimension(ThermoMath.p_min, ThermoMath.p_max, p); if (pplot > highest_y) { highest_y = pplot; highest_y_i = mesh_positions.Count; } float tplot = plot_dimension(ThermoMath.t_min, ThermoMath.t_max, t); double v; float vplot; Vector3 point; v = ThermoMath.vliq_given_p(p); vplot = plot_dimension(ThermoMath.v_min, ThermoMath.v_max, v); point = new Vector3(vplot, pplot, tplot); mesh_positions.Add(point); v = ThermoMath.vvap_given_p(p); vplot = plot_dimension(ThermoMath.v_min, ThermoMath.v_max, v); point = new Vector3(vplot, pplot, tplot); mesh_positions.Add(point); } highest_y = Mathf.Lerp(highest_y, 1f, 0.01f); //extra nudge up //kill spanning triangles; gather orphans //"ladder"/"rung" terminology a bit arbitrary- attempts to keep track of each side of a "zipper" for each seam ("left" seam, "right" seam, each have own ladder/rung) List <int> left_orphans = new List <int>(); List <int> right_orphans = new List <int>(); int left_ladder_i = position_dome_region; Vector3 left_ladder = mesh_positions[left_ladder_i]; Vector3 left_rung = mesh_positions[left_ladder_i + 2]; int right_ladder_i = left_ladder_i + 1; Vector3 right_ladder = mesh_positions[right_ladder_i]; Vector3 right_rung = mesh_positions[right_ladder_i + 2]; for (var i = 0; i < mesh_triangles.Count; i += 3) { int ai = mesh_triangles[i + 0]; int bi = mesh_triangles[i + 1]; int ci = mesh_triangles[i + 2]; Vector3 a = mesh_positions[ai]; Vector3 b = mesh_positions[bi]; Vector3 c = mesh_positions[ci]; if ((left_rung.y < a.y || left_rung.y < b.y || left_rung.y < c.y) && left_ladder_i + 4 < mesh_positions.Count) { left_ladder_i += 2; left_ladder = mesh_positions[left_ladder_i]; left_rung = mesh_positions[left_ladder_i + 2]; } if ((right_rung.y < a.y || right_rung.y < b.y || right_rung.y < c.y) && right_ladder_i + 4 < mesh_positions.Count) { right_ladder_i += 2; right_ladder = mesh_positions[right_ladder_i]; right_rung = mesh_positions[right_ladder_i + 2]; } float x_cmp = (left_ladder.x + right_ladder.x) / 2f; if ( (a.y < highest_y || b.y < highest_y || c.y < highest_y) && (a.x < x_cmp || b.x < x_cmp || c.x < x_cmp) && (a.x > x_cmp || b.x > x_cmp || c.x > x_cmp) ) { mesh_triangles.RemoveAt(i + 2); mesh_triangles.RemoveAt(i + 1); mesh_triangles.RemoveAt(i + 0); i -= 3; if (a.x < x_cmp && b.x < x_cmp) { left_orphans.Add(ai); left_orphans.Add(bi); right_orphans.Add(ci); } else if (b.x < x_cmp && c.x < x_cmp) { left_orphans.Add(bi); left_orphans.Add(ci); right_orphans.Add(ai); } else if (c.x < x_cmp && a.x < x_cmp) { left_orphans.Add(ci); left_orphans.Add(ai); right_orphans.Add(bi); } else if (a.x < x_cmp) { right_orphans.Add(bi); right_orphans.Add(ci); left_orphans.Add(ai); } else if (b.x < x_cmp) { right_orphans.Add(ai); right_orphans.Add(ci); left_orphans.Add(bi); } else if (c.x < x_cmp) { right_orphans.Add(ai); right_orphans.Add(bi); left_orphans.Add(ci); } else { Debug.Log("NOOOO"); } } } //sort orphans GRAPHPTCMP cmp = new GRAPHPTCMP(mesh_positions); left_orphans.Sort(cmp); for (int i = 1; i < left_orphans.Count; i++) { if (left_orphans[i - 1] == left_orphans[i]) { left_orphans.RemoveAt(i); i--; } } right_orphans.Sort(cmp); for (int i = 1; i < right_orphans.Count; i++) { if (right_orphans[i - 1] == right_orphans[i]) { right_orphans.RemoveAt(i); i--; } } //stitch orphans int left_orphan_i = 0; int right_orphan_i = 0; { int triangle_stitch_region = mesh_triangles.Count; List <int> orphans; int ladder_i; Vector3 ladder; Vector3 rung; int orphan_i; Vector3 orphan; Vector3 orung; int ai = 0; int bi = 0; int ci = 0; //left orphans = left_orphans; orphan_i = 0; orphan = mesh_positions[orphans[orphan_i]]; ladder_i = position_dome_region; ladder = mesh_positions[ladder_i]; rung = mesh_positions[ladder_i + 2]; mesh_triangles.Add(ladder_i); mesh_triangles.Add(orphans[orphan_i]); orphan_i++; orphan = mesh_positions[orphans[orphan_i]]; orung = mesh_positions[orphans[orphan_i + 1]]; mesh_triangles.Add(orphans[orphan_i]); orphan = mesh_positions[orphans[orphan_i]]; while (ladder_i + 2 < mesh_positions.Count) { while (orung.z <= rung.z && orung.y <= rung.y && orphan_i + 1 < orphans.Count) { //increment orphan ai = ladder_i; bi = orphans[orphan_i]; ci = orphans[orphan_i + 1]; mesh_triangles.Add(ai); mesh_triangles.Add(bi); mesh_triangles.Add(ci); orphan_i++; orphan = mesh_positions[orphans[orphan_i]]; if (orphan_i + 1 < orphans.Count) { orung = mesh_positions[orphans[orphan_i + 1]]; //yes, both this AND previous line need +1 (+1 for advance, +1 for orung) } } if (ladder_i + 2 < mesh_positions.Count) { //increment ladder ai = ladder_i; bi = orphans[orphan_i]; ci = ladder_i + 2; mesh_triangles.Add(ai); mesh_triangles.Add(bi); mesh_triangles.Add(ci); ladder_i += 2; ladder = mesh_positions[ladder_i]; if (ladder_i + 2 < mesh_positions.Count) { rung = mesh_positions[ladder_i + 2]; //yes, both this AND previous line need +2 (+2 for advance, +2 for rung) } } } left_orphan_i = orphan_i; //right orphans = right_orphans; orphan_i = 0; orphan = mesh_positions[orphans[orphan_i]]; orung = mesh_positions[orphans[orphan_i + 1]]; ladder_i = position_dome_region + 1; ladder = mesh_positions[ladder_i]; rung = mesh_positions[ladder_i + 2]; mesh_triangles.Add(orphans[orphan_i]); mesh_triangles.Add(ladder_i); ladder_i += 2; ladder = mesh_positions[ladder_i]; mesh_triangles.Add(ladder_i); while (ladder_i + 2 < mesh_positions.Count) { while ((ladder.y > orung.y || rung.z > orung.z) && orphan_i + 1 < orphans.Count) { //increment orphan ai = orphans[orphan_i]; bi = ladder_i; ci = orphans[orphan_i + 1]; mesh_triangles.Add(ai); mesh_triangles.Add(bi); mesh_triangles.Add(ci); orphan_i++; orphan = mesh_positions[orphans[orphan_i]]; if (orphan_i + 1 < orphans.Count) { orung = mesh_positions[orphans[orphan_i + 1]]; //yes, both this AND previous line need +1 (+1 for advance, +1 for orung) } } if (ladder_i + 2 < mesh_positions.Count) { //increment ladder ai = orphans[orphan_i]; bi = ladder_i; ci = ladder_i + 2; mesh_triangles.Add(ai); mesh_triangles.Add(bi); mesh_triangles.Add(ci); ladder_i += 2; ladder = mesh_positions[ladder_i]; if (ladder_i + 2 < mesh_positions.Count) { rung = mesh_positions[ladder_i + 2]; //yes, both this AND previous line need +2 (+2 for advance, +2 for rung) } } } right_orphan_i = orphan_i; } //fan missing top for (int i = left_orphan_i + 1; i < left_orphans.Count; i++) { mesh_triangles.Add(left_orphans[i - 1]); mesh_triangles.Add(left_orphans[i]); mesh_triangles.Add(highest_y_i); } for (int i = right_orphan_i + 1; i < right_orphans.Count; i++) { mesh_triangles.Add(right_orphans[i]); mesh_triangles.Add(right_orphans[i - 1]); mesh_triangles.Add(highest_y_i); } mesh_triangles.Add(left_orphans[left_orphans.Count - 1]); mesh_triangles.Add(right_orphans[right_orphans.Count - 1]); mesh_triangles.Add(highest_y_i); //fill in dome int triangle_inner_dome_region = mesh_triangles.Count; int position_dome_inner_region = mesh_positions.Count; for (int i = position_dome_region; i < position_dome_inner_region; i++) //duplicate inner positions so each can have own normal at seam { mesh_positions.Add(mesh_positions[i]); } for (int y = 0; y < concentrated_samples - 1; y++) { mesh_triangles.Add(position_dome_inner_region + y * 2 + 0); mesh_triangles.Add(position_dome_inner_region + y * 2 + 2); mesh_triangles.Add(position_dome_inner_region + y * 2 + 1); mesh_triangles.Add(position_dome_inner_region + y * 2 + 1); mesh_triangles.Add(position_dome_inner_region + y * 2 + 2); mesh_triangles.Add(position_dome_inner_region + y * 2 + 3); } //set normals mesh_normals = new List <Vector3>(new Vector3[mesh_positions.Count]); for (int i = 0; i < triangle_inner_dome_region; i += 3) { int ai = mesh_triangles[i + 0]; int bi = mesh_triangles[i + 1]; int ci = mesh_triangles[i + 2]; Vector3 a = mesh_positions[ai]; Vector3 b = mesh_positions[bi]; Vector3 c = mesh_positions[ci]; Vector3 n = Vector3.Cross(Vector3.Normalize(b - a), Vector3.Normalize(c - a)); mesh_normals[ai] = n; mesh_normals[bi] = n; mesh_normals[ci] = n; } for (int i = triangle_inner_dome_region; i < mesh_triangles.Count; i += 3) { int ai = mesh_triangles[i + 0]; int bi = mesh_triangles[i + 1]; int ci = mesh_triangles[i + 2]; Vector3 a = mesh_positions[ai]; Vector3 b = mesh_positions[bi]; Vector3 c = mesh_positions[ci]; Vector3 n = Vector3.Cross(Vector3.Normalize(b - a), Vector3.Normalize(c - a)); mesh_normals[ai] = n; mesh_normals[bi] = n; mesh_normals[ci] = n; } Mesh mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.vertices = mesh_positions.ToArray(); mesh.normals = mesh_normals.ToArray(); mesh.triangles = mesh_triangles.ToArray(); GameObject graphObject = new GameObject("graph_mesh", typeof(MeshFilter), typeof(MeshRenderer), typeof(Lightable)); graphObject.transform.parent = graph.transform; graphObject.transform.localPosition = new Vector3(0f, 0f, 0f); graphObject.transform.localScale = new Vector3(1f, 1f, 1f); graphObject.transform.localRotation = Quaternion.identity; graphObject.GetComponent <MeshFilter>().mesh = mesh; graphObject.GetComponent <MeshRenderer>().material = graph_material; var lightable = graphObject.GetComponent <Lightable>(); lightable.use_custom_mats = true; lightable.base_mat = graph_material; lightable.lit_mat = graph_material_lit; }
void Awake() { ThermoMath.Init(); }