<jupyter_start><jupyter_text>On the cost of geographic-centric thingsThis notebook can be used to evaluate the energy and memory efficiency of geographic forwarding for a wireless sensor network depending on the network size, density, and dynamicity.For sake of completeness, we remind here the 4 IoT reference deployments:      Deployment name      Deployment class       of nodes      Node degree      Ref   A     Place de la Nation      Smart City      97      3.8      [Peters2016]   B     Great Duck Island      Environmental Sensor network      150      4.6      [Szewczyk2004]   C     CASAS      Home automation      30      8      [Cook2012]   D     Sensor Andrew      Building automation      1000      15      [Rowe2011]    Memory and CPU consuptionIn a first step, we look at the memory and CPU consumption for both F&L name-based forwarding and for GPSR-based geographic forwarding.<jupyter_code>from ipywidgets import *
from comp_mem_notebook import *

style = {'description_width': 'initial'}
d=FloatSlider(min=4, max=15, step=1, value=8, description="Network density", style=style)
n=IntSlider(min=10, max=2000, step=1, value=100, description="Number of nodes", style=style)
sloc=Dropdown(
    options={'1': 1, '2': 2, '4': 4, '8': 8},
    value=8,
    description='$s_{loc}$ (bytes)',
)

ex_a=ToggleButton(value=False, description='A', disabled=False)
ex_b=ToggleButton(value=False, description='B', disabled=False)
ex_c=ToggleButton(value=False, description='C', disabled=False)
ex_d=ToggleButton(value=False, description='D', disabled=False)


def enable_checkbox (checkbox):
    ex_a.value=False
    ex_b.value=False
    ex_c.value=False
    ex_d.value=False
    if checkbox is not None:
        checkbox.value=True

A = (97,4)
B = (150,5)
C = (30,8)
D = (1000,15)

def check_ex (*args):
    if (n.value,d.value) == A:
        enable_checkbox(ex_a)
    elif (n.value,d.value) == B:
        enable_checkbox(ex_b)
    elif (n.value,d.value) == C:
        enable_checkbox(ex_c)
    elif (n.value,d.value) == D:
        enable_checkbox(ex_d)
    else:
        enable_checkbox(None)

d.observe(check_ex,'value')
n.observe(check_ex,'value')

def ex_a_func (*args):
    if ex_a.value == True:
        d.value = 4
        n.value = 97

def ex_b_func (*args):
    if ex_b.value == True:
        d.value = 5
        n.value = 150

def ex_c_func (*args):
    if ex_c.value == True:
        d.value = 8
        n.value = 30

def ex_d_func (*args):
    if ex_d.value == True:
        d.value = 15
        n.value = 1000

ex_a.observe(ex_a_func, 'value')
ex_b.observe(ex_b_func, 'value')
ex_c.observe(ex_c_func, 'value')
ex_d.observe(ex_d_func, 'value')

ex_box = VBox([HTML("<h4>Deployment parameters</h4>"),
               HBox([d, n, sloc]),
               HBox([HTML("<b>Reference example:</b> (see Sec. II)"),ex_a, ex_b, ex_c, ex_d])])

