diff --git a/src/topupopt/problems/esipp/model.py b/src/topupopt/problems/esipp/model.py
index e686001a0a68374f52726398e2ef5d87ec7bd023..9a23a7554d629174e522783a4d0864cfd15c27f3 100644
--- a/src/topupopt/problems/esipp/model.py
+++ b/src/topupopt/problems/esipp/model.py
@@ -4,8 +4,8 @@ import pyomo.environ as pyo
 
 from math import isfinite, inf
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 def create_model(name: str,
                  enable_default_values: bool = True,
@@ -14,15 +14,15 @@ def create_model(name: str,
     
     # TODO: make default values, validation, and initialisation optional
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # create model object
     
     model = pyo.AbstractModel(name)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
         
     # naming convention:
     # variables start with "var_"
@@ -41,19 +41,19 @@ def create_model(name: str,
     
     # TODO: add piecewise constraints for the import and export flows/prices
     
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # sets
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # input sets
     
-    #**************************************************************************
+    # *************************************************************************
     
     # set of assessments
     
@@ -93,8 +93,8 @@ def create_model(name: str,
     model.set_L_max_in_g = pyo.Set(model.set_G,
                                    within=model.set_L) # should inherently exclude import nodes
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # sparse sets
     
@@ -210,8 +210,8 @@ def create_model(name: str,
             )
         )
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # input sets
     
@@ -298,8 +298,8 @@ def create_model(name: str,
     model.set_J_stt_ds = pyo.Set(model.set_GLL,
                                  within=model.set_J_stt)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # systems
     
@@ -311,7 +311,7 @@ def create_model(name: str,
     
     model.set_I_new = pyo.Set(within=model.set_I)
 
-    #**************************************************************************
+    # *************************************************************************
     
     # inputs
     
@@ -344,7 +344,7 @@ def create_model(name: str,
     model.set_M_ext = pyo.Set(model.set_I,
                               within=model.set_M)
 
-    #**************************************************************************
+    # *************************************************************************
     
     # outputs
     
@@ -376,7 +376,7 @@ def create_model(name: str,
     
     model.set_R_ext = pyo.Set(model.set_I)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # states
     
@@ -429,12 +429,12 @@ def create_model(name: str,
     model.set_N_ref_d = pyo.Set(model.set_I,
                                 within=model.set_N)
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # sparse index sets
 
-    #**************************************************************************
+    # *************************************************************************
     
     # set of price segments
     
@@ -480,7 +480,7 @@ def create_model(name: str,
         initialize=(init_set_GLQPKS_imp if enable_initialisation else None)
         )
     
-    #**************************************************************************
+    # *************************************************************************
     
     # all arcs
     
@@ -538,7 +538,7 @@ def create_model(name: str,
             )
         )
 
-    #**************************************************************************
+    # *************************************************************************
     
     # sets of GLLJ tuples for directed arcs
     
@@ -609,7 +609,7 @@ def create_model(name: str,
         model.set_GLLJ_dir_new - model.set_GLLJ_dir_new_mdt
         )
     
-    #**************************************************************************
+    # *************************************************************************
     
     # sets of GLLJ tuples for undirected arcs
                              
@@ -698,7 +698,7 @@ def create_model(name: str,
         initialize=(init_set_GLLJ_int if enable_initialisation else None)
         )
     
-    #**************************************************************************
+    # *************************************************************************
                            
     # set of complementary GLLJ tuples for undirected arcs
     
@@ -824,7 +824,7 @@ def create_model(name: str,
         model.set_GLLJ_static & model.set_GLLJ_und_new
         )
     
-    #**************************************************************************
+    # *************************************************************************
     
     # set of GLLJ tuples for undirected arcs with redundancies
     
@@ -860,7 +860,7 @@ def create_model(name: str,
         model.set_GLLJ_und_pre_red - model.set_GLLJ_und_pre_inf_red
         )
 
-    #**************************************************************************
+    # *************************************************************************
     
     # sets of GLLJ tuples for directed and undirected arcs (no redundancies)
     
@@ -896,7 +896,7 @@ def create_model(name: str,
             )
         )
         
-    #**************************************************************************
+    # *************************************************************************
     
     # sets of GLLJ tuples for directed and undirected arcs (with redundancies)
     
@@ -935,7 +935,7 @@ def create_model(name: str,
             )
         )
     
-    #**************************************************************************
+    # *************************************************************************
     
     # set of arc options
     
@@ -977,7 +977,7 @@ def create_model(name: str,
             )
         )
 
-    #**************************************************************************
+    # *************************************************************************
     
     # arc selection using SOS1
                              
@@ -1026,7 +1026,7 @@ def create_model(name: str,
             )
         )
     
-    #**************************************************************************
+    # *************************************************************************
 
     # flow sense determination using SOS1
         
@@ -1067,7 +1067,7 @@ def create_model(name: str,
         dimen=6, 
         initialize=init_set_GLLJQK_und_sns_sos1_red_gllj)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # inputs
     
@@ -1122,7 +1122,7 @@ def create_model(name: str,
                                initialize=init_set_IM_ext,
                                within=model.set_IM)
 
-    #**************************************************************************
+    # *************************************************************************
     
     # states
     
@@ -1225,7 +1225,7 @@ def create_model(name: str,
                                  initialize=init_set_IN_ref_d,
                                  within=model.set_IN)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # outputs
     
@@ -1292,7 +1292,7 @@ def create_model(name: str,
     model.set_IR_ext = pyo.Set(dimen=2,
                                initialize=init_set_IR_ext)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # combined inputs/states/outputs
 
@@ -1333,8 +1333,8 @@ def create_model(name: str,
     model.set_IRN = pyo.Set(dimen=3,
                             initialize=init_set_IRN)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # set of arc groups
     
@@ -1469,19 +1469,19 @@ def create_model(name: str,
     
     model.var_v_amp_t = pyo.Var(model.set_T)    
         
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # parameters
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # objective function
     
-    #**************************************************************************
+    # *************************************************************************
     
     # general parameters
     
@@ -1603,7 +1603,7 @@ def create_model(name: str,
                                            within=pyo.NonNegativeReals,
                                            default=0)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # arcs
     
@@ -1652,7 +1652,7 @@ def create_model(name: str,
         model.set_GLLJQK_und_sns_sos1_red,
         within=pyo.NonNegativeReals)
                                                     
-    #**************************************************************************
+    # *************************************************************************
         
     # relative variation of arc-dependent losses
     
@@ -1668,7 +1668,7 @@ def create_model(name: str,
                                          model.set_QK,
                                          within=pyo.NonNegativeReals)
                                                            
-    #**************************************************************************
+    # *************************************************************************
     
     # network
 
@@ -1711,7 +1711,7 @@ def create_model(name: str,
                                         default=0, # default: no effect
                                         within=pyo.Reals)
     
-    #**************************************************************************
+    # *************************************************************************
  
     # inputs
     
@@ -1734,7 +1734,7 @@ def create_model(name: str,
                                          within=pyo.PositiveReals,
                                          default=1)
   
-    #**************************************************************************
+    # *************************************************************************
     
     # states
     
@@ -1801,7 +1801,7 @@ def create_model(name: str,
                                         default=0, # default: no effect
                                         within=pyo.Reals)
   
-    #**************************************************************************
+    # *************************************************************************
     
     # outputs
     
@@ -1862,15 +1862,15 @@ def create_model(name: str,
                                         default=0, # default: no effect
                                         within=pyo.Reals)
           
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # variables
           
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # objective function
     
@@ -1938,7 +1938,7 @@ def create_model(name: str,
                                   within=pyo.NonNegativeReals,
                                   bounds=bounds_var_if_glqpks)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # arcs
     
@@ -1978,7 +1978,7 @@ def create_model(name: str,
                                      model.set_QK,
                                      within=pyo.NonNegativeReals)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # decision to install a given arc
     
@@ -2013,7 +2013,7 @@ def create_model(name: str,
     model.var_xi_arc_inv_gllj = pyo.Var(model.set_GLLJ_int, 
                                         within=pyo.UnitInterval)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # converters  
         
@@ -2054,7 +2054,7 @@ def create_model(name: str,
     model.var_u_amp_im = pyo.Var(model.set_IM_dim,
                                  within=pyo.NonNegativeReals)
 
-    #**************************************************************************
+    # *************************************************************************
     
     # outputs
     
@@ -2093,7 +2093,7 @@ def create_model(name: str,
     model.var_y_amp_neg_ir = pyo.Var(model.set_IR_dim_neg,
                                      within=pyo.Reals)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # states
     
@@ -2135,15 +2135,15 @@ def create_model(name: str,
                                            model.set_QK,
                                            within=pyo.NonNegativeReals)
     
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # objective function
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # maximise npv
     
@@ -2155,19 +2155,19 @@ def create_model(name: str,
             )
     model.obj_f = pyo.Objective(rule=obj_f_rule, sense=pyo.maximize)
     
-    #**************************************************************************
-    #**************************************************************************                                 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************                                 
+    # *************************************************************************
+    # *************************************************************************
 
     # Constraints
                               
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # objective function
     
-    #**************************************************************************
+    # *************************************************************************
     
     # opex
     
@@ -2267,7 +2267,7 @@ def create_model(name: str,
                                             model.set_QPK,
                                             rule=rule_constr_imp_flows)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # sum of discounted externalities
     
@@ -2326,7 +2326,7 @@ def create_model(name: str,
             )
     model.constr_sdext_q = pyo.Constraint(model.set_Q, rule=rule_sdext_q)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # capex
     
@@ -2411,13 +2411,13 @@ def create_model(name: str,
     model.constr_capex_system = pyo.Constraint(model.set_I_new,
                                                rule=rule_capex_converter)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # network
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # flow equilibrium equation
     
@@ -2547,7 +2547,7 @@ def create_model(name: str,
                                                model.set_QK,
                                                rule=rule_node_balance)
                                                
-    #**************************************************************************
+    # *************************************************************************
     
     # limit number of directed arcs per direction
     
@@ -2712,7 +2712,7 @@ def create_model(name: str,
         model.set_GLL_arc_max,
         rule=rule_constr_limited_parallel_arcs_per_direction)
                                                                                           
-    #**************************************************************************
+    # *************************************************************************
     
     # there can only one incoming arc at most, if there are no outgoing arcs
     
@@ -2746,11 +2746,11 @@ def create_model(name: str,
         
         else: # more than one incoming arc is possible
         
-            #******************************************************************
+            # *****************************************************************
             
             # number of (new) incoming directed arcs in a group
                         
-            #******************************************************************
+            # *****************************************************************
         
             b_max_in_gl = 0
         
@@ -2760,7 +2760,7 @@ def create_model(name: str,
                 
             temp_constr = (
                 sum(
-                    #**********************************************************
+                    # *********************************************************
                     # interfaced groups
                     sum(
                         sum(1
@@ -2771,7 +2771,7 @@ def create_model(name: str,
                         for t in m.set_T_int
                         )
                     +
-                    #**********************************************************
+                    # *********************************************************
                     # optional non-interfaced groups
                     sum(
                         sum(
@@ -2786,7 +2786,7 @@ def create_model(name: str,
                         if t not in m.set_T_int # not interfaced
                         )
                     +
-                    #**********************************************************
+                    # *********************************************************
                     # interfaced arcs
                     sum(
                         m.var_xi_arc_inv_gllj[(g,l_circ,l,j_circ)]
@@ -2796,7 +2796,7 @@ def create_model(name: str,
                         if j_circ not in m.set_J_col[(g,l_circ,l)] # individual
                         ) if (g,l_circ,l) in m.set_J else 0
                     +
-                    #**********************************************************
+                    # *********************************************************
                     # optional non-interfaced arcs
                     sum(
                         sum(m.var_delta_arc_inv_glljh[(g,l_circ,l,j_dot,h_dot)]
@@ -2808,7 +2808,7 @@ def create_model(name: str,
                         if j_dot not in m.set_J_mdt[(g,l_circ,l)] # optional
                         ) if (g,l_circ,l) in m.set_J else 0
                     +
-                    #**********************************************************
+                    # *********************************************************
                     # preexisting directed arcs
                     sum(
                         1
@@ -2816,20 +2816,20 @@ def create_model(name: str,
                         if j_pre_dir not in m.set_J_und[(g,l_circ,l)] # directed
                         ) if (g,l_circ,l) in m.set_J_pre else 0
                     +
-                    #**********************************************************
+                    # *********************************************************
                     # mandatory directed arcs
                     sum(
                         1
                         for j_mdt_dir in m.set_J_mdt[(g,l_circ,l)]
                         if j_mdt_dir not in m.set_J_und[(g,l_circ,l)] # directed
                         ) if (g,l_circ,l) in m.set_J_mdt else 0
-                    #**********************************************************
+                    # *********************************************************
                     for l_circ in m.set_L[g]
                     if l_circ not in m.set_L_exp[g]
                     if l_circ != l
                     ) <= 1 #+ 
                 # M_gl*sum(
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # outgoing arcs in interfaced groups, nominal direction
                 #     sum(sum(1
                 #             for j in m.set_J_col[(g,l,l_diamond)]
@@ -2849,7 +2849,7 @@ def create_model(name: str,
                 #         for t in m.set_T_int
                 #         ) if (g,l_diamond,l) in m.set_J_col else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # TODO: outgoing arcs in non-interfaced optional groups, nominal
                 #     sum(sum(1
                 #             for j in m.set_J_col[(g,l,l_diamond)]
@@ -2879,14 +2879,14 @@ def create_model(name: str,
                 #         if t not in m.set_T_int 
                 #         ) if (g,l_diamond,l) in m.set_J_col else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # interfaced individual outgoing arcs, nominal direction
                 #     sum(m.var_xi_arc_inv_gllj[(g,l,l_diamond,j)]
                 #         for j in m.set_J_int[(g,l,l_diamond)] # interfaced
                 #         if j not in m.set_J_col[(g,l,l_diamond)] # individual
                 #         ) if (g,l,l_diamond) in m.set_J_int else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # interfaced individual undirected arcs, reverse direction
                 #     sum(m.var_xi_arc_inv_gllj[(g,l,l_diamond,j)]
                 #         for j in m.set_J_und[(g,l_diamond,l)] # undirected
@@ -2894,7 +2894,7 @@ def create_model(name: str,
                 #         if j not in m.set_J_col[(g,l_diamond,l)] # individual
                 #         ) if (g,l_diamond,l) in m.set_J_und else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # outgoing non-interfaced individual optional arcs 
                 #     sum(
                 #         sum(m.var_delta_arc_inv_glljh[(g,l,l_diamond,j,h)]
@@ -2905,7 +2905,7 @@ def create_model(name: str,
                 #         if j not in m.set_J_int[(g,l,l_diamond)] # interfaced
                 #         ) if (g,l,l_diamond) in m.set_J else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # individual non-interfaced undirected arcs, reverse dir.
                 #     sum(
                 #         sum(m.var_delta_arc_inv_glljh[(g,l_diamond,l,j,h)]
@@ -2916,30 +2916,30 @@ def create_model(name: str,
                 #         if j not in m.set_J_int[(g,l_diamond,l)] # interfaced
                 #         ) if (g,l_diamond,l) in m.set_J_und else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # preselected outgonig arcs, nominal direction
                 #     len(m.set_J_pre[(g,l,l_diamond)]
                 #         ) if (g,l,l_diamond) in m.set_J_pre else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # mandatory outgoing arcs, nominal direction
                 #     len(m.set_J_mdt[(g,l,l_diamond)]
                 #         ) if (g,l,l_diamond) in m.set_J_mdt else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # undirected preselected arcs, reverse direction
                 #     sum(1
                 #         for j in m.set_J_pre[(g,l_diamond,l)]
                 #         if j in m.set_J_und[(g,l_diamond,l)]
                 #         ) if (g,l_diamond,l) in m.set_J_pre else 0
                 #     +
-                #     #**********************************************************
+                #     # *********************************************************
                 #     # undirected mandatory arcs, reverse direction
                 #     sum(1
                 #         for j in m.set_J_mdt[(g,l_diamond,l)]
                 #         if j in m.set_J_und[(g,l_diamond,l)]
                 #         ) if (g,l_diamond,l) in m.set_J_mdt else 0
-                #     #**********************************************************
+                #     # *********************************************************
                 #     for l_diamond in m.set_L[g]
                 #     if l_diamond not in m.set_L_imp[g]
                 #     if l_diamond != l
@@ -2963,7 +2963,7 @@ def create_model(name: str,
         rule=rule_constr_max_incoming_directed_arcs
         )
         
-    #**************************************************************************
+    # *************************************************************************
     
     # def rule_constr_max_outgoing_directed_arcs(m, g, l):
         
@@ -2974,7 +2974,7 @@ def create_model(name: str,
     #     rule=rule_constr_max_outgoing_directed_arcs
     #     )
     
-# #**************************************************************************
+# # *************************************************************************
     
     # # there can only one outgoing arc at most, if there are no incoming arcs
     
@@ -3089,13 +3089,13 @@ def create_model(name: str,
     #     model.set_GL_not_exp_imp,
     #     rule=rule_constr_max_outgoing_arcs)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # arcs
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # maximum flow amplitude per time interval
     
@@ -3139,7 +3139,7 @@ def create_model(name: str,
         model.set_QK, # once per time interval
         rule=rule_constr_arc_max_flow_time_rev)  
         
-    #**************************************************************************
+    # *************************************************************************
         
     # maximum nominal flow amplitude (applies to both directions)
     
@@ -3156,7 +3156,7 @@ def create_model(name: str,
         model.set_GLLJ_sgl, # directed and undirected arcs, new only
         rule=rule_constr_max_nominal_flow_amplitude)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # one option per arc
     # note: one constraint per (undirected) arc
@@ -3183,7 +3183,7 @@ def create_model(name: str,
         model.set_GLLJ_sgl, # directed and undirected arcs, new only
         rule=rule_constr_one_arc_option_per_arc)
     
-    #**************************************************************************
+    # *************************************************************************
         
     # # interface equations (unnecessary if the domain is UnitInterval)
     
@@ -3195,7 +3195,7 @@ def create_model(name: str,
     #     model.set_GLLJ_int,
     #     rule=rule_constr_single_arc_interfaces)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # SOS1 constraints for arc selection
         
@@ -3206,7 +3206,7 @@ def create_model(name: str,
         weights=model.param_arc_inv_sos1_weights_glljh, # key: GLLJH; alue: weight
         sos=1)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # one flow direction per time interval in undirected preexisting arcs
     
@@ -3240,7 +3240,7 @@ def create_model(name: str,
         model.set_QK, # once per time interval
         rule=rule_constr_one_sns_per_time_interval)
             
-    #**************************************************************************
+    # *************************************************************************
     
     # no flow except in the flow direction, for new undirected arcs
         
@@ -3310,7 +3310,7 @@ def create_model(name: str,
         model.set_QK, # once per time interval
         rule=rule_constr_no_flow_except_in_sns_rev)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # SOS1 constraints for flow sense determination (undirected arcs)
         
@@ -3322,7 +3322,7 @@ def create_model(name: str,
         weights=model.param_arc_sns_sos1_weights_glljqk,
         sos=1)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # static losses
     
@@ -3350,7 +3350,7 @@ def create_model(name: str,
         model.set_QK,
         rule=rule_constr_static_losses_existence)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # static losses placed downstream
     
@@ -3426,7 +3426,7 @@ def create_model(name: str,
         model.set_QK,
         rule=rule_constr_static_losses_downstream_und_rev)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # static losses modulated by flow sense for pre-existing arcs
     
@@ -3574,13 +3574,13 @@ def create_model(name: str,
         model.set_QK,
         rule=rule_constr_static_losses_sense_new_eq2_rev)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # groups of arcs
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # maximum flow amplitude per time interval, for arcs in arc groups
     
@@ -3623,7 +3623,7 @@ def create_model(name: str,
         model.set_QK, # all time intervals
         rule=rule_constr_arc_group_max_flow_time_rev)  
         
-    #**************************************************************************
+    # *************************************************************************
         
     # maximum nominal flow amplitude for arc groups
     
@@ -3640,7 +3640,7 @@ def create_model(name: str,
         model.set_T, # all arc groups
         rule=rule_constr_arc_group_max_nominal_flow_amplitude)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # one option per arc group
     
@@ -3659,7 +3659,7 @@ def create_model(name: str,
         model.set_T, # all arc groups
         rule=rule_constr_one_arc_option_per_arc_group)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # SOS1 constraints for arc group selection
         
@@ -3670,7 +3670,7 @@ def create_model(name: str,
         weights=model.param_arc_inv_sos1_weights_th, # key: TH; value: weight
         sos=1)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # one flow direction per time interval, for undirected arcs within groups
     
@@ -3702,7 +3702,7 @@ def create_model(name: str,
         model.set_QK, # once per time interval
         rule=rule_constr_one_sns_per_time_interval_group)
             
-    #**************************************************************************
+    # *************************************************************************
     
     # no flow except in the flow direction, for new undirected arcs in groups
         
@@ -3754,7 +3754,7 @@ def create_model(name: str,
         model.set_QK, # once per time interval
         rule=rule_constr_no_flow_except_in_sns_group_rev)
     
-    #**************************************************************************
+    # *************************************************************************
         
     # interface equations for arc groups
     
@@ -3768,13 +3768,13 @@ def create_model(name: str,
         model.set_T_int,
         rule=rule_constr_arc_group_interfaces)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # converters
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # input signal limits for dimensionable inputs
     
@@ -3859,7 +3859,7 @@ def create_model(name: str,
                                                model.set_QK,
                                                rule=rule_constr_u_bin_limits)
     
-    #**************************************************************************
+    # *************************************************************************
     
     # outputs 
     
@@ -3941,7 +3941,7 @@ def create_model(name: str,
         model.set_IR_dim_eq,
         rule=rule_constr_y_amp_pos_neg_match)
         
-    #**************************************************************************
+    # *************************************************************************
     
     # states 
     
@@ -4029,16 +4029,16 @@ def create_model(name: str,
         model.set_IN_dim_eq,
         rule=rule_constr_x_amp_pos_neg_match)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     return model
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
 
-#******************************************************************************
-#******************************************************************************
-#******************************************************************************
-#******************************************************************************
-#******************************************************************************
\ No newline at end of file
+# *****************************************************************************
+# *****************************************************************************
+# *****************************************************************************
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file
diff --git a/src/topupopt/problems/esipp/network.py b/src/topupopt/problems/esipp/network.py
index 6ce4c2a86f5fac077b9502fadbc958d07bc30225..cfbb71dc1efd698a623895ef3709d2c89e73e28b 100644
--- a/src/topupopt/problems/esipp/network.py
+++ b/src/topupopt/problems/esipp/network.py
@@ -17,9 +17,10 @@ from math import inf
 import networkx as nx
 
 from ...data.gis.identify import find_unconnected_nodes
+from .resource import are_prices_time_invariant
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 class Arcs:
     """A class for arc technologies in a network."""
@@ -63,16 +64,16 @@ class Arcs:
         
             Arcs.validate(self)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def number_options(self):
         "Return the number of arc options."
         
         return len(self.minimum_cost)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def is_isotropic(self,
                      reverse_none_means_isotropic: bool = True) -> bool:
@@ -128,24 +129,24 @@ class Arcs:
                
             return True
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def has_been_selected(self) -> bool:
         """Returns True if an option has been selected and False otherwise."""
         
         return True in self.options_selected
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def is_infinite_capacity(self) -> bool:
         """Returns True if there is one capacity and it is infinite."""
         
         return len(self.capacity) == 1 and self.capacity == (inf,)
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def has_proportional_losses(self) -> bool:
         """Returns False if the efficiency is always one, otherwise True."""
@@ -188,8 +189,8 @@ class Arcs:
                         tuple(1 for _ in range(len(self.efficiency_reverse)))
                         )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def has_static_losses(self) -> bool:
         """Returns False if the static losses are always zero, otherwise True."""
@@ -209,8 +210,8 @@ class Arcs:
                 tuple(0 for _ in range(len(self.static_loss)))
                 )
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def validate_sizes(self, 
                        number_options: int, 
@@ -260,12 +261,12 @@ class Arcs:
                     'of options, scenarios and intervals.'
                     )
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def validate(self):
         
-        #**********************************************************************
+        # *********************************************************************
     
         # check the types
         
@@ -354,7 +355,7 @@ class Arcs:
                 'The information about capacities being instantaneous or not'+
                 ' should be given as a boolean variable.')
                     
-        #**********************************************************************
+        # *********************************************************************
         
         # the number of techs. in capacity and minimum_cost should be the same
         
@@ -371,7 +372,7 @@ class Arcs:
                 'No capacity and minimum cost values were provided. At le'
                 +'ast one option should be provided.')
                  
-        #**********************************************************************
+        # *********************************************************************
             
         # if efficiency is not None (i.e., the arc has proportional losses)
 
@@ -519,14 +520,14 @@ class Arcs:
                 raise ValueError(
                     'Minimum cost values must be positive or zero.')
                 
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 class ArcsWithoutProportionalLosses(Arcs):
     """A class for arc technologies without proportional losses."""
@@ -553,8 +554,8 @@ class ArcsWithoutProportionalLosses(Arcs):
             validate=validate
             )
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 class ArcsWithoutStaticLosses(Arcs):
     """A class for arc technologies without static losses."""
@@ -582,8 +583,8 @@ class ArcsWithoutStaticLosses(Arcs):
             validate=validate
             )
         
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 class ArcsWithoutLosses(Arcs):
     """A class for arc technologies without losses."""
@@ -609,8 +610,8 @@ class ArcsWithoutLosses(Arcs):
             validate=validate
             )
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
    
 class Network(nx.MultiDiGraph):
     
@@ -674,49 +675,51 @@ class Network(nx.MultiDiGraph):
         self.nodes_wo_in_dir_arc_limitations = []
         
         self.nodes_wo_out_dir_arc_limitations = []
-    
-    #**************************************************************************
-    #**************************************************************************
+
+    # *************************************************************************
+    # *************************************************************************
     
     # add a new import node
     
     def add_import_node(self, 
                         node_key, 
-                        prices: dict, # ResourcePrice,
-                        prices_are_time_invariant: bool = False):
+                        prices: dict):
         
         node_dict = {
             self.KEY_NODE_TYPE: self.KEY_NODE_TYPE_IMP,
             self.KEY_NODE_PRICES: prices,
-            self.KEY_NODE_PRICES_TIME_INVARIANT: prices_are_time_invariant
+            self.KEY_NODE_PRICES_TIME_INVARIANT: ( 
+                are_prices_time_invariant(prices)
+                )
             }
         
         self.add_node(
             node_key, 
             **node_dict)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # add a new export node
     
     def add_export_node(self, 
                         node_key, 
-                        prices: dict, # ResourcePrice,
-                        prices_are_time_invariant: bool = False):
+                        prices: dict):
         
         node_dict = {
             self.KEY_NODE_TYPE: self.KEY_NODE_TYPE_EXP,
             self.KEY_NODE_PRICES: prices,
-            self.KEY_NODE_PRICES_TIME_INVARIANT: prices_are_time_invariant
+            self.KEY_NODE_PRICES_TIME_INVARIANT: ( 
+                are_prices_time_invariant(prices)
+                )
             }
         
         self.add_node(
             node_key, 
             **node_dict)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # add a new supply/demand node
     
@@ -733,8 +736,8 @@ class Network(nx.MultiDiGraph):
             node_key, 
             **node_dict)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # add a new waypoint node
     
@@ -749,8 +752,8 @@ class Network(nx.MultiDiGraph):
             node_key, 
             **node_dict)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # modify an existing network node
     
@@ -843,8 +846,8 @@ class Network(nx.MultiDiGraph):
             
             raise ValueError('No such node was found.')
                       
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
      
     # identify importing nodes
     
@@ -858,8 +861,8 @@ class Network(nx.MultiDiGraph):
                 == self.KEY_NODE_TYPE_IMP)
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # identify exporting nodes
     
@@ -873,8 +876,8 @@ class Network(nx.MultiDiGraph):
                 == self.KEY_NODE_TYPE_EXP)
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # identify waypoint nodes
     
@@ -888,8 +891,8 @@ class Network(nx.MultiDiGraph):
                 == self.KEY_NODE_TYPE_WAY)
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # identify source sink nodes
     
@@ -903,8 +906,8 @@ class Network(nx.MultiDiGraph):
                 == self.KEY_NODE_TYPE_SOURCE_SINK)
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # verify if everything is alright 
     
@@ -953,8 +956,8 @@ class Network(nx.MultiDiGraph):
                         'export nodes.'
                         )
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     # identify node types
     
@@ -981,8 +984,8 @@ class Network(nx.MultiDiGraph):
         
         self.validate()
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def add_directed_arc(
             self,
@@ -1027,8 +1030,8 @@ class Network(nx.MultiDiGraph):
                self.KEY_ARC_UND: False}
             )
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def add_undirected_arc(
             self,
@@ -1057,8 +1060,8 @@ class Network(nx.MultiDiGraph):
                self.KEY_ARC_UND: True}
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def get_pseudo_unique_arc_key(self, 
                                   node_key_start, 
@@ -1105,8 +1108,8 @@ class Network(nx.MultiDiGraph):
             iteration += 1          
         raise ValueError('No unique arc key could be produced.')
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def modify_network_arc(self,
                            node_key_a,
@@ -1125,8 +1128,8 @@ class Network(nx.MultiDiGraph):
             **data_dict
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
         
     def add_infinite_capacity_arc(
             self,
@@ -1183,8 +1186,8 @@ class Network(nx.MultiDiGraph):
             arcs=arcs
             )
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
         
     def add_preexisting_directed_arc(
             self,
@@ -1249,8 +1252,8 @@ class Network(nx.MultiDiGraph):
             arcs=arcs
             )
                 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def add_preexisting_undirected_arc(
             self,
@@ -1319,8 +1322,8 @@ class Network(nx.MultiDiGraph):
             node_key_b=node_key_b, 
             arcs=arcs)
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def arc_is_undirected(self, arc_key) -> bool:
         "Returns True if the arc is undirected and False otherwise."
@@ -1341,8 +1344,8 @@ class Network(nx.MultiDiGraph):
             
             return False
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def has_tree_topology(self) -> bool:
         """
@@ -1386,5 +1389,5 @@ class Network(nx.MultiDiGraph):
     
             return nx.is_tree(network_view)
 
-#******************************************************************************
-#******************************************************************************
\ No newline at end of file
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file
diff --git a/src/topupopt/problems/esipp/problem.py b/src/topupopt/problems/esipp/problem.py
index a85d6f8f87fb38c720c9c91853926871f456d1cc..9f965d1fd3f11878e466ea8a573bf1308adaf2d5 100644
--- a/src/topupopt/problems/esipp/problem.py
+++ b/src/topupopt/problems/esipp/problem.py
@@ -23,15 +23,17 @@ from ...data.finance.invest import discount_factor
 from .network import Network, Arcs
 
 from .system import EnergySystem
+
+from .resource import ResourcePrice
            
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 class InfrastructurePlanningProblem(EnergySystem):
     """A class for optimisation of infrastructure planning problems."""
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     SOS1_ARC_WEIGHTS_NONE = None
     SOS1_ARC_WEIGHTS_COST = 1
@@ -66,8 +68,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         STATIC_LOSS_MODE_DS
         )
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
         
     def __init__(self, 
                  name: str,
@@ -82,7 +84,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                  prepare_model: bool = True,
                  validate_inputs: bool = True): # TODO: switch to False when everything is more mature
         
-        #**********************************************************************
+        # *********************************************************************
                 
         if validate_inputs: 
             
@@ -170,7 +172,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             self.assessment_weights = dict(assessment_weights)
             
-        #**********************************************************************
+        # *********************************************************************
         
         # set the name
         
@@ -182,7 +184,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.optimisation_problem_type = SolverInterface.PROBLEM_MILP
         
-        #**********************************************************************
+        # *********************************************************************
         
         # initialise dynamic systems and networks objects
         
@@ -192,7 +194,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             converters=converters
             ) 
     
-        #**********************************************************************
+        # *********************************************************************
         
         # modelling options
         
@@ -228,7 +230,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.use_arc_interface_variables = []
         
-        #**********************************************************************
+        # *********************************************************************
         
         # groups
         
@@ -259,7 +261,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.groups_arc_nnr = {}
         
-        #**********************************************************************
+        # *********************************************************************
         
         # static losses
         
@@ -279,14 +281,14 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.static_losses_downstream = {}
         
-        #**********************************************************************
+        # *********************************************************************
         
         if prepare_model:
             
             self.prepare()
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def _validate_inputs(
             self,
@@ -463,8 +465,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             number_time_intervals
             )
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def reset_arc_groups(self):
         "Clears the dictionaries for the groups of arcs under consideration."
@@ -493,8 +495,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.groups_arc_nnr = {}
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def create_arc_group(self, 
                          gllj_tuples: tuple,
@@ -604,8 +606,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         return new_t
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def clear_static_loss_configurations(self):
         """
@@ -625,8 +627,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.static_losses_upstream = {}
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def place_static_losses(self, network_key, arc_key, mode):
         """
@@ -685,7 +687,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                     
                     return
                 
-                #**************************************************************
+                # *************************************************************
                 
                 # departure node
                 
@@ -721,7 +723,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                         self.static_losses_departure_node[
                             (network_key,*arc_key[0:2])].append(arc_key[2])
                             
-                #**************************************************************
+                # *************************************************************
                 
                 # arrival node
                 
@@ -758,7 +760,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                             (network_key,*arc_key[0:2])].append(arc_key[2])
                         
                 
-                #**************************************************************
+                # *************************************************************
                 
                 # upstream
                 
@@ -794,7 +796,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                         self.static_losses_upstream[
                             (network_key,*arc_key[0:2])].append(arc_key[2])
                 
-                #**************************************************************
+                # *************************************************************
                 
                 # downstream
                 
@@ -830,7 +832,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                         self.static_losses_downstream[
                             (network_key,*arc_key[0:2])].append(arc_key[2])
                 
-                #**************************************************************
+                # *************************************************************
                 
             else: # the arc does not exist
                 
@@ -843,8 +845,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                 'Either the network key provided is incorrect or the arc key '+
                 'lacks the proper size.')
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def place_static_losses_departure_node(self):
         """
@@ -914,8 +916,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                             'import and export nodes. Use an intermediate arc'+
                             ' to obtain the same outcome.')
                 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def place_static_losses_arrival_node(self):
         """
@@ -987,8 +989,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                             'import and export nodes. Use an intermediate arc'+
                             ' to obtain the same outcome.')
                 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def place_static_losses_upstream(self):
         """
@@ -1058,8 +1060,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                             'import and export nodes. Use an intermediate arc'+
                             ' to obtain the same outcome.')
                         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def place_static_losses_downstream(self):
         """
@@ -1127,7 +1129,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                             'import and export nodes. Use an intermediate arc'+
                             ' to obtain the same outcome.')
                 
-    # #**************************************************************************
+    # # *************************************************************************
     
     # def favour_placing_fixed_directed_arc_losses_upstream(self):
     #     """
@@ -1182,12 +1184,12 @@ class InfrastructurePlanningProblem(EnergySystem):
     #                     (network_key,*arc_key)
     #                     )
                 
-    #             #**************************************************************
+    #             # *************************************************************
                 
-    #         #******************************************************************
+    #         # *****************************************************************
 
-    # #**************************************************************************
-    # #**************************************************************************
+    # # *************************************************************************
+    # # *************************************************************************
     
     # def do_not_place_fixed_losses_downstream(self, network_key, arc_key):
     #     """
@@ -1219,8 +1221,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
     #     # if it does not, ignore
 
-    # #**************************************************************************
-    # #**************************************************************************
+    # # *************************************************************************
+    # # *************************************************************************
     
     # def place_fixed_losses_downstream(self, network_key, arc_key):
     #     """
@@ -1297,8 +1299,8 @@ class InfrastructurePlanningProblem(EnergySystem):
     #             'Either the network key provided is incorrect or the arc key '+
     #             'lacks the proper size.')
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
 
     def use_interface_variables_for_arc_selection(self,
                                                   network_key,
@@ -1364,8 +1366,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                 'Either the network key provided is incorrect or the arc key '+
                 'lacks the proper size.')
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def do_not_use_interface_variables_for_arc_selection(self,
                                                          network_key,
@@ -1395,8 +1397,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         # if it does not, ignore
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def do_not_use_sos1_for_arc_selection(self,
                                           network_key,
@@ -1427,8 +1429,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         # if it does not, ignore
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def do_not_use_sos1_for_flow_sense(self,
                                        network_key,
@@ -1459,8 +1461,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         # if it does not, ignore
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def use_sos1_for_flow_senses(
             self,
@@ -1610,8 +1612,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                 'Either the network key provided is incorrect or the arc key '+
                 'lacks the proper size.')
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def use_sos1_for_arc_selection(
             self,
@@ -1734,8 +1736,8 @@ class InfrastructurePlanningProblem(EnergySystem):
                 'Either the network key provided is incorrect or the arc key '+
                 'lacks the proper size.')
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def compute_arc_sos1_weights(self, 
                                  arcs: Arcs,
@@ -1787,8 +1789,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         return sos1_weights
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def prepare(self):
         """Sets up the problem model with which instances can be built."""
@@ -1797,8 +1799,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         self.model = create_model(self.name)
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def instantiate(self, 
                     pyomo_dict: dict = None,
@@ -1827,6 +1829,10 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         else:
             
+            # make pre-instantiation preparations
+            
+            
+            
             # generate pyomo-ready dictionary
             
             pyomo_dict = self.create_pyomo_dictionary(
@@ -1837,8 +1843,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             self.instance = self.model.create_instance(pyomo_dict) 
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
             
     def optimise(self, 
                  solver_name: str,
@@ -1899,8 +1905,8 @@ class InfrastructurePlanningProblem(EnergySystem):
     
         # TODO: reach this statement, perhaps using a small solver budget
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def create_pyomo_dictionary(self, 
                                 include_ancillary_sets: bool = False) -> dict:
@@ -1908,17 +1914,17 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         print('creating the dictionary...')
     
-        #**********************************************************************
-        #**********************************************************************    
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
+        # *********************************************************************
         
         # sets
     
-        #**********************************************************************
-        #**********************************************************************    
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
+        # *********************************************************************
         
         # time
         
@@ -1952,7 +1958,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         set_QPK = [(q,p,k) for (q,p) in set_QP for k in set_K_q[q]]
         
-        #**********************************************************************
+        # *********************************************************************
         
         # set of networks
         
@@ -2029,7 +2035,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             if l1 != l2
             )
         
-        #**********************************************************************
+        # *********************************************************************
             
         # set of price segments
         
@@ -2037,14 +2043,14 @@ class InfrastructurePlanningProblem(EnergySystem):
             (g, l, q, p, k): tuple(
                 s 
                 for s in range(self.networks[g].nodes[l][
-                    Network.KEY_NODE_PRICES][(q,p,k)].number_segments)
+                    Network.KEY_NODE_PRICES][(q,p,k)].number_segments())
                 ) if not self.networks[g].nodes[l][
                     Network.KEY_NODE_PRICES_TIME_INVARIANT] 
                     else tuple(
                         s 
                         for s in range(self.networks[g].nodes[l][
                             Network.KEY_NODE_PRICES][
-                                (q,p,k)].number_segments)
+                                (q,p,k)].number_segments())
                         )
             # for g in self.networks.keys()
             # for l in self.networks[g].nodes
@@ -2064,7 +2070,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         set_GLQPKS_imp = tuple(glqpks for glqpks in set_GLQPKS
                                if glqpks[1] in set_L_imp[glqpks[0]])
         
-        #**********************************************************************
+        # *********************************************************************
         
         # dynamic systems
         
@@ -2076,7 +2082,7 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         set_I_new = self.optional_converters # or [key for key in self.optional_converters]
         
-        #**********************************************************************
+        # *********************************************************************
         
         # inputs
         
@@ -2112,7 +2118,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             converter_key: converter.externality_inducing_inputs
             for converter_key, converter in self.converters.items()}
             
-        #**********************************************************************
+        # *********************************************************************
         
         # set of outputs
         
@@ -2140,7 +2146,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             converter_key: converter.externality_inducing_outputs
             for converter_key, converter in self.converters.items()}
         
-        #**********************************************************************
+        # *********************************************************************
         
         # states
         
@@ -2172,7 +2178,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             converter_key: converter.externality_inducing_states
             for converter_key, converter in self.converters.items()}
         
-        #**********************************************************************
+        # *********************************************************************
         
         # arcs
         
@@ -2352,17 +2358,28 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         # TODO: replace this with validation rule in the pyomo model, asap
         
-        for (g,u,v) in set_J_stt:
+        for u in self.networks[g].import_nodes:
             
-            for j in set_J_stt[(g,u,v)]:
+            for v in self.networks[g].export_nodes:
                 
-                if (u in self.networks[g].import_nodes and
-                    v in self.networks[g].export_nodes):
+                if (g, u, v) in set_J_stt and len(set_J_stt[(g,u,v)]) != 0:
                     
                     raise ValueError(
                         'There cannot be arcs with fixed losses between import'
                         +' and export nodes.'
                         )
+        
+        # for (g,u,v) in set_J_stt:
+            
+        #     for j in set_J_stt[(g,u,v)]:
+                
+        #         if (u in self.networks[g].import_nodes and
+        #             v in self.networks[g].export_nodes):
+                    
+        #             raise ValueError(
+        #                 'There cannot be arcs with fixed losses between import'
+        #                 +' and export nodes.'
+        #                 )
                     
         # directed arcs:
         # 1) in the start node (also upstream)
@@ -2522,9 +2539,9 @@ class InfrastructurePlanningProblem(EnergySystem):
             if j not in set_J_col[(g, u, v)]    # individual
             }  
             
-        #**********************************************************************
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
         # ancillary sets
                 
@@ -2588,8 +2605,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             tuple((g,v,u,j) for (g,u,v,j) in set_GLLJ_static_und_red)
             ) 
             
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
         # set of arc groups
         
@@ -2631,22 +2648,22 @@ class InfrastructurePlanningProblem(EnergySystem):
             for t in set_T
             }
         
-        #**********************************************************************
-        #**********************************************************************    
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
+        # *********************************************************************
         
         # parameters
     
-        #**********************************************************************
-        #**********************************************************************    
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
+        # *********************************************************************
         
         # objective function
         
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
         
         # assessment weight
         
@@ -2708,17 +2725,17 @@ class InfrastructurePlanningProblem(EnergySystem):
                     )
             }
             
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
         
         # converters
         
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
         
         # objective function
     
-        #**********************************************************************  
+        # *********************************************************************  
         
         # minimum cost
         
@@ -2784,11 +2801,11 @@ class InfrastructurePlanningProblem(EnergySystem):
             for (q,k) in set_QK
             }
         
-        #**********************************************************************    
+        # *********************************************************************    
         
         # inputs
         
-        #********************************************************************** 
+        # ********************************************************************* 
         
         # upper bound for input signals
                   
@@ -2826,11 +2843,11 @@ class InfrastructurePlanningProblem(EnergySystem):
                 
         #     param_f_amp_u_imqk = {}
             
-        #**********************************************************************   
+        # *********************************************************************   
         
         # outputs
         
-        #**********************************************************************
+        # *********************************************************************
         
         # upper bounds for outputs (default: none)
                   
@@ -2940,7 +2957,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             for (q,k) in set_QK
             }
             
-        #**********************************************************************   
+        # *********************************************************************   
         
         # states
     
@@ -3027,13 +3044,13 @@ class InfrastructurePlanningProblem(EnergySystem):
                 
         #     param_f_amp_x_inqk = {}
         
-        #**********************************************************************  
-        #**********************************************************************  
+        # *********************************************************************  
+        # *********************************************************************  
                 
         # nodes
         
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
     
         # static balance for nodes (default: 0)
                     
@@ -3073,13 +3090,13 @@ class InfrastructurePlanningProblem(EnergySystem):
             # for (grid, node_key, m, k), a_glmk in dynsys.a_glmk.items()
             }
         
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
         
         # arcs
         
-        #**********************************************************************    
-        #**********************************************************************
+        # *********************************************************************    
+        # *********************************************************************
         
         # nominal flow amplitude limit adjustment coefficient (1 if the time intervals are regular)
                         
@@ -3251,7 +3268,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         set_GLLJ_sgl = tuple(param_c_arc_var_gllj.keys())
         
-        #**********************************************************************
+        # *********************************************************************
         
         # sos1 weights for arc selection
         
@@ -3306,8 +3323,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             param_arc_sns_sos1_weights_glljqk.keys()
             )
         
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
         # parameters for groups of arcs
         
@@ -3351,7 +3368,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             for h in set_H_t[t]
             }
         
-        #**********************************************************************
+        # *********************************************************************
             
         # fixed arc losses for preselected arcs
         
@@ -3423,22 +3440,22 @@ class InfrastructurePlanningProblem(EnergySystem):
             set((g,u,v,j,h) for (g,u,v,j,h,q,k) in param_w_new_glljhqk.keys())
             )
             
