diff --git a/docs/gettingstarted/gettingstarted.md b/docs/gettingstarted/gettingstarted.md index 07758a1..b6b8352 100644 --- a/docs/gettingstarted/gettingstarted.md +++ b/docs/gettingstarted/gettingstarted.md @@ -23,15 +23,15 @@ You can also download a zip archive of the repository from its github front page ### 2. Get the MobiView2 program. -For now we only support MobiView2 on Windows. It is technically possible to compile it on Linux, so if you need that, please contact us. +For now we only support MobiView2 on Windows. It is theoretically possible to compile it on Linux, so if you need that, please contact us. Open ftp://mobiserver.niva.no/Mobius2 in a file explorer (not a web browser), then download the entire MobiView2 folder by copying it over to somewhere on your machine. -In your local copy, edit MobiView2/config.txt so that the "Mobius2 base path" field contains the location where you put Mobius2 repository, e.g. `"C:/Data/Mobius2"`. +In your local copy, edit MobiView2/config.txt so that the "Mobius2 base path" field contains the location where you put the Mobius2 repository, e.g. `"C:/Data/Mobius2"`. -You can now run MobiView2.exe. Click the ![Open](../img/toolbar/Open.png) open icon in the top left and select e.g. `"Mobius2/models/simplyq.txt"`, then `"Mobius2/models/data/simplyq_simple.dat"`. If the model loaded correctly you can now run it by clicking the ![Run](../img/toolbar/Run.png) runner icon in the MobiView2 toolbar. You can then select series to plot in the result and input series selections in the bottom right. +You can now run MobiView2.exe. Click the ![Open](../img/toolbar/Open.png) open icon in the top left and select e.g. `"Mobius2/models/simplyq.txt"`, then `"Mobius2/models/data/simplyq_simple.dat"`. If the model loaded correctly you can now run it by clicking the ![Run](../img/toolbar/Run.png) runner icon in the MobiView2 toolbar. You can then select the series to plot in the result and input series selections in the bottom right. -If you chose simplyq.txt, you are running [SimplyQ](../existingmodels/simply.html#simplyq), which is a simple hydrology model for predicting river discharge. +If you chose `simplyq.txt`, you are running [SimplyQ](../existingmodels/simply.html#simplyq), which is a simple hydrology model for predicting river discharge. ![MobiView2](../img/mobiview_gettingstarted.png) @@ -74,4 +74,4 @@ The [Guide](../mobius2docs/guide.html) is a good place to start. ### Involve yourself with feedback to the developer team, or become a developer. -Please use the github issues tracker to report bugs. You can also contact us at `magnus.norling@niva.no` \ No newline at end of file +Please use the [github issues tracker](https://github.com/NIVANorge/Mobius2/issues) to report bugs. You can also contact us at `magnus.norling@niva.no` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 508b469..93da384 100644 --- a/docs/index.md +++ b/docs/index.md @@ -44,7 +44,7 @@ Mobius2 also provides special support for transport along directed graphs and gr ## Authors and acknowledgement -The Mobius2 framework is developed by Magnus Dahler Norling for [The Norwegian Institute for Water Research](https://www.niva.no/en) (NIVA). +The Mobius2 framework is developed by Magnus Dahler Norling for [the Norwegian Institute for Water Research](https://www.niva.no/en) (NIVA). Additional contributions: Leah Jackson-Blake (Simply models, general testing), François Clayer (EasyLake model, general testing). diff --git a/models/modules/hbv_snow.txt b/models/modules/hbv_snow.txt index 93335f4..f539ec5 100644 --- a/models/modules/hbv_snow.txt +++ b/models/modules/hbv_snow.txt @@ -12,9 +12,9 @@ module("HBVSnow", version(1, 0, 0), """ This is an adaption of the snow module from HBV-Nordic (Sælthun 1995) -[NVE home page](https://www.nve.no/vann-og-vassdrag/vannets-kretslop/analysemetoder-og-modeller/hbv-modellen/) +[NVE home page](https://www.nve.no/vann-og-vassdrag/vannets-kretsloep/analysemetoder-og-modeller/hbv-modellen/) -[Model description](https://www.uio.no/studier/emner/matnat/geofag/nedlagte-emner/GEO4430/v06/undervisningsmateriale/HBVMOD.PDF) +[Model description](https://publikasjoner.nve.no/publication/1996/publication1996_07.pdf) Authors: Magnus D. Norling """ diff --git a/models/modules/nivafjord/basin.txt b/models/modules/nivafjord/basin.txt index e00aeb4..d89e104 100644 --- a/models/modules/nivafjord/basin.txt +++ b/models/modules/nivafjord/basin.txt @@ -35,6 +35,7 @@ module("NIVAFjord basin", version(0, 0, 3), area : property, freeze_temp : property, sw : property, + ice_ind : loc, vert : connection, sw_vert : connection, sw_sed : loc, @@ -85,6 +86,7 @@ Authors: Magnus D. Norling par_group("Layer specific mixing", layer) { K0 : par_real("Mixing factor reference", [m 2, s-1], 0.5e-4, "Mixing factor when the B-V frequency is equal to the reference") + K0ice : par_real("Mixing factor reference under ice", [m 2, s-1], 0.5e-4) } par_group("Initial layer physical", layer) { @@ -178,7 +180,7 @@ Authors: Magnus D. Norling #TODO: Make wind mixing instead dependent on the B-V frequency also? One issue is to determine how much energy gets "used" in each layer. var(basin.emix, [J], "Total wind mixing energy") { - A[vert.top]*sqrt(stress^3/layer.water.rho[vert.top])*time.step_length_in_seconds + (!ice_ind)*A[vert.top]*sqrt(stress^3/layer.water.rho[vert.top])*time.step_length_in_seconds } var(layer.water.sumV, [m 3]) { @@ -208,8 +210,9 @@ Authors: Magnus D. Norling } var(layer.water.v_t, [m, s-1]) { + K := { K0ice if ice_ind, K0 otherwise }, dz_ := 0.5*(dz + dz[vert.below]), - safe_divide(K0, dz_*(Nfreq/N0)^alpha) + safe_divide(K, dz_*(Nfreq/N0)^alpha) } var(layer.water.v_s, [m, s-1]) { diff --git a/models/modules/nivafjord/fjordchem.txt b/models/modules/nivafjord/fjordchem.txt index 1f6467d..a492827 100644 --- a/models/modules/nivafjord/fjordchem.txt +++ b/models/modules/nivafjord/fjordchem.txt @@ -90,6 +90,7 @@ module("NIVAFjord chemistry", version(0, 0, 5), chem_par : preamble ) { #TODO: Would be nice to unify easychem and fjordchem a bit more, maybe some shared code. + # Esp. for surface O2 exchange par_group("Initial chem", layer) { init_O2 : par_real("Initial O₂ saturation", [], 1, 0, 1) @@ -145,7 +146,7 @@ module("NIVAFjord chemistry", version(0, 0, 5), } var(layer.water.o2satconc, [m g, l-1]) { - o2_saturation(temp, salin)*o2_mol_mass -> [m g, l-1] + o2_saturation(temp, salin)*o2_mol_mass ->> } #@no_store var(layer.water.o2sat, []) { diff --git a/models/nivafjord_isolated_basin_fpv_model.txt b/models/nivafjord_isolated_basin_fpv_model.txt new file mode 100644 index 0000000..4c9750d --- /dev/null +++ b/models/nivafjord_isolated_basin_fpv_model.txt @@ -0,0 +1,60 @@ + + +model("NIVAFjord Isolated Basin FPV") { +""" +NIVAFjord in a single basin without open boundary conditions. Also, you can cover basins with FPV (floating photovoltaics). + +It is also currently without horizontal exchange between basins, so it only works in a single one (or several isolated ones) for now. +""" + + # TODO: FPV cover does not dynamically affect wind mixing (not sure to how large a degree that would happen). + extend("nivafjord_lake_model.txt") + + fpv : compartment("FPV", basin_idx) + + load("modules/airsea_fpv.txt", + module("AirSea FPV", air, basin, fpv, ice, heat, temp, precip, wind, g_rad, pressure, rho, a_hum, lwd, sw, attn, indicator, + evap, cos_z, loc(basin.freeze_t), loc(basin.area), loc(layer.water[vert.top]), loc(layer.water.heat[sw_vert.top]))) + + module("Basin inflow", version(0, 0, 0)) { + + var(air.precip, [m m, day-1], "Precipitation") + var(air.temp, [deg_c], "Air temperature") + + + load("stdlib/seawater.txt", library("Sea oxygen")) + load("stdlib/physiochemistry.txt", library("Chemistry"), library("Water utils")) + + # Water + + flow : property("Basin inflow") + var(basin.flow, [m 3, s-1]) # Input series + + # Just directing the catchment runoff to the top layer instead of doing the density check. + flux(out, layer.water[vert.top], [m 3, s-1], "Discharge from land to basin") { basin.flow->> } + + # O2 + + par_group("Inflow oxygen") { + f_o2sat : par_real("Inflow O₂ saturation fraction", [], 0.9, 0, 1) + } + + flux(out, layer.water.o2[vert.top], [k g, day-1], "Oxygen from land") { + inflow_t := air.temp, # Assume inflow temperature = air temperature (see also below) + land_conc := f_o2sat*o2_saturation(inflow_t, 0) * o2_mol_mass, + basin.flow*land_conc->> + } + + # Heat / temperature + + flux(out, layer.water.heat[vert.top], [J, day-1], "Heat from land") { + inflow_t := air.temp, # Assume inflow temperature = air temperature (see also above) + (water_temp_to_heat(basin.flow => [m 3], inflow_t) => [J, s-1]) ->> + } + + # TODO: Add other substances that may be washed in. + + # TODO: Also outflow? + } +} + diff --git a/models/nivafjord_model.txt b/models/nivafjord_model.txt index aac4ae3..bd5d023 100644 --- a/models/nivafjord_model.txt +++ b/models/nivafjord_model.txt @@ -59,7 +59,7 @@ model("NIVAFjord") { load("modules/nivafjord/basin.txt", dims : preamble("NIVAFjord dimensions", all_basins, layer_idx, layer), - module("NIVAFjord basin", air, basin, layer, water, salt, heat, temp, salinity, pressure, wind, g_rad, rho, attn, z, dz, h, area, freeze_t, sw, vert, sw_vert, loc(sediment.heat), dims)) + module("NIVAFjord basin", air, basin, layer, water, salt, heat, temp, salinity, pressure, wind, g_rad, rho, attn, z, dz, h, area, freeze_t, sw, loc(basin.ice.indicator), vert, sw_vert, loc(sediment.heat), dims)) load("modules/nivafjord/boundary_basin.txt", module("NIVAFjord boundary", bnd_basin, bnd_layer, water, heat, salt, temp, salinity, dz, h, rho, pressure, vert, dims)) diff --git a/models/nivafjord_simplycnp_isolated_basin_model.txt b/models/nivafjord_simplycnp_isolated_basin_model.txt deleted file mode 100644 index 9ecdf41..0000000 --- a/models/nivafjord_simplycnp_isolated_basin_model.txt +++ /dev/null @@ -1,137 +0,0 @@ - - -model("NIVAFjord-SimplyCNP-IsolatedBasin") { -""" -NIVAFjord in a single basin without open boundary conditions. Also, you can cover basins with FPV (floating photovoltaics). - -It is also currently without horizontal exchange between basins, so it only works in a single one (or several isolated ones) for now. -""" - - # TODO: FPV cover does not dynamically affect wind mixing (not sure to how large a degree that would happen). - - basin_idx : index_set("Basin index") - layer_idx : index_set("Layer index") @sub(basin_idx) - - air : compartment("Atmosphere") - basin : compartment("Basin", basin_idx) - layer : compartment("Fjord layer", basin_idx, layer_idx) - sediment : compartment("Fjord sediment", basin_idx, layer_idx) - - fpv : compartment("FPV", basin_idx) - - water : quantity("Water") - ice : quantity("Ice") - salt : quantity("Salt") - heat : quantity("Heat energy") - - sed : quantity("Sediments") - oc : quantity("Organic carbon") - on : quantity("Organic nitrogen") - op : quantity("Organic phosphorous") - din : quantity("Nitrate") - phos : quantity("Phosphate") - - temp : property("Temperature") - salinity : property("Salinity") - precip : property("Precipitation") - wind : property("Wind speed") - g_rad : property("Global radiation") - pressure : property("Pressure") - a_hum : property("Actual specific humidity") - rho : property("Density") - lwd : property("Downwelling longwave radiation") - sw : property("Shortwave radiation") - cos_z : property("Cosine of the solar zenith angle") - attn : property("Attenuation") - freeze_t : property("Ice formation temperature") - indicator : property("Ice indicator") - a_vap : property("Actual vapor pressure") - s_vap : property("Saturation vapor pressure") - - z : property("Depth") - dz : property("Thickness") - h : property("Sea level") - evap : property("Evaporation") - area : property("Area") - - vert : connection("Fjord vertical") @grid1d(layer, layer_idx) - sw_vert : connection("Shortwave vertical") @grid1d(layer, layer_idx) - - par_group("Solver step") { - solver_h : par_real("Initial solver step", [hr], 1) - solver_hmin : par_real("Solver relative min step", [], 0.01) - } - - load("modules/atmospheric.txt", - module("Atmospheric", air, temp, wind, g_rad, pressure, a_hum, rho, lwd, cos_z, a_vap, s_vap)) - - - #TODO: Replace with the one that has FPV covering. - load("modules/airsea_fpv.txt", - module("AirSea FPV", air, basin, fpv, ice, heat, temp, precip, wind, g_rad, pressure, rho, a_hum, lwd, sw, attn, indicator, - evap, cos_z, loc(basin.freeze_t), loc(basin.area), loc(layer.water[vert.top]), loc(layer.water.heat[sw_vert.top]))) - - load("modules/nivafjord/basin.txt", - dims : preamble("NIVAFjord dimensions", basin_idx, layer_idx, layer), - module("NIVAFjord basin", air, basin, layer, water, salt, heat, temp, salinity, pressure, wind, g_rad, rho, attn, z, dz, h, area, freeze_t, sw, vert, sw_vert, loc(sediment.heat), dims)) - - sol : solver("NIVAFjord solver", inca_dascru, solver_h, solver_hmin) - solve(sol, layer.water, basin.ice) - - fjord_phyt : quantity("Fjord phytoplankton") - zoo : quantity("Zooplankton") - o2 : quantity("O₂") - chl_a : property("Chlorophyll-a") - - load("modules/nivafjord/fjordchem.txt", - chem_par : preamble("NIVAFjord chemistry rates", fjord_phyt), - module("NIVAFjord chemistry", air, basin, layer, sediment, water, o2, ice, oc, din, on, phos, op, sed, fjord_phyt, zoo, chl_a, temp, salinity, wind, z, dz, indicator, attn, precip, area, cos_z, sw, vert, chem_par, dims)) - - load("modules/nivafjord/sediment.txt", - module("NIVAFjord sediments", layer, sediment, water, o2, sed, oc, din, on, phos, op, heat, area, temp, dz, vert, chem_par, dims)) - - solve(sol, sediment.sed, sediment.heat) - solve(sol, air.cos_z, air.g_rad) - - module("Basin inflow", version(0, 0, 0)) { - - var(air.precip, [m m, day-1], "Precipitation") - var(air.temp, [deg_c], "Air temperature") - - - load("stdlib/seawater.txt", library("Sea oxygen")) - load("stdlib/physiochemistry.txt", library("Chemistry"), library("Water utils")) - - # Water - - flow : property("Basin inflow") - var(basin.flow, [m 3, s-1]) # Input series - - # Just directing the catchment runoff to the top layer instead of doing the density check. - flux(out, layer.water[vert.top], [m 3, s-1], "Discharge from land to basin") { basin.flow->> } - - # O2 - - par_group("Inflow oxygen") { - f_o2sat : par_real("Inflow O₂ saturation fraction", [], 0.9, 0, 1) - } - - flux(out, layer.water.o2[vert.top], [k g, day-1], "Oxygen from land") { - inflow_t := air.temp, # Assume inflow temperature = air temperature (see also below) - land_conc := f_o2sat*o2_saturation(inflow_t, 0) * o2_mol_mass, - basin.flow*land_conc->> - } - - # Heat / temperature - - flux(out, layer.water.heat[vert.top], [J, day-1], "Heat from land") { - inflow_t := air.temp, # Assume inflow temperature = air temperature (see also above) - (water_temp_to_heat(basin.flow => [m 3], inflow_t) => [J, s-1]) ->> - } - - # TODO: Add other substances that may be washed in. - - # TODO: Also outflow? - } -} -