Electricity system simulation¶
Preparation¶
Now that we have completed both the electricity generation and demand inputs for our investigation we are almost ready to simulate an electricity system. This will allow us to model the technical performance of an electricity system of a given size and its ability to meet the load demanded by the community. At this stage we consider only the technical performance, rather than the financial or environmental considerations, which will come later when we optimise the sizing of the systems.
Before we can simulate a system we must first provide inputs for its technical performance and the conditions of the scenario under which we want it to operate.
Electricity system inputs¶
The inputs for the technical performance of the system are included in
the Energy system inputs
file, which is located in the Simulation
folder of your location folder.
Let’s look at the inputs included for the Bahraich case study:
import pandas as pd
energy_system_inputs = pd.read_csv("/Users/prs09/Documents/CLOVER/Locations/Bahraich/Simulation/Energy system inputs.csv",header=None)
energy_system_inputs.head(len(energy_system_inputs))
| 0 | 1 | 2 | |
|---|---|---|---|
| 0 | Battery maximum charge | 0.900 | State of charge (0.0-1.0) |
| 1 | Battery minimum charge | 0.400 | State of charge (0.0-1.0) |
| 2 | Battery leakage | 0.004 | Fractional leakage per hour |
| 3 | Battery conversion in | 0.950 | Conversion efficiency (0.0-1.0) |
| 4 | Battery conversion out | 0.950 | Conversion efficiency (0.0-1.0) |
| 5 | Battery cycle lifetime | 1500.000 | Expected number of cycles over lifetime |
| 6 | Battery lifetime loss | 0.400 | Fractional loss over lifetime (0.0-1.0) |
| 7 | Battery C rate discharging | 0.330 | Discharge rate |
| 8 | Battery C rate charging | 0.330 | Charge rate |
| 9 | Transmission efficiency DC | 0.950 | Efficiency of DC distribution network |
| 10 | Transmission efficiency AC | 0.950 | Efficiency of AC distribution network |
| 11 | DC to AC conversion | 0.950 | Conversion efficiency (0.0-1.0) |
| 12 | DC to DC conversion | 0.950 | Conversion efficiency (0.0-1.0) |
| 13 | AC to DC conversion | 0.800 | Conversion efficiency (0.0-1.0) |
| 14 | AC to AC conversion | 0.980 | Conversion efficiency (0.0-1.0) |
These variables control how the electricity system performs, in particular the performance of the battery storage and the conversion efficiencies in the system. The table below describes in more detail what each one means:
| Variable | Explanation |
|---|---|
Battery maximum charge |
Maximum permitted state of charge of the battery |
Battery minimum charge |
Minimum permitted state of charge of the battery |
Battery leakage |
Fraction of the energy stored in the battery lost per hour |
Battery conversion in |
Conversion efficiency of energy entering the battery |
Battery conversion out |
Conversion efficiency of energy leaving the battery |
Battery cycle lifetime |
Number of charging cycles expected from the battery over its lifetime |
Battery C rate discharging |
C-rate of the battery whilst providing energy |
Battery C rate charging |
C-rate of the battery whilst receiving energy |
Transmission efficiency DC |
Transmission efficiency of a DC distribution network |
Transmission efficiency AC |
Transmission efficiency of an AC distribution network |
DC to AC conversion |
Conversion efficiency from DC power to an AC distribution network |
DC to DC conversion |
Conversion efficiency from DC power to an DC distribution network |
AC to DC conversion |
Conversion efficiency from AC power to an DC distribution network |
AC to AC conversion |
Conversion efficiency from AC power to an AC distribution network |
The variables Battery maximum charge
and Battery minimum charge
refer to the maximum and minimum permitted states of charge of the
battery: in this case the battery is allowed to cycle between 90% and
40% of its total capacity, resulting in a depth of discharge (DOD) of
50%, and meaning that 50% of the total installed battery capacity is
actually usable by the system. Battery leakage
is the fraction of
energy that leaks out of the battery every hour, in this case 0.004
or 0.4% of the energy presently stored in it per hour.
Battery conversion in
and Battery conversion out
are the
conversion efficiencies of energy being supplied to and from the battery
respectively; when multiplied together these give the battery round-trip
efficiency.
Battery cycle lifetime
refers to the number of charging and
discharging cycles that the battery can be expected to perform over its
lifetime, with the lifetime defined to be over when the battery has
degraded by Battery lifetime loss
; in this case
Battery lifetime loss = 0.2
(as is typical for this definition) and
so the lifetime is over when the battery provides just 80% of its
original capacity. The battery degradation is calculated by multiplying
the lifetime loss by the energy throughput of the battery (at a given
point in time) and then dividing by the expected cumulative energy
throughput over the lifetime of the battery (the cycle lifetime
multiplied by the depth of discharge and total capacity). This
simplified method does not account for the effects of temperature or
reduced cycling which may affect the lifetime of a battery in practice.
Finally for the battery parameters, Battery C rate discharging
and
Battery C rate charging
are the C-rates for discharging and charging
the batteries, measured as the maximum permitted fraction of the battery
capacity that can be stored or supplied in one hour. These battery
parameters can be taken from a datasheet provided by a battery
manufacturer or used as indicative values in more general
investigations. They are also agnostic to the type of battery technology
being investigated, for example lead acid or lithium ion batteries. Some
of these parameters will be dependent on one another: for example, a
given battery being used with a higher DOD will likely have a lower
cycle lifetime. These relationships are often available on battery
datasheets (for example as performance curves) but need to be input
manually and individually here. Similarly, higher C-rates will also
likely result in lower cycle lifetimes.
Let’s take a look at some of the variables:
max_charge = energy_system_inputs.iloc[0][1]
min_charge = energy_system_inputs.iloc[1][1]
DOD = max_charge - min_charge
print('Maximum state of charge: ' + str((int(100 * max_charge))) + '%')
print('Minimum state of charge: ' + str((int(100 * min_charge))) + '%')
print('Depth of discharge: ' + str(int(100 * DOD)) + '%\n')
battery_conversion_in = energy_system_inputs.iloc[3][1]
battery_conversion_out = energy_system_inputs.iloc[4][1]
round_trip_efficiency = battery_conversion_in * battery_conversion_out
print('Battery input efficiency: ' + str((int(100 * battery_conversion_in))) + '%')
print('Battery output efficiency: ' + str((int(100 * battery_conversion_out))) + '%')
print('Round trip efficiency: ' + str(int(100 * round_trip_efficiency)) + '%')
Maximum state of charge: 90%
Minimum state of charge: 40%
Depth of discharge: 50%
Battery input efficiency: 95%
Battery output efficiency: 95%
Round trip efficiency: 90%
The next two variables, Transmission efficiency AC
and
Transmission efficiency DC
, describe the efficiency of the power
distribution network being used to transmit power from the generation
and storage source to the consumers. This can be AC (alternating
current, generally better for high-power applications and long-range
transmission) or DC (direct current, generally better for low-power
applications and short-range transmission). Only one of these will be
used at a time but both should be completed, for example using a dummy
value if only one is ever to be investigated. Finally,
DC to AC conversion
(for example) gives the conversion efficiency of
DC power sources, such as solar or batteries, to an AC distribution
network. These are the efficiencies of inverters, rectifiers and voltage
converters that would be used in the system; as before, these should all
be included for completeness but dummy values (or the defaults) could be
used if only one distribution network is being considered.
Complete the Energy system inputs
CSV with the technical
performance parameters for your investigation.
Scenario inputs¶
The inputs which describe the situation we are investigating are provided in the Scenario inputs CSV file in the Scenario folder of your location folder. These describe parameters such as the types of technologies that are being used in the system and the loads that are being met. Let’s take a look at the default inputs for Bahraich:
scenario_inputs = pd.read_csv("/Users/prs09/Documents/CLOVER/Locations/Bahraich/Scenario/Scenario inputs.csv",header=None)
scenario_inputs.head(len(scenario_inputs))
| 0 | 1 | 2 | |
|---|---|---|---|
| 0 | PV | Y | (Y/N) |
| 1 | Battery | Y | (Y/N) |
| 2 | Diesel backup | Y | (Y/N) |
| 3 | Diesel backup threshold | 0.1 | Maximum acceptible blackouts (0.0-1.0) |
| 4 | Grid | Y | (Y/N) |
| 5 | Grid type | bahraich | Grid profile |
| 6 | Prioritise self generation | Y | (Y/N) |
| 7 | Domestic | Y | (Y/N) |
| 8 | Commercial | Y | (Y/N) |
| 9 | Public | Y | (Y/N) |
| 10 | Distribution network | DC | DC or AC distribution network |
Many of these may be straightforward, but the table below describes them explicitly.
| Variable | Explanation |
|---|---|
PV |
Whether solar PV is available
(Y ) or not (N ) |
Battery |
Whether battery storage is
available (Y ) or not (N ) |
Diesel backup |
Whether a diesel generator backup
is available (Y ) or not
(N ) |
Diesel backup threshold |
The blackout threshold which the diesel generator is used to achieve |
Grid |
Whether the national grid is
available (Y ) or not (N ) |
PV |
Whether solar PV is available
(Y ) or not (N ) |
Prioritise self generation |
Whether to prioritise local
generation (Y ) or energy from
the grid (N ) |
Domestic |
Whether Domestic loads are
included in the load profile
(Y ) or not (N ) |
Commercial |
Whether Commercial loads are
included in the load profile
(Y ) or not (N ) |
Public |
Whether Public loads are
included in the load profile
(Y ) or not (N ) |
Distribution network |
Whether an AC or DC
distribtion network is used to
transmit electricity |
The three of the variables, PV
, Battery
and Grid
, are
present for future-proofing and have no effect at present: solar and
battery storage must be considered in simulations for now, although (as
we will see in we will see
later) they can have
capacities of zero which mean they are not actually included. Similarly
Grid type
describes the grid availability profile to be used from
the Grid module, which can be similarly switched off by selecting a
profile with no availability (e.g. Grid type = none
).
The Diesel backup
variable is active and controls whether a diesel
generator can be used to supply additional power during times of
blackouts. Periods of blackouts will be described in more detail later,
but for now the blackouts
parameter can be described as the fraction
of time that insufficient energy is available in the system to meet the
loads. If a system of a specified solar and storage capacity, operating
with a given grid availability, has a blackouts
parameter greater
than Diesel backup threshold
then the diesel generator is used
retroactively to top up hours where blackouts occur, up to the point at
which the system blackouts
and Diesel backup threshold
are
equal. For example, if a system had blackouts = 0.17
and (as in
default values) Diesel backup threshold = 0.1
, then the diesel
generator would be used to supply power in 7% (0.07
) of the hours to
make blackouts = 0.10
after its implementation.
Prioritise self generation
describes whether the system will use its
own locally-generated energy from solar first before drawing power from
the grid if available and then storage (Y
), or whether it will take
power from the grid first if available and then from solar and then
storage (N
). In either case, it may be that either locally generated
or grid power is unavailable and therefore this should be thought of as
a prioritisation of sources rather than a backup. In both cases the
diesel backup is considered after this prioritisation occurs.
Domestic
, Commercial
and Public
refer to whether these
demand types are to be included in the load profile used in the
investigation. Finally the Distribution network
defines whether an
AC
or DC
transmission network is used to distribute electricity
from the sources to the loads, which will affect the conversion
efficiencies used as inputs in the previous section.
Complete the Scenario inputs
CSV with the details of the situation
of your investigation.
Performing a simulation of an electricity system¶
Inputs¶
We are now able to perform a simulation of an energy system using the Energy_System module. This relies on all of the information we have input and generated previously in the electricity generation and load profiles sections, and the earlier parts of this section. This will let us investigate the technological performance of a system with a specified solar and battery capacity, operating under the conditions we defined earlier.
To perform a simulation we must first run the Energy_System script (using the green arrow in the Spyder console), which we do here using the following:
import sys
sys.path.insert(0, '/Users/prs09/Documents/CLOVER/Scripts/Simulation scripts/')
from Energy_System import Energy_System
To simulate an energy system we need to specify four further parameters; these are taken as inputs for convenience when investigating many system sizes, for example during optimisations which we will explore further later. These are:
| Variable | Explanation |
|---|---|
start_year |
Starting year of the simulation |
end_year |
End year of the simualation |
PV_size |
Installed solar capacity in kWp |
storage_size |
Installed battery storage capacity in kWh |
These tell the function running the simulation both the time period to
consider and the capacity of the system that is being investigated. The
parameters start_year
and end_year
are defined by the first day
of their respective years and (as with the rest of Python) start from
0
. For example, running a simulation for only the first year of a
20-year timeline would require start_year = 0
and end_year = 1
,
i.e. running from the first day of Year 0 up to (but not including) the
first day of Year 1. These inputs must be integers.
The parameters PV_size
and storage_size
refer to the installed
capacities of the solar and battery storage components in their
functional units of kWp and kWh respectively. These inputs can be any
number, including decimals (for example as a multiple of a given solar
panel size) and zero if they are not to be included, as we saw earlier
in ` <#scenario-inputs>`__.
The Energy_System().simulation(...)
function includes default values
for each of these parameters which are used if the user does not specify
any of their input values. In our example, we will simulate a system
over the first year of its lifetime (start_year = 0, end_year = 1)
and with PV_size = 5
kWp and storage_size = 20
kWh.
Running a simulation¶
To run a simulation we run the following function in the console
with our choice of input variables, saving the output as a variable
called example_simulation
so we can look at the outputs in more
detail:
example_simulation = Energy_System().simulation(start_year=0, end_year=1, PV_size=5, storage_size=20)
Time taken for simulation: 0.45 seconds per year
When we run this function we get an output, which we called
example_simulation
, which is composed of two further outputs: one
describing the technical performance of the system, and one describing
the input parameters that we gave to the function. If we did not save
the output of this function as a variable then the results would have
been printed to the screen, but not available to use later. We also get
an estimate of the time taken to perform each year of the simulation:
running the entire function likely looking much longer than this, but
this value can be useful in identifying potential errors if the value is
much higher for some simulations rather than others.
When this function is called it automatically takes into account all of the earlier input data and operating conditions to simulate the system over the defined time period - making the function itself very straightforward to use.
Simulation outputs¶
The important parts of this function are its two outputs which tell us
how the system has performed over the simulated time period. Let’s take
a look at the first component by defining a new variable called
example_simulation_performance
:
example_simulation_performance = example_simulation[0]
example_simulation_performance.head(24).round(3)
| Load energy (kWh) | Total energy used (kWh) | Unmet energy (kWh) | Blackouts | Renewables energy used (kWh) | Storage energy supplied (kWh) | Grid energy (kWh) | Diesel energy (kWh) | Diesel times | Diesel fuel usage (l) | Storage profile (kWh) | Renewables energy supplied (kWh) | Hourly storage (kWh) | Dumped energy (kWh) | Battery health | Households | Kerosene lamps | Kerosene mitigation | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1.166 | 1.166 | 0.0 | 0.0 | 0.000 | 1.166 | 0.000 | 0.000 | 0.0 | 0.000 | -1.166 | 0.000 | 16.834 | 0.000 | 1.0 | 100 | 0.0 | 75.0 |
| 1 | 0.938 | 0.938 | 0.0 | 0.0 | 0.000 | 0.000 | 0.938 | 0.000 | 0.0 | 0.000 | 0.000 | 0.000 | 16.766 | 0.000 | 1.0 | 100 | 0.0 | 103.0 |
| 2 | 0.920 | 0.968 | 0.0 | 0.0 | 0.000 | 0.968 | 0.000 | 0.000 | 0.0 | 0.000 | -0.920 | 0.000 | 15.731 | 0.000 | 1.0 | 100 | 0.0 | 81.0 |
| 3 | 0.377 | 0.377 | 0.0 | 0.0 | 0.000 | 0.000 | 0.377 | 0.000 | 0.0 | 0.000 | 0.000 | 0.000 | 15.668 | 0.000 | 1.0 | 100 | 0.0 | 91.0 |
| 4 | 0.402 | 0.423 | 0.0 | 0.0 | 0.000 | 0.423 | 0.000 | 0.000 | 0.0 | 0.000 | -0.402 | 0.000 | 15.182 | 0.000 | 1.0 | 100 | 0.0 | 74.0 |
| 5 | 0.412 | 0.412 | 0.0 | 0.0 | 0.000 | 0.000 | 0.412 | 0.000 | 0.0 | 0.000 | 0.000 | 0.000 | 15.121 | 0.000 | 1.0 | 100 | 0.0 | 73.0 |
| 6 | 0.446 | 0.470 | 0.0 | 0.0 | 0.000 | 0.470 | 0.000 | 0.000 | 0.0 | 0.000 | -0.446 | 0.000 | 14.591 | 0.000 | 1.0 | 100 | 0.0 | 70.0 |
| 7 | 1.258 | 1.322 | 0.0 | 0.0 | 0.041 | 1.281 | 0.000 | 0.000 | 0.0 | 0.000 | -1.217 | 0.041 | 13.251 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 8 | 1.479 | 1.513 | 0.0 | 0.0 | 0.830 | 0.683 | 0.000 | 0.000 | 0.0 | 0.000 | -0.649 | 0.830 | 12.515 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 9 | 1.300 | 1.300 | 0.0 | 0.0 | 1.300 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 0.591 | 1.891 | 13.027 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 10 | 0.726 | 0.726 | 0.0 | 0.0 | 0.726 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 1.941 | 2.667 | 14.818 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 11 | 1.668 | 1.668 | 0.0 | 0.0 | 1.668 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 1.432 | 3.100 | 16.119 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 12 | 1.105 | 1.105 | 0.0 | 0.0 | 1.105 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 2.202 | 3.308 | 17.999 | 0.148 | 1.0 | 100 | 0.0 | 0.0 |
| 13 | 1.100 | 1.100 | 0.0 | 0.0 | 1.100 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 2.045 | 3.145 | 17.999 | 1.871 | 1.0 | 100 | 0.0 | 0.0 |
| 14 | 1.947 | 1.947 | 0.0 | 0.0 | 1.947 | 0.000 | 0.000 | 0.000 | 0.0 | 0.000 | 0.733 | 2.680 | 17.999 | 0.624 | 1.0 | 100 | 0.0 | 0.0 |
| 15 | 2.226 | 2.244 | 0.0 | 0.0 | 1.882 | 0.363 | 0.000 | 0.000 | 0.0 | 0.000 | -0.345 | 1.882 | 17.564 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 16 | 1.479 | 1.511 | 0.0 | 0.0 | 0.866 | 0.645 | 0.000 | 0.000 | 0.0 | 0.000 | -0.613 | 0.866 | 16.849 | 0.000 | 1.0 | 100 | 0.0 | 0.0 |
| 17 | 3.626 | 3.626 | 0.0 | 0.0 | 0.077 | 0.000 | 3.550 | 0.000 | 0.0 | 0.000 | 0.000 | 0.077 | 16.782 | 0.000 | 1.0 | 100 | 0.0 | 122.0 |
| 18 | 2.001 | 2.106 | 0.0 | 0.0 | 0.000 | 2.106 | 0.000 | 0.000 | 0.0 | 0.000 | -2.001 | 0.000 | 14.608 | 0.000 | 1.0 | 100 | 0.0 | 333.0 |
| 19 | 4.447 | 4.447 | 0.0 | 0.0 | 0.000 | 3.473 | 0.000 | 0.974 | 1.0 | 0.560 | -4.447 | 0.000 | 11.076 | 0.000 | 1.0 | 100 | 0.0 | 338.0 |
| 20 | 1.961 | 2.064 | 0.0 | 0.0 | 0.000 | 2.064 | 0.000 | 0.000 | 0.0 | 0.000 | -1.961 | 0.000 | 8.968 | 0.000 | 1.0 | 100 | 0.0 | 336.0 |
| 21 | 1.576 | 1.576 | 0.0 | 0.0 | 0.000 | 0.000 | 1.576 | 0.000 | 0.0 | 0.000 | 0.000 | 0.000 | 8.932 | 0.000 | 1.0 | 100 | 0.0 | 277.0 |
| 22 | 2.226 | 2.226 | 0.0 | 0.0 | 0.000 | 0.898 | 0.000 | 1.329 | 1.0 | 0.560 | -2.226 | 0.000 | 7.999 | 0.000 | 1.0 | 100 | 0.0 | 132.0 |
| 23 | 2.038 | 2.038 | 0.0 | 0.0 | 0.000 | 0.000 | 0.000 | 2.038 | 1.0 | 0.815 | -2.038 | 0.000 | 7.998 | 0.000 | 1.0 | 100 | 0.0 | 108.0 |
This component gives the performance of the system at an hourly resolution, with the first 24 hours of the simulation shown here and rounded to three decimal places for convenience. They are defined in the table below:
| Variable | Explanation |
|---|---|
Load energy (kWh) |
Load energy demanded by the community |
Total energy used (kWh) |
Total energy used by the community |
Unmet energy (kWh) |
Energy that would have been needed to meet energy demand |
Blackouts |
Whether there was a blackout
period (1 ) or not (0 ) |
Renewables energy used (kWh) |
Renewable energy used directly by the community |
Storage energy supplied (kWh) |
Energy supplied by battery storage |
Grid energy (kWh) |
Energy supplied by the grid network |
Diesel energy (kWh) |
Energy supplied by the diesel generator |
Diesel times |
Whether the diesel generator was
on (1 ) or off (0 ) |
Diesel fuel usage (l) |
Litres of diesel fuel used |
Storage profile (kWh) |
Dummy profile of energy into (+) or out of (-) the battery |
Renewables energy supplied (kWh
) |
Total renewable energy generation supplied to the system |
Hourly storage (kWh) |
Total energy currently stored in the battery |
Dumped energy (kWh) |
Energy dumped due to overgeneration when storage is full |
Battery health |
Measure of the relative health of the battery |
Households |
Number of households currently in the community |
Kerosene lamps |
Number of kerosene lamps used |
Kerosene mitigation |
Number of kerosene lamps mitigated through power availability |
The majority of these variables describe the energy flows within the system, the sources that they come from and the amount of load energy that is being met. Others describe a binary characteristic of whether or not an hour experiences a blackout (defined as any shortfall in service availability during that hour) or if a diesel generator is being used, and others (such as the number of households, kerosene usage and mitigation, and storage profile) are used either in the computation of this function or later functions that rely on this output.
Let’s now take a look at the other output of
Energy_System().simulation(...)
, which we will define as a new
variable called example_system_description
:
example_simulation_description = example_simulation[1]
example_simulation_description.head()
| Start year | End year | Initial PV size | Initial storage size | Final PV size | Final storage size | Diesel capacity | |
|---|---|---|---|---|---|---|---|
| System details | 0.0 | 1.0 | 5.0 | 20.0 | 4.95 | 19.229097 | 4 |
This variable provides details of the system that was simulated,
including several of the input variables such as the time period being
investigated and the solar and storage capacities we used. It also
describes three new variables: Final PV size
and
Final storage size
describe the relative capacities of the solar and
battery components at the end of the simulation period after accounting
for degradation, and Diesel capacity
is the minimum diesel generator
capacity (in kW) necessary to supply power as a backup system.
The outputs of this variable are primarily used as inputs for later functions, particularly those that deal with optimisation as it is necessary to know the status of an earlier system when considering periodic improvements over time.
Saving simulation results and opening saved files¶
Saving simulation outputs as variables allows us to explore them in more detail but, once the session is closed, these variables are deleted and the data is lost - meaning that the same simulation would need to be performed again in order to investigate the same scenario. As the simulation function relies on data previously stored elsewhere, as long as the input conditions are unchanged then the same result will be generated, but this is not convenient in the long term.
CLOVER provides a function to save the output of simulations as CSV
files, storing the data much more conveniently. To save an output
(simulation_name
) we need to have first stored it as a variable, and
choose a filename (filename
) to store it (note that the filename
variable in this function must be a string). In our case
simulation_name = example_simulation_performance
, and we choose
file_name = 'my_saved_simulation'
. To save the simulation results
we run the function:
Energy_System().save_simulation(simulation_name = example_simulation_performance, filename = 'my_saved_simulation')
This function creates a new CSV file in the Saved simulations folder
in the Simulation folder in your location folder titled
my_saved_simulation.csv
. If the filename
variable is left blank,
the title of the CSV will default to the time when the save operation
was performed. Be aware that running this function with a filename
that already exists will overwrite the existing file. Notice as well
that we used example_simulation_performance
as the variable to be
saved, rather than the two-component output example_simulation
:
performing this function with the latter will result in an error.
To open a saved file, we use the name of the CSV file to open the correct result, for example:
opened_simulation = Energy_System().open_simulation(filename = 'my_saved_simulation')
This will open the my_saved_simulation.csv
file and record the data
as a new variable, opened_simulation
, which will be in the same
format as the original saved variable
example_simulation_performance
.
Troubleshooting¶
Most of the Energy System functionality is contained within the
Energy_System().simulation(...)
function and so potential issues are
most likely to come either from how the module gathers data from other
parts of CLOVER:
- Ensure that the
self.location
variable is correct in all of the modules that Energy_System imports - Check that your
Scenario inputs
CSV is completed with the scenario you want to investigate, and any changes are saved in the CSV file before running another simulation - Ensure that you use the correct
filename
when saving and opening previous simulations - When running simulations, remember to save the output of
Energy_System().simulation(...)
as a variable
Extension and visualisation¶
Exploring the performance of the system¶
We can use the example_simulation_performance
variable to
investigate the performance of the system. Some variables make more
sense to look at their average over the simulation period:
example_simulation_performance_averages = example_simulation_performance[['Blackouts','Diesel times']].mean().round(3)
print(example_simulation_performance_averages)
Blackouts 0.100
Diesel times 0.104
dtype: float64
Here we can see that the average for Blackouts
is 0.100
meaning
that power is unavailable for 10% of the time, or equivalently the
system has power 90% of the time. We could have expected this from our
earlier condition in the Scenario inputs
CSV which set
Diesel backup threshold = 0.1
, forcing the diesel backup generator
to be used to provide this level of reliability. In this case the
average of Diesel times
is 0.104
, meaning that the generator is
switched on for 10.4% of the time in order to provide the desired level
of reliability.
Other variables make more sense to look at their sum, so here we look at their performance over the year but then presented as a daily average:
example_simulation_performance_sums = example_simulation_performance[[
'Total energy used (kWh)','Unmet energy (kWh)','Renewables energy used (kWh)','Storage energy supplied (kWh)',
'Grid energy (kWh)','Diesel energy (kWh)','Renewables energy supplied (kWh)','Dumped energy (kWh)'
]].sum()/365.0
print(example_simulation_performance_sums.round(3))
Total energy used (kWh) 30.465
Unmet energy (kWh) 0.909
Renewables energy used (kWh) 11.940
Storage energy supplied (kWh) 7.920
Grid energy (kWh) 7.239
Diesel energy (kWh) 3.366
Renewables energy supplied (kWh) 22.656
Dumped energy (kWh) 1.468
dtype: float64
These values show the average daily energy supply and usage in the system. Here we see that 30.5 kWh per day are consumed by the community, with a further 0.9 kWh going unmet on average. The supply is composed of renewable energy from our solar capacity directly (11.9 kWh) and from the battery storage (7.9 kWh), with the grid (7.2 kWh) and the backup diesel generator (3.4 kWh) also supplying energy. Our solar capacity generates an average of 45.3 kWh per day: 13.1 kWh is used directly, then the rest is stored in the batteries, an average of 1.5 kWh per day is dumped when the batteries are already full, and the remainder is lost owing to the transmission and conversion efficiencies in the system.
Adding up the renewables energy used, storage energy, grid energy and diesel energy gives us the total energy used, and when we also add the unmet energy this gives us the amount of energy required to meet the load demanded by the community. This combined value is slightly higher than the value for load energy from the Load module because the former accounts for the losses in the system needed to entirely satisfy the latter.
Electricity usage on an average day¶
We can use these outputs to visualise the energy flows in the system on an average day:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
total_used = np.mean(np.reshape(example_simulation_performance['Total energy used (kWh)'].values,(365,24)),axis=0)
renewable_energy = np.mean(np.reshape(example_simulation_performance['Renewables energy used (kWh)'].values,(365,24)),axis=0)
storage_energy = np.mean(np.reshape(example_simulation_performance['Storage energy supplied (kWh)'].values,(365,24)),axis=0)
grid_energy = np.mean(np.reshape(example_simulation_performance['Grid energy (kWh)'].values,(365,24)),axis=0)
diesel_energy = np.mean(np.reshape(example_simulation_performance['Diesel energy (kWh)'].values,(365,24)),axis=0)
unmet_energy = np.mean(np.reshape(example_simulation_performance['Unmet energy (kWh)'].values,(365,24)),axis=0)
renewables_supplied = np.mean(np.reshape(example_simulation_performance['Renewables energy supplied (kWh)'].values,(365,24)),axis=0)
plt.plot(total_used, label = 'Total used')
plt.plot(renewable_energy, label = 'Solar used directly')
plt.plot(storage_energy, label = 'Storage')
plt.plot(grid_energy, label = 'Grid')
plt.plot(diesel_energy, label = 'Diesel')
plt.plot(unmet_energy, label = 'Unmet')
plt.plot(renewables_supplied, label = 'Solar generated')
plt.legend()
plt.xlim(0,23)
plt.ylim(0,5)
plt.xticks(range(0,24,1))
plt.yticks(range(0,6,1))
plt.xlabel('Hour of day')
plt.ylabel('Average energy (kWh per hour)')
plt.title('Energy supply and demand on an average day')
plt.show()
Here we can see that, on average, the solar generation in this system exceeds the demand during the middle of the day, resulting in the total energy used by the community being almost entirely satisfied by solar energy. In the evening, when the load demanded by the community increases and the solar generation decreases, the energy is instead supplied by a combination of battery storage, the grid network, and the diesel generator which continue to be used throughout the night.
It is important to note that the values shown here are for an “average” day and likely not reflective of any single day. Aside from the variations in solar generation and the load demanded, it is far more likely that in any given hour only one or two energy sources would be used at a time. By considering all of the days in the simulation we have artificially smoothed the data to present the averages.
Let’s instead look at the first day of data for the simulation period:
total_used = example_simulation_performance.iloc[0:24]['Total energy used (kWh)']
renewable_energy = example_simulation_performance.iloc[0:24]['Renewables energy used (kWh)']
storage_energy = example_simulation_performance.iloc[0:24]['Storage energy supplied (kWh)']
grid_energy = example_simulation_performance.iloc[0:24]['Grid energy (kWh)']
diesel_energy = example_simulation_performance.iloc[0:24]['Diesel energy (kWh)']
unmet_energy = example_simulation_performance.iloc[0:24]['Unmet energy (kWh)']
renewables_supplied = example_simulation_performance.iloc[0:24]['Renewables energy supplied (kWh)']
plt.plot(total_used, label = 'Total used')
plt.plot(renewable_energy, label = 'Solar used directly')
plt.plot(storage_energy, label = 'Storage')
plt.plot(grid_energy, label = 'Grid')
plt.plot(diesel_energy, label = 'Diesel')
plt.plot(unmet_energy, label = 'Unmet')
plt.plot(renewables_supplied, label = 'Solar generated')
plt.legend()
plt.xlim(0,23)
plt.ylim(0,5)
plt.xticks(range(0,24,1))
plt.yticks(range(0,6,1))
plt.xlabel('Hour of day')
plt.ylabel('Energy (kWh per hour)')
plt.title('Energy supply and demand on a specific day')
plt.show()
As we can see, the data is much spikier as it displays the variation between consecutive hours, rather than smoother averages. We can see how once again solar meets most of the demand during the day but during the evening and night the energy is supplied by either battery storage or, if available, the national grid - whose sporadic availability results in a seemingly peaked supply profile.
Electricity availability¶
We can also use the outputs of example_simulation_performance
to
investigate the availability of different electricity services and the
times at which different energy sources are used, including the overall
measure of service availability recorded in the Blackouts
variable.
Let’s once again consider an “average” day to visualise the availability:
blackouts = np.mean(np.reshape(example_simulation_performance['Blackouts'].values,(365,24)),axis=0)
solar_usage = np.mean(np.reshape(example_simulation_performance['Renewables energy used (kWh)'].values>0,(365,24)),axis=0)
diesel_times = np.mean(np.reshape(example_simulation_performance['Diesel times'].values,(365,24)),axis=0)
grid_usage = np.mean(np.reshape(example_simulation_performance['Grid energy (kWh)'].values>0,(365,24)),axis=0)
storage_usage = np.mean(np.reshape(example_simulation_performance['Storage energy supplied (kWh)'].values>0,(365,24)),axis=0)
plt.plot(blackouts, label = 'Blackouts')
plt.plot(solar_usage, label = 'Solar')
plt.plot(storage_usage, label = 'Storage')
plt.plot(grid_usage, label = 'Grid')
plt.plot(diesel_times, label = 'Diesel')
plt.legend()
plt.xlim(0,23)
plt.ylim(0,1)
plt.xticks(range(0,24,1))
plt.yticks(np.arange(0,1.1,0.25))
plt.xlabel('Hour of day')
plt.ylabel('Probability')
plt.title('Energy availability on an average day')
plt.show()
Here we can see that the blackout periods are not consistent throughout the day: although the average is 10% of the time they are much more frequent in the early morning, likely because the battery storage is depleted and the sun has not yet risen. As expected solar energy is always available (at least somewhat) during the day and never at night. Battery storage is used most of the time in the evening and more rarely throughout the night, when grid power is more commonly used. The diesel generator is also sometimes used during the evening and early hours of the morning, but rarely throughout the night.
Visualising seasonality¶
CLOVER allows us to investigate both the magnitude and timings of electricity supply and demand in the system at several different timescales. Given that the demand profiles and resource availability change throughout the year, it can be useful to visualise the variation at an annual timescale to identify any seasonal variation:
import seaborn as sns
total_used = np.reshape(example_simulation_performance['Total energy used (kWh)'].values,(365,24))
renewable_energy = np.reshape(example_simulation_performance['Renewables energy used (kWh)'].values,(365,24))
storage_energy = np.reshape(example_simulation_performance['Storage energy supplied (kWh)'].values,(365,24))
grid_energy = np.reshape(example_simulation_performance['Grid energy (kWh)'].values,(365,24))
diesel_energy = np.reshape(example_simulation_performance['Diesel energy (kWh)'].values,(365,24))
unmet_energy = np.reshape(example_simulation_performance['Unmet energy (kWh)'].values,(365,24))
renewables_supplied = np.reshape(example_simulation_performance['Renewables energy supplied (kWh)'].values,(365,24))
fig,([ax1,ax2],[ax3,ax4]) = plt.subplots(2,2)#,sharex=True, sharey=True)
g1 = sns.heatmap(renewable_energy,
vmin = 0.0, vmax = 4.0,
cmap = 'Reds', cbar=True, ax = ax1)
ax1.set(xticks = range(0,25,6), xticklabels = range(0,25,6),
yticks = range(0,365,60), yticklabels = range(0,365,60),
xlabel = 'Hour of day', ylabel = 'Day of year',
title = 'Solar')
g2 = sns.heatmap(storage_energy,
vmin = 0.0, vmax = 4.0,
cmap = 'Greens', cbar=True, ax = ax2)
ax2.set(xticks = range(0,25,6), xticklabels = range(0,25,6),
yticks = range(0,365,60), yticklabels = range(0,365,60),
xlabel = 'Hour of day', ylabel = 'Day of year',
title = 'Storage')
g3 = sns.heatmap(grid_energy,
vmin = 0.0, vmax = 4.0,
cmap = 'Blues', cbar=True, ax = ax3)
ax3.set(xticks = range(0,25,6), xticklabels = range(0,25,6),
yticks = range(0,365,60), yticklabels = range(0,365,60),
xlabel = 'Hour of day', ylabel = 'Day of year',
title = 'Grid')
g4 = sns.heatmap(diesel_energy,
vmin = 0.0, vmax = 4.0,
cmap = 'Greys', cbar=True, ax = ax4)
ax4.set(xticks = range(0,25,6), xticklabels = range(0,25,6),
yticks = range(0,365,60), yticklabels = range(0,365,60),
xlabel = 'Hour of day', ylabel = 'Day of year',
title = 'Diesel')
plt.tight_layout()
fig.suptitle('Electricity from different sources (kWh)')
fig.subplots_adjust(top=0.87)
plt.xticks(rotation = 0)
plt.show()
From this we can see that, as expected, solar energy provides most of the energy during the daytime but has periods of reduced supply in the third quarter of the year. Battery storage provides electricity mainly during the evening just after the sun goes down, with the time of sunset visibly later in the day during the middle of the year, whilst the grid provides power both during the evening and early hours of the morning. The diesel generator has a more seasonally varying profile: it is used less often in the summer months, when solar generation is higher and lasts for longer during the day, pushing back the times when storage is required and reducing the need for diesel generation.


