diff --git a/docs/img/datafiles/flags.png b/docs/img/datafiles/flags.png index 6f8f6938..ede8d774 100644 Binary files a/docs/img/datafiles/flags.png and b/docs/img/datafiles/flags.png differ diff --git a/docs/mobiviewdocs/plots.md b/docs/mobiviewdocs/plots.md index e3066dea..a324d6ec 100644 --- a/docs/mobiviewdocs/plots.md +++ b/docs/mobiviewdocs/plots.md @@ -10,7 +10,7 @@ has_children: true You can use the plot to visualize inputs and results of the model. Time series can be selected in the result and model input trees to the left of the plot. -![Series selecter](../img/mobiview/series_selecter.png) +![Series selecter](../img/mobiview/series_selection.png) Series are organized in a tree structure according to their [location](../mobius2docs/central_concepts.html#components-and-locations). For instance, the soil water organic carbon is found under `Soil->Water->Organic carbon`. Non-primary state variables are instead organized under the location that makes the most sense, for instance a flux is organized under its source location if it is valid, otherwise its target location. diff --git a/src/model_application.cpp b/src/model_application.cpp index e1adaf72..f5bb2cfe 100644 --- a/src/model_application.cpp +++ b/src/model_application.cpp @@ -1309,6 +1309,20 @@ Model_Application::find_base_flux(Var_Id dissolved_flux_id) { return result_id; } +Var_Id +Model_Application::find_flux_var_of_decl(Entity_Id flux_id) { + // Find the flux state variable corresponding to a model flux declaration. + + // TODO: This is a bit inefficient, should we have a lookup structure for it? + for(auto var_id : vars.all_fluxes()) { + auto var = vars[var_id]; + if(var->type != State_Var::Type::declared) continue; + if(as(var)->decl_id == flux_id) + return var_id; + } + return invalid_var; +} + std::string Model_Application::serialize(Var_Id id) { diff --git a/src/model_application.h b/src/model_application.h index 00c7ca9d..4a0dae60 100644 --- a/src/model_application.h +++ b/src/model_application.h @@ -454,8 +454,7 @@ Model_Application { bool all_indexes_are_set(); - Math_Expr_FT * - get_index_count_code(Entity_Id index_set, Index_Exprs &indexes); + Math_Expr_FT * get_index_count_code(Entity_Id index_set, Index_Exprs &indexes); Sub_Indexed_Component *find_connection_component(Entity_Id conn_id, Entity_Id comp_id, bool make_error = true); Var_Location get_primary_location(Var_Id source, bool &is_conc); @@ -464,6 +463,7 @@ Model_Application { Var_Id get_connection_target_variable(Var_Id source, Entity_Id connection_id, Entity_Id target_component); Var_Id find_base_flux(Var_Id dissolved_flux_id); + Var_Id find_flux_var_of_decl(Entity_Id flux_id); void build_from_data_set(Data_Set *data_set); void save_to_data_set(Model_Data *save_from=nullptr); @@ -496,7 +496,7 @@ read_single_parameter_data(Model_Application *app, Entity_Id par_id, Parameter_D Entity_Id avoid_index_set_dependency(Model_Application *app, Var_Loc_Restriction restriction); -// The point of this one is to make a structure that can be used for local computations, this is not the same as the connection_structure, which is used in the model code generation itself. +// The use case of this one is to make a structure that can be used for local computations, this is not the same as the connection_structure, which is used in the model code generation itself. void make_connection_component_indexing_structure(Model_Application *app, Storage_Structure *components, Entity_Id connection_id); diff --git a/src/model_compilation.cpp b/src/model_compilation.cpp index bff96a7b..be23524a 100644 --- a/src/model_compilation.cpp +++ b/src/model_compilation.cpp @@ -1049,16 +1049,21 @@ set_up_external_computation_instruction(Model_Application *app, Var_Id var_id, s } void -maybe_process_discrete_flux(Model_Application *app, std::vector &instructions, Var_Id var_id, bool is_aggregate, bool has_aggregate) { +maybe_process_discrete_flux(Model_Application *app, std::vector &instructions, Var_Id var_id) { // Generate instructions for updating quantities based on discrete fluxes. auto model = app->model; auto var = app->vars[var_id]; + if(!var->is_flux()) return; + auto loc1 = var->loc1; auto loc2 = var->loc2; + bool is_aggregate = var->type == State_Var::Type::regular_aggregate; + bool has_aggregate = var->has_flag(State_Var::has_aggregate); + std::vector sub_add_instrs; bool is_discrete = false; @@ -1157,14 +1162,10 @@ maybe_process_discrete_flux(Model_Application *app, std::vectorfluxes) { if(after) { - // TODO: Ugh, we have to do this just to find the single state variable corresponding to a given flux declaration. - // should have a lookup structure for it! - for(auto var_id_2 : app->vars.all_fluxes()) { - auto var2 = app->vars[var_id_2]; - if(var2->type != State_Var::Type::declared) continue; - if(as(var2)->decl_id == flux_id) - instructions[var_id_2.id].depends_on_instruction.insert(sub_add_instrs.begin(), sub_add_instrs.end()); - } + auto var_id_2 = app->find_flux_var_of_decl(flux_id); + + if(is_valid(var_id_2)) + instructions[var_id_2.id].depends_on_instruction.insert(sub_add_instrs.begin(), sub_add_instrs.end()); } if(flux_id == flux_decl_id) after = true; @@ -1239,15 +1240,12 @@ build_instructions(Model_Application *app, std::vector &instr auto var = app->vars[var_id]; - bool is_aggregate = var->type == State_Var::Type::regular_aggregate; - bool has_aggregate = var->has_flag(State_Var::has_aggregate); - if(var->type == State_Var::Type::external_computation) { set_up_external_computation_instruction(app, var_id, instructions, initial); continue; } - if(is_aggregate) { + if(var->type == State_Var::Type::regular_aggregate) { // NOTE: We have to look up the solver here. This is because we can't necessarily set it up before this point. // although TODO: Couldn't we though? @@ -1293,9 +1291,9 @@ build_instructions(Model_Application *app, std::vector &instr insert_dependency(app, agg_instr, index_set); } - if(initial || !var->is_flux()) continue; + if(initial) continue; - maybe_process_discrete_flux(app, instructions, var_id, is_aggregate, has_aggregate); + maybe_process_discrete_flux(app, instructions, var_id); } }