def memcpu(density, number_of_nodes, sloc, _a, _b, _c, _d):
    mem_mpr = mem_cost(number_of_nodes)
    mem_geo = mem_cost_geo(number_of_nodes, density, sloc)
    
    lowest_style = "<span style=\"color:green; background-color: #ffffff; font-weight:bold;\">{}</span>"
    
    if mem_mpr > mem_geo:
        mem_geo=lowest_style.format(mem_geo)
    elif mem_mpr < mem_geo:
        mem_mpr=lowest_style.format(mem_mpr)
    
    comp_mpr = "{:2.2f}".format(fwd_cost(number_of_nodes))
    comp_geo = "{:2.2f}".format(fwd_cost_geo(density))
    
    if comp_mpr > comp_geo:
        comp_geo=lowest_style.format(comp_geo)
    elif comp_mpr < comp_geo:
        comp_mpr = lowest_style.format(comp_mpr)
    
    display(HTML("<h4>Results</h4>"))
    display(HTML("""
    <table style=\"border-color: black; border: 1px solid black; \">
        <tr style=\"border: 1px solid black;\"> <th style=\"padding: 10px; border: 1px solid black;\">      </th><th style=\"padding: 10px; border: 1px solid black;\">Required memory</th><th style=\"padding: 10px; border: 1px solid black;\">Computation cost   </th> </tr>
        <tr style=\"border: 1px solid black;\"> <th style=\"padding: 10px; border: 1px solid black;\"> GPSR </th><td style=\"padding: 10px; border: 1px solid black;\"> {gpsrmem} B   </td><td style=\"padding: 10px; border: 1px solid black;\"> {gpsrcomp} J  </td></tr>
        <tr style=\"border: 1px solid black;\"> <th style=\"padding: 10px; border: 1px solid black;\"> MPR  </th><td style=\"padding: 10px; border: 1px solid black;\"> {mprmem} B    </td><td style=\"padding: 10px; border: 1px solid black;\"> {mprcomp} J   </td></tr>
    </table>""".format(gpsrmem=mem_geo, gpsrcomp=comp_geo, mprmem=mem_mpr, mprcomp=comp_mpr)))

ou = interactive_output(memcpu, { 'density':d, 'number_of_nodes':n, 'sloc': sloc,
                            '_a':ex_a, '_b': ex_b, '_c': ex_c, '_d': ex_d}
                       )

display(ex_box, ou)<jupyter_output><empty_output><jupyter_text>Energy consumptionThe performance of a forwarding strategy depends on many parameters: obviously size and density of the network, but also dynamicity, average hop-count or payload size.Using this tool, you can set up your own parameters to test whether MPR or geographic forwarding yiels the best energy consumption for your network.You can also use the references IoT deployments settings directly  Per interest-data exchangeIn a first step, we explore how much energy is used by an on-path node to forward a single interest/data exchange.<jupyter_code>import matplotlib.pyplot as plt
from energy_cost_notebook import *

style = {'description_width': 'initial'}
d=FloatSlider(min=4, max=15, step=1, value=8, description="Network density", style=style)
n=IntSlider(min=10, max=2000, step=1, value=100, description="Number of nodes", style=style)
sloc=Dropdown(
    options={'1': 1, '2': 2, '4': 4, '8': 8},
    value=8,
    description='$s_{loc}$ (bytes)',
)
pay=IntSlider(min=1, max=48, value=32, description="Payload size (bytes)", style=style)

ex_a=ToggleButton(value=False, description='A', disabled=False)
ex_b=ToggleButton(value=False, description='B', disabled=False)
ex_c=ToggleButton(value=False, description='C', disabled=False)
ex_d=ToggleButton(value=False, description='D', disabled=False)


def enable_checkbox (checkbox):
    ex_a.value=False
    ex_b.value=False
    ex_c.value=False
    ex_d.value=False
    if checkbox is not None:
        checkbox.value=True

A = (97,4)
B = (150,5)
C = (30,8)
D = (1000,15)

def check_ex (*args):
    if (n.value,d.value) == A:
        enable_checkbox(ex_a)
    elif (n.value,d.value) == B:
        enable_checkbox(ex_b)
    elif (n.value,d.value) == C:
        enable_checkbox(ex_c)
    elif (n.value,d.value) == D:
        enable_checkbox(ex_d)
    else:
        enable_checkbox(None)

d.observe(check_ex,'value')
n.observe(check_ex,'value')

def ex_a_func (*args):
    if ex_a.value == True:
        d.value = 4
        n.value = 97

def ex_b_func (*args):
    if ex_b.value == True:
        d.value = 5
        n.value = 150

