Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulator with python #15

Merged
merged 6 commits into from
May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ requests==2.27.1
scipy==1.8.0
six==1.16.0
urllib3==1.26.9
python-dateutil==2.8.2
windows-curses==2.3.0 ; sys_platform == 'win32'
46 changes: 8 additions & 38 deletions src/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,17 @@

path_positions_txt = f"{PATH_POSITIONS_BASE}.txt"

def get_sun_positions():
def get_sun_positions(start_date, days_horizon=3, unpickle=True):
a = datetime.datetime.now()
start_date = datetime.datetime(2020, 1, 1)
path_positions_file_name = f"{PATH_POSITIONS_BASE}-{start_date.year}-{start_date.month}-{start_date.day}"
path_positions_file_name = f"{PATH_POSITIONS_BASE}-{start_date.year}-{start_date.month}-{start_date.day}-{days_horizon}"
path_positions = path_positions_file_name + ".dat"
if os.path.isfile(path_positions):
if unpickle and os.path.isfile(path_positions):
print("Reading from:", path_positions)
with open(path_positions, "rb") as handle:
pos = pickle.load(handle)
b = datetime.datetime.now()
else:
start = datetime.datetime(2020, 1, 1)
dti = pd.date_range(start, periods=30 * 8 * 24, freq="H")
else:
dti = pd.date_range(start_date, periods=days_horizon * 24, freq="H")

pos = pvlib.solarposition.get_solarposition(dti, sunrise_lib.LAT, sunrise_lib.LON)
b = datetime.datetime.now()
Expand Down Expand Up @@ -187,36 +185,6 @@ def print_relative(val, relative):
print("Overvolted = ", print_relative(self.num_overvolted, relative))
if self.num_overused > 0:
print("Overused = ", print_relative(self.num_overused, relative))

class BatterySimulatorCpp(BatterySimulator):
def iter_get_load(self, inp, out, hours=T_DELTA_HOURS):
discharge = hours * self.DISCHARGE_PER_HOUR
balance = inp - out - discharge
change = balance * MUL_POWER_2_CAPACITY
if change > MAX_USAGE:
#if out > MAX_USAGE: # A valid possibility
self.num_overused += 1
change = MAX_USAGE
#print(change)
self.load += change

if self.load > self.MAX_CAPACITY:
self.load = self.MAX_CAPACITY
self.num_overvolted += 1

if self.load < self.MIN_LOAD:
if self.initial_load:
self.num_undervolted_initial += 1
else:
self.num_undervolted += 1
if self.load < 0:
self.load = 0

if self.initial_load:
if self.load > self.MIN_LOAD:
self.initial_load = False

return self.get_load()

def get_usage_endor_example(available):
# TODO: use the available power wisely
Expand Down Expand Up @@ -330,7 +298,9 @@ def run_algo(elev, show_plots, algo):


def test(show_plots=False):
pos = get_sun_positions()
start_date = datetime.datetime(2020, 1, 1)
days_horizon = 30 * 9
pos = get_sun_positions(start_date, days_horizon)
#print(pos)

proc = proc_data(pos)
Expand Down
35 changes: 27 additions & 8 deletions src/opti-lib/src/OptiEnProfitSubject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "GnuplotIOSWrap.h"

#include <Ios/Ofstream.hpp>
#include <Math/GeneralMath.hpp>
#include <Util/CoutBuf.hpp>
#include <Util/ToolsMixed.hpp>
Expand All @@ -29,8 +30,8 @@ OptiSubjectEnProfit::~OptiSubjectEnProfit()

