vlab-example

Virtual Lab Example

This page lays out how you can write and use your own ChemCollective virtual lab using a simple html and JavaScript webpage that can be hosted on Github pages or any other static webhost.

Make a new virtual lab

You can create your own virtual lab by forking this repository on Github or by using the CodePen example, where you can make live changes to the example lab.

The virtual lab object

To create and host your own virtual lab, you create a javascript object with the following format.

The virtual lab object should contain the following 6 keys:

  1. assignment: This informational key should contain
    {"assignmentText": "Assignment description (displayed when title clicked)"}
    
  2. species: This key contains information about chemical species. It contains a list of chemical species (in "SPECIES_LIST": { "SPECIES": [list_of_species]) described in detail below:

    Species specification

    Mandatory keys

    id
    a unique integer
    name
    Can contain superscripts / subscripts using html tags <sup> and <sub> respectively
    enthalpy
    (kJ/mol) at 25 °C
    entropy
    (J/mol-K) at 25 °C
    molecularWeight
    (g/mol) should be provided

    Optional keys

    density
    (g/mL)
    state
    s, l, g, or aq (assumed aqueous if omitted)
    simpleName
    a simpler/shorter name
    specificHeat
    (cal/g-K) Note the specific heat model.
    waterReplacement
    Document this - If aqueous, note that this interacts with waterReplacement when using the default waterInfinite model for solvent Concentration Solution modeler.

    Color keys

    colorConcentration
    For aqueous species, specify the concentration (M) that gives the color determined by the hue, saturation, and value given (inversely related to molar absorptivity).
    hue
    The color’s hue (0 to 360)
    saturation
    The color’s saturation (0 to 100)
    value
    The color’s value (0 to 100)

    Example Here is a complete example showing several species:

     {
         "SPECIES_LIST": {
             "SPECIES": [
                 {
                     "id": 0,
                     "name": "H<sub>2</sub>O",
                     "enthalpy": -285.83,
                     "entropy": 69.91,
                     "state": "l",
                     "molecularWeight": 18.016
                 },
                 {
                     "id": 1,
                     "name": "H<sup>+</sup>",
                     "enthalpy": 0.0,
                     "entropy": 0.0,
                     "molecularWeight": 1.008
                 },
                 {
                     "id": 2,
                     "name": "OH<sup>-</sup>",
                     "enthalpy": -229.99,
                     "entropy": -10.75,
                     "molecularWeight": 17.008
                 },
                 {
                     "id": 3,
                     "name": "Fe<sup>3+</sup>",
                     "simpleName": "Fe3+",
                     "state": "aq",
                     "enthalpy": -48.5,
                     "entropy": -315.9,
                     "density": 3,
                     "specificHeat": 0.0,
                     "molecularWeight": 55.845,
                     "hue": 44.0,
                     "saturation": 72.0,
                     "value": 96.0,
                     "colorConcentration": 0.1
                 },
                 {
                     "id": 5,
                     "name": "FeSCN<sup>2+</sup>",
                     "simpleName": "FeSCN2+",
                     "state": "aq",
                     "enthalpy": 31.25,
                     "entropy": -119.0,
                     "density": 6,
                     "specificHeat": -0.165,
                     "molecularWeight": 113.925,
                     "hue": 0.0,
                     "saturation": 98.0,
                     "value": 54.0,
                     "colorConcentration": 0.001
                 }
             ]
         }
     }
    
  3. configuration: Choose what options and models are used. Here’s an example:
    {
      "title": "Iron Thiocyanate Equilibrium", // Displayed in top corner
     "solutionModellers": {
       // This specific heat model adds heat capacity
       // of solids to liquids / solution species
       "specificHeat": "solvent2" // Other choices...
       // There are several other modelling choices available -
       // if not specified, defaults will be used.
      },
      "solutionViewers": [
     // Control tools users have to display solution information
     // Disable display of key tools that would give answers away...
     {"id": "solutionProperties","displayDefault": true,
        "args": {"honorSignificantFigures": false}
     },
     {"id": "aqueous", "displayDefault": true,
         "args": {"unitsToggleEnabled": true}
     },
     {"id": "solid", "displayDefault": true,
         "args": {"unitsToggleEnabled": true}
     },
     {"id": "spectrometer", "displayDefault": false},
     {"id": "particleView", "displayDefault": false},
     {"id": "thermometer", "displayDefault": true},
     {"id": "pH", "displayDefault": true},
     {"id": "vesselTrackingControl", "displayDefault": false}
      ],
      // Allow all three transfer modes:
      "transfer": ["precise", "significantFigures","realistic"] 
    }
    

SolutionModellers These settings determine how the solution’s properties are computed.

solventConcentration or waterConcentration : solventInfinite/waterInfinite (default), solventFinite/waterFinite

solvent : water/aqueous (default). Uses heat capacity, boiling point, molecular weight, and density defined in Constants. nonwater/nonaqueous. Uses specificHeat, molecularWeight, and density from species with id = 0. undefined/nosolvent Assumes no specific solvent in the system. Calculations are based on the mixture of species. Requires SolventConcentrationModel (solventConcentration parameter in solutionModellers in configuration.json) to be set as SOLVENTFINITE. Automatically switches to NONWATER if SolventConcentrationModel is SOLVENTINFINITE. Property methods (which are these?) should not be called when using this model.

specificHeat : default (What is this model doing?) or solvent2 - Logical model that adds heat capacity of solids to liquids/solution species. NOTE: What about gases?

Needs a longer explanation and perhaps a fix to deal with setting the heat capacity of substances in solution correctly.

liquidVolume : nominal (default) Assumes the volumes are purely additive (when mixing solutions, etc). evaluated assumes that the moles of solvent (id = 0) is properly set in all solutions and calculates volume by using the moles, molecular weight, and density of each species (with no special regard for the solvent). Only applied when solventFinite chosen for solventConcentration.

weight : No settings here, but the solution weight depends on if solventFinite or solventInfinite is chosen. If solventInfinite, then mass of solution = `solventDensity*liquidVolume + mass of species - (moles of species * waterReplacement * solventMolecularWeight). This helps keep the density of the solution from getting too high.

boilingPoint : nominal (default), evaluated Uses mole fraction (potentially requiring solventFinite?) and the boiling point factor from Constants.jl.

freezingPoint : nominal (default), evaluated Uses mole fraction (potentially requiring solventFinite?) and the boiling point factor from Constants.jl.

EquilibriumSettings

liquidUnitActivity
true (default - activity = 1 for all liquids, so they are not included in Q for reactions) or false (liquid activity = mole fraction in solution. Does this require using solventFinite?) This also allows Raolt’s law activities and other colligative properties - vapor pressure reduction with solute, etc.
  1. solutions: This contains all of the solutions available to users:
    {
      "FILESYSTEM": {
     "DIRECTORY": [
       {
         "name": "stockroom",
         "SOLUTION": [ // List of solutions available
           { // Example solution
                  "name": "1.0 M HNO<sub>3</sub>",
                  "description": "1.0 M Nitric acid",
                  "volume": 0.1, // In liters
                  "species": [
                  {"id": 0 // Solvent can be specified with id only unless using `solventConcentration: solventFinite` in solutionModellers
                  },
                  {"id": 1, "amount": 0.1 // Other species need amounts in mol
                  },
                  {"id": 6, "amount": 0.1}
                  ]
           },
           {
                   "name": "Distilled H<sub>2</sub>O", 
                   "description": "Distilled Water", 
                   "volume": "3.0", 
                   "vessel": "3LCarboy", // Vessel defaults to 250 mL Erlenmeyer flask
                   "species": [
                      {
                         "id": 0
                      }
                   ]
           }
         ]
       }
     ]
      }
    }
    
  2. reactions: A list of reactions (the vlab will ensure each reaction listed quickly reaches equilibrium at a given temperature)

     {
         "REACTION": [
           {"SPECIES_REF": [
               {"id": "0", "coefficient": "-1"},
               {"id": "1","coefficient": "1"},
               {"id": "2","coefficient": "1"}
             ]
           }
         ]
     }
    
  3. spectra: This key contains spectral information (displayed in the spectrum viewer).
    {
      "SPECTRA_LIST": {
     "SPECIES": []
      }
    }
    

Keys:


4. solutions.json

This file defines the solutions available in the lab.

Structure:

{
    "FILESYSTEM": {
        "DIRECTORY": [
            {
                "name": "stockroom",
                "SOLUTION": [
                    {
                        "name": "1.0 M HNO<sub>3</sub>",
                        "description": "1.0 M Nitric acid",
                        "volume": 0.1,
                        "species": [
                            {"id": 0},
                            {"id": 1, "amount": 0.1},
                            {"id": 6, "amount": 0.1}
                        ]
                    }
                ]
            }
        ]
    }
}

Keys:


5. reactions.json

This file defines the chemical reactions available in the lab.

Structure:

{
    "REACTION": [
        {
            "SPECIES_REF": [
                {"id": 0, "coefficient": -1},
                {"id": 1, "coefficient": 1},
                {"id": 2, "coefficient": 1}
            ]
        }
    ]
}

Keys:


6. spectra.json

This file defines the spectral data for species.

Structure:

{
    "SPECTRA_LIST": {
        "SPECIES": [
            {
                "id": 0,
                "BAND": [
                    {"wavelength": 400, "e": 0.8, "width": 50},
                    {"wavelength": 500, "e": 0.6, "width": 1000}
                ]
            }
        ]
    }
}

Keys:


By following this guide, you can create the six JSON files required for the Virtual Lab. Ensure all files are properly formatted and validated before use.

Similar code found with 1 license type

Technical Overview

  1. Leave an empty element (div, section, etc…) that the vlab will be loaded into:

     <div id="vlab"></div>
    
  2. On the html page, load the scripts shown below:

     <link href="https://nifty-newton-c83258.netlify.app/bundled/911.css" rel="stylesheet">
     <script src="https://nifty-newton-c83258.netlify.app/bundled/850.js"></script>
     <script src="https://nifty-newton-c83258.netlify.app/bundled/526.js"></script>
     <script src="https://nifty-newton-c83258.netlify.app/bundled/911.js"></script>
     <script src="https://nifty-newton-c83258.netlify.app/bundled/lib.js"></script>
    
  3. Define the virtual lab as a javascript object (see above for details).

     const data = {
     assignment: {...
     }, ...
     }
    
  4. Define global variables and load the virtual lab into the empty element with the following lines:

     const language = 'en';
     const allowLoadAssignment = false;
     const showFirstTimeTips = false;
     const appModel = new VLab.AppModel();
     const appView = new VLab.AppView({ model: appModel,
                                       el: document.getElementById("vlab"),
                                       vlab: data,
                 domain: "https://chemcollective.org/chem/jsvlab/"});
    

Example Lab

To view the full javascript for the example below, see Github. Note that on GitHub pages, there are slight formatting/color issues due to clashing CSS rules-the CodePen example has correct color/font CSS behavior.