-        #**********************************************************************
-        #**********************************************************************
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
         # produce a dictionary with the data for the problem
         
         data_dict = {None: {
             
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             # sets
                 
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             # common sets
             
@@ -3480,7 +3497,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'set_GLL': set_GLL,
             
-            #******************************************************************
+            # *****************************************************************
             
             # tariff
             
@@ -3492,7 +3509,7 @@ class InfrastructurePlanningProblem(EnergySystem):
                                  
             'set_GLQPKS_imp': set_GLQPKS_imp,
             
-            #******************************************************************
+            # *****************************************************************
             
             # converter sets
             
@@ -3536,7 +3553,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'set_R_ext': set_R_ext,
             
-            #******************************************************************
+            # *****************************************************************
             
             # arc related sets
             
@@ -3574,7 +3591,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'set_H_gllj': set_H_gllj,
             
-            #******************************************************************
+            # *****************************************************************
             
             # groups of arcs
             
@@ -3640,13 +3657,13 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'param_arc_inv_sos1_weights_th': param_arc_inv_sos1_weights_th,
                     
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             # ancillary sets
             
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             'set_GLLJ': set_GLLJ,
             
@@ -3697,13 +3714,13 @@ class InfrastructurePlanningProblem(EnergySystem):
     # model.set_GLLJ_static_und_pre,
     # model.set_GLLJ_static_und_new, 
             
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             # parameters
             
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
             # objective function
             
@@ -3717,7 +3734,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'param_v_max_glqpks': param_v_max_glqpks,
             
-            #******************************************************************
+            # *****************************************************************
             
             # converters
             
@@ -3791,7 +3808,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'param_f_amp_y_irqk': param_f_amp_y_irqk,
             
-            #******************************************************************
+            # *****************************************************************
             
             # network
             
@@ -3803,7 +3820,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'param_a_nw_glirqk': param_a_nw_glirqk,
             
-            #******************************************************************
+            # *****************************************************************
             
             # arc parameters
           
@@ -3833,8 +3850,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             'param_arc_sns_sos1_weights_glljqk': param_arc_sns_sos1_weights_glljqk,
                 
-            #******************************************************************
-            #******************************************************************
+            # *****************************************************************
+            # *****************************************************************
             
         }}
         