This is a caramel cake £14 Description of caramel cake.
This is a birthday cake £30 Description of a birthday cake.
YUMMY £££ CAKE


Create a React component using ES2015 class syntax
Describe when it’s appropriate to use a class component
Initialize and update state within a class component
Provide default values for a class component’s props
Add event listeners to elements
Prevent event default behavior
Safely use the this
keyword within event handlers
Describe what the React SyntheticEvent object is and the role it plays in handling events
Create a React class component containing a simple form
Define a single event handler method to handle onChange events for multiple elements
Implement form validations
Describe the lifecycle of a React component
Recall that the commonly used component lifecycle methods include componentDidMount, componentDidUpdate, and componentWillUnmount
Use the componentDidMount component lifecycle method to fetch data from an API
this
keyword
.call()
or .apply()
: We explicitly set the context and give the functions arguments at the same time..bind()
we can explicitly set the context of a function.event.target
event.currentTarget
event.preventDefault();


(A) Use this section for setting a Token and getting a Project ID
1. Insert a Token
You can get this token in My Profile Settings > Apps > Manage > PERSONAL ACCESS TOKENS
2. Select a Workspace
Choose the workspace you want to display projects from
3. Select a Project
Select the project you want to display the chart for (only active projects)
(B) Use this section for displaying the graph
1. Enter Start and End date
The Scrum plot shall be drawn based on this values (in safari enter in format 2017-03-01)
2. Enter Project ID
Get this ID directly or use the workflow on the left side


