コード例 #1
0
    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();
    }
コード例 #2
0
    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);
    }
コード例 #3
0
    //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();
    }
コード例 #4
0
    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();
    }
コード例 #5
0
    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();
    }
コード例 #6
0
    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;
    }
コード例 #7
0
 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;
 }
コード例 #8
0
    //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;
    }
コード例 #9
0
 void Awake()
 {
     ThermoMath.Init();
 }