def ex_c_func (*args):
    if ex_c.value == True:
        d.value = 8
        n.value = 30

def ex_d_func (*args):
    if ex_d.value == True:
        d.value = 15
        n.value = 1000

ex_a.observe(ex_a_func, 'value')
ex_b.observe(ex_b_func, 'value')
ex_c.observe(ex_c_func, 'value')
ex_d.observe(ex_d_func, 'value')

ex_box = VBox([HTML("<h4>Deployment parameters</h4>"),
               HBox([d, n]),
               HBox([pay, sloc]),
               HBox([HTML("<b>Reference example:</b> (see Sec. II)"),ex_a, ex_b, ex_c, ex_d])])

def barplot(density, number_of_nodes, payload_size, sloc, _a, _b, _c, _d):
    comm_cost = nb_tries_per_message(pc[density])*communication_cost(icn_int_packet_size(number_of_nodes) + icn_cnt_packet_size(number_of_nodes, payload_size))
    crypto_cost = crypto_cost_uj(icn_int_packet_size(number_of_nodes))+crypto_cost_uj(icn_cnt_packet_size(number_of_nodes, payload_size))
    fwd_cost= COST_FIB_UJ*fib_size(number_of_nodes)+INTERCEPT_FIB_UJ

    comm_cost_geo = nb_tries_per_message(pc[density])*communication_cost(icn_geo_int_packet_size(number_of_nodes, sloc) + icn_cnt_packet_size(number_of_nodes, payload_size))
    crypto_cost_geo = crypto_cost_uj(icn_geo_int_packet_size(number_of_nodes, sloc))+crypto_cost_uj(icn_cnt_packet_size(number_of_nodes, payload_size))
    fwd_cost_geo = COST_NEIGH_UJ*density+INTERCEPT_NEIGH_UJ
    
    hdr_cost = 2*HDR_802154_LEN*(COST_RX_UJ+COST_TX_UJ)*nb_tries_per_message(pc[density])
    
    display(HTML("<h4>Results</h4>"))
    total_mpr_cost = comm_cost + crypto_cost + fwd_cost + hdr_cost
    total_geo_cost = comm_cost_geo + crypto_cost_geo + fwd_cost_geo + hdr_cost
    
    print("Energy cost of forwarding an Interest/Data exchange for MPR: {}J".format(total_mpr_cost))
    print("Energy cost of forwarding an Interest/Data exchange for GPSR: {}J".format(total_geo_cost))
    
    if total_mpr_cost > total_geo_cost:
        print("GPSR is more efficient by {:2.2f}%".format((total_mpr_cost-total_geo_cost)*100/total_geo_cost))
    else:
        print("MPR is more efficient by {:2.2f}%".format((total_geo_cost-total_mpr_cost)*100/total_mpr_cost))
    fig = plt.figure()
    ax = fig.gca()
    
    ind = [1,2]
    width = .3
    ax.set_ylabel(r"Energy cost ($\mu J$)") 
    hdr_arr = 2*HDR_802154_LEN*(COST_RX_UJ+COST_TX_UJ)*nb_tries_per_message(pc[density])
    hdr = ax.bar(ind[0], hdr_arr, width, color='w', hatch="//", edgecolor='black', bottom=comm_cost)       
    comm = ax.bar(ind[0], comm_cost, width, color='w', edgecolor='black')                                                     
    crypto = ax.bar(ind[0], crypto_cost, width, hdr_arr+comm_cost, color='grey', edgecolor='black')
    fwd = ax.bar(ind[0], fwd_cost, width, bottom=crypto_cost+comm_cost+hdr_arr, color='black')
                                
    hdr_geo = ax.bar(ind[1], hdr_arr, width, color='w', hatch="//", edgecolor='black', bottom=comm_cost_geo)       
    comm_geo = ax.bar(ind[1], comm_cost_geo, width, color='w', edgecolor='black')                                                     
    crypto_geo = ax.bar(ind[1], crypto_cost_geo, width, hdr_arr+comm_cost_geo, color='grey', edgecolor='black')
    fwd_geo = ax.bar(ind[1], fwd_cost_geo, width, bottom=crypto_cost_geo+comm_cost_geo+hdr_arr, color='black')
    
    ax.set_xticks(ind)
    ax.set_xticklabels(["MPR", "Geo"])
    
    plt.legend([comm[0], hdr[0], crypto[0], fwd[0]],('Comm. (L3)','Comm. (L2 hdr)','Crypto','Fwd'),
               loc='upper center', bbox_to_anchor=(0,1.15,1,0.102), ncol=4, columnspacing=0.8, handletextpad=0.4)
    