--- layout: post title: Networking Basics date: 2018-02-01 15:34:57.000000000 +05:30 type: post parent_id: '0' published: true password: '' status: publish categories: [] tags: [] authors: - vik-y ---
We had a session on basics of networking. This post has links and materials which you might want to refer to after the session.
What is Internet?
Protocols - how do they work in reality?
Common networking terms:
What happens when you type google.com?
What is NAT?
What is a proxy server?
Network debugging tools and how they are used?
Converting your linux system to a router and what you can do with it.
Explain:
SSH Tunnel and socks proxy
Network scanning tools


Logic Programming
Imperative/functional programming
Program = Algorithm + Data Structures
Execute
Logic programming
Program = Facts + Rules
Query
Example
Collection of Facts
- Carnitas is Mexican
isMexican(carnitas).
Collection of Rules
- All Mexican food is delicious
isDelicious(X) :- isMexican(X).
Query
- Hey Prolog! What is a delicious food ?
?- isDelicious(Y)
Answer
- Carnitas!
You don’t “run” a Prolog program, you ask it questions!
Why Prolog?
Prolog History
1970s: developed for Artificial Intelligence
- original vision “expert systems”
Out came the whole field of declarative programming:
Specify what you want
Not how to obtain result
Ideal for searching large space of results
Declarative Programming: Example
Flight search: Orbitz / Expedia / etc.
Collection of Facts
- Airports, Flights, Times, Durations, Costs
Collection of Rules
- If travel from
A
toB
with price (P1
) ANDB
toC
with price (P2
) - then travel from
A
toC
with price (P1 + P2
)
Queries
- What is cheapest flight from SAN to JFK with duration < 6 Hrs ?
Declarative Programming: Applications
Used heavily in many domains (together with statistical methods)
Scheduling
- travel, sports, …
Rule-based Anomaly detection
- Credit card fraud
SQL (and similar DB Query Languages)
Many of these are inspired-by or are subsets of Prolog
Why Prolog?
Most importantly:
yet another new way to think about programming!
(Remember the goal of this class: open your mind)
Plan
Language
- Terms
- Facts
- Queries
- implementation: unification
- Rules
- Programs
- implementation: backtracking search
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Language: Terms
Prolog Program
- Facts
- Rules
- Queries
… about what ? Terms!
Syntax of Prolog terms:
::= n -- number: 1, 92, 4.4
t | a -- atom
| X -- variable
| a (t1, t2, ..) -- compound term
where
a
is an identifier that starts with a lower-case letterX
is an identifier that starts with an upper-case letter
Prolog Terms: Atoms
Atom: any identifier starting with lower-case
Examples: x
, alice
, taco
, giraffe
, appleSauce
Prolog knows NOTHING about the atoms, except that:
- Each atom is equal to itself
alice = alice
taco = taco
- Each atem is disequal to every other atom
alice = taco
never holds
You can think of atoms as constructors of a single mega enum type:
data Atom = x | alice | taco | giraffe | appleSauce | ...
- except that in Haskell, constructors start with upper case :(
Prolog Terms: Variables
Variable: any identifier starting with upper-case
Examples:
X
,Y
,Z
,Head
,Tail
,Taco
,Burrito
,Alice
,Bob
_
is the wildcard variable, similar to Haskell
A variable stands for (and can be substituted with) any term:
alice = taco
never holds- but
X = taco
holds is we replace[X = taco]
- what about
Alice = taco
?
Prolog Terms: Compound Terms
Compound terms are of the form
a (t1, t2, t3, ..)
where
a
is a lower-case string (a function symbol)- each
ti
is a term (an argument to the function symbol)
Examples:
, z) % y, z are atoms
x(y, bob) % alice, bob are atoms
parent(alice, Child) % alice is an atom, Child is a variable parent(alice
You can think of compound terms as trees:
They are not function calls!
Prolog terms: Haskell representation
If we were implementing a Prolog interpreter in Haskell, we would represent terms like so:
data Term
= Num Int
| Atom LId
| Var UId
| Compound LId [Term]
type LId = String -- lower-case
type UId = String -- upper-case
QUIZ
data Term
= Num Int
| Atom LId
| Var UId
| Compound LId [Term]
What Haskell value of type Term
represents Prolog term
parent(alice, Bob)
?
A. parent ("alice", "Bob")
B. parent (Atom "alice") (Var "Bob")
C. [Atom "parent", Atom "alice", Var "Bob"]
D. Compound "parent" [Atom "alice", Var "Bob"]
E. Compound (Atom "parent") [Atom "alice", Var "Bob"]
QUIZ
data Term
= Num Int
| Atom LId
| Var UId
| Compound LId [Term]
What Haskell value of type Term
represents Prolog term
factorial(5)
?
A. factorial(5)
B. factorial(Atom 5)
C. 120
D. Num 120
E. Compound "factorial" [Num 5]
Prolog Terms
Prolog term factorial(5)
is simply the tree
Prolog has no idea what factorial
is (it’s just a name)
Plan
Language
Terms- Facts
- Queries
- Rules
- Programs
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Language: Facts
A fact is a “boolean” term (typically without variables) followed by .
Examples:
The following facts specify a list of parent-child relationships:
, holly).
parent(kim, kim).
parent(margaret, margaret).
parent(herbert, kim).
parent(john, john).
parent(felix, felix).
parent(albert, dana).
parent(albert, maya). parent(felix
albert| |
herbert felix dana| | |
margaret john maya| |
kim|
holly
Here:
kim
,holly
,margaret
etc. are all atomsparent
is a predicate (i.e. a boolean function symbol)- … of arity 2 (i.e. takes two arguments)
Predicates have no meaning to Prolog, but the programmer mentally notes that:
parent(kim, holly)
meanskim
is a “parent-of”holly
parent(margaret, kim)
meansmargaret
is a “parent-of”kim
- etc.
Database of facts
Prolog maintains a database (collection) of facts
Suppose we have a collection of facts saved in intro.pl
You can load the facts into the Prolog interpreter
?- consult('intro.pl').
true.
… or you can add them one-at-a-time
?- assert(parent(margaret, kim)).
Once facts are loaded, you query Prolog
- “Hey Prolog! Is this new fact in your Database … or can it be inferred from your database?”
Plan
Language
TermsFacts- Queries (Implementation: Unification)
- Rules
- Programs (Implementation: Backtracking Search)
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Language: Query
A query is a boolean term (possibly with variables), which we type into a prompt
Example 1:
?- parent(margaret, kim).
Prolog replies:
true.
- As this was indeed one of the facts loaded in intro
Example 2:
?- parent(margaret, john).
What does Prolog reply? Why?
The meaning of the query is “Is this fact provable”?
So the answer is: “No”
Pfft. Big deal? Is Prolog just a table lookup?!
Queries With Variables
What should Prolog reply to this query?
?- parent(margaret, X).
Meaning:
“Hey Prolog, for which value(s) of X
is the fact provable”?
Prolog replies:
X = kim.
- Because it can plug-in
kim
forX
, - and then can infer
parent(margaret, kim)
from the facts
More examples
Example 3:
?- parent(X, kim).
Meaning: ???
Prolog replies: ???
Example 4:
?- parent(X, Y).
Meaning: ???
Prolog replies: ???
QUIZ
How do we ask Prolog the following query:
Does there exist any person who is their own parent ?
A. parent(kim, kim)
B. parent(x, x)
C. parent(X, X)
D. parent(X, Y)
E. parent(Y, X)
More examples
Example 4:
How do we ask Prolog:
Does there exist any person who has more than one child?
Queries work like magic
In Java/C#/Haskell you would need
- Some
parentOf
orchildOf
data structure / methods- to represent parent-child relationship
- Some looping or iteration
- to search through all pairs
- Instead, Prolog uses facts and queries
- to search forwards and backwards
- to enumerate all results
- in a single uniform declarative manner!
How?
Magic = Unification + Backtracking Search
Plan
Language
TermsFacts- Queries
- implementation: unification
- Rules
- Programs
- implementation: backtracking search
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Unification
When does one term match (= unify with) another?
A term unifies with another term when we can substitute values for their variables to make them identical
Unification is the computational heart of Prolog
When you write
?- term1 = term2.
you are asking whether term1
can be unified with term2
.
Unification By Example
?- kim = kim.
true.
% atom is identical to itself!
?- kim = holly.
false.
% different atoms are never identical
?- foo(kim) = foo(kim).
true.
% compound term: recursively unify subtrees
?- foo(kim) = foo(holly).
???
?- X = kim.
X = kim.
% X can be made identical to kim if we substitute [X = kim]
?- X = foo(kim).
???
?- foo(X) = foo(kim).
???
?- X = Y.
???
QUIZ
How does Prolog respond to the following query?
?- p(X, dog) = p(cat, Y).
A. false
B. X = cat, Y = cat.
C. X = dog, Y = dog.
D. X = dog, Y = cat.
E. X = cat, Y = dog.
QUIZ
How does Prolog respond to the following query?
?- p(X, dog, X) = p(cat, Y, Y).
A. false
B. X = cat, Y = cat.
C. X = dog, Y = dog.
D. X = dog, Y = cat.
E. X = cat, Y = dog.
Unification step-by-step
Let’s see how Prolog reasons about this query:
?- p(X, dog, X) = p(cat, Y, Y).
Two compound terms: function symbols match, so recursively unify arguments…
To unify X
and cat
, extend the current substitution with X = cat
…
Apply substitution [X = cat]
to both terms. Move on to next leaf…
To unify dog
and Y
, extend the current substitution with Y = dog
…
… and apply this substitution throughout both terms.
Uh oh! Now we have different atoms in the last leaf! Unification fails.
Unification in Prolog vs Nano?
It’s the same thing, except!
| Unification in Nano | Unification in Prolog |
|---|---|
| on two types | on two terms |
| is a pain to implement | is built-in |
So, if we implemented Nano type inference in Prolog instead of Haskell,
we wouldn’t have to implement unify
, we could just use =
!
?- int = int.
true.
?- int = bool.
false.
?- funT(int,A) = funT(B,bool).
A = bool, B = int.
?- A = funT(A,A).
???
Unification for answering queries
What happens when we ask
?- parent(margaret, X).
Prolog goes through the list of facts in its database
For each fact, checking if it can be unified with the query
If unification fails it moves on to the next fact
If unification succeeds it returns the unifier (the unifying substitution)
- if the unifier is empty, it just replies
true
- if the unifier is empty, it just replies
If unification fails for each fact, it relies
false
More examples
?- parent(X, kim).
This query has multiple solutions!
- Once the first solution is found, we can ask Prolog to keep going through the facts
?- parent(X, Y).
Plan
Language
TermsFactsQueries- implementation: unification
- Rules
- Programs
- implementation: backtracking search
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Complex queries
How do we determine if margaret
is the grandparent of holly
?
We use a conjunction (comma-separated sequence of terms):
?- parent(margaret, X), parent(X, holly).
Is there a person X
who is a child of margaret
AND a parent of holly
?
Note: how we link the terms with the same variable to capture relationships.
How do we determine who is the great-grandparent of holly
?
?- parent(GGP, GP), parent(GP,P), parent(P, holly).
QUIZ
Which of these queries returns all pairs X
, Y
of (half-) siblings?
A. parent(X, Y), X \= Y.
B. parent(X, Z), parent(Z, Y), X \= Y.
C. parent(X, Z), parent(Y, Z), X \= Y.
D. parent(Z, X), parent(Z, Y), X \= Y.
Complex queries
?- parent(GGP, GP), parent(GP,P), parent(P, holly).
This is getting a tad repetitive!
What do we do in other languages to avoid repeating ourselves?
Abstract things into functions!
In Prolog, they are called rules
Rules
Rules let us build complex predicates from queries
Syntax:
:- t1, t1, t2,... t
t
is called the head of the rulet1, t2, t3,...
is called the body of the rule- all
t, t1, t2, t3,...
are predicate applications
Intuition:
To prove the head t
, you must prove all sub-goals t1
AND t2
AND t3
…
Example:
We can build a new (complex) predicate grandparent
from parent
predicates:
GP, GC) :- parent(GP, P), parent(P, GC). grandparent(
GP
is a grandparent of GC
if GP
is a parent of P
and P
is a parent of GC
Now we can use the new predicate in a query:
?- grandparent(X, kim). % who are the grandparents of kim
X = herbert ; % hit ; to see next
X = felix ; % hit ; to see next
false. % thats it!
Why? Because Prolog can prove the sub-goals:
?- parent(herbert, P), parent(P, kim). % Solution 1. X = herbert
P = margaret.
?- parent(felix, P), parent(P, kim). % Solution 2. X = felix
P = john .
QUIZ
Which of the following is a valid greatgrandparent
predicate?
A. greatgrandparent(X, Y) :- parent(X, Y), grandparent(X, Y).
B. greatgrandparent(X, Y) :- parent(X, Z), grandparent(Z, Y).
C. greatgrandparent(X, Y) :- grandparent(X, Z), parent(Z, Y).
D. greatgrandparent(X, Y) :- parent(X, Z), parent(Z, Y).
E. greatgrandparent(X, Y) :- parent(X, Z1), parent(Z1, Z2), parent(Z2, Y).
Rules: complex predicates from queries
GGP, GC) :- parent(GGP, GP), grandparent(GP, GC). greatgrandparent(
That was your first Prolog program!
Let’s take it out for a spin!
?- greatgrandparent(X, holly).
X = herbert ;
X = felix ;
false.
Plan
Language
TermsFactsQueriesimplementation: unification
Rules- Programs
- implementation: backtracking search
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Prolog Programs
A program is a collection of facts and rules
Facts and Rules are two kinds of clauses:
Fact: clause without any conditions
Rule: clause with conditions
- used to derive new facts
Program structure
How do combine multiple rules into a program?
Scope
Disjunction
Recursion
Scope
In the grandparent
rule, the variable GP
appears twice:
GGP, GC) :- parent(GGP, GP), grandparent(GP, GC). greatgrandparent(
Is it the same GP
?
Below we use X
in both rules:
X) :- isMexican(X).
isDelicious(X) :- isVegan(X). isVegetarian(
Is is the same X
?
In Prolog, the scope of a variable is the single rule where it appears.
There is no connection between variables across rules.
Program structure
How do combine multiple rules into a program?
 % Second rule fires for holly
?- has_family(sansa).
false. % Neither rule fires for sansa
Complex Predicates: Disjunction
X) :- parent(X, _). % if X is the parent of some _
has_family(X) :- parent(_, X). % if X is the child of some _ has_family(
Can be abbreviated to
X) :- parent(X, _) ; parent(_, X). has_family(
Semicolon ;
indicates disjunction.
Program structure
How do combine multiple rules into a program?
Scope
Disjunction
Recursion
Recursion
Lets write a predicate ancestor(A, X)
which is true if
parent(A, X)
… orparent(A, P)
andparent(P, X)
… orparent(A, GP)
andparent(GP, P)
andparent(P, X)
… or… if some chain of parent-links holds between
A
andX
.
A
is an ancestor of X
if:
Base case:
A
is a parent ofX
ancestor(A, X) :- parent(A, X).
Inductive case:
A
is an ancestor ofX
’s parentancestor(A, X) :- parent(P, X), ancestor(A, P).
To sum up:
A, X) :- parent(A, X).
ancestor(A, X) :- parent(P, X), ancestor(A, P). ancestor(
What can we do with this predicate?
We can find descendants (forwards)
?- ancestor(kim, X).
X = holly.
We can find ancestors (backwards)
?- ancestor(X,kim).
X = margaret ;
X = john ;
X = herbert ;
X = felix ;
X = albert .
Pretty neat: search forward or back, in just two lines!
- Try doing that in any other language!
Plan
Language
TermsFactsQueriesimplementation: unification
Rules- Programs
- implementation: backtracking search
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Backtracking Search
How does Prolog answer recursive queries?
- Brute force backtracking search
View each clause as a proof rule:
:- subgoal_1, subgoal_2, ...
goal :- subgoal_3, subgoal_4, ...
goal ...
To prove goal
, try to:
- Prove
subgoal_1
and then provesubgoal_2
etc, or, failing that, - Prove
subgoal_3
and then provesubgoal_4
, etc, or, failing that…
Example:
A,X) :- parent(A,X).
ancestor(A,X) :- parent(P,X), ancestor(A,P). ancestor(
To prove ancestor(A,X)
, try to:
- Prove
parent(A,X)
, or, failing that, - Prove
parent(P,X)
, and then proveancestor(A,P)
.
Suppose we ask it the query:
?- ancestor(felix,holly).
To prove this query, it undertakes the following backtracking search:
,holly)?
ancestor(felix/ \
,holly) parent(P0,holly)
parent(felixNO ancestor(felix,P0)
|
------------------
|P0=kim (by fact)
|
|,kim)
ancestor(felix/ \
,kim) parent(P1,kim)
parent(felixNO ancestor(felix,P1)
| |P1 = margaret | | P1 = john
| | ,margaret) ancestor(felix,john)
ancestor(felix/ \ |
,margaret) parent(P2,margaret) parent(felix,john)
parent(felixNO ancestor(felix,P2) YES
|P2 = herbert |
|, herbert)
ancestor(felix/ |
,herbert) parent(P3,herbert)
parent(felixNO NO
NOTE: Prolog introduces a fresh P
variable (P1, P2, P3...
)
every time the second rule for ancestor
is triggered
HINT: Trace mode in Prolog shows the search tree!
?- trace.
?- ancestor(felix,holly).
Queries with Variables
Backtracking Search is done for every query.
?- ancestor(X,kim).
- Prolog does the proof search
- Returns all unifiers for
X
for which the proof succeeds withYES
.
Order matters
Order of clauses & terms influences unification & backtracking.
For each
- goal different clauses are selected in order
- clause subgoals are solved (and unified!) from left-to-right
QUIZ
Which alternative definitions of ancestor
are correct?
% A
A,X) :- parent(P,X), ancestor(A,P).
ancestor(A,X) :- parent(A,X).
ancestor(
% B
A,X) :- parent(A,X).
ancestor(A,X) :- ancestor(A,P), parent(P,X).
ancestor(
% C
A,X) :- ancestor(A,P), parent(P,X).
ancestor(A,X) :- parent(A,X).
ancestor(
% D: All of the above
% E: None of the above
Bad orders
A bad order of sub-goals of in a recursive rule can cause non-termination
If we define:
A,X) :- ancestor(A,P), parent(P,X).
ancestor(A,X) :- parent(A,X). ancestor(
The following query doesn’t terminate:
?- ancestor(felix,holly).
Why? The search tree looks like this now!
,holly)?
ancestor(felix
|
|
|,P0) %prove first subgoal,
ancestor(felix%then parent(P,holly)
|
|
|,P1) %prove first subgoal,
ancestor(felix%then parent(P1,P0)
|
|
|,P2)
ancestor(felix.
.
.
To avoid infinite recursion:
Always place the base-case subgoal first in a recursive rule
Then unification with the base facts fixes the variable
P
Thereby guaranteeing termination
QUIZ
What is the best definition of sibling
?
- where
sibling(X, Y)
ifX
andY
share a parent.
% A
X, Y) :- parent(P, X), parent(P, Y).
sibling(
% B
X, Y) :- parent(P, X), parent(P, Y), not(X = Y).
sibling(
% C
X, Y) :- not(X = Y), parent(P, X), parent(P, Y). sibling(
Ordering and Unification
Remember: =
means unification!
So, X = Y
always holds:
?- X = Y.
X = Y
Hence, not(X=Y)
(which is the same as X \= Y
) always fails!
?- not(X = Y).
false.
So, if we define:
X, Y) :- not(X = Y), parent(P, X), parent(P, Y). sibling(
Then sibling(X,Y)
(with variables for inputs) always fails!
Solution
Always ensure the sub-goal not(X=Y)
fires after X
and Y
have been fully instantiated:
X, Y) :- parent(P, X), parent(P, Y), not(X = Y). sibling(
and now we get:
?- sibling(X,Y).
X = john
Y = maya ;
X = felix
Y = dana ;
X = dana
Y = felix ;
X = maya
Y = john ;
No
Plan
Language
Programming
- Numeric Computation
- Data Structures
- Puzzle Solving
Numeric Computation
Two big problems:
How do we even evaluate? e.g.
2 + 3
?How do we write functions? e.g.
add x y = x + y
Problem 1: How to Evaluate?
Everything is a term and =
is a unification operator:
?- X = 2 + 3.
X = 2 + 3
But to “compute” we need to be able to evaluate 2 + 3
to 5
!
Prolog has a magic operator called is
that evaluates its second argument:
?- X is 2 + 3.
X = 5.
To solve the goal t1 is t2
, Prolog:
- evaluates
t2
and then - unifies result with
t1
All variables in t2
must be instantiated before evaluation!
% Not good:
?- Y is X+2, X=1.
ERROR: Args are not sufficiently instantiated
% This is okay:
?- X=1, Y is X+2.
X=1
Y=3
Problem 2: How to Write Functions?
In Prolog we can define predicates using clauses (facts and rules)
Can we represent a function definition like
= x + y add x y
using predicates and clauses?
QUIZ
Which of the following represents add x y = x + y
?
% A
X, Y) :- Z is X + Y.
addP(
% B
X, Y, Z) :- Z is X + Y.
addP(
% C
X, Y, X + Y).
addP(
% D
X, Y) :- X + Y.
addP(
% E
X, Y, Z) :- X + Y is Z. addP(
Functions as Predicates
Every function of the form:
= Res foo x y
corresponds to a predicate of the form:
X, Y, Res). fooP(
i.e. a predicate that is True
for those triples (X, Y, Res)
s.t.
the function foo X Y
evaluated to Res
The predicate captures the input-output relation of the function.
Example: Fibonacci
Recall the definition of Fibonacci numbers in Haskell:
fib :: Int -> Int
0 = 1
fib 1 = 1
fib = fib (n - 1) + fib (n -2) fib n
Lets write a Prolog predicate capturing the IO relationship of fib
:
N, Res) fib(
holds only when Res
is the N-th
Fibonacci number.
When we are done, we can call the function with a query:
?- fib(0, Res).
Res = 1
?- fib(5, Res).
Res = 8
QUIZ
What is the correct Prolog implementation of factorial?

H = 1,
T = [2,3].
Feels a lot like Haskell pattern matching
- no wonder: pattern matching is unification!
Unlike Haskell, can mix ,
and |
:
?- [X,Y|T] = [1,2,3].
X = 1,
Y = 2,
T = [3].
Head and tail
We have to write them as predicates:
H|_],H).
headOf([
_|T],T). tailOf([
QUIZ
How do we write a predicate hasThreeOrMore
that satisfies the following test cases:
?-hasThreeOrMore([]).
false.
?-hasThreeOrMore([1,two]).
false.
?-hasThreeOrMore([1,two,dog]).
true.
?-hasThreeOrMore([1,two,dog,taco]).
true.
A. hasThreeOrMore([_|_]).
B. hasThreeOrMore([_,_|_]).
C. hasThreeOrMore([_,_,_|_]).
D. hasThreeOrMore([_,_,_,_|_]).
E. hasThreeOrMore([_,_,_]).
Recursive functions on lists
Example 1: isIn
Let’s write the Prolog equivalent of the following Haskell function:
isIn :: a -> [a] -> Bool
= False
isIn _ [] :ys) = x == y || isIn x ys isIn x (y
X,[X|_]).
isIn(X,[_|T]) :- isIn(X,T). isIn(
Example 2: sum
Let’s write the Prolog equivalent of the following Haskell function:
sum :: [Int] -> Int
sum [] = 0
sum (x:xs) = x + sum xs
,0).
sum([]H|T],R) :- sum(T,R1), R is R1 + H. sum([
Example 3: append
Let’s write the Prolog equivalent of the following Haskell function:
append :: [a] -> [a] -> [a]
= ys
append [] ys :xs) ys = x:(append xs ys) append (x
,Ys,Ys).
append([]H|T],Ys,[H|R]) :- append(T,Ys,R). append([
Unlike in Haskell, Prolog’s append is magical!
?- append(Xs,Ys,[1,2,3,4]).
Xs = [], Ys = [1,2,3,4] ;
Xs = [1], Ys = [2,3,4] ;
Xs = [1,2], Ys = [3,4] ;
Xs = [1,2,3], Ys = [4] ;
Xs = [1,2,3,4], Ys = [] .
Prolog has a built-in library of list functions, including append
, reverse
, etc
Plan
Language
Programming
Numeric ComputationData Structures- Puzzle Solving
Farmer, Wolf, Goat, Cabbage
Farmer needs to end up on the east bank of the river.
He has a little boat that can only carry him and one of the goods.
Goat can’t be left alone with the cabbage, wolf can’t be left alone with the goat.
Let’s ask Prolog to solve it for us!
We will encode the state of the game as a list with four positions:
P_Farmer,P_Wolf,P_Goat,P_Cab] [
Each position can take on one of the two atoms: east
or west
.
First, we define four legal moves that have the farmer at at most one good in the boat:
X,X,P_Goat,P_Cab], move_wolf, [Y,Y,P_Goat,P_Cab])
move([:- change(X,Y).
X,P_Wolf,X,P_Cab], move_goat, [Y,P_Wolf,Y,P_Cab])
move([:- change(X,Y).
X,P_Wolf,P_Goat,X], move_cabbage,[Y,P_Wolf,P_Goat,Y])
move([:- change(X,Y).
X,P_Wolf,P_Goat,P_Cab],move_nothing,[Y,P_Wolf,P_Goat,P_Cab])
move([:- change(X,Y).
,west).
change(east,east). change(west
Next, we define the safety condition:
P_Farmer,P_Wolf,P_Goat,P_Cab]) :-
safe([P_Farmer,P_Wolf,P_Goat),
one_equal(P_Farmer,P_Goat,P_Cab).
one_equal(
X,X,_).
one_equal(X,_,X). one_equal(
Finally, we define a solution as a sequence of legal moves that ends in the final state:
,[]).
solution([east,east,east,east]State,[FirstMove|RemainingMoves]) :-
solution(State,FirstMove,NextState),
move(NextState),
safe(NextState,RemainingMoves). solution(
Now we can ask Prolog to solve the puzzle like so:
?- length(Moves,7), solution([west,west,west,west],Moves).
Why do we need length(Moves,7)
?
Backtracking control
Sometimes we want more fine-grained control over the backtracking
For example:
?- length(Moves,7), solution([west,west,west,west],Moves).
gives us a gazillion solutions, most that all look the same (-ish?)
Stop backtracking
The cut operator !
is a goal that
- always succeeds
- cannot be back-tracked out of
We can use cut to tell Prolog: once you found a solution to the puzzle, look no further!
,[]).
solution([east,east,east,east]State,[FirstMove|RemainingMoves]) :-
solution(State,FirstMove,NextState),
move(NextState),
safe(NextState,RemainingMoves), !. solution(
Collect all solutions
Sometimes you want to localize the backtracking and collect all solutions in a list.
?- isIn(X,[2,1,3,2]).
X = 2.
X = 1.
X = 3.
X = 2.
Use bagof
to get the list of all solutions:
?- bagof(X, isIn(X,[2,1,3,2]), Sols).
Sols = [2,1,3,2].
Use setof
to get the list of all unique solutions:
?- setof(X, isIn(X,[2,1,3,2]), Sols).
Sols = [1,2,3].
How do we find all unique solutions to the farmer puzzle?
That’s all folks!


Nullatech is where science and technology converges. In order to represent massive financial data, we combine the expertise of our financial experts, data scientists and system analysts to provide a SaaS built on flexible and scalable machine learning algorithms to solve the most complicated problems in data analysis and machine intelligence.


Success
You will receive an email from us shortly with details on how to log in to the ${brand_name} Customer Portal.
Your login credentials are the username and password you selected during signup.
If you want to learn more about the ${brand_name} APIs then go to Technical Documentation.


dancer.js
JavaScript Audio Library
toggle FFT spectrum
view API/source
by
jordan santell
Now playing...
Zircon - Devil's Spirit
Loading . . .


Base
You could add .uix-nav--line
or .uix-nav--separation
to the .uix-nav
to change style of nav.
Alignment
Add .uix-t-c
or .uix-t-r
to the .uix-nav
to change them to center or right aligned.
Responsive Dropdown
Please reduce the screen to see the effect.


Licenses
We have set up a variety of licenses in order to maintain good relationship between we (Optimum Technology Roblox) and you (customers).
We have set up a variety of licenses in order to maintain good relationship between we (Optimum Technology Roblox) and you (customers).


Smoking is one of the worst things that one could do for her or his health.
This project is to raise an awareness for smoking by using the technique of double exposure.
homepage


"He who knows others is clever; He who knows himself has discernment"
Wendell Britt is once of the hosts of the Tone Podcast, freelance writer, and budding web developer. When not doing any of the above, he enjoys waatching TV and Movies, reading comics books, and consuiming Chinese Literature
Graduted in 2014 with a degree in Chinese Literature from Reed College. Worked for 3 years at the Apple store as a Customer Service Specialist and for 2.5 years at Airbnb in Portland. All the while, practicing and developing writing and podcast production skills


Products and Services
Animated-inflection will sell new and used musical instruments and accessories. Our primary items
will be new band and orchestral instruments, electric and acoustic guitars, amplifiers and
electronic keyboards. In addition we will have a full service, on-site repair and customization
department (band instruments, guitars and electronics).
We will offer a “state of the art” music lesson program featuring top degreed instructors, as
part of our overall focus on educating our customer base. This program will include private and
group lessons, as well as outreach to local schools. We will also develop music clubs geared to
children and seniors, to further serve our local community.
Although offering school band and orchestral instruments, service and lessons will be our main
competitive advantage, guitars will remain the primary revenue producer for musical instrument
stores for the foreseeable future.
Product and Service Description
- A large selection of band instruments by Selmer/Bach, Yamaha, and Leblanc with an emphasis on the intermediate level instruments.
- Electric and acoustic guitars including Albuquerque exclusive lines by Fernandez, Suzuki, Wechter and other nationally known brands, such as Takemine, Ovation and Martin.
- Amplifiers by Crate, Kustom, Traynor and Hiwatt to support our guitar sales.
- Keyboards by Yamaha, Suzuki and Korg.


Home
About us
Page
Shop
Blog
Contact us
<
>
AFFORDABLE PARIS TOURS
CITY TOURS / TOUR TICKETS / TOUR GUIDES
New collection
ADD TO CART
Blue tshirt
$26
ADD TO CART
Woman shirt
$31
ADD TO CART
Yellow tshirt
$21
ADD TO CART
Cool lingerie
$56


Ramazon Fluffy Plushie Store
This part of the site is under construction.
Please check again for more info at a later date.
Here is some music for your listening pleasure while you wait for construction to be finished. May take awhile so don't stick around too long.


{% load static %}
Please wait for other player
Send him this link to join: {{ game.get_absolute_url }}
You are {{ player }}.
{{game.message}}
or start a new game with somebody else.


Add Requirement
List Requirements
Search Requirements
Add Candidate
List Candidates
Search Candidates
Load Email
List Email
Search Email
List Email
Sl.No
To Address
From Address
Sent Date
Subject
Attachments
Delete
Delete


--- layout: default title: Contacts subtitle: Storage4Grid Contacts ---
For any enquiry about the Storage4Grid project, please contact the project coordinator:
SciengLab
E-mail: jiong.scieng@gmail.com


I'm a freelancer and contractor specializing in front-end applications built with Vue.js, living in Vancouver, BC.
I have experience with a variety of frontend frameworks, progressive web apps (PWA), server-side rendering (SSR), Node/Express back ends and linux devops.
I'm always looking for a new challenge. Please check out my projects page to see some of the projects I've worked on and read the recommendations on my LinkedIn profile.
If you think I might be a good fit for remote or local work in the Vancouver, BC area, please contact me.