@@ -3842,8 +3859,8 @@ class InfrastructurePlanningProblem(EnergySystem):
         
         return data_dict
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def assert_solver_problem_compatibility(self, solver_name):
         
@@ -3851,8 +3868,8 @@ class InfrastructurePlanningProblem(EnergySystem):
             solver_name, 
             self.optimisation_problem_type)
 
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def import_results(self,
                        solved_instance: pyo.ConcreteModel = None,
@@ -3864,7 +3881,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
             solved_instance = self.instance
             
-        #**********************************************************************
+        # *********************************************************************
         
         # upload investment results, namely the NPV, NCFs and DFs
         
@@ -3892,7 +3909,7 @@ class InfrastructurePlanningProblem(EnergySystem):
             
         #     Warning('The NPV results are not consistent with the input data.')
             
-        #**********************************************************************
+        # *********************************************************************
         
         # for each arc subject to optimisation
         
@@ -3912,16 +3929,16 @@ class InfrastructurePlanningProblem(EnergySystem):
                     )
                 )
             
-            #******************************************************************
+            # *****************************************************************
             
             # update the object
             
             self.networks[g].edges[(l1,l2,j)][
                 Network.KEY_ARC_TECH].options_selected[h] = decision
                             
-            #******************************************************************
+            # *****************************************************************
         