ou = interactive_output(barplot, { 'density':d, 'number_of_nodes':n, 'sloc': sloc, 'payload_size': pay,
                            '_a':ex_a, '_b': ex_b, '_c': ex_c, '_d': ex_d}
                       )

display(ex_box, ou)<jupyter_output><empty_output><jupyter_text>Using the full model to compare MPR F&L and geographic forwardingWe know provide a tool to derive the global message budget for the network, depending on whether the user chose geographic forwarding or MPR Flood-&-Learn<jupyter_code>from model_result_notebook import *

def f(density,number_of_nodes,change_freq, sloc, ttl, payload_size, _a, _b, _c, _d):
    display(HTML("<h4>Results</h4>"))
    geo = geo_energy_capacity(number_of_nodes, density, change_freq, sloc=sloc, ttl=ttl, payload_size=payload_size)
    mpr = mpr_energy_capacity(number_of_nodes,density,change_freq, ttl=ttl, payload_size=payload_size)
    print("Message budget with MPR: {:2.0f} messages".format(mpr))
    print("Message budget with geographic forwarding: {:2.0f} messages".format(geo))
    
    if geo > mpr:
        display(HTML("<b>Geographic forwarding</b> is the most efficient in these settings by {:2.2f}%".format(100*(geo-mpr)/geo)))
    else:
        display(HTML("<b>MPR F&L</b> is the most efficient in these settings by {:2.2f}%".format(100*(mpr-geo)/mpr)))
    
style = {'description_width': 'initial'}
d=FloatSlider(min=4, max=15, step=1, value=8, description="Network density", style=style)
n=IntSlider(min=10, max=2000, step=1, value=100, description="Number of nodes", style=style)
#f=FloatSlider(min=1, max=10, step=.1, value=3, description="Change freq. ($\log_{10}$)",style=style)
fc=FloatText(value=60, description="Change frequency", style=style)
ttl=IntSlider(min=1, max=14, value=4, description="Avg hop count", style=style)
sloc=Dropdown(
    options={'1': 1, '2': 2, '4': 4, '8': 8},
    value=8,
    description='$s_{loc}$ (bytes)',
)
pay=IntSlider(min=1, max=48, value=32, description="Payload size (bytes)", style=style)

ex_a=ToggleButton(value=False, description='A', disabled=False)
ex_b=ToggleButton(value=False, description='B', disabled=False)
ex_c=ToggleButton(value=False, description='C', disabled=False)
ex_d=ToggleButton(value=False, description='D', disabled=False)


def enable_checkbox (checkbox):
    ex_a.value=False
    ex_b.value=False
    ex_c.value=False
    ex_d.value=False
    if checkbox is not None:
        checkbox.value=True

A = (97,4)
B = (150,5)
C = (30,8)
D = (1000,15)

def check_ex (*args):
    if (n.value,d.value) == A:
        enable_checkbox(ex_a)
    elif (n.value,d.value) == B:
        enable_checkbox(ex_b)
    elif (n.value,d.value) == C:
        enable_checkbox(ex_c)
    elif (n.value,d.value) == D:
        enable_checkbox(ex_d)
    else:
        enable_checkbox(None)