struct Computer
{
double cores = 1;
double wattPerCore = 10;
double cores = 2;
double wattPerCore = 11.5;
double hashPerCore = 250;
double scalingFactor = 0.85;
double GetHashRate(double freqGhz) const
Expand Down Expand Up @@ -100,7 +101,7 @@ double OptiSubjectEnProfit::GetVerbose(const double * inp, int n, bool verbose)
CorPtr<ISimulatorTS> psim = TSUtil().GetSimPred(m_period, fun->GetOptiVec(), m_startEndFrame);
*/
//LOG << n << Nl;
Computer comp;
Computer comp; /// TODO: This has to become an array of computers, configurable by the User.
BatterySimulation battery;
double sum = 0;
double penalitySum = 0;
Expand Down Expand Up @@ -186,7 +187,7 @@ double OptiSubjectEnProfit::GetVerbose(const double * inp, int n, bool verbose)
LOGL << ": New goal = " << sumAdjusted << ", m_sumMax = " << m_sumMax << ", penality = " << penality << ", after " << 0 << " iterations\n";

BatterySimulation batteryCopy;
VecD hashes, loads, penalityUnder, input, prod, hashrateBonus;
VecD hashes, loads, penalityUnder, input, prod, hashrateBonus, usages;
for (int i = 0; i < n; ++i)
{
/// TODO: Remove duplication
Expand All @@ -200,24 +201,30 @@ double OptiSubjectEnProfit::GetVerbose(const double * inp, int n, bool verbose)

const double load = batteryCopy.iter_get_load(m_dataModel.GetPowerProduction(i), usage);

usages.Add(usage);
input.Add(val);
loads.Add(load);
prod.Add(m_dataModel.GetPowerProduction(i));
hashes.Add(sum);
hashrateBonus.Add(HashrateBonus(i % 24));
}
m_usages = usages;
m_input = input;
m_loads = loads;
m_prod = prod;
m_hashes = hashes;
m_hashrateBonus = hashrateBonus;
//ToolsMixed().SystemCallWarn("clear", __PRETTY_FUNCTION__);
GnuplotPlotTerminal1d(hashes, "hashes", 1, 0.5);
GnuplotPlotTerminal1d(loads, "battery", 1, 0.5);
OutputVar(hashes, "hashrates");
OutputVar(loads, "battery");
OutputVar(usages, "usage", false);

//GnuplotPlotTerminal1d(input, "input", 1, 0.5);
GnuplotPlotTerminal1d(prod, "prod", 1, 0.5);
GnuplotPlotTerminal1d(hashrateBonus, "hashrateBonus", 1, 0.5);



}
}
}
Expand All @@ -226,6 +233,17 @@ double OptiSubjectEnProfit::GetVerbose(const double * inp, int n, bool verbose)
//return -sum;
}

void OptiSubjectEnProfit::OutputVar(const EnjoLib::VecD & data, const EnjoLib::Str & descr, bool plot) const
{
if (plot)
{

GnuplotPlotTerminal1d(data, descr, 1, 0.5);
}
Ofstream fout("/tmp/soloptout-" + descr + ".txt");
fout << data.Print() << Nl;
}