-        #**********************************************************************
+        # *********************************************************************
         
         # for each arc group
         
@@ -3942,12 +3959,305 @@ class InfrastructurePlanningProblem(EnergySystem):
                 self.networks[g].edges[(l1,l2,j)][
                     Network.KEY_ARC_TECH].options_selected[h] = decision
                                 
-            #******************************************************************
+            # *****************************************************************
         
-        #**********************************************************************
+        # *********************************************************************
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    
+# *****************************************************************************
+# *****************************************************************************
+
+def simplify_peak_total_problem(
+        problem: InfrastructurePlanningProblem
+        ) -> InfrastructurePlanningProblem:
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    # check if the simplification is feasible
+    if not is_peak_total_problem(problem):
+        # it is not possible to simplify the problem
+        return problem
+            
+    # *************************************************************************
+    # *************************************************************************
+    
+    # identify the peak assessment
+    ref_found = False
+    for key, net in problem.networks.items():
+        for node_key in net.source_sink_nodes:
+            q_ref, k_ref = sorted(
+                ((value, key) 
+                 for key, value in net.nodes[node_key][
+                         Network.KEY_NODE_BASE_FLOW
+                         ].items()
+                 ),
+                reverse=True
+                )[0][1]
+            ref_found = True
+            break
+        if ref_found:
+            break
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    # define the peak assessment and the peak interval
+    q_peak = 'peak'
+    k_peak = 0
+    # define the total assessment and the total interval
+    q_total = 'total'
+    k_total = 0
+        
+    # *************************************************************************
+    # *************************************************************************
+    
+    # create one peak scenario per polarity within each network
+    # create one total scenario per polarity within each network
+    for key, net in problem.networks.items():
+        # 1) losses in arcs: 
+        # 1.1) sum the static losses for all time intervals (total assessment)
+        # 1.2) insert the static losses for the peak assessment
+        # 1.3) remove all static losses but for the peak assessment
+        # 1.4) insert the static losses for the total assessment
+        for arc_key in net.edges(keys=True):
+            # check if the arc has static losses
+            if net.edges[arc_key][Network.KEY_ARC_TECH].has_static_losses():
+                # 1.1) sum the static losses for all time intervals
+                loss_sum = {
+                    (h, q_total, k_total): sum(
+                        net.edges[arc_key][Network.KEY_ARC_TECH].static_loss[
+                        (h, q_ref, k)
+                        ]
+                        for k in range(problem.number_time_intervals[q_ref])
+                        )
+                    for h in range(
+                            net.edges[arc_key][
+                                Network.KEY_ARC_TECH
+                                ].number_options()
+                            )
+                    }
+                # 1.2) insert the static losses for the peak assessment
+                net.edges[arc_key][Network.KEY_ARC_TECH].static_loss.update({
+                    (h, q_peak, k_peak): (
+                        net.edges[arc_key][Network.KEY_ARC_TECH].static_loss[
+                            (h, q_ref, k_ref)
+                            ]
+                        )
+                    for h in range(
+                            net.edges[arc_key][
+                                Network.KEY_ARC_TECH].number_options()
+                            )
+                    })
+                # 1.3) remove all static losses but for the peak assessment
+                for hqk in tuple(net.edges[arc_key][
+                        Network.KEY_ARC_TECH].static_loss):
+                    if hqk[1:] != (q_peak, k_peak):
+                        net.edges[arc_key][
+                            Network.KEY_ARC_TECH].static_loss.pop(hqk)
+                # 1.4) insert the static losses for the total assessment
+                net.edges[arc_key][Network.KEY_ARC_TECH].static_loss.update(
+                    loss_sum)
+            
+            # efficiency
+            # 1.2) insert the efficiencies for the peak and total assessments
+            # 1.3) remove all efficiencies but for the peak and total assessm.
+            
+            if net.edges[arc_key][
+                    Network.KEY_ARC_TECH
+                    ].has_proportional_losses():
+                # peak assessment efficiency
+                net.edges[arc_key][Network.KEY_ARC_TECH].efficiency.update({
+                    (q_peak, k_peak): (
+                        net.edges[arc_key][Network.KEY_ARC_TECH].efficiency[
+                            (q_ref, k_ref)
+                            ]
+                        )
+                    })
+                # total assessment efficiency
+                net.edges[arc_key][Network.KEY_ARC_TECH].efficiency.update({
+                    (q_total, k_total): (
+                        net.edges[arc_key][Network.KEY_ARC_TECH].efficiency[
+                            (q_ref, k_ref)
+                            ]
+                        )
+                    })
+                for qk in tuple(net.edges[arc_key][
+                        Network.KEY_ARC_TECH].efficiency):
+                    if qk != (q_peak, k_peak) and qk != (q_total, k_total):
+                        net.edges[arc_key][
+                            Network.KEY_ARC_TECH].efficiency.pop(qk)
+        
+        # 2) prices in import/export nodes:
+        # 2.1) determine the price for the total assessment
+        # 2.2) insert the prices for the peak assessment
+        # 2.3) remove all prices but those for the peak assessment
+        # 2.4) insert the prices for the total assessment
+        for node_key in net.nodes():
+            # 2.1) determine the price for the total assessment
+            # 2.2) insert the prices for the peak assessment
+            if node_key in net.import_nodes or node_key in net.export_nodes:
+                # import node: 
+                # - get the current price
+                # - insert the peak price = 0
+                # export node:
+                # - get the current price
+                # - insert the peak price = 0
+                total_price = {
+                    (q_total, p, k_total): (
+                        net.nodes[node_key][Network.KEY_NODE_PRICES][
+                            (q_ref, p, k_ref)
+                            ]
+                        )
+                    for p in problem.reporting_periods[q_ref]
+                    }
+                net.nodes[node_key][Network.KEY_NODE_PRICES].update({
+                    (q_peak, p, k_peak): ResourcePrice(prices=0)
+                    for p in problem.reporting_periods[q_ref]
+                    })
+            else: # other nodes
+                continue
+            # 2.3) remove all prices but those for the peak assessment
+            for qpk in tuple(
+                    net.nodes[node_key][Network.KEY_NODE_PRICES].keys()
+                    ):
+                if qpk[0] != q_peak and qpk[2] != k_peak:
+                    net.nodes[node_key][Network.KEY_NODE_PRICES].pop(qpk)
+            # 2.4) insert the prices for the total assessment
+            net.nodes[node_key][Network.KEY_NODE_PRICES].update(total_price)
+        
+        # 3) flows in other nodes: 
+        # 3.1) determine the flow volume for the total assessment
+        # 3.2) insert the prices and base flows for the peak scenario
+        # 3.3) remove all but the peak scenario and intervals
+        # 3.4) insert the flow volume for the total assessment
+        
+        for node_key in net.source_sink_nodes:
+            # 3.1) determine the flow volume for the total assessment
+            total_flow = {
+                (q_total, k_total): sum(
+                    net.nodes[node_key][Network.KEY_NODE_BASE_FLOW][(q_ref, k)]
+                    for k in range(problem.number_time_intervals[q_ref])
+                    )
+                }
+            # 3.2) insert the prices and base flows for the peak scenario
+            net.nodes[node_key][Network.KEY_NODE_BASE_FLOW].update(
+                {(q_peak, k_peak): net.nodes[node_key][
+                    Network.KEY_NODE_BASE_FLOW
+                    ][(q_ref, k_ref)]
+                    }
+                )
+            # 3.3) remove all but the peak scenario and intervals
+            for qk in tuple(net.nodes[node_key][Network.KEY_NODE_BASE_FLOW]):
+                if qk != (q_peak, k_peak):
+                    net.nodes[node_key][Network.KEY_NODE_BASE_FLOW].pop(qk)
+            # 3.4) insert the flow volume for the total assessment
+            net.nodes[node_key][Network.KEY_NODE_BASE_FLOW].update(total_flow)            
+            
+    # *************************************************************************
+    # *************************************************************************
+    
+    # update the assessments, reporting periods, intervals and segments
+    
+    # assessments
+    problem.assessment_keys = (q_peak, q_total)
+    problem.number_assessments = len(problem.assessment_keys)
+    
+    # reporting periods
+    problem.reporting_periods = {
+        q: tuple(problem.reporting_periods[q_ref])
+        for q in problem.assessment_keys
+        }
+    problem.number_reporting_periods = {
+        q: len(problem.reporting_periods[q])
+        for q in problem.assessment_keys
+        }
+    
+    # time intervals
+    problem.time_intervals = {
+        q_peak: [problem.time_intervals[q_ref][k_ref]], 
+        q_total: [sum(problem.time_intervals[q_ref])]
+        }
+    problem.number_time_intervals = {
+        q: len(problem.time_intervals[q])
+        for q in problem.assessment_keys
+        }
+    
+    # average time interval
+    problem.average_time_interval = {
+        q: mean(problem.time_intervals[q])
+        for q in problem.assessment_keys
+        }
+    # normalised time interval duration   
+    # problem.normalised_time_interval_duration = {
+    #     (q,k): duration/problem.average_time_interval[q]
+    #     for q in problem.assessment_keys
+    #     for k, duration in enumerate(problem.time_intervals[q])
+    #     }   
+    problem.normalised_time_interval_duration = {
+        (q_peak, k_peak): 1, 
+        (q_total, k_total): (
+            sum(problem.time_intervals[q_total])/
+            problem.time_intervals[q_peak][k_total]
+            )
+        }
+    
+    # discount factors (use the reference assessment)
+    problem.discount_rates[q_peak] = tuple(problem.discount_rates[q_ref])
+    problem.discount_rates[q_total] = tuple(problem.discount_rates[q_ref])
+    problem.discount_rates.pop(q_ref)
+    
+    # f coefficients
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    # return the modified problem
+    return problem
+    
+# *****************************************************************************
+# *****************************************************************************
+
+def is_peak_total_problem(problem: InfrastructurePlanningProblem) -> bool:
+    """Returns True if the problem only concerns peak capacity and volume."""
+    
+    # conditions:
+    # 1) maximum congestion occurs simultaneously across the network
+    #     - corollary: there are no dynamic behaviours in the network
+    #     - simplifying assumption: no proportional losses in the network
+    # 2) the time during which maximum congestion occurs can be determined
+    # 3) energy prices are constant in time and volume
+    
+    # check #1
+    
+    # check #2
+    # check #3: energy prices are constant in time and volume
+    for key, net in problem.networks.items():
+        # check import nodes
+        for imp_node_key in net.import_nodes:
+            # is an import node, check if it is time invariant
+            if not net.nodes[imp_node_key][
+                    Network.KEY_NODE_PRICES_TIME_INVARIANT]:
+                return False # is not time invariant
+            # it is time invariant, but is it volume invariant? check any qpk
+            for qpk in net.nodes[imp_node_key][Network.KEY_NODE_PRICES]:
+                if not net.nodes[imp_node_key][
+                        Network.KEY_NODE_PRICES][qpk].is_volume_invariant():
+                    # it is not volume invariant
+                    return False
+                # if the entries are time invariant, checking one will do
+                break
+    
+    # # check #4: none of the arcs can have proportional losses
+    # for key, net in problem.networks.items():
+    #     # check each edge
+    #     for edge_key in net.edges(keys=True):
+    #         if net.edges[edge_key][
+    #                 Network.KEY_ARC_TECH].has_proportional_losses():
+    #             return False # has proportional losses, return False
+    return True # all conditions are true
     