d.observe(check_ex,'value')
n.observe(check_ex,'value')

def ex_a_func (*args):
    if ex_a.value == True:
        d.value = 4
        n.value = 97

def ex_b_func (*args):
    if ex_b.value == True:
        d.value = 5
        n.value = 150

def ex_c_func (*args):
    if ex_c.value == True:
        d.value = 8
        n.value = 30

def ex_d_func (*args):
    if ex_d.value == True:
        d.value = 15
        n.value = 1000

ex_a.observe(ex_a_func, 'value')
ex_b.observe(ex_b_func, 'value')
ex_c.observe(ex_c_func, 'value')
ex_d.observe(ex_d_func, 'value')

ex_box = VBox([HTML("<h4>Deployment parameters</h4>"),
               HBox([d, n, fc]),
               HBox([ttl, pay, sloc]),
               HBox([HTML("<b>Reference example:</b> (see Sec. II)"),ex_a, ex_b, ex_c, ex_d])])

ou = interactive_output(f, { 'density':d, 'number_of_nodes':n, 'change_freq':fc,
                            'sloc': sloc, 'ttl': ttl, 'payload_size': pay,
                            '_a':ex_a, '_b': ex_b, '_c': ex_c, '_d': ex_d}
                       )

display(ex_box, ou)<jupyter_output><empty_output><jupyter_text>Per parameter approachIn this section, we focus on the impact of each parameter. Chose first a parameter to vary, then setup the other ones to see how the energy efficiency of each strategy vary with your chosen parameter<jupyter_code>parameter=Dropdown(options={"Network density": 0,
                    "Number of nodes": 1,
                    "Change frequency": 2,
                    "Average hop count": 3,
                    "Payload size": 4,
                    "Coordinates size": 5},
                  value=2,
                  description="Parameter to vary")

style = {'description_width': 'initial'}
d=FloatSlider(min=4, max=15, step=1, value=8, description="Network density", style=style)
n=IntSlider(min=10, max=2000, step=1, value=100, description="Number of nodes", style=style)
fc=FloatText(value=60, description="Change frequency", style=style, disable=True)
ttl=IntSlider(min=1, max=14, value=4, description="Avg hop count", style=style)
sloc=Dropdown(
    options={'1': 1, '2': 2, '4': 4, '8': 8},
    value=8,
    description='$s_{loc}$ (bytes)',
    disable=True
)
pay=IntSlider(min=1, max=48, value=32, description="Payload size (bytes)", style=style)

ex_a=ToggleButton(value=False, description='A', disabled=False)
ex_b=ToggleButton(value=False, description='B', disabled=False)
ex_c=ToggleButton(value=False, description='C', disabled=False)
ex_d=ToggleButton(value=False, description='D', disabled=False)


def enable_checkbox (checkbox):
    ex_a.value=False
    ex_b.value=False
    ex_c.value=False
    ex_d.value=False
    if checkbox is not None:
        checkbox.value=True

A = (97,4)
B = (150,5)
C = (30,8)
D = (1000,15)

def check_ex (*args):
    if (n.value,d.value) == A:
        enable_checkbox(ex_a)
    elif (n.value,d.value) == B:
        enable_checkbox(ex_b)
    elif (n.value,d.value) == C:
        enable_checkbox(ex_c)
    elif (n.value,d.value) == D:
        enable_checkbox(ex_d)
    else:
        enable_checkbox(None)

d.observe(check_ex,'value')
n.observe(check_ex,'value')

def ex_a_func (*args):
    if ex_a.value == True:
        d.value = 4
        n.value = 97

def ex_b_func (*args):
    if ex_b.value == True:
        d.value = 5
        n.value = 150

def ex_c_func (*args):
    if ex_c.value == True:
        d.value = 8
        n.value = 30

def ex_d_func (*args):
    if ex_d.value == True:
        d.value = 15
        n.value = 1000