/*
void OptiSubjectEnProfit::UpdateOutput()
{
Expand Down Expand Up @@ -259,13 +277,14 @@ EnjoLib::Array<EnjoLib::OptiMultiSubject::Bounds> OptiSubjectEnProfit::GetBounds

double OptiSubjectEnProfit::HashrateBonus(int hour) const
{
/// TODO: This is meant to be dynamically read from tsqsim
if (hour > 10 && hour < 16)
{
return 0.90;
return 0.97;
}
else if (hour > 18)
{
return 1.10;
return 1.03;
}
else
{
Expand Down
3 changes: 2 additions & 1 deletion src/opti-lib/src/OptiEnProfitSubject.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ class OptiSubjectEnProfit : public EnjoLib::OptiMultiSubject // IOptiSubject

//STDFWD::vector<OptiVarF> GetOptiVarsResult() override { return m_optiFloatResult; }
void UpdateOutput();
EnjoLib::VecD m_hashes, m_loads, m_penalityUnder, m_input, m_prod, m_hashrateBonus;
EnjoLib::VecD m_hashes, m_loads, m_penalityUnder, m_input, m_prod, m_hashrateBonus, m_usages;

double HashrateBonus(int hour) const;
void OutputVar(const EnjoLib::VecD & data, const EnjoLib::Str & descr, bool plot = true) const;

protected:

Expand Down
5 changes: 3 additions & 2 deletions src/opti-lib/src/OptimizerEnProfit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ void OptimizerEnProfit::operator()()
int alreadyCombined = 0;
for (int i = 0; i < maxEl; ++i)
{
const int minHoursTogether = 2;
const int minHoursTogether = 3; /// TODO: This should be computer's parameter or user's tolerance
const int minHoursTogetherHalf = GMat().round(minHoursTogether/2.0);
bool cont = false;
const int index = GMat().round(rmath.Rand(0, horizonHours-0.999));
//binary[index] = binary[index] == 0 ? 1 : 0;
Expand All @@ -131,7 +132,7 @@ void OptimizerEnProfit::operator()()
hashStr[index] = bitC;
if (bit == 1)
{
for (int j = index - minHoursTogether; j <= index + minHoursTogether; ++j)
for (int j = index - minHoursTogetherHalf; j <= index + minHoursTogetherHalf; ++j)
{
if (j < 0 || j >= horizonHours)
{
Expand Down
88 changes: 88 additions & 0 deletions src/prod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# https://stackoverflow.com/a/11236372
# apt install gfortran libffi-dev
# pip3 install pvlib ephem pytz beautifulsoup4 cairosvg wget requests Pillow


import os
import datetime
import pandas as pd
import time
import traceback
import argparse
import pickle
import numpy as np
import dateutil

from pytz import timezone
from matplotlib import pyplot as plt

import sunrise_lib
import generator
import kraken
from profitability import POW_Coin

from python_json_config import ConfigBuilder

DATE_NOW_STR = sunrise_lib.DATE_NOW.isoformat()
DEFAULT_HORIZON_DAYS = 3

def get_args():
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--start-date', default=DATE_NOW_STR, type=str, help="Start date, ISO format (default: {})".format(DATE_NOW_STR))
parser.add_argument('-d', '--days-horizon', default=DEFAULT_HORIZON_DAYS, type=int, help="Horizon in days (default: {})".format(DEFAULT_HORIZON_DAYS))
#parser.add_argument('-v', '--verbose', default=TESTING, action='store_true', help="Test (default: OFF)")
return parser.parse_args()


class BatterySimulatorCpp(generator.BatterySimulator):
def __init(self):
pass

def run(self):
basePath = 'build/src/opti/opti' # TODO: Pass on days horizon
path = basePath
if not os.path.isfile(path):
path = '../' + path
result = sunrise_lib.run_cmd(path, True)
if result.returncode != 0:
raise RuntimeError("Failed to run opti")

basePathIn = "/tmp/soloptout-{}.txt"

self.hashrates = np.loadtxt(basePathIn.format('hashrates'))
self.loads = np.loadtxt(basePathIn.format('battery'))
self.usage = np.loadtxt(basePathIn.format('usage'))

def get_usage_prod(available):
bat_sim = BatterySimulatorCpp()
bat_sim.run()
hashrates = bat_sim.hashrates
loads = bat_sim.loads
usage = bat_sim.usage
incomes = [0]* len(available)
costs = [0]* len(available)
effs = [0]* len(available)

return "Production", hashrates, usage, loads, bat_sim, incomes, costs, effs

def run_main(elev, show_plots):
generator.run_algo(elev, show_plots, get_usage_prod)
generator.run_algo(elev, show_plots, generator.get_usage_simple)


def main(args):
start_date = dateutil.parser.parse(args.start_date)
pos = generator.get_sun_positions(start_date, args.days_horizon, unpickle=False)
#print(pos)
show_plots = True
proc = generator.proc_data(pos)
elev = generator.extr_data(proc)
print(elev)
run_main(elev, show_plots)

if __name__ == "__main__":
args = get_args()
main(args)
1 change: 1 addition & 0 deletions src/sunrise_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def read_file(fname):
return fin.read()

def run_cmd(cmd, print_result=False):
print("Running command:\n" + cmd)
result = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
if print_result:
print(result.returncode, result.stdout, result.stderr)
Expand Down
9 changes: 9 additions & 0 deletions util/ci-debian.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ GEN="CodeBlocks - Unix Makefiles"

#cd externals/tsqsim/
#./util/prep-env.sh
#./util/prep-env.sh
#./util/deps-pull.sh
#./util/deps-build.sh
#./ci-default
#cd ../..

#./util/deps-build.sh
#./ci-default
#cd ../..

python3 src/tests.py
# Now test unpickling:
python3 src/tests.py
Expand All @@ -23,3 +28,7 @@ export R_HOME=/usr/lib/R && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$R_HOME/lib
src/opti/opti --help
src/opti/opti --horizon-days 3 --start-day 30
src/opti/opti --help

echo "Testing the entire production chain:"
cd ..
python3 src/prod.py