-#******************************************************************************
-#******************************************************************************
\ No newline at end of file
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file
diff --git a/src/topupopt/problems/esipp/resource.py b/src/topupopt/problems/esipp/resource.py
index 028ab660ce6315715e83c10fe1bbeb6187321aae..039f8874e44384c5d660d1246287c46429fa1655 100644
--- a/src/topupopt/problems/esipp/resource.py
+++ b/src/topupopt/problems/esipp/resource.py
@@ -1,10 +1,12 @@
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
 
 from numbers import Real
 
-#******************************************************************************
-#******************************************************************************
+# *****************************************************************************
+# *****************************************************************************
+
+# TODO: change name to ResourceTariff
 
 class ResourcePrice:
     """A class for piece-wise linear resource prices in network problems."""
@@ -16,30 +18,27 @@ class ResourcePrice:
         # - a flag
         
         # accepted inputs:     
-        # 1) prices and volumes as dicts
-        # - keys can be segment indexes or (segment index, time index) tuples
-        # - values can be numeric and non-negative or None (last segment only) 
-        # - the number of segments is not
-        # - the number of intervals does not change
-        # 2) prices and values as lists with matching sizes
+        # 1) prices and values as lists with matching sizes
         # - all elements in the lists need to be numeric
         # - all prices need to be non-negative
         # - all volumes need to be positive
-        # 3) price as a list, volume as None
+        # 2) price as a list, volume as None
         # - all elements in the list need to be numeric and non-negative
         
-        (self.number_segments, 
+        (self._number_segments, 
          self.prices, 
          self.volumes) = self.validate_list(
             prices, 
             volumes
             )
+             
+        self._volume_invariant = self.is_volume_invariant()
             
-        #**********************************************************************
-        #**********************************************************************
+        # *********************************************************************
+        # *********************************************************************
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
             
     def validate_list(self, prices, volumes):
         """Validates the inputs provided in list format."""
@@ -133,7 +132,7 @@ class ResourcePrice:
             
             return number_segments, prices, volumes
         
-        elif type(volumes) == type(None):
+        elif type(volumes) == type(None) or isinstance(volumes, Real):
                         
             # the prices must be numeric and positive
             
@@ -156,17 +155,14 @@ class ResourcePrice:
                     
             # done
             
-            return number_segments, [prices], [None]
+            return number_segments, [prices], [volumes]
         
         else:
             
-            raise TypeError(
-                'The volumes should be provided as list or None when the '+
-                'prices are provided as a list.'
-                )
+            raise TypeError('Unrecognised type for volumes.')
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def price_monotonically_increasing_with_volume(self) -> bool:
             
@@ -174,13 +170,13 @@ class ResourcePrice:
         
         # if there is only one segment, return false
         
-        if self.number_segments == 1:
+        if self._number_segments == 1:
             
             return True
         
         # check one interval:
             
-        for segment_index in range(self.number_segments-1):
+        for segment_index in range(self._number_segments-1):
             
             # check consecutive segments
             
@@ -194,8 +190,8 @@ class ResourcePrice:
         
         return True
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def price_monotonically_decreasing_with_volume(self) -> bool:
                     
@@ -203,13 +199,13 @@ class ResourcePrice:
         
         # if there is only one segment, return false
         
-        if self.number_segments == 1:
+        if self._number_segments == 1:
             
             return True
         
         # check one interval:
             
-        for segment_index in range(self.number_segments-1):
+        for segment_index in range(self._number_segments-1):
             
             # check consecutive segments
             
@@ -223,15 +219,79 @@ class ResourcePrice:
         
         return True
     
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
     
     def is_volume_capped(self) -> bool:
             
         return not (type(self.volumes[-1]) == type(None))
         
-    #**************************************************************************
-    #**************************************************************************
+    # *************************************************************************
+    # *************************************************************************
+    
+    def is_volume_invariant(self) -> bool:
+        """Returns True if the prices are the same regardless of the volume."""
+        # is a list
+        if len(set(self.prices)) == 1:
+            return True # a list with the same price >> volume invariant
+        else:
+            return False # a list with more than 1 price >> volume sensitive
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    def number_segments(self, redo: bool = False) -> int:
+        """Returns the number of price segments."""
+        if hasattr(self, "_number_segments") and not redo:
+            return self._number_segments
+        return len(self.prices)
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    def is_equivalent(self, other) -> bool:
+        """Returns True if a given ResourcePrice is equivalent to another."""
+        # resources are equivalent if:
+        # 1) the prices are the same
+        # 2) the volume limits are the same
+        
+        # the number of segments has to match
+        if self.number_segments() != other.number_segments():
+            return False # the number of segments do not match
+        # check the prices
+        if self.prices != other.prices:
+            return False # prices are different
+        # prices match, check the volumes
+        if self.volumes != other.volumes:
+            return False # volumes are different
+        return True # all conditions have been met
+
+    # *************************************************************************
+    # *************************************************************************
         
-#******************************************************************************
-#******************************************************************************
\ No newline at end of file
+# *****************************************************************************
+# *****************************************************************************
+
+def are_prices_time_invariant(resource_prices_qpk: dict) -> bool:
+    """Returns True if all prices are identical per time interval."""
+    # check if there is only one or no (q,p,k) entry
+    if len(resource_prices_qpk) <= 1:
+        return True # only one or no entry = is time invariant
+    # check if the entries for the same period and assessment are time invariant
+    entries_qp = set([qpk[0:2] for qpk in resource_prices_qpk])
+    qpk_qp = {
+        qp: [qpk for qpk in resource_prices_qpk if qp == qpk[0:2]]
+        for qp in entries_qp
+        }
+    # check if the tariffs per period and assessment are equivalent
+    for qp, qpk_list in qpk_qp.items():
+        for i in range(len(qpk_list)-1):
+            if not resource_prices_qpk[qpk_list[0]].is_equivalent(
+                    resource_prices_qpk[qpk_list[i+1]]
+                    ):
+                return False
+    # all tariffs are equivalent per period and assessment: they are invariant
+    return True
+
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file
diff --git a/tests/examples_esipp_network.py b/tests/examples_esipp_network.py
index bb790cf6e3d11242acc7411e57e313b32e023d05..e1ab98fa8a4b5e69ed5466ef3410a5814383e677 100644
--- a/tests/examples_esipp_network.py
+++ b/tests/examples_esipp_network.py
@@ -1266,7 +1266,7 @@ def examples_arc_technologies():
         volumes=[ *[random.random() for k in range(number_time_intervals-1)], None]
         )
     