ex_a.observe(ex_a_func, 'value')
ex_b.observe(ex_b_func, 'value')
ex_c.observe(ex_c_func, 'value')
ex_d.observe(ex_d_func, 'value')

def parameter_func(option):
    d.disabled=False
    n.disabled=False
    fc.disabled=False
    ttl.disabled=False
    pay.disabled=False
    sloc.disabled=False
    if option==0:
        d.disabled=True
    elif option ==1:
        n.disabled=True
    elif option ==2:
        fc.disabled=True
    elif option ==3:
        ttl.disabled=True
    elif option ==4:
        pay.disabled=True
    elif option ==5:
        sloc.disabled=True

from matplotlib.ticker import FuncFormatter
formatter = FuncFormatter(lambda x,y : '%dM' % (x*1e-6) if x!=0 else '') 

def plot_function(option, d, n, fc, ttl, pay, sloc, _a, _b, _c, _d):
    plt.figure()
    parameter_func(option)
    if option==0:
        keys = np.arange(4,15)
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(n, x, fc, sloc=sloc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(n, x, fc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim([4,14])
        plt.xlabel("Average network density")
    elif option==1:
        keys=np.arange(10,2000)
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(x, d, fc, sloc=sloc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(x, d, fc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim(10,2000)
        plt.xlabel("Network size")
    elif option==2:
        keys=np.arange(1,10**4)
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(n, d, x, sloc=sloc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(n, d, x, ttl=ttl, payload_size=pay))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim(1, 10**4)
        plt.xscale("log")
        plt.xlabel("Number of readings between two route changes")
    elif option==3:
        keys=np.arange(1,14)
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(n, d, fc, sloc=sloc, ttl=x, payload_size=pay))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(n, d, fc, ttl=x, payload_size=pay))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim(1, 14)
        plt.xlabel("Average hop count")
    elif option==4: #pay
        keys=np.arange(1,48)
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(n, d, fc, sloc=sloc, ttl=ttl, payload_size=x))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(n, d, fc, ttl=ttl, payload_size=x))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim(1, 48)
        plt.xlabel("Payload size (bytes)")
    elif option==5: #sloc
        keys=[1,2,4,8]
        plt.plot(keys, 
                 np.vectorize(lambda x : geo_energy_capacity(n, d, fc, sloc=x, ttl=ttl, payload_size=pay))(keys),
                 linestyle='dotted', label='Geographic forwarding')
        plt.plot(keys, 
                 np.vectorize(lambda x : mpr_energy_capacity(n, d, fc, ttl=ttl, payload_size=pay))(keys),
                 linestyle='solid', label='MPR F\&L')
        plt.xlim(1, 8)
        plt.xlabel("Coordinates size (bytes)")
    plt.legend()
    plt.gca().yaxis.set_major_formatter(formatter)
    plt.ylabel("Message budget with one AA battery")


ex_box = VBox([HTML("<h4>Deployment parameters</h4>"),
               HBox([parameter]),
               HBox([d, n, fc]),
               HBox([ttl, pay, sloc]),
               HBox([HTML("<b>Reference example:</b> (see Sec. II)"),ex_a, ex_b, ex_c, ex_d])])

ou = interactive_output(plot_function, { 'd':d, 'n':n, 'fc':fc,
                            'sloc': sloc, 'ttl': ttl, 'pay': pay,
                            '_a':ex_a, '_b': ex_b, '_c': ex_c, '_d': ex_d, 'option': parameter}
                       )

display(ex_box,ou)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1450767502807937, 'fraction_numerical': 0.02232309996256084, 'mean_word_length': 3.2601674641148324, 'pattern_counts': {'":': 6, '<': 73, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '617328', 'license': 'Apache-2.0', 'n_tokens_mistral': 7926, 'n_tokens_neox': 7556, 'n_words': 1651, 'path': 'models/geographic-icthings.ipynb', 'repo_name': 'marceleng/geographic-icthings', 'size': '21368'}