-    net.add_import_node(node_key='G', prices=imp_resource_price)
+    net.add_import_node(node_key='G', prices={(0,0,0): imp_resource_price})
 
     # add export node
     
@@ -1276,7 +1276,7 @@ def examples_arc_technologies():
         volumes=[ *[random.random() for k in range(number_time_intervals-1)], None]
         )
     
-    net.add_export_node(node_key='H', prices=exp_resource_price)
+    net.add_export_node(node_key='H', prices={(0,0,0): exp_resource_price})
     
     net.add_waypoint_node(node_key='Z')
     
@@ -1401,22 +1401,22 @@ def examples_modifying_nodes():
     # add isolated import node
     
     net.add_import_node(node_key='I_iso', 
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # add import node with outgoing arcs
 
     net.add_import_node(node_key='I', 
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
                     
     # add isolated export node
     
     net.add_import_node(node_key='E_iso', 
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # add export node with incoming arcs
 
     net.add_export_node(node_key='E', 
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # add isolated normal node
     
@@ -1844,12 +1844,12 @@ def examples_network_disallowed_cases():
     # add import node I
     
     net.add_import_node(node_key='I',
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # add export node E
     
     net.add_export_node(node_key='E',
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # add regular node A
     
@@ -1941,7 +1941,7 @@ def examples_network_disallowed_cases():
     # create a new export node
     
     net.add_export_node(node_key='E1',
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # create an arc starting in that export node
     
@@ -1964,7 +1964,7 @@ def examples_network_disallowed_cases():
     # create a new import node
     
     net.add_import_node(node_key='I1',
-                        prices=resource_price)
+                        prices={(0,0,0): resource_price})
     
     # create an arc ending in that import node
     
diff --git a/tests/examples_esipp_resource.py b/tests/examples_esipp_resource.py
deleted file mode 100644
index e45105e81c047c0043de591ec00b23deb171cb36..0000000000000000000000000000000000000000
--- a/tests/examples_esipp_resource.py
+++ /dev/null
@@ -1,357 +0,0 @@
-# imports
-
-import random
-
-from src.topupopt.problems.esipp.resource import ResourcePrice
-
-#******************************************************************************
-#******************************************************************************
-
-def examples():
-
-    # test ResourcePrice objects created with lists
-    
-    example_resource_prices_lists()
-    
-#******************************************************************************
-#******************************************************************************
-
-def example_resource_prices_lists():
-    
-    #**************************************************************************
-    
-    # aspects that were tested:
-    # i) number of segments (1, multiple or none)
-    # ii) price variations (increasing, decreasing and stable)
-    # iii) volume limits
-    
-    #**************************************************************************
-    
-    # 1) multiple segments, prices increase, volume limits
-    # 2) multiple segments, prices decrease, volume limits
-    # 3) multiple segments, prices are stable, volume limits
-    # 4) multiple segments, prices increase, no volume limit
-    # 5) multiple segments, prices decrease, no volume limit
-    # 6) multiple segments, prices are stable, no volume limit
-    # 7) one segment, prices are stable, volume limits
-    # 8) one segment, prices are stable, no volume limit
-    
-    #**************************************************************************
-    
-    # 1) multiple segments, prices increase, volume limits
-    
-    prices = [1,2,3]
-            
-    volumes = [2,1,3]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert not res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 2) multiple segments, prices decrease, volume limits
-    
-    prices = [3,2,1]
-            
-    volumes = [2,1,3]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert res_p.is_volume_capped()
-    
-    assert not res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 3) multiple segments, prices are stable, volume limits
-    
-    prices = [2,2,2]
-            
-    volumes = [2,1,3]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 4) multiple segments, prices increase, no volume limit
-    
-    prices = [1,2,3]
-            
-    volumes = [2,1,None]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert not res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert not res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 5) multiple segments, prices decrease, no volume limit
-    
-    prices = [2,2,2]
-            
-    volumes = [2,1,None]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert not res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 6) multiple segments, prices are stable, no volume limit
-    
-    prices = [2,2,2]
-            
-    volumes = [2,1,None]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 3
-    
-    assert not res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 7) one segment, prices are stable, volume limits
-    
-    prices = [2]
-            
-    volumes = [2]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 1
-    
-    assert res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    
-    # 8) one segment, prices are stable, no volume limit
-    
-    prices = [3]
-            
-    volumes = [None]
-    
-    res_p = ResourcePrice(prices=prices, volumes=volumes)
-    
-    assert res_p.number_segments == 1
-    
-    assert not res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    res_p = ResourcePrice(prices=prices[0], volumes=volumes[0])
-    
-    assert res_p.number_segments == 1
-    
-    assert not res_p.is_volume_capped()
-    
-    assert res_p.price_monotonically_increasing_with_volume()
-    
-    assert res_p.price_monotonically_decreasing_with_volume()
-    
-    #**************************************************************************
-    #**************************************************************************
-    
-    # errors
-    
-    #**************************************************************************
-    
-    # create object without prices
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=None,
-                          volumes=volumes)
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with negative prices in lists
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,-3,2],
-                          volumes=[3,4,5])
-    except ValueError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object where an intermediate segment has no volume limit
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,4,2],
-                          volumes=[3,None,5])
-    except ValueError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with negative volumes in lists
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,2],
-                          volumes=[4,-1,2])
-    except ValueError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with non-numeric prices in lists
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,'4',2],
-                          volumes=[3,4,5])
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with non-numeric volumes in lists
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,2],
-                          volumes=[4,'3',2])
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with mismatched price and volume lists
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,2],
-                          volumes=[5,7])
-    except ValueError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with a price list as an input and an unsupported type
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,2],
-                          volumes='hello')
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with negative prices in lists (no volumes are provided)
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,-2],
-                          volumes=None)
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with non-numeric prices in lists (no volumes are provided)
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=[7,3,'a'],
-                          volumes=None)
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with non-numeric prices in lists (no volumes are provided)
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=5,
-                          volumes=[7,3,4])
-    except TypeError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-    
-    # create object with negative prices
-
-    error_triggered = False
-    
-    try:
-        _ = ResourcePrice(prices=-3,
-                          volumes=None)
-    except ValueError:
-        error_triggered = True
-    assert error_triggered
-    
-    #**************************************************************************
-        
-#******************************************************************************
-#******************************************************************************
\ No newline at end of file
diff --git a/tests/test_all.py b/tests/test_all.py
index 1a028d48ab290b807c39c04046b706646a926af9..ca908e5e1ecbd574540e923f18403b83dd8e1e98 100644
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -10,7 +10,6 @@ from examples_converter import examples as examples_converter
 from examples_dynsys import examples as examples_dynsys
 from examples_esipp_network import examples as examples_esipp_network
 from examples_esipp_problem import examples as examples_esipp_problem
-from examples_esipp_resource import examples as examples_esipp_resource
 from examples_esipp import examples as examples_esipp
 from examples_signal import examples as examples_signal
 
@@ -33,9 +32,6 @@ def test_suite():
     test_examples_esipp_problem = True
     # test_examples_esipp_problem = False
     
-    test_examples_esipp_resource = True
-    # test_examples_esipp_resource = False
-    
     test_examples_esipp = True
     # test_examples_esipp = False
     
@@ -46,7 +42,6 @@ def test_suite():
     # test_examples_dynsys = True
     # test_examples_esipp_network = True
     # test_examples_esipp_problem = True
-    # test_examples_esipp_resource = True
     # test_examples_esipp = True
     # test_examples_gis = True
     # test_examples_signal = True
@@ -194,18 +189,6 @@ def test_suite():
     
     #**************************************************************************
     
-    # esipp-resource
-    
-    if test_examples_esipp_resource:
-    
-        print('\'esipp-resource\': testing about to start...')
-        
-        examples_esipp_resource()
-        
-        print('\'esipp-resource\': testing complete.')
-    
-    #**************************************************************************
-    
     # esipp
     
     if test_examples_esipp:
diff --git a/tests/test_esipp_problem.py b/tests/test_esipp_problem.py
new file mode 100644
index 0000000000000000000000000000000000000000..26d15f9244d2a9dfa4e69297dc550aa809e19b57
--- /dev/null
+++ b/tests/test_esipp_problem.py
@@ -0,0 +1,607 @@
+# imports
+
+# standard
+
+import math
+
+from statistics import mean
+
+# local
+
+# import numpy as np
+
+# import networkx as nx
+
+import pyomo.environ as pyo
+    
+# import src.topupopt.problems.esipp.utils as utils
+
+from src.topupopt.data.misc.utils import generate_pseudo_unique_key
+
+from src.topupopt.problems.esipp.problem import InfrastructurePlanningProblem
+
+from src.topupopt.problems.esipp.network import Arcs, Network
+
+from src.topupopt.problems.esipp.resource import ResourcePrice
+
+from src.topupopt.problems.esipp.problem import simplify_peak_total_problem
+
+from src.topupopt.problems.esipp.problem import is_peak_total_problem
+
+# *****************************************************************************
+# *****************************************************************************
+
+class TestESIPPProblem:
+
+    def build_solve_ipp(
+            self,
+            solver: str = 'glpk',
+            solver_options: dict = None,
+            use_sos_arcs: bool = False,
+            arc_sos_weight_key: str = (
+                InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE),
+            arc_use_real_variables_if_possible: bool = False,
+            use_sos_sense: bool = False,
+            sense_sos_weight_key: int = (
+                InfrastructurePlanningProblem.SOS1_SENSE_WEIGHT_NOMINAL_HIGHER
+                ),
+            sense_use_real_variables_if_possible: bool = False,
+            sense_use_arc_interfaces: bool = False,
+            perform_analysis: bool = False,
+            plot_results: bool = False,
+            print_solver_output: bool = False,
+            irregular_time_intervals: bool = False,
+            networks: dict = None,
+            number_intraperiod_time_intervals: int = 4,
+            static_losses_mode = None,
+            mandatory_arcs: list = None,
+            max_number_parallel_arcs: dict = None,
+            arc_groups_dict: dict = None,
+            init_aux_sets: bool = False,
+            discount_rates: dict = None,
+            reporting_periods: dict = None,
+            time_intervals: dict = None,
+            assessment_weights: dict = None,
+            simplify_problem: bool = False):
+        
+        reporting_period_duration = 365*24*3600
+        
+        if type(discount_rates) != dict:
+        
+            discount_rates = {
+                0: tuple([0.035, 0.035])
+                }
+            
+        if type(assessment_weights) != dict:
+            
+            assessment_weights = {} # default
+        
+        if type(reporting_periods) != dict:
+            
+            reporting_periods = {0: (0,1)}
+            
+        # time intervals
+        
+        if type(time_intervals) != dict:
+                
+            if irregular_time_intervals:
+                
+                time_step_max_relative_variation = 0.25
+                
+                intraperiod_time_interval_duration = [
+                    (reporting_period_duration/number_intraperiod_time_intervals)*
+                    (1+(k/(number_intraperiod_time_intervals-1)-0.5)*
+                     time_step_max_relative_variation)
+                    for k in range(number_intraperiod_time_intervals)]
+                
+            else:
+            
+                intraperiod_time_interval_duration = [
+                    reporting_period_duration/number_intraperiod_time_intervals
+                    for k in range(number_intraperiod_time_intervals)]
+            
+            # average time interval duration
+            
+            average_time_interval_duration = round(
+                mean(
+                    intraperiod_time_interval_duration
+                    )
+                )
+            
+            time_intervals = {
+                0: tuple(dt for dt in intraperiod_time_interval_duration)
+                }
+                
+        # time weights
+        
+        # relative weight of time period
+        
+        # one interval twice as long as the average is worth twice
+        # one interval half as long as the average is worth half
+        
+        # time_weights = [
+        #     [time_period_duration/average_time_interval_duration 
+        #       for time_period_duration in intraperiod_time_interval_duration] 
+        #     for p in range(number_periods)]
+        
+        time_weights = None # nothing yet
+    
+        normalised_time_interval_duration = None # nothing yet
+        
+        # create problem object
+        
+        ipp = InfrastructurePlanningProblem(
+            name='problem', 
+            discount_rates=discount_rates, 
+            reporting_periods=reporting_periods,
+            time_intervals=time_intervals,
+            time_weights=time_weights,
+            normalised_time_interval_duration=normalised_time_interval_duration,
+            assessment_weights=assessment_weights
+            )
+        
+        # add networks and systems
+        
+        for netkey, net in networks.items():
+        
+            ipp.add_network(network_key=netkey, network=net)
+            
+        # define arcs as mandatory
+        
+        if type(mandatory_arcs) == list:
+        
+            for full_arc_key in mandatory_arcs:
+                
+                ipp.make_arc_mandatory(full_arc_key[0], full_arc_key[1:])
+        
+        # if make_all_arcs_mandatory:
+            
+        #     for network_key in ipp.networks:
+                
+        #         for arc_key in ipp.networks[network_key].edges(keys=True):
+                    
+        #             # preexisting arcs are no good
+                    
+        #             if ipp.networks[network_key].edges[arc_key][
+        #                     Network.KEY_ARC_TECH].has_been_selected():
+                        
+        #                 continue 
+        
+        #             ipp.make_arc_mandatory(network_key, arc_key)
+        
+        # set up the use of sos for arc selection
+        
+        if use_sos_arcs:
+            
+            for network_key in ipp.networks:
+                
+                for arc_key in ipp.networks[network_key].edges(keys=True):
+                    
+                    if ipp.networks[network_key].edges[arc_key][
+                            Network.KEY_ARC_TECH].has_been_selected():
+                        
+                        continue
+            
+                    ipp.use_sos1_for_arc_selection(
+                        network_key, 
+                        arc_key,
+                        use_real_variables_if_possible=(
+                            arc_use_real_variables_if_possible),
+                        sos1_weight_method=arc_sos_weight_key)
+        
+        
+        # set up the use of sos for flow sense determination
+        
+        if use_sos_sense:
+            
+            for network_key in ipp.networks:
+                
+                for arc_key in ipp.networks[network_key].edges(keys=True):
+                    
+                    if not ipp.networks[network_key].edges[arc_key][
+                            Network.KEY_ARC_UND]:
+                        
+                        continue
+                    
+                    ipp.use_sos1_for_flow_senses(
+                        network_key, 
+                        arc_key,
+                        use_real_variables_if_possible=(
+                            sense_use_real_variables_if_possible
+                            ),
+                        use_interface_variables=sense_use_arc_interfaces,
+                        sos1_weight_method=sense_sos_weight_key)
+        
+        elif sense_use_arc_interfaces: # set up the use of arc interfaces w/o sos1
+            
+            for network_key in ipp.networks:
+                
+                for arc_key in ipp.networks[network_key].edges(keys=True):
+                    
+                    if ipp.networks[network_key].edges[arc_key][
+                            Network.KEY_ARC_TECH].has_been_selected():
+                        
+                        continue
+            
+                    ipp.use_interface_variables_for_arc_selection(
+                        network_key, 
+                        arc_key
+                        )
+                    
+        # static losses
+            
+        if static_losses_mode == ipp.STATIC_LOSS_MODE_ARR:
+            
+            ipp.place_static_losses_arrival_node()
+            
+        elif static_losses_mode == ipp.STATIC_LOSS_MODE_DEP:
+            
+            ipp.place_static_losses_departure_node()
+            
+        elif static_losses_mode == ipp.STATIC_LOSS_MODE_US:
+            
+            ipp.place_static_losses_upstream()
+        
+        elif static_losses_mode == ipp.STATIC_LOSS_MODE_DS:
+            
+            ipp.place_static_losses_downstream()
+            
+        else:
+            
+            raise ValueError('Unknown static loss modelling mode.')
+                            
+        # *********************************************************************
+        
+        # groups
+        
+        if type(arc_groups_dict) != type(None):
+            
+            for key in arc_groups_dict:
+                
+                ipp.create_arc_group(arc_groups_dict[key])
+                        
+        # *********************************************************************
+            
+        # maximum number of parallel arcs
+        
+        for key in max_number_parallel_arcs:
+        
+            ipp.set_maximum_number_parallel_arcs(
+                network_key=key[0], 
+                node_a=key[1], 
+                node_b=key[2], 
+                limit=max_number_parallel_arcs[key])
+            
+        # *********************************************************************
+            
+        if simplify_problem:
+            
+            ipp = simplify_peak_total_problem(ipp)
+        
+        # *********************************************************************
+            
+        # instantiate (disable the default case v-a-v fixed losses)
+        
+        # ipp.instantiate(place_fixed_losses_upstream_if_possible=False)
+        
+        ipp.instantiate(initialise_ancillary_sets=init_aux_sets)
+        
+        # optimise
+        
+        ipp.optimise(solver_name=solver, 
+                     solver_options=solver_options, 
+                     output_options={},
+                     print_solver_output=print_solver_output)
+            
+        # return the problem object
+            
+        return ipp
+    
+        # *********************************************************************
+        # *********************************************************************
+        
+    # *************************************************************************
+    # *************************************************************************
+    
+    def test_single_network_single_arc_problem(self):
+        
+        # scenario
+        q = 0
+        # time
+        number_intervals = 3
+        # periods
+        number_periods = 2
+    
+        # 2 nodes: one import, one regular
+        mynet = Network()
+        
+        # import node        
+        node_IMP = generate_pseudo_unique_key(mynet.nodes())
+        mynet.add_import_node(
+            node_key=node_IMP, 
+            prices={
+                (q,p,k): ResourcePrice(
+                    prices=1.0,
+                    volumes=None
+                    )
+                for p in range(number_periods)
+                for k in range(number_intervals)
+                }
+            )
+        
+        # other nodes
+        
+        node_A = generate_pseudo_unique_key(mynet.nodes())
+        
+        mynet.add_source_sink_node(
+            node_key=node_A, 
+            # base_flow=[0.5, 0.0, 1.0], 
+            base_flow={
+                (q,0):0.50,
+                (q,1):0.00,
+                (q,2):1.00} 
+            )
+        
+        # arc IA
+        
+        arc_tech_IA = Arcs(
+            name='any',
+            #efficiency=[0.5, 0.5, 0.5], 
+            efficiency={
+                (q,0): 0.5,
+                (q,1): 0.5,
+                (q,2): 0.5
+                },
+            efficiency_reverse=None,
+            static_loss=None,
+            capacity=[3],
+            minimum_cost=[2],
+            specific_capacity_cost=1, 
+            capacity_is_instantaneous=False,
+            validate=False)
+        
+        mynet.add_directed_arc(
+            node_key_a=node_IMP, 
+            node_key_b=node_A,
+            arcs=arc_tech_IA)
+        
+        # identify node types
+        
+        mynet.identify_node_types()
+        
+        # no sos, regular time intervals
+        
+        ipp = self.build_solve_ipp(
+            # solver=solver,
+            solver_options={},
+            # use_sos_arcs=use_sos_arcs,
+            # arc_sos_weight_key=sos_weight_key,
+            # arc_use_real_variables_if_possible=use_real_variables_if_possible,
+            # use_sos_sense=use_sos_sense,
+            # sense_sos_weight_key=sense_sos_weight_key,
+            # sense_use_real_variables_if_possible=sense_use_real_variables_if_possible,
+            # sense_use_arc_interfaces=use_arc_interfaces,
+            perform_analysis=False,
+            plot_results=False, # True,
+            print_solver_output=False,
+            # irregular_time_intervals=irregular_time_intervals,
+            networks={'mynet': mynet},
+            number_intraperiod_time_intervals=number_intervals,
+            static_losses_mode=True, # just to reach a line,
+            mandatory_arcs=[],
+            max_number_parallel_arcs={},
+            # init_aux_sets=init_aux_sets,
+            simplify_problem=False
+            )
+        
+        assert is_peak_total_problem(ipp)
+        assert ipp.results['Problem'][0]['Number of constraints'] == 24
+        assert ipp.results['Problem'][0]['Number of variables'] == 22
+        assert ipp.results['Problem'][0]['Number of nonzeros'] == 49
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+        # validation
+        
+        # the arc should be installed since it is the only feasible solution
+        assert True in ipp.networks['mynet'].edges[(node_IMP, node_A, 0)][
+            Network.KEY_ARC_TECH].options_selected
+        
+        # the flows should be 1.0, 0.0 and 2.0
+        assert math.isclose(
+            pyo.value(
+                ipp.instance.var_v_glljqk[
+                    ('mynet', node_IMP, node_A, 0, q, 0)
+                    ]
+                ),
+            1.0,
+            abs_tol=1e-6)
+        assert math.isclose(
+            pyo.value(
+                ipp.instance.var_v_glljqk[
+                    ('mynet', node_IMP, node_A, 0, q, 1)
+                    ]
+                ),
+            0.0,
+            abs_tol=1e-6)
+        assert math.isclose(
+            pyo.value(
+                ipp.instance.var_v_glljqk[
+                    ('mynet', node_IMP, node_A, 0, q, 2)
+                    ]
+                ),
+            2.0,
+            abs_tol=1e-6)
+        
+        # arc amplitude should be two
+        assert math.isclose(
+            pyo.value(
+                ipp.instance.var_v_amp_gllj[('mynet', node_IMP, node_A, 0)]
+                ),
+            2.0,
+            abs_tol=0.01)
+        
+        # capex should be four
+        assert math.isclose(pyo.value(ipp.instance.var_capex), 4.0, abs_tol=1e-3)
+        
+        # sdncf should be -5.7
+        assert math.isclose(
+            pyo.value(ipp.instance.var_sdncf_q[q]), -5.7, abs_tol=1e-3
+            )
+        
+        # the objective function should be -9.7
+        assert math.isclose(pyo.value(ipp.instance.obj_f), -9.7, abs_tol=1e-3)
+        
+    # *************************************************************************
+    # *************************************************************************
+    
+    def test_single_network_single_arc_problem_simpler(self):
+        
+        # scenario
+        q = 0
+        # time
+        number_intervals = 3
+        # periods
+        number_periods = 2
+    
+        # 2 nodes: one import, one regular
+        mynet = Network()
+        
+        # import node        
+        # node_IMP = generate_pseudo_unique_key(mynet.nodes())
+        node_IMP = 'thatimpnode'
+        mynet.add_import_node(
+            node_key=node_IMP, 
+            prices={
+                (q,p,k): ResourcePrice(
+                    prices=1.0,
+                    volumes=None
+                    )
+                for p in range(number_periods)
+                for k in range(number_intervals)
+                }
+            )
+        
+        # other nodes
+        
+        # node_A = generate_pseudo_unique_key(mynet.nodes())
+        node_A = 'thatnodea'
+        
+        mynet.add_source_sink_node(
+            node_key=node_A, 
+            # base_flow=[0.5, 0.0, 1.0], 
+            base_flow={
+                (q,0):0.50,
+                (q,1):0.00,
+                (q,2):1.00} 
+            )
+        
+        # arc IA
+        
+        arc_tech_IA = Arcs(
+            name='any',
+            #efficiency=[0.5, 0.5, 0.5], 
+            efficiency={
+                (q,0): 0.5,
+                (q,1): 0.5,
+                (q,2): 0.5
+                },
+            efficiency_reverse=None,
+            static_loss=None,
+            capacity=[3],
+            minimum_cost=[2],
+            specific_capacity_cost=1, 
+            capacity_is_instantaneous=False,
+            validate=False)
+        
+        mynet.add_directed_arc(
+            node_key_a=node_IMP, 
+            node_key_b=node_A,
+            arcs=arc_tech_IA)
+        
+        # identify node types
+        
+        mynet.identify_node_types()
+        
+        # no sos, regular time intervals
+        
+        ipp = self.build_solve_ipp(
+            # solver=solver,
+            solver_options={},
+            # use_sos_arcs=use_sos_arcs,
+            # arc_sos_weight_key=sos_weight_key,
+            # arc_use_real_variables_if_possible=use_real_variables_if_possible,
+            # use_sos_sense=use_sos_sense,
+            # sense_sos_weight_key=sense_sos_weight_key,
+            # sense_use_real_variables_if_possible=sense_use_real_variables_if_possible,
+            # sense_use_arc_interfaces=use_arc_interfaces,
+            perform_analysis=False,
+            plot_results=False, # True,
+            print_solver_output=False,
+            # irregular_time_intervals=irregular_time_intervals,
+            networks={'mynet': mynet},
+            number_intraperiod_time_intervals=number_intervals,
+            static_losses_mode=True, # just to reach a line,
+            mandatory_arcs=[],
+            max_number_parallel_arcs={},
+            # init_aux_sets=init_aux_sets,
+            simplify_problem=True
+            )
+        
+        assert is_peak_total_problem(ipp)
+        assert ipp.results['Problem'][0]['Number of constraints'] == 20
+        assert ipp.results['Problem'][0]['Number of variables'] == 19
+        assert ipp.results['Problem'][0]['Number of nonzeros'] == 36
+        
+        # *********************************************************************
+        # *********************************************************************
+            
+        # validation
+        
+        # the arc should be installed since it is the only feasible solution
+        assert True in ipp.networks['mynet'].edges[(node_IMP, node_A, 0)][
+            Network.KEY_ARC_TECH].options_selected
+        
+        # capex should be four
+        assert math.isclose(pyo.value(ipp.instance.var_capex), 4.0, abs_tol=1e-3)
+        
+        # the objective function should be -9.7
+        assert math.isclose(pyo.value(ipp.instance.obj_f), -9.7, abs_tol=1e-3)
+        
+        # TODO: compare model pretty print with expected one
+        
+        # from contextlib import redirect_stdout
+        # import io
+
+        # ipp.instance.constr_imp_flow_cost.pprint() # only one constraint
+        # f = io.StringIO()
+        # with redirect_stdout(f):
+        #     # ipp.instance.pprint() # full model
+        #     ipp.instance.constr_imp_flow_cost.pprint() # only one constraint
+                
+        # expected_string = r"""constr_imp_flow_cost : Size=4, Index=constr_imp_flow_cost_index, Active=True
+        #     Key                                     : Lower : Body                                                                                      : Upper : Active
+        #      ('mynet', 'thatimpnode', 'peak', 0, 0) :   0.0 : 0*var_if_glqpks[mynet,thatimpnode,peak,0,0,0] - var_ifc_glqpk[mynet,thatimpnode,peak,0,0] :   0.0 :   True
+        #      ('mynet', 'thatimpnode', 'peak', 1, 0) :   0.0 : 0*var_if_glqpks[mynet,thatimpnode,peak,1,0,0] - var_ifc_glqpk[mynet,thatimpnode,peak,1,0] :   0.0 :   True
+        #     ('mynet', 'thatimpnode', 'total', 0, 0) :   0.0 : var_if_glqpks[mynet,thatimpnode,total,0,0,0] - var_ifc_glqpk[mynet,thatimpnode,total,0,0] :   0.0 :   True
+        #     ('mynet', 'thatimpnode', 'total', 1, 0) :   0.0 : var_if_glqpks[mynet,thatimpnode,total,1,0,0] - var_ifc_glqpk[mynet,thatimpnode,total,1,0] :   0.0 :   True
+        # """
+        # assert expected_string == f.getvalue()
+        
+        
+        # from contextlib import redirect_stdout
+        # import io
+        # f = io.StringIO()
+        # with redirect_stdout(f):
+        #     print('foobar')
+        #     print(12)
+        #     12+3
+        # print('Got stdout: "{0}"'.format(f.getvalue()))
+        
+        
+        # *********************************************************************
+        # *********************************************************************
+    
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file
diff --git a/tests/test_esipp_resource.py b/tests/test_esipp_resource.py
new file mode 100644
index 0000000000000000000000000000000000000000..642a3e1aa61ecdbde10a04cd7fbaff43b2428fe6
--- /dev/null
+++ b/tests/test_esipp_resource.py
@@ -0,0 +1,761 @@
+# imports
+
+from src.topupopt.problems.esipp.resource import ResourcePrice
+from src.topupopt.problems.esipp.resource import are_prices_time_invariant
+
+# *****************************************************************************
+# *****************************************************************************
+
+class TestResourcePrice:
+    
+    # *************************************************************************
+    # *************************************************************************
+    
+    def test_resources_time_invariant(self):
+        
+        # single entry
+        
+        resource_prices = {
+            (0, 0, 0): ResourcePrice(prices=1, volumes=None),
+            }
+        
+        assert are_prices_time_invariant(resource_prices)
+        
+        # *********************************************************************
+            
+        # single assessment, two periods, same prices for both periods
+        
+        resource_prices = {
+            (0, 0, 0): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 1): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 2): ResourcePrice(prices=1, volumes=None),
+            (0, 1, 0): ResourcePrice(prices=1, volumes=None),
+            (0, 1, 1): ResourcePrice(prices=1, volumes=None),
+            (0, 1, 2): ResourcePrice(prices=1, volumes=None),
+            }
+        
+        assert are_prices_time_invariant(resource_prices)
+        
+        # *********************************************************************
+                
+        # single assessment, two periods, same prices per period
+        
+        resource_prices = {
+            (0, 0, 0): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 1): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 2): ResourcePrice(prices=1, volumes=None),
+            (0, 1, 0): ResourcePrice(prices=2, volumes=None),
+            (0, 1, 1): ResourcePrice(prices=2, volumes=None),
+            (0, 1, 2): ResourcePrice(prices=2, volumes=None),
+            }
+        
+        assert are_prices_time_invariant(resource_prices)
+        
+        # *********************************************************************
+                
+        # single assessment, two periods, different prices in a given period
+        
+        resource_prices = {
+            (0, 0, 0): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 1): ResourcePrice(prices=1, volumes=None),
+            (0, 0, 2): ResourcePrice(prices=1, volumes=None),
+            (0, 1, 0): ResourcePrice(prices=2, volumes=None),
+            (0, 1, 1): ResourcePrice(prices=2.5, volumes=None),
+            (0, 1, 2): ResourcePrice(prices=2, volumes=None),
+            }
+        
+        assert not are_prices_time_invariant(resource_prices)
+        
+        # *********************************************************************
+        
+    # *************************************************************************
+    # *************************************************************************
+
+    def test_resource_prices_reals(self):
+        
+        # 1) single segment, no volume limit, real input
+        
+        prices = 3
+                
+        volumes = None
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=False) == 1 
+        
+        assert res_p.number_segments(redo=True) == 1 
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+            
+        # 2) single segment, volume limit, real input
+        
+        prices = 3
+                
+        volumes = 1.5
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=False) == 1 
+        
+        assert res_p.number_segments(redo=True) == 1 
+        
+        assert res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+            
+    # *************************************************************************
+    # *************************************************************************
+
+    def test_equivalence_single(self):
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+        # single segment
+    
+        # *********************************************************************
+        # *********************************************************************
+        
+        # no volume limit
+        
+        # single segment, no volume limit, different formats
+        # prices and volumes match =  True
+        
+        prices = 3
+        volumes = None
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices], volumes=[volumes])
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+    
+        # *********************************************************************
+        
+        # single segment, no volume limit, different formats
+        # prices do not match = False
+        
+        prices = 3
+        volumes = None
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices+1], volumes=[volumes])
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, no volume limit, same format
+        # prices and volumes match =  True
+        
+        prices = 3
+        volumes = None
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, no volume limit, same format
+        # prices do not match = False
+        
+        prices = 3
+        volumes = None
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices+1, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+        # with volume limits
+        
+        # single segment, volume limit, different formats
+        # prices and volumes match =  True
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices], volumes=[volumes])
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+    
+        # *********************************************************************
+        
+        # single segment, volume limit, different formats: False
+        # prices do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices+1], volumes=[volumes])
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, volume limit, same format
+        # prices and volumes match =  True
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, volume limit, same format: False
+        # prices do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices+1, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+    
+        # *********************************************************************
+        
+        # single segment, volume limit, different formats
+        # volumes do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices], volumes=[volumes+1])
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, volume limit, same format
+        # volumes do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes+1)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+    
+        # *********************************************************************
+        
+        # single segment, volume limit, different formats
+        # volumes do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=[prices], volumes=[None])
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # single segment, volume limit, same format
+        # volumes do not match = False
+        
+        prices = 3
+        volumes = 1
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=None)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+    # *************************************************************************
+    # *************************************************************************
+
+    def test_equivalence_multiple_segments(self):
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+        # multiple segments
+        
+        # *********************************************************************
+        # *********************************************************************
+        
+        # no volume limit
+        
+        # two segments, no volume limit, same format
+        # prices and volumes match =  True
+        
+        prices = [1,3]
+        volumes = [1,None]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+        
+        # two segments, no volume limit, same format
+        # prices do not match = False
+        
+        prices = [1,3]
+        volumes = [1,None]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        prices = [2,3]
+        volumes = [1,None]
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        
+        # with volume limits
+        
+        # two segments segment, volume limit, same format
+        # prices and volumes match =  True
+        
+        prices = [1,3]
+        volumes = [1,3]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert res_p1.is_equivalent(res_p2)
+        assert res_p2.is_equivalent(res_p1)
+        
+        # two segments, volume limit, same format: False
+        # prices do not match = False
+        
+        prices = [1,3]
+        volumes = [1,4]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        prices = [1,4]
+        volumes = [1,4]
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+    
+        # *********************************************************************
+        
+        # volumes do not match
+        
+        # single segment, volume limit, same format
+        # volumes do not match = False
+        
+        prices = [1,3]
+        volumes = [1,4]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        prices = [1,3]
+        volumes = [1,5]
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # single segment, volume limit, same format
+        # volumes do not match = False
+        
+        prices = [1,3]
+        volumes = [1,4]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        prices = [1,3]
+        volumes = [1,None]
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        # *********************************************************************  
+        
+        # different number of segments
+        
+        prices = [1,3]
+        volumes = [1,4]
+        res_p1 = ResourcePrice(prices=prices, volumes=volumes)
+        prices = [1,3,5]
+        volumes = [1,4,None]
+        res_p2 = ResourcePrice(prices=prices, volumes=volumes)
+        assert not res_p1.is_equivalent(res_p2)
+        assert not res_p2.is_equivalent(res_p1)
+        
+        # *********************************************************************
+        # *********************************************************************        
+        
+    # *************************************************************************
+    # *************************************************************************
+
+    def test_resource_prices_lists(self):
+        
+        # *********************************************************************
+        
+        # aspects that were tested:
+        # i) number of segments (1, multiple or none)
+        # ii) price variations (increasing, decreasing and stable)
+        # iii) volume limits
+        
+        # *********************************************************************
+        
+        # 1) multiple segments, prices increase, volume limits
+        # 2) multiple segments, prices decrease, volume limits
+        # 3) multiple segments, prices are stable, volume limits
+        # 4) multiple segments, prices increase, no volume limit
+        # 5) multiple segments, prices decrease, no volume limit
+        # 6) multiple segments, prices are stable, no volume limit
+        # 7) one segment, prices are stable, volume limits
+        # 8) one segment, prices are stable, no volume limit
+        
+        # *********************************************************************
+        
+        # 1) multiple segments, prices increase, volume limits
+        
+        prices = [1,2,3]
+                
+        volumes = [2,1,3]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 3
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert not res_p.price_monotonically_decreasing_with_volume()
+        
+        assert not res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 2) multiple segments, prices decrease, volume limits
+        
+        prices = [3,2,1]
+                
+        volumes = [2,1,3]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert res_p.is_volume_capped()
+        
+        assert not res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert not res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 3) multiple segments, prices are stable, volume limits
+        
+        prices = [2,2,2]
+                
+        volumes = [2,1,3]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 3
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 4) multiple segments, prices increase, no volume limit
+        
+        prices = [1,2,3]
+                
+        volumes = [2,1,None]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 3
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert not res_p.price_monotonically_decreasing_with_volume()
+        
+        assert not res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 5) multiple segments, prices decrease, no volume limit
+        
+        prices = [2,2,2]
+                
+        volumes = [2,1,None]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 3
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 6) multiple segments, prices are stable, no volume limit
+        
+        prices = [2,2,2]
+                
+        volumes = [2,1,None]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 3
+        
+        assert res_p.number_segments(redo=False) == 3
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 7) one segment, prices are stable, volume limits
+        
+        prices = [2]
+                
+        volumes = [2]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 1
+        
+        assert res_p.number_segments(redo=False) == 1
+        
+        assert res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # 8) one segment, prices are stable, no volume limit
+        
+        prices = [3]
+                
+        volumes = [None]
+        
+        res_p = ResourcePrice(prices=prices, volumes=volumes)
+        
+        assert res_p.number_segments(redo=True) == 1
+        
+        assert res_p.number_segments(redo=False) == 1
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        res_p = ResourcePrice(prices=prices[0], volumes=volumes[0])
+        
+        assert res_p.number_segments(redo=True) == 1
+        
+        assert res_p.number_segments(redo=False) == 1
+        
+        assert not res_p.is_volume_capped()
+        
+        assert res_p.price_monotonically_increasing_with_volume()
+        
+        assert res_p.price_monotonically_decreasing_with_volume()
+        
+        assert res_p.is_volume_invariant()
+        
+        # *********************************************************************
+        
+        # errors
+        
+        # *********************************************************************
+        
+        # create object without prices
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=None,
+                              volumes=volumes)
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with negative prices in lists
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,-3,2],
+                              volumes=[3,4,5])
+        except ValueError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object where an intermediate segment has no volume limit
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,4,2],
+                              volumes=[3,None,5])
+        except ValueError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with negative volumes in lists
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,2],
+                              volumes=[4,-1,2])
+        except ValueError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with non-numeric prices in lists
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,'4',2],
+                              volumes=[3,4,5])
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with non-numeric volumes in lists
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,2],
+                              volumes=[4,'3',2])
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with mismatched price and volume lists
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,2],
+                              volumes=[5,7])
+        except ValueError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with a price list as an input and an unsupported type
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,2],
+                              volumes='hello')
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with negative prices in lists (no volumes are provided)
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,-2],
+                              volumes=None)
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with non-numeric prices in lists (no volumes are provided)
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=[7,3,'a'],
+                              volumes=None)
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with non-numeric prices in lists (no volumes are provided)
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=5,
+                              volumes=[7,3,4])
+        except TypeError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+        # create object with negative prices
+    
+        error_triggered = False
+        
+        try:
+            _ = ResourcePrice(prices=-3,
+                              volumes=None)
+        except ValueError:
+            error_triggered = True
+        assert error_triggered
+        
+        # *********************************************************************
+        
+# *****************************************************************************
+# *****************************************************************************
\ No newline at end of file