from GJEMS.morph.swcTreeRep import *
from matplotlib import pyplot as plt
import os
import numpy as np
import shutil

plt.ion()
# part = '-DB'
part = '-VB'
FLDLimit = 0.95
AIlimit = 0.9

outDir = 'sim/Results/thickerBPs' + part

if os.path.isdir(outDir):
    shutil.rmtree(outDir)

os.mkdir(outDir)

fig1 = plt.figure()
plt.xlim([0, 300])
plt.ylim([0, 1])
plt.xlabel('Distance from common point(um)')
plt.ylabel('len Downstream / total len')
plt.title('Branching points with fracLenDownstream >' + str(FLDLimit) + 'and Assymetry Index <' + str(AIlimit))

# fig2 = plt.figure()
# plt.xlabel('Assymetry Index')
# plt.ylabel('Fraction of tips downstream')

flne = []
nlne = []

fRadii = []
nRadii = []

fEucLens = []
nEucLens = []

# ----------------------------------------------------------------------------------------------------------------------
foragerSWCPath = 'shapeBasedAlignment/Results/DL-Int1_v2_MultipleAlignment/'

foragerNrns = [
              'HB130313-4',
            'HB130322-1',
            # 'HB130326-2',
            'HB130408-1',
            'HB130425-1',
            'HB130501-2',
            # 'HB130705-1',
            'HB140424-1',
                ]
origin = [0, 0, 0]
fSWCFiles = [os.path.join(foragerSWCPath, x, x + part + '_aligned.swc') for x in foragerNrns]
fCols = plt.cm.spectral(np.linspace(0, 1, len(foragerNrns)))
# ----------------------------------------------------------------------------------------------------------------------

for swcInd, swc in enumerate(fSWCFiles):

    print('Doing ' + swc)
    swcTree = importSWC2Tree(swc)
    rootNode = swcTree[swcTree.root]
    initTerminalDegree(swcTree)
    initDownstreamLen(swcTree)
    # initBranchLengths(swcTree)
    # initPathLengths(swcTree)

    # plt.figure(fig2.number)
    # plt.cla()
    # plt.plot([0, 0.9], [0.75, 0.75], 'k:')
    # plt.plot([0.9, 0.9], [0.75, 1], 'k:')

    for node in swcTree.all_nodes():
        if len(node.fpointer) > 1:

            for childNde in node.fpointer:

                n1 = float(swcTree[childNde].data.downstreamLen)
                n2 = float(node.data.downstreamLen - n1)

                assymetryIndex = np.abs(n1 - n2) / (n1 + n2)
                xyzr = getxyzr(node)
                fracLenDownstream = node.data.downstreamLen / float(rootNode.data.downstreamLen)

                # plt.figure(fig2.number)
                # plt.plot(assymetryIndex, fracLenDownstream, 'bo', ms=5)

                if (assymetryIndex < AIlimit) and (fracLenDownstream > FLDLimit):

                    plt.figure(fig1.number)
                    fEL = np.linalg.norm(xyzr[:3])
                    lne, = plt.plot(fEL, fracLenDownstream, color=fCols[swcInd], marker='o', mfc=fCols[swcInd])
                    node.data.extraCol = 1
                    fRad = node.data.r

                # print([n1, n2, n1 + n2, assymetryIndex, fracTipsDownstream])

    flne.append(lne)
    fEucLens.append(fEL)
    fRadii.append(fRad)
    shutil.copyfile(swc, os.path.join(outDir, os.path.split(swc)[1]))
    exportTree2SWC(swcTree, os.path.join(outDir, os.path.split(swc)[1][:-4] + '_impBPs.sswc'), addExtraCol=True)

# ----------------------------------------------------------------------------------------------------------------------
newlyEmergedSWCPath = 'shapeBasedAlignment/Results/DL-Int1_v2_MultipleAlignment/'

newlyEmergedNrns = [
            'HB130523-3',
            'HB130605-1',
            # 'HB130605-2',
            'HB140813-3',
            'HB140917-1',
            'HB140930-1',
            'HB141030-1',
                    ]

origin = [0, 0, 0]

nSWCFiles = [os.path.join(newlyEmergedSWCPath, x, x + part + '_aligned.swc') for x in newlyEmergedNrns]
nCols = plt.cm.spectral(np.linspace(0, 1, len(newlyEmergedNrns)))
# ----------------------------------------------------------------------------------------------------------------------

for swcInd, swc in enumerate(nSWCFiles):

    print('Doing ' + swc)
    swcTree = importSWC2Tree(swc)
    rootNode = swcTree[swcTree.root]
    initTerminalDegree(swcTree)
    initDownstreamLen(swcTree)
    # initBranchLengths(swcTree)
    # initPathLengths(swcTree)

    #branching point features
    bpFeatures = {}

    # plt.figure(fig2.number)
    # plt.cla()
    # plt.plot([0, 0.75], [0.75, 0.75], 'k:')
    # plt.plot([0.75, 0.75], [0.75, 1], 'k:')

    for node in swcTree.all_nodes():
        if len(node.fpointer) > 1:

            for childNde in node.fpointer:

                n1 = float(swcTree[childNde].data.downstreamLen)
                n2 = float(node.data.downstreamLen - n1)

                assymetryIndex = np.abs(n1 - n2) / (n1 + n2)
                xyzr = getxyzr(node)
                fracLenDownstream = node.data.downstreamLen / float(rootNode.data.downstreamLen)

                # plt.figure(fig2.number)
                # plt.plot(assymetryIndex, fracLenDownstream, 'bo', ms=5)

                if (assymetryIndex < AIlimit) and (fracLenDownstream > FLDLimit):

                    plt.figure(fig1.number)
                    nEL = np.linalg.norm(xyzr[:3])
                    lne, = plt.plot(nEL, fracLenDownstream, color=nCols[swcInd], marker='s', mfc=nCols[swcInd])
                    node.data.extraCol = 1
                    nRad = node.data.r

                # print([n1, n2, n1 + n2, assymetryIndex, fracTipsDownstream])

    nlne.append(lne)
    nRadii.append(nRad)
    nEucLens.append(nEL)
    shutil.copyfile(swc, os.path.join(outDir, os.path.split(swc)[1]))
    exportTree2SWC(swcTree, os.path.join(outDir, os.path.split(swc)[1][:-4] + '_impBPs.sswc'), addExtraCol=True)

plt.figure(fig1.number)

plt.legend(flne + nlne, foragerNrns + newlyEmergedNrns)

fig3 = plt.figure()
# bins = np.arange(0, 3, 0.1)
# binCenters = bins[:-1] + 0.5 * (bins[1] - bins[0])
#
# hist, bins = np.histogram(fRadii, bins)
# plt.plot(binCenters, hist, 'b-o')
#
# hist, bins = np.histogram(nRadii, bins)
# plt.plot(binCenters, hist, 'r-s')
#
# plt.xlabel('Radius in um')
# plt.ylabel('Bin Count')
# plt.legend(['forager', 'newly emerged'])

plt.errorbar(0, np.mean(fRadii), np.std(fRadii), color='b', marker='o', mfc='b')
plt.errorbar(1, np.mean(nRadii), np.std(nRadii), color='r', marker='s', mfc='r')
plt.xticks([0, 1], ['forager', 'newly emerged'])
plt.xlim([-0.5, 1.5])

fig4 = plt.figure()
plt.plot(nEucLens, nRadii, 'rs', ms=5)
plt.plot(fEucLens, fRadii, 'bo', ms=5)


# exemplo com o classificadores CNN com Keras - sinal tratado como imagem
# Banco de dados de epilepsia

import scipy.io as sio
import numpy as np

from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

#Input
sinal_ = sio.loadmat('sinal')
sinal_ = sinal_.get('sinal', 0)
#cria uma matriz
sinal = np.zeros(shape = (sinal_.shape[0], 1, sinal_.shape[1], 1))
#preenche a matriz com os valores desejados
for k in range(0, sinal_.shape[0]):
    sinal[k, 0, :, 0] = sinal_[k, :]

quantidade_exemplos = sinal.shape[0]
quantidade_amostras = sinal.shape[2]

#Label
label_ = sio.loadmat('label')
label_ = label_.get('label', 0)
#cria uma matriz
label = np.zeros(shape = (label_.shape[0], ))
#preenche a matriz com os valores desejados
for k in range(0, label_.shape[0]):
    label[k] = label_[k, 0] - 1
label = label.astype(np.uint8)

from keras.utils import to_categorical
label= to_categorical(label, num_classes=None)

print(sinal.shape)
print(label.shape)

# Separa treinamento e validação
X_train, X_val, y_train, y_val = train_test_split(sinal,label, test_size=0.2)

# definir arquitetura da CNN com Keras

from keras import models
model = models.Sequential()
model.add(layers.Conv2D(10, (1, 5), activation='relu', input_shape=(1, quantidade_amostras, 1)))
model.add(layers.MaxPooling2D((1, 2)))
model.add(layers.Conv2D(10, (1, 5), activation='relu'))
model.add(layers.MaxPooling2D((1, 2)))
model.add(layers.Conv2D(10, (1, 5), activation='relu'))

model.add(layers.Flatten())
model.add(layers.Dense(10, activation='relu'))
model.add(layers.Dense(2, activation='softmax'))

model.summary()

model.compile(optimizer='rmsprop',
              loss='mse',
              metrics=['accuracy'])
model.fit(X_train,  y_train, epochs=50)

val_loss, val_acc = model.evaluate(X_val, y_val)


from celery import Celery
from pymongo import MongoClient
from bson.objectid import ObjectId
from bson import json_util
from python_json_config import ConfigBuilder
import json

config = ConfigBuilder().parse_config('../config.json')
HOST = config.server.host
PORT = config.server.port
DB = config.server.db

app = Celery('tasks', backend='redis://' + HOST+ ':' + PORT.celery +'/' + str(DB), broker='redis://' + HOST +':' + PORT.celery +'/' + str(DB))
conn = MongoClient(HOST+':'+PORT.mongo)
db = conn.sensor

@app.task
def set_sensor(data):
    app.send_task('tasks.set_key', args=[json.dumps(data)])
    _id  = db.device.insert(data)
    return str(_id)

@app.task
def set_key(data):
    data = json.loads(data)
    kList = [key for key in data]
    for i in kList:
        doc = { 'key':i , 'sensor':data }
        db.keys.insert(doc)

@app.task
def get_key(value):
    kList = []
    if(value == None):
        li = list(db.keys.find({},{ 'key':1 }))
        for i in li:
            kList.append(i['key'])
        kList = list(set(kList))
    else:
        li = list(db.keys.find({ 'key':value },{ 'sensor':1 }))
        for i in li:
            tmp = i['sensor']
            kList.append(tmp)
    return str(json.dumps(kList, default=json_util.default))

@app.task
def get_sensor(key, value):
    if(key == None):
        li = list(db.device.find({}))
    else:
        if(key == '_id'):
            value = ObjectId(value)
        li = list(db.device.find({ key:value }))
    print(f'탐색된 센서의 개수: {len(li)}')
    return str(json.dumps(li, default=json_util.default))

@app.task
def update_sensor(key, value, skey, svalue):
    db.device.update_sensor_one({ key:value },{'$set':{ skey: svalue }})
    result = db.device.find_one({ key:value })
    return json.dumps(result,default=json_util.default)

@app.task
def delete_sensor(key, value):
    if(key == None):
        db.device.drop()
        db.keys.drop()
    else:
        tmp = list(db.device.find({ key:value }, {'_id':0 }))
        for i in tmp:
            app.send_task('tasks.delete_key', args=[json.dumps(i)])
        result = db.device.remove({ key:value })

@app.task
def delete_key(data):
    data = json.loads(data)
    db.keys.remove({ 'sensor':data })


import hashlib
import json
import logging
import os
import sys
from datetime import datetime, timezone, timedelta

import requests

from marvel.utils import get_previous_byday

MARVEL = "https://gateway.marvel.com:443/v1/public"
MARVEL_PUBLIC_KEY = os.environ["MARVEL_PUBLIC_KEY"]
MARVEL_PRIVATE_KEY = os.environ["MARVEL_PRIVATE_KEY"]

class MarvelApi(object):
    def __init__(self):
        logging.basicConfig()
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)

    def hash(self, timestamp):
        """Authorisation as per:
           https://developer.marvel.com/documentation/authorization
        """
        key = "".join([timestamp,
                       MARVEL_PRIVATE_KEY,
                       MARVEL_PUBLIC_KEY])
        m = hashlib.md5()
        m.update(key.encode("utf-8"))
        return m.hexdigest()

    def _get(self, url, params):
        """Base API call; handles auth. methods.
        """
        ts = datetime.now(timezone.utc).isoformat()
        base = {"apikey": MARVEL_PUBLIC_KEY,
                "ts": ts,
                "hash": self.hash(ts)}
        params.update(base)
        r = requests.get(url, params=params)
        return json.loads(r.text)

    def _all(self, url, params):
        """Return all `results`.
        """
        results = []
        offset = 0
        total = 1
        while offset < total:
            params.update({"offset": offset})
            data = self._get(url, params)
            results += data["data"]["results"]
            count = data["data"]["count"]
            offset += count
            total = data["data"]["total"]
            self.logger.debug("Received {} of {} comics.".format(count, total))
        return results

    def comics(self, **kwargs):
        self.logger.debug("Finding comics...")
        url = "{}/comics".format(MARVEL)
        results = self._all(url, kwargs)
        return results

    def comic(self, comicId=None):
        self.logger.debug("Getting comic...")
        url = "{}/comics/{}".format(MARVEL, comicId)
        results = self._get(url, {})
        return results

    def series(self, **kwargs):
        """Return only issues in series whose title starts with the input.
        """
        self.logger.debug("Finding series...")
        url = "{}/series".format(MARVEL)
        results = self._all(url, kwargs)
        return results

    def last_wednesday(self, weeks=0):
        """All releases for the previous Wednesday.
        """
        wednesday = get_previous_byday("Wednesday",
                                       start_date=datetime.today() - timedelta(weeks=int(weeks)))
        self.logger.debug("Getting comics for Wednesday {}...".format(wednesday.date().isoformat()))
        date_range = [wednesday.date().isoformat()] * 2
        return self.comics(dateRange=",".join(date_range))

if __name__ == "__main__":
    m = MarvelApi()
    print("\n".join(sorted(["{}\t{}".format(c["title"],
                                            c["id"]) for c in m.last_wednesday(weeks=sys.argv[1] if len(sys.argv) > 1 else 0)])))


import gi
import json
import random
import threading
import time

gi.require_version("Gdk", "3.0")
gi.require_version("Gtk", "3.0")

from gi.repository import Gdk
from gi.repository import Gtk

# Display time in seconds (rough)
DISPLAY_TIME = 5
# Full path to the quotes dataset  https://www.kaggle.com/akmittal/quotes-dataset Download, unzip and refer to the location
#QUOTES_JSON_PATH = "/home/desktop-notifications/quotes.json"

CSS = b"""
#toplevel {
    background-color: rgba(0, 0, 0, 0.1);
}
#mybox {
    margin: 20px;
}
#main_content {
    color: white;
    font-size: 20px;
    font-weight:bold;
}
#other_content {
    color: white;
    font-size: 14px;
    font-style: italic;
}
"""

def load_quotes(quotes_json_path):
    with open(quotes_json_path) as f:
        return json.loads(f.read())

quotes = load_quotes('quotes.json')

#print(quotes[0])
#Output:
# {
#    'Quote': "Don't cry because it's over, smile because it happened.",
#    'Author': 'Dr. Seuss',
#    'Tags': ['attributed-no-source', 'cry', 'crying', 'experience', 'happiness', 'joy', 'life', 'misattributed-dr-seuss', 'optimism', 'sadness', 'smile', 'smiling '],
#    'Popularity': 0.15566615566615566,
#    'Category': 'life'
# }

random_quote_idx = random.randint(0, len(quotes))

quote_content = quotes[random_quote_idx]["Quote"]
quote_author = quotes[random_quote_idx]["Author"]

style_provider = Gtk.CssProvider()
style_provider.load_from_data(CSS)

Gtk.StyleContext.add_provider_for_screen(
    Gdk.Screen.get_default(),
    style_provider,
    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)

content_label = Gtk.Label(name="main_content")
content_label.set_text(quote_content)
content_label.set_justify(Gtk.Justification.CENTER)
content_label.set_max_width_chars(50)
content_label.set_line_wrap(True)

author_label = Gtk.Label(name="other_content")
author_label.set_text(quote_author)
author_label.set_justify(Gtk.Justification.CENTER)
author_label.set_max_width_chars(50)
author_label.set_line_wrap(True)
# author_label.set_size_request(250, -1)
box = Gtk.Box(name="mybox", orientation=Gtk.Orientation.VERTICAL)
box.pack_start(content_label, False, False, 0)
box.pack_end(author_label, False, False, 0)

window = Gtk.Window(title="", name="toplevel")
screen = window.get_screen()
visual = screen.get_rgba_visual()
window.set_visual(visual)
window.set_decorated(False)
window.add(box)

window.set_position(Gtk.WindowPosition.CENTER)
window.set_resizable(False)
window.connect("destroy", Gtk.main_quit)
window.show_all()

#def thread_function(name):
#   time.sleep(DISPLAY_TIME)
#    Gtk.main_quit()
#x = threading.Thread(target=thread_function, args=(1,))
#x.start()

Gtk.main()

x.join()


# coding: utf-8
# author: ives
# date: 2017-10-24
# desc: 公共函数
import json_codec
import utility
import bottle
import webutility
import log

#用于wmqtt控制重联
class WmqttException(Exception):
	def __init__(self,*p,**pp):
		super(WmqttException, self).__init__(*p,**pp)

class AuthException(Exception):
	def __init__(self,*p,**pp):
		super(AuthException, self).__init__(*p,**pp)

def get(url,cacheSecond=0):
	return _route(url,method=["GET","POST"],cacheSecond=cacheSecond)

def post(url):
	return _route(url,method=["GET","POST"])

def getNormal(url):
	return _route(url,method="GET")

#每个后端页面都需要返回的信息
def _addBackResult(errorno, errormsg, retDic = None):
	if retDic is None:
		retDic = {}
	retDic["errorno"] = errorno
	if errorno != 0:
		retDic["errormsg"] = errormsg
	else:
		assert not errormsg
		retDic["errormsg"] = ""
	return json_codec.dump(retDic)

def _catch(func):
	def __call(*p,**pp):
		try:
			ret = func(*p,**pp)
			if ret is None:
				return _addBackResult(0,"")
			if not isinstance(ret,dict):
				print("type must be dict",type(ret),str(ret))
			assert isinstance(ret,dict)
			return _addBackResult(0,"",ret)
		except AuthException as e1:
			log.error("auth failed! ",str(e1))
			return _addBackResult(-1000, str(e1))
		except WmqttException as e2:
			log.error("wmqtt failed! ",str(e2))
			return _addBackResult(-1001, str(e2))
		except Exception as e:
			if hasattr(e,"noprint"):
				log.error("catch Exception:",str(e))
			else:
				log.exception("invoke "+str(func),e)
			return _addBackResult(-1, str(type(e).__name__)+": "+str(e))
	__call.__name__ = func.__name__
	return __call

@webutility.allow_cross_domain
def _optionDefault():
	return "OK"

def _route(url,method,cacheSecond=0):
	def __call(func):
		f1 = func
		if cacheSecond:
			f1 = cacheFunc(func,cacheSecond)
		ff = webutility.allow_cross_domain(_catch(f1))
		ff = webutility.set_content_type(ff,'application/json;charset=utf-8')
		bottle.route(url,"OPTIONS", _optionDefault)
		return bottle.route(url, method, callback=ff)
	# __call.__name__ = func.__name__
	return __call

def add(url,func,cacheSecond=0):
	f1 = func
	if cacheSecond:
		f1 = cacheFunc(func,cacheSecond)
	ff = webutility.allow_cross_domain(_catch(f1))
	ff = webutility.set_content_type(ff,'application/json;charset=utf-8')
	bottle.route(url,"OPTIONS", _optionDefault)
	return bottle.route(url, ["GET","POST"], callback=ff)

class cacheInfo:
	def __init__(self,cacheSecond):
		self.timeout = cacheSecond*1000
		self.data = None
		self.visitTicks = 0

g_cacheInfo = {}

def cacheFunc(func,cacheSecond):
	g_cacheInfo[func] = cacheInfo(cacheSecond)
	def __call(*p,**pp):
		if func in g_cacheInfo:
			c = g_cacheInfo[func]
			now = utility.ticks()
			if now - c.visitTicks > c.timeout:
				c.data = func(*p,**pp)
				c.visitTicks = now
			return c.data
		else:
			return func(*p,**pp)
	__call.__name__ = func.__name__
	return __call

#=================== unit test ======================
def test_addbackResult():
	import json,datetime

	dic1 = json.loads(_addBackResult(-1, "eefsdafas错误信息"))
	assert len(dic1) == 2
	assert dic1["errorno"] == -1
	assert dic1["errormsg"] == "eefsdafas错误信息"

	dic2 = {}
	dic2["key1"] = 1
	dic2["key2"] = "string"
	dic2["date"] = datetime.datetime(1998,12,31,11,45,22)
	dic2["list"] = [1,2,3,4]
	dic2 = json.loads(_addBackResult(2, "aaa", dic2))
	assert len(dic2) == 6
	assert dic2["errorno"] == 2
	assert dic2["errormsg"] == "aaa"
	assert dic2["key1"] == 1
	assert dic2["key2"] == "string"
	assert dic2["date"] == "1998-12-31 11:45:22"
	assert dic2["list"] ==  [1,2,3,4]

if __name__ == '__main__':
	utility.run_tests()


#!/usr/bin/python3
import argparse

import torch
import numpy as np

def extract_filts(model_files, out_filename):
    filts = []
    for filename in model_files:
        state_dict = torch.load(filename, map_location='cpu')
        # Hacky way to detect CorrelatorExtractor log files
        if "CorrelatorExtractor" in filename:
            filts.append(state_dict['correlator.conv_filt'].cpu().numpy())
        else:
            filts.append(state_dict['conv1.weight'].cpu().numpy())
    filts = np.concatenate(filts, axis=0)
    np.save(out_filename, filts)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Extract filters from .pt model files')
    parser.add_argument('model_files', type=str, nargs='+', help='List of model .pt files to extract from')
    parser.add_argument('out_filename', type=str, help='Name of output (.npy) file')
    args = parser.parse_args()

    extract_filts(args.model_files, args.out_filename)


import numpy as np
import matplotlib.pyplot as plt
import gym
import cv2

class deep_mobile_printing_2d1r(gym.Env):
    def __init__(self, plan_choose=0):
        # plan_choose: 0 Dense triangle, 1 Sparse triangle

        self.step_size = 1
        self.plan_width = 20
        self.plan_height = 20
        self.environment_memory = None
        self.count_brick = None
        self.brick_memory = None
        self.HALF_WINDOW_SIZE = 3
        self.environment_width = self.plan_width + 2 * self.HALF_WINDOW_SIZE
        self.environment_height = self.plan_height + 2 * self.HALF_WINDOW_SIZE
        self.position_memory = None
        self.observation = None
        self.count_step = 0
        self.total_step = 600
        self.plan = None
        self.input_plan = None
        self.total_brick = 0
        self.one_hot = None
        self.action_dim = 5
        self.state_dim = (2 * self.HALF_WINDOW_SIZE + 1) ** 2 + 2
        self.plan_choose = plan_choose

    def create_plan(self):
        if not(self.plan_choose == 1 or self.plan_choose == 0 ):
            raise ValueError(' 0: Dense triangle, 1: Sparse triangle')

        plan = np.zeros((self.environment_height, self.environment_width))
        area = [50,20]
        total_area = 0
        while total_area <= area[self.plan_choose]:
            x = np.random.randint(0, self.plan_width, size=3)
            y = np.random.randint(0, self.plan_height, size=3)

            img_rgb = np.ones((self.plan_height, self.plan_width, 3), np.uint8) * 255
            vertices = np.array([[x[0], y[0]], [x[1], y[1]], [x[2], y[2]]], np.int32)
            pts = vertices.reshape((-1, 1, 2))
            cv2.polylines(img_rgb, [pts], isClosed=True, color=(0, 0, 0))
            if self.plan_choose == 1:
                cv2.fillPoly(img_rgb, [pts], color=(0, 0, 0))

            plan[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height,
            self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width] = 1 - img_rgb[:, :, 0] / 255
            total_area = sum(sum(plan))

        return plan, total_area

    def reset(self):
        self.plan, self.total_brick = self.create_plan()
        if self.total_brick < 30:
            self.total_brick = 30
        self.input_plan = self.plan[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height, \
                          self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width]
        self.environment_memory = np.zeros((self.environment_height, self.environment_width))
        self.environment_memory[:, :self.HALF_WINDOW_SIZE] = -1
        self.environment_memory[:, -self.HALF_WINDOW_SIZE:] = -1
        self.environment_memory[:self.HALF_WINDOW_SIZE, :] = -1
        self.environment_memory[-self.HALF_WINDOW_SIZE:, :] = -1

        self.count_brick = 0
        #
        self.position_memory = []
        self.observation = None
        self.count_step = 0
        initial_position = [self.HALF_WINDOW_SIZE, self.HALF_WINDOW_SIZE]

        self.position_memory.append(initial_position)
        #
        return np.hstack((self.observation_(initial_position), np.array([[self.count_brick]]), np.array([[self.count_step]])))[0]

    def observation_(self, position):
        observation = self.environment_memory[
                      position[0] - self.HALF_WINDOW_SIZE:position[0] + self.HALF_WINDOW_SIZE + 1, \
                      position[1] - self.HALF_WINDOW_SIZE:position[1] + self.HALF_WINDOW_SIZE + 1]
        return observation.flatten().reshape(1, -1)

    def clip_position(self, position):
        if position[0] <= self.HALF_WINDOW_SIZE:
            position[0] = self.HALF_WINDOW_SIZE
        if position[1] <= self.HALF_WINDOW_SIZE:
            position[1] = self.HALF_WINDOW_SIZE
        if position[0] >= self.plan_width + self.HALF_WINDOW_SIZE - 1:
            position[0] = self.plan_width + self.HALF_WINDOW_SIZE - 1
        if position[1] >= self.plan_width + self.HALF_WINDOW_SIZE - 1:
            position[1] = self.plan_width + self.HALF_WINDOW_SIZE - 1
        return position

    def step(self, action):
        self.count_step += 1
        self.step_size = np.random.randint(1, 4)

        ### 0 left, 1 right, 2 up, 3 down
        if action == 0:
            position = [self.position_memory[-1][0], self.position_memory[-1][1] - self.step_size]
            position = self.clip_position(position)
            self.position_memory.append(position)
        #
        if action == 1:
            position = [self.position_memory[-1][0], self.position_memory[-1][1] + self.step_size]
            position = self.clip_position(position)
            self.position_memory.append(position)
        #
        if action == 2:
            position = [self.position_memory[-1][0] + self.step_size, self.position_memory[-1][1]]
            position = self.clip_position(position)
            self.position_memory.append(position)
        if action == 3:
            position = [self.position_memory[-1][0] - self.step_size, self.position_memory[-1][1]]
            position = self.clip_position(position)
            self.position_memory.append(position)

        #######    4   drop
        if action == 4:
            self.count_brick += 1
            position = self.position_memory[-1]
            self.position_memory.append(position)

            self.environment_memory[position[0], position[1]] += 1.0

            done = bool(self.count_brick > self.total_brick)
            if done:
                if self.environment_memory[position[0], position[1]] > 1:
                    self.environment_memory[position[0], position[1]] = 1.0

                observation = [np.hstack(
                    (self.observation_(position), np.array([[self.count_brick]]), np.array([[self.count_step]]))),self.input_plan]
                reward = 0.0
                return observation[0][0], reward, done
            else:
                done = bool(self.count_step >= self.total_step)
                if self.environment_memory[position[0], position[1]] > self.plan[position[0], position[1]]:

                    reward = 0
                elif self.environment_memory[position[0], position[1]] == self.plan[position[0], position[1]]:
                    reward = 5.0
                if self.environment_memory[position[0], position[1]] > 1.0:
                    self.environment_memory[position[0], position[1]] = 1.0
                observation = [np.hstack(
                    (self.observation_(position), np.array([[self.count_brick]]), np.array([[self.count_step]]))),self.input_plan]
                return observation[0][0], reward, done

        done = bool(self.count_step >= self.total_step)
        observation = [np.hstack(
            (self.observation_(position), np.array([[self.count_brick]]), np.array([[self.count_step]]))),self.input_plan]
        reward = 0

        return observation[0][0], reward, done
    def iou(self):
        environment_memory = self.environment_memory
        environment_plan = self.plan
        HALF_WINDOW_SIZE = self.HALF_WINDOW_SIZE
        plan_height = self.plan_height
        plan_width = self.plan_width
        component1=environment_plan[HALF_WINDOW_SIZE:HALF_WINDOW_SIZE+plan_height,\
                           HALF_WINDOW_SIZE:HALF_WINDOW_SIZE+plan_width].astype(bool)
        component2=environment_memory[HALF_WINDOW_SIZE:HALF_WINDOW_SIZE+plan_height,\
                           HALF_WINDOW_SIZE:HALF_WINDOW_SIZE+plan_width].astype(bool)
        overlap = component1*component2 # Logical AND
        union = component1 + component2 # Logical OR
        IOU = overlap.sum()/float(union.sum())
        return IOU
    def render(self, axe, iou_min=None, iou_average=None, iter_times=100):

        axe.clear()
        plan = self.plan[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height, \
               self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width]
        env_memory = self.environment_memory[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height, \
                     self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width]
        background = np.zeros((self.plan_height, self.plan_width))
        img = np.stack((env_memory, plan, background), axis=2)
        plt.imshow(img)
        plt.plot(self.position_memory[-1][1] - self.HALF_WINDOW_SIZE,
                 self.position_memory[-1][0] - self.HALF_WINDOW_SIZE, "*")
        ###  compute IOU
        component1 = self.plan[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height, \
                     self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width].astype(bool)
        component2 = self.environment_memory[self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_height, \
                     self.HALF_WINDOW_SIZE:self.HALF_WINDOW_SIZE + self.plan_width].astype(bool)
        overlap = component1 * component2  # Logical AND
        union = component1 + component2  # Logical OR
        IOU = overlap.sum() / float(union.sum())

        # Add the patch to the Axes
        if iou_min == None:
            iou_min = IOU
        if iou_average == None:
            iou_average = IOU
        # axe.add_patch(rect)
        axe.title.set_text('step=%d,used_paint=%d,IOU=%.3f' % (self.count_step, self.count_brick, IOU))
        plt.text(0, 21.5, 'Iou_min_iter_%d = %.3f' % (iter_times, iou_min), color='red', fontsize=12)
        plt.text(0, 20.5, 'Iou_average_iter_%d = %.3f' % (iter_times, iou_average), color='blue', fontsize=12)
        axe.axis('off')

        plt.draw()

if __name__ == "__main__":
    env = deep_mobile_printing_2d1r(plan_choose=2)

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    total_reward = 0
    env.reset()
    env.render(ax)
    print(env.total_brick)
    while True:
        obs, reward, done = env.step(np.random.randint(5))
        env.render(ax)
        plt.pause(0.1)
        total_reward += reward
        if done:
            break

    print("reward:", total_reward)
    plt.show()


#!/usr/bin/env python

"""
CABLE site run with full biogeochemistry (CNP) and POP
=======================================================

- Spin-up: using pre-industrial CO2, NDEP, PDEP. Currently this is using
           values from AmazonFACE experiment, i.e. CO2=284.7;
           NDEP-0.79 kg N ha-1 yr-1; PDEP=0.144 kg P ha-1 yr-1
- Transient: 1851-1998, varying CO2, NDEP and PDEP with recycled met data
- Simulation: actual experiment CO2, NDEP/PDEP & met

Options to turn use C/CN/CNP with POP on/off

That's all folks.

"""

__author__ = "Martin De Kauwe, Vanessa Haverd"
__version__ = "1.0 (21.07.2018)"
__email__ = "mdekauwe@gmail.com, Vanessa.Haverd@csiro.au"

import os
import sys
import glob
import shutil
import tempfile
import pandas as pd
import xarray as xr
import numpy as np
import subprocess

class RunCable(object):

    def __init__(self, experiment_id, startyear, endyear, lai_feedback,
                 site_dir, obs_dir, plot_dir, namelist_dir, param_dir, output_dir, restart_dir,
                 dump_dir, met_fname, co2_ndep_fname, nml_fn,
                 site_nml_fn,veg_param_fn,log_dir, exe, aux_dir,
                 biogeochem, call_pop, verbose):

        self.experiment_id = experiment_id
        self.startyear = startyear
        self.endyear = endyear
        self.lai_feedback = lai_feedback
        self.site_dir = site_dir
        self.obs_dir = obs_dir
        self.plot_dir = plot_dir
        self.namelist_dir = namelist_dir
        self.param_dir = param_dir
        self.output_dir = output_dir
        self.restart_dir = restart_dir
        self.dump_dir = dump_dir
        self.met_fname = met_fname
        self.co2_ndep_fname = co2_ndep_fname
        self.nml_fn = nml_fn
        self.site_nml_fn = site_nml_fn
        self.veg_param_fn = veg_param_fn
        self.cable_restart_fname = "%s_cable_rst.nc" % (self.experiment_id)
        self.casa_restart_fname = "%s_casa_rst.nc" % (self.experiment_id)
        self.pop_restart_fname = "%s_pop_rst.nc" % (self.experiment_id)
        self.climate_restart_fname = "%s_climate_rst.nc" % (self.experiment_id)
        self.log_dir = log_dir
        self.cable_exe = exe
        self.aux_dir = aux_dir
        self.verbose = verbose
        self.nyear_spinup = 30
        self.limit_labile =".FALSE."
        if biogeochem == "C":
            self.biogeochem = 1
            #self.vcmax = "standard"
            self.vcmax = "Walker2014"
            self.vcmax_feedback = ".TRUE."
        elif biogeochem == "CN":
            self.biogeochem = 2
            self.vcmax = "Walker2014"
            self.vcmax_feedback = ".TRUE."
        elif biogeochem == "CNP":
            self.biogeochem = 3
            self.vcmax = "Walker2014"
            self.vcmax_feedback = ".TRUE."
        else:
            raise ValueError("Unknown biogeochemistry option: C, CN, CNP")
        self.call_pop = call_pop
        if self.call_pop:
            self.pop_flag = ".TRUE."
        else:
            self.pop_flag = ".FALSE."
        self.debug = True

    def main(self, SPIN_UP=False, TRANSIENT=False, SIMULATION=False):

        os.chdir(site_dir + '/' + site)
        out_file=site_dir + '/' + site + "/" + output_dir + '/' + experiment_id + '_out_cable.nc'

        if not os.path.exists(restart_dir):
            os.makedirs(restart_dir)

        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        if not os.path.exists(log_dir):
            os.makedirs(log_dir)

        if not os.path.exists(dump_dir):
            os.makedirs(dump_dir)

        num = 1
        not_in_equilibrium = True

        (st_yr, en_yr,
         st_yr_trans, en_yr_trans,
         st_yr_spin, en_yr_spin) = self.get_years()

        self.initial_setup(st_yr_spin, en_yr_spin, st_yr, en_yr)

        if SPIN_UP == True:

            # initial spin
            print("Spinup")
            self.limit_labile =".TRUE."
            self.run_me()
            self.clean_up(end=False, tag="zero")
            #sys.exit()

            while num < 4:
                self.logfile="log_ccp%d" % (num)
                self.setup_re_spin(number=num)
                self.run_me()
                self.clean_up(end=False, tag="ccp%d" % (num))
                self.logfile="log_sa%d" % (num)
                self.setup_analytical_spin(number=num, st_yr_spin=st_yr_spin,
                                           en_yr_spin=en_yr_spin )
                self.run_me()
                self.clean_up(end=False, tag="saa%d" % (num))
                not_in_equilibrium = self.check_steady_state(num)
                num += 1

            not_in_equilibrium=True
            self.limit_labile =".FALSE."
            while not_in_equilibrium:

                self.logfile="log_ccp%d" % (num)
                self.setup_re_spin(number=num)
                self.run_me()
                self.clean_up(end=False, tag="ccp%d" % (num))
                #sys.exit()
                self.logfile="log_sa%d" % (num)
                self.setup_analytical_spin(number=num, st_yr_spin=st_yr_spin,
                                           en_yr_spin=en_yr_spin )
                self.run_me()
                self.clean_up(end=False, tag="saa%d" % (num))
                #sys.exit()
                not_in_equilibrium = self.check_steady_state(num)

                num += 1

            # one final spin
            self.logfile="log_ccp%d" % (num)
            self.setup_re_spin(number=num)
            self.run_me()
            self.clean_up(end=False, tag="ccp%d" % (num))

        if TRANSIENT == True:
            print("Transient")

            self.setup_transient(st_yr_trans, en_yr_trans, st_yr, en_yr)
            self.run_me()
            self.clean_up(end=False, tag="transient")

        if SIMULATION == True:
            print("Simulation")

            self.setup_simulation(st_yr, en_yr)
            self.run_me()

            print("Plotting")
            #subprocess.call(["./CABLE_plots.R", site, str(st_yr), str(en_yr), out_file, self.obs_dir])
            subprocess.call([os.path.join(self.plot_dir,"CABLE_plots.R"), self.experiment_id, str(st_yr), str(en_yr), out_file, self.obs_dir, self.plot_dir])

        self.clean_up(end=True)

    def get_years(self):
        """
        Figure out the start and end of the met file, the number of times we
        need to recycle the met data to cover the transient period and the
        start and end of the transient period.
        """
        pre_indust = 1850

        ds = xr.open_dataset(self.met_fname)

        # st_yr = pd.to_datetime(ds.time[0].values).year
        ## Note: start- and endyear now determined in the wrapper script
        st_yr = self.startyear
        en_yr = self.endyear

        # PALS met files final year tag only has a single 30 min, so need to
        # end at the previous year, which is the real file end
        # en_yr = pd.to_datetime(ds.time[-1].values).year

        # length of met record
        nrec = en_yr - st_yr + 1

        # number of times met data is recycled during transient simulation
        nloop_transient = np.ceil((st_yr - 1 - pre_indust) / nrec) - 1

        # number of times met data is recycled with a spinup run of nyear_spinup
        nloop_spin = np.ceil( self.nyear_spinup / nrec)

        st_yr_transient = st_yr - 1 - nloop_transient * nrec + 1
        en_yr_transient = st_yr_transient + nloop_transient * nrec - 1

        en_yr_spin = st_yr_transient - 1
        st_yr_spin = en_yr_spin - nloop_spin * nrec + 1

        return (st_yr, en_yr, st_yr_transient, en_yr_transient,
                st_yr_spin, en_yr_spin)

    def adjust_nml_file(self, fname, replacements):
        """
        Adjust the params/flags in the CABLE namelise file. Note this writes
        over whatever file it is given!

        Parameters:
        ----------
        fname : string
            parameter filename to be changed.
        replacements : dictionary
            dictionary of replacement values.

        """
        f = open(fname, 'r')
        param_str = f.read()
        f.close()
        new_str = self.replace_keys(param_str, replacements)
        fd, path = tempfile.mkstemp()
        os.write(fd, str.encode(new_str))
        os.close(fd)
        shutil.copy(path, fname)
        os.remove(path)

    def replace_keys(self, text, replacements_dict):
        """ Function expects to find CABLE namelist file formatted key = value.

        Parameters:
        ----------
        text : string
            input file data.
        replacements_dict : dictionary
            dictionary of replacement values.

        Returns:
        --------
        new_text : string
            input file with replacement values

        """
        lines = text.splitlines()
        for i, row in enumerate(lines):
            # skip blank lines
            if not row.strip():
                continue
            if "=" not in row:
                lines[i] = row
                continue
            elif not row.startswith("&"):
                key = row.split("=")[0]
                val = row.split("=")[1]
                lines[i] = " ".join((key.rstrip(), "=",
                                     replacements_dict.get(key.strip(),
                                     val.lstrip())))

        return '\n'.join(lines) + '\n'

    def initial_setup(self, st_yr_spin, en_yr_spin, st_yr, en_yr):
        """
        Setup CABLE namelist file for spinup from zero
        """
        shutil.copyfile(os.path.join(self.namelist_dir, "site.nml"),
                        self.site_nml_fn)
        shutil.copyfile(os.path.join(self.namelist_dir, "cable.nml"),
                        self.nml_fn)
        #self.add_missing_options_to_nml_file(self.nml_fn)

        out_fname = os.path.join(self.output_dir,
                                 "%s_out_cable_zero.nc" % (self.experiment_id))
        if os.path.isfile(out_fname):
            os.remove(out_fname)

        out_fname_CASA = os.path.join(self.output_dir,
                                 "%s_out_CASA_zero.nc" % (self.experiment_id))
        if os.path.isfile(out_fname_CASA):
            os.remove(out_fname_CASA)

        out_fname_POP = os.path.join(self.output_dir,
                                 "%s_out_POP_zero.nc" % (self.experiment_id))
        if os.path.isfile(out_fname_POP):
            os.remove(out_fname_POP)

        out_log_fname = os.path.join(self.log_dir,
                                     "%s_log_zero.txt" % (self.experiment_id))
        if os.path.isfile(out_log_fname):
            os.remove(out_log_fname)

        replace_dict = {
                        "RunType": '"spinup"',
                        "CO2NDepFile": "'%s'" % (self.co2_ndep_fname),
                        "spinstartyear": "%d" % (st_yr),
                        "spinendyear": "%d" % (en_yr),
                        "spinCO2": "284.7",
                        "spinNdep": "0.79",
                        "spinPdep": "0.144",
        }
        self.adjust_nml_file(self.site_nml_fn, replace_dict)

        replace_dict = {
                        "filename%met": "'%s'" % (self.met_fname),
                        "filename%out": "'%s'" % (out_fname),
                        "casafile%out": "'%s'" % (out_fname_CASA),
                        "cable_user%POP_outfile" : "'%s'" % (out_fname_POP),
                        "filename%log": "'%s'" % (out_log_fname),
                        "filename%restart_out": "'%s'" % os.path.join(self.restart_dir, self.cable_restart_fname),
                        "cable_user%climate_restart_out": "'%s'" % os.path.join(self.restart_dir, self.climate_restart_fname),
                        "cable_user%POP_restart_out": "'%s'" % os.path.join(self.restart_dir, self.pop_restart_fname),
                        "casafile%cnpepool": "'%s'" % os.path.join(self.restart_dir, self.casa_restart_fname),
                        "filename%restart_in": "''" ,
                        "cable_user%climate_restart_in": "''" ,
                        "cable_user%POP_restart_in": "''",
                        "filename%type": "'%s'" % (os.path.join(self.aux_dir, "offline/gridinfo_CSIRO_1x1.nc")),
                        "filename%veg": "'%s'" % os.path.join(self.param_dir, veg_param_fn),
                        "filename%soil": "'%s'" % os.path.join(self.param_dir, soil_param_fn),
                        "output%restart": ".TRUE.",
                        "casafile%phen": "'%s'" % (os.path.join(self.aux_dir, "core/biogeochem/modis_phenology_csiro.txt")),
                        "casafile%cnpbiome": "'%s'" % (os.path.join(self.param_dir, bgc_param_fn)),
                        "cable_user%RunIden": "'%s'" % (self.experiment_id),
                        "cable_user%POP_out": "'rst'",
                        "cable_user%POP_rst": "'./'",
                        "cable_user%POP_fromZero": ".T.",
                        "cable_user%CASA_fromZero": ".T.",
                        "cable_user%CLIMATE_fromZero": ".T.",
                        "cable_user%vcmax": "'%s'" % (self.vcmax),
                        "cable_user%YearStart": "%d" % (st_yr_spin),
                        "cable_user%YearEnd": "%d" % (en_yr_spin),
                        "cable_user%CASA_SPIN_STARTYEAR": "%d" % (st_yr_spin),
                        "cable_user%CASA_SPIN_ENDYEAR": "%d" % (en_yr_spin),
                        "cable_user%CALL_POP": "%s" % (self.pop_flag),
                        "output%averaging": "'monthly'",
                        "output%patch": ".TRUE.",
                        "icycle": "%d" % (self.biogeochem),
                        "leaps": ".TRUE.",
                        "l_vcmaxFeedbk": "%s" % (self.vcmax_feedback),
                        "l_laiFeedbk": ".%s." % (self.lai_feedback),
                        "cable_user%CASA_OUT_FREQ":  "'annually'" ,
                        "cable_user%limit_labile": "%s" % (self.limit_labile) ,
                        "cable_user%SRF":  ".T." ,
                        "cable_user%STRF": "'DAMM'" ,
                        "cable_user%SMRF": "'DAMM'"
          }
        self.adjust_nml_file(self.nml_fn, replace_dict)

    def setup_re_spin(self, number=None):
        """
        Adjust the CABLE namelist file with the various flags for another spin
        """
        out_log_fname = "%s_log_ccp%d.txt" % (self.experiment_id, number)
        out_log_fname = os.path.join(self.log_dir, out_log_fname)
        if os.path.isfile(out_log_fname):
            os.remove(out_log_fname)

        out_fname = "%s_out_cable_ccp%d.nc" % (self.experiment_id, number)
        out_fname = os.path.join(self.output_dir, out_fname)
        if os.path.isfile(out_fname):
            os.remove(out_fname)

        out_fname_CASA = "%s_out_CASA_ccp%d.nc" % (self.experiment_id, number)
        out_fname_CASA = os.path.join(self.output_dir, out_fname_CASA)
        if os.path.isfile(out_fname_CASA):
            os.remove(out_fname_CASA)

        out_fname_POP = "%s_out_POP_ccp%d.nc" % (self.experiment_id, number)
        out_fname_POP = os.path.join(self.output_dir, out_fname_POP)
        if os.path.isfile(out_fname_POP):
            os.remove(out_fname_POP)

        replace_dict = {
                        "filename%log": "'%s'" % (out_log_fname),
                        "filename%restart_in": "'%s'" % os.path.join(self.restart_dir, self.cable_restart_fname),
                        "cable_user%climate_restart_in": "'%s'" % os.path.join(self.restart_dir, self.climate_restart_fname),
                        "cable_user%POP_restart_in": "'%s'" % os.path.join(self.restart_dir, self.pop_restart_fname),
                        "casafile%cnpipool": "'%s'" % os.path.join(self.restart_dir,self.casa_restart_fname),
                        "cable_user%POP_fromZero": ".F.",
                        "cable_user%CASA_fromZero": ".F.",
                        "cable_user%POP_rst": "'./'",
                        "cable_user%CLIMATE_fromZero": ".F.",
                        "cable_user%CASA_DUMP_READ": ".FALSE.",
                        "cable_user%CASA_DUMP_WRITE": ".TRUE.",
                        "cable_user%CASA_NREP": "0",
                        "cable_user%SOIL_STRUC": "'sli'",
                        "icycle": "%d" % (self.biogeochem),
                        "leaps": ".TRUE.",
                        "spincasa": ".FALSE.",
                        "casafile%c2cdumppath": "' '",
                        "output%restart": ".TRUE.",
                        "filename%out": "'%s'" % (out_fname),
                        "casafile%out": "'%s'" % (out_fname_CASA),
                        "cable_user%POP_outfile" : "'%s'" % (out_fname_POP),
                        "cable_user%limit_labile": "%s" % (self.limit_labile) ,
        }
        self.adjust_nml_file(self.nml_fn, replace_dict)

    def setup_analytical_spin(self, number, st_yr_spin, en_yr_spin):
        """
        Adjust the CABLE namelist file with the various flags for the
        analytical spin step
        """
        out_log_fname = "%s_log_analytic_%d.txt" % (self.experiment_id, number)
        out_log_fname = os.path.join(self.log_dir, out_log_fname)
        if os.path.isfile(out_log_fname):
            os.remove(out_log_fname)

        out_fname_CASA = "%s_out_CASA_analytic_%d.nc" % \
                            (self.experiment_id, number)
        out_fname_CASA = os.path.join(self.output_dir, out_fname_CASA)
        if os.path.isfile(out_fname_CASA):
            os.remove(out_fname_CASA)

        out_fname_POP = "%s_out_POP_analytic_%d.nc" % (self.experiment_id, number)
        out_fname_POP = os.path.join(self.output_dir, out_fname_POP)
        if os.path.isfile(out_fname_POP):
            os.remove(out_fname_POP)

        replace_dict = {
                        "filename%log": "'%s'" % (out_log_fname),
                        "icycle": "%d" % (self.biogeochem + 10), # Need to add 10 for spinup
                        "cable_user%CASA_DUMP_READ": ".TRUE.",
                        "cable_user%CASA_DUMP_WRITE": ".FALSE.",
                        "cable_user%CASA_NREP": "1",
                        "cable_user%SOIL_STRUC": "'default'",
                        "leaps": ".FALSE.",
                        "spincasa": ".TRUE.",
                        "casafile%c2cdumppath": "'./'",
                        "cable_user%CASA_SPIN_STARTYEAR": "%d" % (st_yr_spin),
                        "cable_user%CASA_SPIN_ENDYEAR": "%d" % (en_yr_spin),
                        "casafile%out": "'%s'" % (out_fname_CASA),
                        "cable_user%POP_outfile" : "'%s'" % (out_fname_POP),
                        "cable_user%limit_labile": "%s" % (self.limit_labile) ,
        }
        self.adjust_nml_file(self.nml_fn, replace_dict)

    def setup_transient(self, st_yr_trans, en_yr_trans, st_yr, en_yr):
        """
        Adjust the CABLE namelist file for the transient run, i.e. 1850 to XXXX
        """
        replace_dict = {
                        "RunType": '"transient"',
                        "CO2NDepFile": "'%s'" % (self.co2_ndep_fname),
                        "spinstartyear": "%d" % (st_yr),
                        "spinendyear": "%d" % (en_yr),
           }
        self.adjust_nml_file(self.site_nml_fn, replace_dict)

        out_log_fname = "%s_log_transient.txt" % (self.experiment_id)
        out_log_fname = os.path.join(self.log_dir, out_log_fname)
        if os.path.isfile(out_log_fname):
            os.remove(out_log_fname)

        out_fname = "%s_out_cable_transient.nc" % (self.experiment_id)
        out_fname = os.path.join(self.output_dir, out_fname)
        if os.path.isfile(out_fname):
            os.remove(out_fname)

        out_fname_CASA = "%s_out_casa_transient.nc" % (self.experiment_id)
        out_fname_CASA = os.path.join(self.output_dir, out_fname_CASA)
        if os.path.isfile(out_fname_CASA):
            os.remove(out_fname_CASA)

        replace_dict = {
                        "filename%out": "'%s'" % (out_fname),
                        "filename%log": "'%s'" % (out_log_fname),
                        "cable_user%CASA_DUMP_READ": ".FALSE.",
                        "cable_user%CASA_DUMP_WRITE": ".FALSE.",
                        "cable_user%CASA_NREP": "0",
                        "cable_user%SOIL_STRUC": "'sli'",
                        "output%restart": ".TRUE.",
                        "output%averaging": "'monthly'",
                        "spinup": ".FALSE.",
                        "icycle": "%d" % (self.biogeochem),
                        "POPLUC": ".T.",
                        "filename%out": "'%s'" % (out_fname),
                        "casafile%out": "'%s'" % (out_fname_CASA),
                        "cable_user%YearStart": "%d" % (st_yr_trans),
                        "cable_user%YearEnd": "%d" % (en_yr_trans),
                        "filename%restart_in": "'%s'" % os.path.join(self.restart_dir, self.cable_restart_fname),
                        "cable_user%climate_restart_in": "'%s'" % os.path.join(self.restart_dir, self.climate_restart_fname),
                        "cable_user%POP_restart_in": "'%s'" % os.path.join(self.restart_dir, self.pop_restart_fname),
                        "casafile%cnpipool": "'%s'" % os.path.join(self.restart_dir,self.casa_restart_fname),
                        "cable_user%POP_fromZero": ".F.",
                        "cable_user%CASA_fromZero": ".F.",
                        "cable_user%CLIMATE_fromZero": ".F.",
        }
        self.adjust_nml_file(self.nml_fn, replace_dict)

    def setup_simulation(self, st_yr, en_yr):
        """
        Adjust the CABLE namelist file for the experiment years
        """
        replace_dict = {
                        "RunType": '"historical"',
                        "CO2NDepFile": "'%s'" % (self.co2_ndep_fname),
                        "spinstartyear": "%d" % (st_yr),
                        "spinendyear": "%d" % (en_yr)
        }
        self.adjust_nml_file(self.site_nml_fn, replace_dict)

        out_log_fname = "%s_log_simulation.txt" % (self.experiment_id)
        out_log_fname = os.path.join(self.log_dir, out_log_fname)
        if os.path.isfile(out_log_fname):
            os.remove(out_log_fname)

        out_fname = "%s_out_cable.nc" % (self.experiment_id)
        out_fname = os.path.join(self.output_dir, out_fname)

        out_fname_CASA = "%s_out_casa.nc" % (self.experiment_id)
        out_fname_CASA = os.path.join(self.output_dir, out_fname_CASA)

        if os.path.isfile(out_fname):
            os.remove(out_fname)

        replace_dict = {
                        "filename%log": "'%s'" % (out_log_fname),
                        "output%averaging": "'daily'",
                        "icycle": "%d" % (self.biogeochem),
                        "cable_user%YearStart": "%d" % (st_yr),
                        "cable_user%YearEnd": "%d" % (en_yr),
                        "filename%out": "'%s'" % (out_fname),
                        "POPLUC": ".F.",
                        "cable_user%CASA_DUMP_READ": ".FALSE.",
                        "cable_user%CASA_DUMP_WRITE": ".FALSE.",
                        "cable_user%SOIL_STRUC": "'sli'",
                        "spincasa": ".FALSE.",
                        "spinup": ".FALSE.",
                        "output%averaging": "'all'",
                        "casafile%out": "'%s'" % (out_fname_CASA),
                        "filename%restart_in": "'%s'" % os.path.join(self.restart_dir, self.cable_restart_fname),
                        "cable_user%climate_restart_in": "'%s'" % os.path.join(self.restart_dir, self.climate_restart_fname),
                        "cable_user%POP_restart_in": "'%s'" % os.path.join(self.restart_dir, self.pop_restart_fname),
                        "casafile%cnpipool": "'%s'" % os.path.join(self.restart_dir,self.casa_restart_fname),
                        "cable_user%POP_fromZero": ".F.",
                        "cable_user%CASA_fromZero": ".F.",
                        "cable_user%CLIMATE_fromZero": ".F.",
        }
        self.adjust_nml_file(self.nml_fn, replace_dict)

    def run_me(self):
        if self.verbose: # output is printed to console
            os.system("%s" % (self.cable_exe))
        else:
            # No outputs to the screen, stout and stderr to dev/null
            #os.system("%s > /dev/null 2>&1" % (self.cable_exe))
            # JK: stdout and stderr are printed to files (but not to console)
            os.system("%s > %s.out 2>%s.err" % (self.cable_exe,self.experiment_id,self.experiment_id))

    def check_steady_state(self, num):
        """
        Check whether the plant (leaves, wood and roots) and soil
        (fast, slow and active) carbon pools have reached equilibrium. To do
        this we are checking the state of the last year in the previous spin
        cycle to the state in the final year of the current spin cycle.
        """
        tol = 0.2 # This is quite high, I use 0.005 in GDAY
        g_2_kg = 0.001

        if num == 1:
            prev_cplant = 99999.9
            prev_csoil = 99999.9
        else:
            fname = "%s_out_CASA_ccp%d.nc" % (self.experiment_id, num-1)
            fname = os.path.join(self.output_dir, fname)
            ds = xr.open_dataset(fname)
            prev_cplant = ds.cplant[:,:,0].values[-1].sum() * g_2_kg
            prev_csoil = ds.csoil[:,:,0].values[-1].sum() * g_2_kg

        fname = "%s_out_CASA_ccp%d.nc" % (self.experiment_id, num)
        fname = os.path.join(self.output_dir, fname)
        ds = xr.open_dataset(fname)
        new_cplant = ds.cplant[:,:,0].values[-1].sum() * g_2_kg
        new_csoil = ds.csoil[:,:,0].values[-1].sum() * g_2_kg

        if ( np.fabs(prev_cplant - new_cplant) < tol and
             np.fabs(prev_csoil - new_csoil) < tol ):
            not_in_equilibrium = False
        else:
            not_in_equilibrium = True

        if self.debug:
            print("*", num, not_in_equilibrium,
                  "*cplant", np.fabs(prev_cplant - new_cplant),
                  "*csoil", np.fabs(prev_csoil - new_csoil))

        return not_in_equilibrium

    def clean_up(self, end=True, tag=None):
        """
        Move restart files to a directory and delete various files we no longer
        need that CABLE spits out as it spins up.
        """
        if end:
            for f in glob.glob("c2c_*_dump.nc"):
                shutil.move(f, os.path.join(self.dump_dir, f))
            f = "cnpfluxOut.csv"
            if os.path.isfile(f):
                os.remove(f)
            f = "new_sumbal"
            if os.path.isfile(f):
                os.remove(f)
            #JK: no longer remove .out files
            #for f in glob.glob("*.out"):
            #    os.remove(f)
            for f in glob.glob("restart_*.nc"):
                os.remove(f)
        else:
            old = os.path.join(self.restart_dir, self.cable_restart_fname)
            new = "%s_%s.nc" % (old[:-3], tag)
            shutil.copyfile(old, new)

            old = os.path.join(self.restart_dir, self.casa_restart_fname)
            new = "%s_%s.nc" % (old[:-3], tag)
            shutil.copyfile(old, new)

            old = os.path.join(self.restart_dir, self.climate_restart_fname)
            new = "%s_%s.nc" % (old[:-3], tag)
            shutil.copyfile(old, new)

            if self.call_pop:
                old = os.path.join(self.restart_dir, self.pop_restart_fname)
                new = "%s_%s.nc" % (old[:-3], tag)
                shutil.copyfile(old, new)

    def add_missing_options_to_nml_file(self, fname, line_start=None):
        """
        Some of the flags we may wish to change are missing from the default
        file so we can't adjust them via this script...add them
        """
        if line_start is None:
            line_start = sum(1 for line in open(fname)) - 1

        f = open(fname, "r")
        contents = f.readlines()
        f.close()

        arg = "   cable_user%GW_MODEL = .FALSE.\n"
        contents.insert(line_start, arg)
        line_start += 1

        arg = "   cable_user%or_evap = .FALSE.\n"
        contents.insert(line_start, arg)
        line_start += 1

        arg = "   filename%gw_elev = 'GSWP3_elevation_slope_stddev.nc'\n"
        contents.insert(line_start, arg)
        line_start += 1

        tmp_fname = "tmp.nml"
        f = open(tmp_fname, "w")
        contents = "".join(contents)
        f.write(contents)
        f.close()

        shutil.move(tmp_fname, fname)

if __name__ == "__main__":

    # command line parameters
    site=sys.argv[1]
    startyear=int(sys.argv[2])
    endyear=int(sys.argv[3])
    lai_feedback=sys.argv[4]
    site_dir=sys.argv[5]
    obs_dir=sys.argv[6]
    plot_dir=sys.argv[7]
    exp_name=sys.argv[8]

    cwd = os.getcwd()
    namelist_dir = "namelists"
    param_dir = "params"
    dump_dir = "dump"
    met_dir = "met"
    co2_ndep_dir = "met"
    aux_dir = "./CABLE-AUX/"
    log_dir = "logs"
    output_dir = "outputs"
    restart_dir = "restart_files"
    nml_fn = "cable.nml"
    site_nml_fn = "site.nml"
    #met_fname = os.path.join(met_dir, '%s.1.4_met.nc' % (experiment_id))
    met_fname = os.path.join(met_dir, site + '_' + str(startyear) + '_' + str(endyear) + '_2tiles.nc')
    co2_ndep_fname = os.path.join(co2_ndep_dir,
                                  "AmaFACE_co2npdepforcing_1850_2100_AMB.csv")
    veg_param_fn = "Cumberland_veg_params.txt"
    bgc_param_fn = "Cumberland_pftlookup.csv"
    soil_param_fn = "def_soil_params.txt"   # only used when soilparmnew = .FALSE. in cable.nml
    exe = "./cable"

    # special for PEST
    #veg_param_fn = "veg_params_pest.txt"
    #bgc_param_fn = "pftlookup_pest.csv"
    #param_dir = "./"

    call_pop = True
    verbose = False

    #for biogeochem in ["C", "CN", "CNP"]:
    for biogeochem in ["CNP"]:

        # experiment_id = "Cumberland_POP_%s" % (biogeochem)
        experiment_id = site + "_%s_2tiles_%s" % (biogeochem,exp_name)
        C = RunCable(experiment_id, startyear, endyear, lai_feedback,
                     site_dir, obs_dir, plot_dir,  namelist_dir,
                     param_dir,output_dir, restart_dir,dump_dir, met_fname, co2_ndep_fname,
                     nml_fn, site_nml_fn,veg_param_fn, log_dir, exe, aux_dir,
                     biogeochem, call_pop,verbose)
        C.main(SPIN_UP=True, TRANSIENT=True, SIMULATION=True)


import os
import pandas as pd
from PIL import Image
from matplotlib.figure import Figure
from xlwings_reports import create_report  # not part of the open-source xlwings package

fig = Figure(figsize=(4, 3))
ax = fig.add_subplot(111)
ax.plot([1, 2, 3, 4, 5])

perf_data = pd.DataFrame(index=['r1', 'r1'],
                         columns=['c0', 'c1'],
                         data=[[1., 2.], [3., 4.]])

wb = create_report('template1.xlsx',
                   'output.xlsx',
                   perf=0.12 * 100,
                   perf_data=perf_data,
                   logo=Image.open(os.path.abspath('xlwings.jpg')),
                   fig=fig)


import numpy
import matplotlib.pyplot as plt
import requests
import json
import pandas
import geopandas as gpd
import pyproj
import fiona
from shapely.geometry import Point, Polygon

my_lacounty_shapefile = 'c:/Users/rasunci/gitstuff/DPW_CITY_BOUNDARIES/DPW_CITY_BOUNDARIES.shp'
my_lacounty_gdf = gpd.read_file(my_lacounty_shapefile)

my_fig = plt.figure(figsize=(16, 10), tight_layout=True)
my_ax = my_fig.add_subplot()
my_ax.set_xlim(6350000, 6650000)
my_ax.set_ylim(1550000, 1900000)
my_lacounty_gdf.plot(ax=my_ax, color='orange', edgecolor='black')

my_url = 'https://mds.bird.co/gbfs/los-angeles/free_bikes'
my_file = 'c:/Users/rasunci/gitstuff/bird/free_bikes.json'
my_bird_data = ''
my_bird_locs = []

if (True):
    my_r = requests.get(my_url)
    if my_r.status_code == 200:
        my_bird_data = my_r.json()
    else:
        print('error handler here')
else:
    with open(my_file) as my_fh:
        my_json = my_fh.read()
    my_bird_data = json.loads(my_json)

my_bird_bikes = my_bird_data['data']['bikes']
for i in range(10):
    my_bike = my_bird_bikes[i]['bike_id']
    my_lon = my_bird_bikes[i]['lon']
    my_lat = my_bird_bikes[i]['lat']
    my_bird_locs.append([my_bike, my_lon, my_lat])

my_bird_df = pandas.DataFrame(my_bird_bikes)
my_bird_geom = [Point(lon, lat) for lon, lat in zip(my_bird_df['lon'], my_bird_df['lat'])]
my_bird_geom_df = pandas.DataFrame(my_bird_geom, columns=['geometry'])
my_bird_gis_df = my_bird_df.join(my_bird_geom_df)
my_bird_gpd = gpd.GeoDataFrame(my_bird_gis_df, crs={'init':'epsg:4326'})
my_bird_gpd['geometry'] = my_bird_gpd['geometry'].to_crs(epsg=2229)

my_bird_gpd.plot(ax=my_ax, color='yellow')

plt.show()


import random
import common

q = 2**255-19 # order of the field---hence the name ed25519

# order of the baseReferencePoint
l = 2**252 + 27742317777372353535851937790883648493

d = (-121665 * pow(121666,q-2,q))%q

# (d+1)^-1 = 121666

def scalar_pack(s):
    s %= l
    result = 32*[0]
    for i in range(32):
        result[i] = s % (2**8)
        s //= (2**8)
    return bytes(result)

def scalar_unpack(data):
    if(len(data)!=32):
        raise Error("invalid encoding of scalar: length is not 32,"
                f" but {len(data)}.")

    s = 0
    for i in range(31):
        s += data[i]*pow(2, 8*i, l)
        s %= l
    # ignore first three bits
    s += (data[31]&0x1f)*pow(2,8*31,l)
    s %= l

    return s

def scalar_random():
    return random.randint(0,l-1)

def scalar_inv(s):
    s %= l
    if s==0:
        raise DivisionByZero()
    return pow(s,l-2,l) # (Fermat's little theorem)

def fe_is_positive(f):
    return (f%q)%2==0

def fe_inv(f):
    f%=q
    if f==0:
        raise DivisionByZero()
    return pow(f,q-2,q) # (Fermat's little theorem)

# returns a positive square root of f
def fe_sqrt(f):
    g = fe_sqrt_any(f)
    if fe_is_positive(g):
        return g
    return q-g

# TODO: add ref to Legendre
def fe_sqrt_any(f):
    f = f % q
    g = pow(f,(q+3)//8,q)
    gg = g**2%q
    if gg==f:
        return g
    elif q-gg==f:
        return (pow(2,(q-1)//4,q)*g)%q
    raise NotASquare()

def fe_is_sqrt(f):
    try:
        fe_sqrt_any(f)
    except NotASquare as e:
        return False
    return True

def fe_random():
    return random.randint(0,q-1)

def fe_pack(f):
    result = 32*[0]
    f %= q
    for i in range(32):
        result[i] = f % (2**8)
        f //= (2**8)
    return bytes(result)

def fe_unpack(data):
    assert(len(data)==32)
    f = 0
    for i in range(31):
        f += data[i]*(2**(8*i))
    # ignore final bit
    f += (0b01111111 & data[31])*(2**(8*31))
    return f

i = fe_sqrt(-1)
magic = fe_inv(-fe_sqrt_any(-d-1))
# magic is the _negative_ square root of -121666

# ReferencePoint on the twisted edwards curve
#   y^2 - x^2 = 1 + dx^2y^2
class ReferencePoint:
    # TODO: correct this method to yield a proper representative
    @staticmethod
    def from_y_and_sign(y,x_is_positive,check=True):
        try:
            x = fe_sqrt((y**2-1)*fe_inv(d*y**2+1))
        except NotASquare:
            raise NotOnCurve()
        if x_is_positive!=fe_is_positive(x):
            x = -x%q
        return ReferencePoint(x,y, check=check)

    @staticmethod
    def from_s(s):
        if not fe_is_positive(s):
            raise SIsNegative()

        try:
            x = fe_sqrt( 4*s**2 * fe_inv(-d*(1-s**2)**2 - (1+s**2)**2) )
        except NotASquare:
            raise Odd()
        y = (1-s**2)*fe_inv(1+s**2)

        if not fe_is_positive(x*y):
            raise InvalidRepresentative("x*y is negative")
        if y%q==0:
            raise InvalidRepresentative("y=0")

        return ReferencePoint(x,y,check=False)

    @staticmethod
    def unpack(data):
        if len(data)!=32:
            raise InvalidEncoding(f"length={len(data)} != 32")
        elif data[31]//128!=0: # the C library ignores this last bit
            raise InvalidEncoding("last bit is not 0")

        return ReferencePoint.from_s(fe_unpack(data))

    @staticmethod
    def hash(data):
        return ReferencePoint.elligator2(fe_unpack(common.sha256(data)))

    @staticmethod
    def random():
        while True:
            try:
                y = fe_random()
                x_is_positive = True #(random.randint(0,1)==1)
                half = ReferencePoint.from_y_and_sign(y,x_is_positive, check=False)
            except InvalidPoint:
                continue
            return half + half

    def __init__(self,x,y, check=True):
        self.x = x % q
        self.y = y % q
        if check:
            self.check()

    def check(self):
        if (self.y**2-self.x**2)%q != (1+d*self.x**2*self.y**2)%q:
            raise NotOnCurve()
        if not (self * (4*l)).is_exactly(ReferencePoint.Zero):
            raise Odd()

    def Copy(self):
        return ReferencePoint(self.x, self.y, check=False)

    def point(self):
        return Point.from_refpoint(self)

    def normalized(self):
        x = self.x
        y = self.y

        if not fe_is_positive(x*y) or y==0:
            x,y = (y*i)%q, (x*i)%q
        if (y+1) % q == 0:  # i.e. y = -1 mod q
            y=1
        if not fe_is_positive(x):
            x,y = q-x,q-y

        return (x,y)

    def normalize(self):
        self.x, self.y = self.normalized()

    def s(self):
        x,y = self.normalized()
        try:
            return fe_sqrt( (1-y)*fe_inv(1+y) )
        except NotASquare:
            assert(False) # should not happen if the ReferencePoint is even

    def pack(self):
        return fe_pack(self.s())

    def __add__(self, other):
        xden = fe_inv(1+d*self.x*other.x*self.y*other.y)
        yden = fe_inv(1-d*self.x*other.x*self.y*other.y)

        return ReferencePoint( (self.x*other.y + other.x*self.y)*xden,
                (self.y*other.y+self.x*other.x)*yden, check=False )

    def __eq__(self, other):
        if not isinstance(other, ReferencePoint):
            return NotImplemented
        return (self.x*other.y - other.x*self.y)%q==0 or \
                (self.x*other.x - self.y*other.y)%q==0

    def equivalence_class(self):
        # doesn't include the odd points
        x,y = self.x,self.y
        yield self
        yield ReferencePoint(-x,-y,check=False)
        yield ReferencePoint(i*y,i*x, check=False)
        yield ReferencePoint(-i*y,-i*x, check=False)

    def is_exactly(self,other):
        if not isinstance(other, ReferencePoint):
            return NotImplemented
        return (self.x==other.x) and (self.y==other.y)

    def __ne__(self, other):
        return not self.__eq__(other)

    def __sub__(self, other):
        if isinstance(other,ReferencePoint):
            return self + -other
        return NotImplemented

    def double(self):
        return self+self

    def double_in_place(self):
        double = self+self
        self.x = double.x
        self.y = double.y

    def __neg__(self):
        return ReferencePoint(-self.x, self.y, check=False)

    def __mul__(self, other):
        return double_and_add_multiplication(self, other, ReferencePoint.Zero)

    def __repr__(self):
        return "ReferencePoint(%s,%s)" % (self.x, self.y)

    # The curve ed25519 is equivalent to the montgomery curve
    #      v**2 + = u**3 + 486662 u**2 + u
    # known as curve25519.  The following methods provide the
    # translation.
    def montgomery(self):
        x,y = self.normalized()
        u = (1-y)*fe_inv(1+y)
        v = u*fe_inv(x)*fe_sqrt(-486664) if x!=0 else 0
        return (u%q,v%q)

    @staticmethod
    def from_montgomery(u, v):
        x = (fe_sqrt(-486664)*u*fe_inv(v))%q if v!=0 else 0
        y = ((1-u)*fe_inv(1+u))%q
        return ReferencePoint(x,y)

    def _jacobi_quartic_slow(self):
        x,y = self.x, self.y
        if x==0:
            # y is now either +1 or -1
            if y==1:
                return JacobiQuartic(0,1,check=False)
            elif y==q-1:
                return JacobiQuartic(1,1,0,check=False)
            else:
                assert(False)
            return JacobiQuartic(0,y,check=False)
        s = fe_sqrt( (1-y)*fe_inv(1+y) ) # y won't be -1 here
        t = (2*s*magic * fe_inv(x))%q
        return JacobiQuartic(s,t, check=False)

    def jacobi_quartic(self):
        x,y = self.x, self.y
        if x==0:
            # y is now either +1 or -1
            if y==1:
                return JacobiQuartic(0,1,check=False)
            elif y==q-1:
                return JacobiQuartic(1,1,0,check=False)
            else:
                assert(False)

        z = ( fe_sqrt(1-pow(y,2,q))*x ) % q
        sz = ( (1-y)*x ) % q
        tz2 = ( 2*z*(1-y)*magic ) % q

        return JacobiQuartic(sz, tz2, z, check=False)

    def t(self):
        x,y = self.normalized()
        return (2*self.s()*magic*fe_inv(x)) % q

    @staticmethod
    def elligator2(x):
        return JacobiQuartic.elligator2(x).refpoint()

    def elligator2_inv(self):
        return self.point().elligator2_inv()

    @staticmethod
    def lizard(payload, N=16):
        return Point.lizard(payload,N).refpoint()

    def lizard_inv(self, N=16):
        return self.point().lizard_inv(N)

# The curve ed25519 is also equivalent to the jacobi quartic
#     s^4 + 2( 1-2d/(d+1) )s^2 + 1 = t^2
# which becomes
#     (sz)^4 + 2( 1-2d/(d+1) )(sz)^2z^2 + z^4 = (tz^2)^2
# in projective coordinates.
a_quartic = ( 1- (2*d)*fe_inv(d+1) ) % q

class JacobiQuartic:
    def __init__(self, sz, tz2, z=1, check=True):
        self._sz = sz % q
        self._tz2 = tz2 % q
        self._z = z % q

        if check: self.check()

    def Copy(self):
        return JacobiQuartic(self._sz, self._tz2, self._z, check=False)

    def check(self):
        sz,tz2,z = self._sz,self._tz2,self._z
        if ( pow(sz,4,q) + 2*a_quartic*pow(sz,2,q)*pow(z,2,q)
                + pow(z,4,q) )%q != pow(tz2,2,q):
            raise InvalidPoint()

    def st(self):
        """Returns (s,t)-coordinates for this point when they exist. """
        """Otherwise throws an Infinite exception."""
        if self._z==0:
            raise Infinite()
        zinv = fe_inv(self._z)
        return ((zinv*self._sz)%q, (zinv**2*self._tz2)%q)

    @staticmethod
    def from_s(s,positive_t=True):
        a = (pow(s,4,q) + 2*a_quartic*pow(s,2,q)+1)%q
        t = fe_sqrt(a)
        if not positive_t:
            t = q - t
        return JacobiQuartic(s,t,check=False)

    @staticmethod
    def random():
        """returns a random non-infinite point on the jacobi quartic"""
        positive_t = (random.getrandbits(1)==0)
        while True:
            try:
                # has 50% chance to succeed
                return JacobiQuartic.from_s(fe_random(),positive_t)
            except NotASquare:
                continue

    def random_infinite():
        """returns a random infinite point on the jacobi quartic"""
        if random.getrandbits(1)==0:
            return JacobiQuartic(1,1,0,check=False)
        else:
            return JacobiQuartic(1,-1,0,check=False)

    def re_z(self):
        """Scales the projective point by a random scalar z """
        """(which doesn't essentially change the point)."""
        w = fe_random()
        return JacobiQuartic(self._sz*w, self._tz2*w*w, self._z*w, check=False)

    def point(self):
        sz,tz2,z = self._sz,self._tz2,self._z
        _2szzmagic = (2*sz*z*magic)%q
        z2 = pow(z,2,q)
        sz_2 = pow(sz,2,q)

        X = _2szzmagic * ( z2 + sz_2 )
        Y = tz2 * ( z2 - sz_2 )
        Z = tz2 * ( z2 + sz_2 )
        T = _2szzmagic * (z2 - sz_2 )

        return Point(X,Y,Z,T)

    def refpoint(self):
        sz,tz2,z = self._sz,self._tz2,self._z
        x = (2*sz*z*magic * fe_inv(tz2)) % q  # tz^2 will never be 0
        y = ((z*z - sz*sz) * fe_inv(z*z + sz*sz)) % q
        #                       \_ z^2 and -(sz)^2 will never be equal
        return ReferencePoint(x, y, check=False)

    def _refpoint_st(self):
        s,t = self.st()
        x = (2*s*magic * fe_inv(t)) % q  # t will never be 0
        y = ((1 - s*s) * fe_inv(1 + s*s)) % q
        #                       \_ 1 and -s^2 will never be equal
        return ReferencePoint(x, y, check=False)

    def is_exactly(self, other):
        if self._z == 0:
            if other._z != 0:
                return False
            return (self._sz**2 * other._tz2
                    - other._sz**2 * self._tz2) % q == 0
        return ( (self._sz * other._z - other._sz * self._z)%q==0 ) \
                and ( (self._tz2 * other._z**2 - other._tz2 * self._z**2)%q==0 )

    def _is_exactly_st(self, other):
        if self._z == 0:
            if other._z != 0:
                return False
            return (self._sz**2 * other._tz2
                    - other._sz**2 * self._tz2) % q == 0
        s1,t1 = self.st()
        s2,t2 = other.st()
        return (s1==s2) and (t1==t2)

    def dual(self):
        return JacobiQuartic(-self._sz, -self._tz2, self._z, check=False)

    def is_exactly_or_dual(self, other):
        return self.is_exactly(other) or self.is_exactly(other.dual())

    def equivalence_class(self):
        for a in self._equivalence_class_part():
            yield a
        for a in (self+JacobiQuartic(1, fe_sqrt(486664), check=False))\
                ._equivalence_class_part():
            yield a

    def _equivalence_class_part(self):
        sz,tz2,z = self._sz,self._tz2,self._z
        yield self.Copy()
        yield JacobiQuartic( -sz, -tz2, z, check=False)
        yield JacobiQuartic( z, -tz2, sz, check=False)
        yield JacobiQuartic( -z, tz2, sz, check=False)

    def __eq__(self, other):
        for a in self.equivalence_class():
            if a.is_exactly(other):
                return True
        return False

    def __repr__(self):
        return f"JacobiQuartic({self._sz}, {self._tz2}, {self._z})"

    def __add__(self, other):
        sz_1, tz2_1, z_1 = self._sz, self._tz2, self._z
        sz_2, tz2_2, z_2 = other._sz, other._tz2, other._z

        z = (pow(z_1,2,q)*pow(z_2,2,q) - pow(sz_1,2,q)*pow(sz_2,2,q) )%q
        s = ( sz_1*z_1*tz2_2 + sz_2*z_2*tz2_1 )%q
        t = ( (tz2_1*tz2_2 + 2*a_quartic*z_1*z_2*sz_1*sz_2)
            * ( pow(z_1,2,q)*pow(z_2,2,q) + pow(sz_1,2,q)*pow(sz_2,2,q) )
            + 2*z_1*z_2*sz_1*sz_2
                * ( pow(sz_1,2,q)*pow(z_2,2,q) + pow(sz_2,2,q)*pow(z_1,2,q) )
            )%q

        return JacobiQuartic(s,t,z,check=False)

    def _add_st(self, other):
        s1,t1 = self.st()
        s2,t2 = other.st()

        den = fe_inv( 1 - pow(s1,2,q)*pow(s2,2,q) )

        s3 = ( (s1*t2 + t1*s2) * den ) % q
        t3 = ( ( (t1*t2+2*a_quartic*s1*s2)*(1+ s1*s1*s2*s2) \
                + 2*s1*s2*(s1*s1+s2*s2) ) * den*den ) % q

        return JacobiQuartic(s3,t3,check=False)

    def __neg__(self):
        return JacobiQuartic(-self._sz,self._tz2,self._z,check=False)

    def __sub__(self,other):
        return self+(-other)

    @staticmethod
    def Zero():
        return JacobiQuartic(0,1,check=False)

    @staticmethod
    def elligator2(x):
        """Provides an injection from the positive scalars below q """
        """to the points of the JacobiQuartic."""
        """Further, elligator(x)=elligator(-x)"""
        r = (i * x * x) % q
        if (d+r)%q==0:
            return JacobiQuartic(0,1,check=False)
        den = fe_inv(((d * r + 1) * (-d - r)) % q)
        n1 = -(r + 1) * (-1 + d) * (d + 1) * den
        n2 = r * n1
        try:
            s, t = fe_sqrt(n1), (-(r-1)*(-1 + d)**2 * den - 1) %q
            # s will be positive
        except NotASquare:
            s, t = -fe_sqrt(n2) % q, (r*(r-1)*(-1 + d)**2 * den - 1) %q
            # s is negative
        return JacobiQuartic(s,t,check=False)

    def _elligator2_inv_slow(self):
        """Returns positive x such that self=elligator2(x)=elligator2(-x)
        if it exists; otherwise throws NoPreimage."""
        try:
            s,t = self.st()
        except Infinite:
            raise NoPreimage()

        if s==0:
            # now either t=1 or t=-1
            if t==1:
                return fe_sqrt(i*d)
            else:
                assert(q-t==1)
                return 0

        # b will be +- (r-1)/(r+1) depending on the sign of s
        b = ( ((t+1)*(d+1)) * fe_inv(s*s*(d-1)) ) % q
        if not fe_is_positive(s):
            b = q - b

        r = ( -(b+1) * fe_inv((b-1)%q) ) % q # b won't be 1

        try:
            return fe_sqrt(-i * r)
        except NotASquare:
            raise NoPreimage()

    def elligator2_inv(self, s_is_positive=None):
        """Returns positive x such that self=elligator2(x)=elligator2(-x)
        if it exists; otherwise throws NoPreimage."""
        sz,tz2,z = self._sz, self._tz2, self._z
        z2 = pow(z,2,q)

        if z==0:
            raise NoPreimage()
        if sz==0:
            if tz2==z2: # that is, t=1
                return fe_sqrt(i*d)
            else:
                assert( (tz2+z2)%q==0 ) # that is, t=-1
                return 0

        sz_2 = pow(sz,2,q)
        a = ( tz2+z2 ) * (d+1)*fe_inv(d-1)
        a2 = pow(a,2,q)
        sz_4 = pow(sz,4,q)
        try:
            y =  fe_inv(fe_sqrt( i* (sz_4 - a2)))
        except NotASquare:
            raise NoPreimage()

        if s_is_positive==None:
            s = ( fe_inv(z)*sz ) % q
            s_is_positive = fe_is_positive(s)

        if s_is_positive:
            x = ( y * (a+sz_2) ) % q
        else:
            x = ( y * (a-sz_2) ) % q

        if fe_is_positive(x):
            return x
        else:
            return q-x

class Error(Exception):
    pass

class NoPreimage(Error):
    pass

class DivisionByZero(Error):
    """raised by fe_inv and scalar_inv"""
    pass

class NotASquare(Error):
    pass

class Invalid(Error):
    pass

class Infinite(Error):
    pass

class InvalidPoint(Invalid):
    pass

class NotOnCurve(InvalidPoint):
    pass

class Odd(InvalidPoint):
    pass

class InvalidEncoding(Invalid):
    pass

class InvalidRepresentative(InvalidEncoding):
    pass

class SIsNegative(InvalidEncoding):
    pass

# the base ReferencePoint
ReferencePoint.Zero = ReferencePoint(0,1, check=False)
ReferencePoint.B = ReferencePoint.from_y_and_sign(
        4*fe_inv(5), True, check=False)
ReferencePoint.B.normalize()

# faster implementation
class Point:
    @staticmethod
    def from_refpoint(a, Z=1):
        return Point(X=a.x*Z, Y=a.y*Z, Z=Z, T=a.x*a.y*Z)

    @staticmethod
    def random():
        return Point.from_refpoint(ReferencePoint.random(),Z=fe_random())

    @staticmethod
    def hash(data):
        return Point.from_refpoint(ReferencePoint.hash(data))

    def __init__(self, X, Y, Z, T):
        # TODO: what should we make of the case that Z=0?
        self.X = X % q
        self.Y = Y % q
        self.Z = Z % q
        self.T = T % q

    def Copy(self):
        return Point(X=self.X, Y=self.Y, Z=self.Z, T=self.T)

    def __repr__(self):
        return f"Point({self.X}, {self.Y}, {self.Z}, {self.T})"

    def __iadd__(self, other):
        if not isinstance(other, Point):
            return NotImplemented

        A = (self.X * other.X)%q
        B = (self.Y * other.Y)%q
        C = (d * (self.T * other.T)%q)%q
        D = (self.Z * other.Z)%q
        E = ( (self.X + self.Y)%q ) * ( (other.X + other.Y)%q )
        E = (E-A-B)%q
        F = (D-C)%q
        G = (D+C)%q
        H = (B+A)%q

        self.X=E*F
        self.Y=G*H
        self.Z=F*G
        self.T=E*H
        return self

    def __add__(self, other):
        result = self.Copy()
        result.__iadd__(other)
        return result

    def __neg__(self):
        return Point(X=-self.X,Y=self.Y,T=-self.T,Z=self.Z)

    def __sub__(self, other):
        return self + -other

    def double_in_place(self):
        A = (self.X * self.X)%q
        B = (self.Y * self.Y)%q
        C = (2 * self.Z * self.Z)%q
        D = -A
        E = (self.X + self.Y)%q
        E = (E*E)%q
        E = (E - A - B)%q
        G = (D+B)%q
        F = (G-C)%q
        H = (D-B)%q

        self.X=E*F
        self.Y=G*H
        self.T=E*H
        self.Z=F*G

        return self

    def double(self):
        result = self.Copy()
        result.double_in_place()
        return result

    def __mul__(self, other):
        return double_and_add_multiplication(self, other, Point.Zero())

    def equivalence_class(self):
        # doesn't include the odd points
        X,Y,Z,T = self.X,self.Y,self.Z,self.T
        yield self.Copy()
        yield Point(X,Y,-Z,T)
        yield Point(Y,X,i*Z,-T)
        yield Point(Y,X,-i*Z,-T)

    def is_exactly(self, other):
        return ( self.X*other.Z - other.X*self.Z )%q==0 and \
                ( self.Y*other.Z - other.Y*self.Z )%q==0

    def __eq__(self, other):
        if not isinstance(other, Point):
            return NotImplemented
        return (self.X*other.Y - other.X*self.Y)%q==0 or \
                (self.X*other.X - self.Y*other.Y)%q==0

    def is_zero(self):
        return self.X==0 or self.Y==0

    def refpoint(self):
        zinv = fe_inv(self.Z)
        return ReferencePoint(self.X * zinv, self.Y * zinv,check=False)

    @staticmethod
    def unpack(data):
        return Point.from_refpoint(ReferencePoint.unpack(data))

    def pack(self):
        return self.refpoint().pack()

    @staticmethod
    def B_times(scalar):
        scalar %= l
        result = Point.Zero()
        i = 0

        while(scalar>0):
            if scalar&1==1:
                result += Point.B_times_two_to_the_power[i]

            scalar >>= 1
            i += 1

        return result

    # since B is passed by-reference, and "+=" is implemented in place,
    # code like
    #
    #   result = self.Point.B
    #   result += result
    #
    # will change the value of B, which is undesirable.
    @staticmethod
    def B():
        return Point._B.Copy()

    @staticmethod
    def Zero():
        return Point._Zero.Copy()

    def jacobi_quartic(self):
        X,Y,Z = self.X, self.Y, self.Z
        if X==0:
            # Y/Z is now either +1 or -1
            if Y==Z:
                return JacobiQuartic(0,1,check=False)
            elif Y==q-Z:
                return JacobiQuartic(1,1,0,check=False)
            else:
                assert(False)

        z = ( fe_sqrt(pow(Z,2,q)-pow(Y,2,q))*X ) % q
        sz = ( (Z-Y)*X ) % q
        tz2 = ( 2*z*Z*(Z-Y)*magic ) % q

        return JacobiQuartic(sz, tz2, z, # check=False
                )

    def four_finite_jacobi_quartics(self):
        """computes the (up to dual) four jacobi quartics associated"""
        """ to this point"""
        X,Y,Z = self.X, self.Y, self.Z
        if X==0 or Y==0:
            yield JacobiQuartic(0,1,check=False)
            yield JacobiQuartic(1,2*magic*i, check=False)
            yield JacobiQuartic(-1,2*magic*i, check=False)
            return

        gamma = fe_inv(fe_sqrt( pow(Y,4,q) * pow(X,2,q) \
                    * (pow(Z,2,q)-pow(Y,2,q))))

        den = gamma*pow(Y,2,q)
        s_X_inv = ( den * (Z-Y) ) % q
        s = (s_X_inv * X) % q
        t = (2*magic*s_X_inv*Z) % q
        sp_Xp_inv = ( den * (Z+Y) ) % q
        sp = (- sp_Xp_inv * X) % q
        tp = (2*magic*sp_Xp_inv*Z) % q

        yield JacobiQuartic(s, t, check=False)
        yield JacobiQuartic(sp, tp, check=False)

        den = fe_inv(fe_sqrt(1+d)) * (pow(Y,2,q)-pow(Z,2,q)) * gamma
        X,Y,Z = Y,X,(i*Z)%q
        s_X_inv = ( den * (Z-Y) ) % q
        s = (s_X_inv * X) % q
        t = (2*magic*s_X_inv*Z) % q
        sp_Xp_inv = ( den * (Z+Y) ) % q
        sp = (- sp_Xp_inv * X) % q
        tp = (2*magic*sp_Xp_inv*Z) % q

        yield JacobiQuartic(s, t, check=False)
        yield JacobiQuartic(sp, tp, check=False)

    @staticmethod
    def elligator2(x):
        return JacobiQuartic.elligator2(x).point()

    def elligator2_inv(self):
        for jc in self.four_finite_jacobi_quartics():
            assert(jc._z==1)
            s_is_positive = fe_is_positive( jc._sz )
            try:
                yield jc.elligator2_inv(s_is_positive)
            except NoPreimage:
                pass
            try:
                yield jc.dual().elligator2_inv(not s_is_positive)
            except NoPreimage:
                pass

    def elligator2_inv_old(self):
        """returns all positive x for which elligator2(x)=elligator2(-x)=self"""
        for b in self.equivalence_class():
            jc = b.jacobi_quartic()
            if jc._z==0: # the result of elligator2 is always finite
                continue
            s_is_positive = fe_is_positive( fe_inv(jc._z)*jc._sz )
            try:
                yield jc.elligator2_inv(s_is_positive)
            except NoPreimage:
                pass
            try:
                yield jc.dual().elligator2_inv(not s_is_positive)
            except NoPreimage:
                pass

    @staticmethod
    def lizard(payload, N=16):
        """provides what is in all probability an injection from """
        """the bytes of length 16 to points on the edwards curve"""
        assert(len(payload)==N)
        assert( N<=30 and N%2==0 )
        return Point.elligator2(fe_unpack(
                lizard_without_elligator(payload, N=N)))

    def lizard_inv(self, N=16):
        assert( N<=30 and N%2==0 )
        for x in self.elligator2_inv():
            data = fe_pack(x)
            payload = data[ 16-N//2 : 16+N//2 ]
            data_hash = bytearray(common.sha256(payload))

            data_hash[0]  &= 0b11111110
            data_hash[31] &= 0b00111111

            if data[:16-N//2]==data_hash[:16-N//2] \
                    and data[16+N//2:]==data_hash[16+N//2:]:
                return payload
        raise NoPreimage()

def lizard_without_elligator(payload, N=16):
    assert( N<=30 and N%2==0 )
    assert(len(payload)==N)
    data = bytearray(common.sha256(payload))
    data[ 16-N//2 : 16+N//2 ] = payload
    data[0] &= 0b11111110
    data[31] &= 0b00111111
    return bytes(data)

Point._Zero = Point.from_refpoint(ReferencePoint.Zero)
Point._B = Point.from_refpoint(ReferencePoint.B)

def double_and_add_multiplication(self, other, zero):
    if not isinstance(other, int):
        return NotImplemented
    other %= 8*l
    result = zero
    power_of_two_times_self = self.Copy()

    while(other>0):
        if other&1==1:
            result += power_of_two_times_self

        power_of_two_times_self.double_in_place()
        other >>= 1

    return result

# TODO: hardcode these values
Point.B_times_two_to_the_power = []
_tmp = Point.B()
for _some_name_not_i in range(253):
    Point.B_times_two_to_the_power.append(_tmp)
    _tmp = _tmp.double()
del _tmp


import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics as ep
import csv
import numpy as np
import math
from geneticalgorithm import geneticalgorithm as ga
from sklearn.metrics import mean_squared_error

days =113
n = 500
beta = 0.3
gamma = 0.3
g = nx.erdos_renyi_graph(n, 0.5)
a = int()

# Model selection
SIRModel = ep.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', beta)
cfg.add_model_parameter('gamma', gamma)
cfg.add_model_parameter("fraction_infected", 0.3)
SIRModel.set_initial_status(cfg)

# Ready CSV
arq = open("casos_sj.csv")
sirSjCsv = csv.DictReader(arq,fieldnames = ["S","R","I"])

matriz_gerada = np.zeros((days,3), dtype = np.int)
sirSj = list()
sirS = list()
sirI = list()
sirR = list()
Igerado = list()
Rgerado = list()
i = 0

for row in sirSjCsv:
    sirSj.insert(i, { "S": int(row['S']), "I": int(row['I']), "R" : int(row['R'])})
    sirS.append(int(row['S']))
    sirI.append(int(row['I']))
    sirR.append(int(row['R']))
    i+=1

#print(sirSj)
data = sirSj

#print(data[0]['I'])

varbound=np.array([[0,1]]*2)

def fitness(x):
    SIRModel.reset()
    cfg.add_model_parameter('beta', x[0])
    cfg.add_model_parameter('gamma', x[1])
    SIRModel.set_initial_status(cfg)
    iterations = SIRModel.iteration_bunch(days)
    print(iterations)
    a = 0
    Igerado.clear()
    Rgerado.clear()
    for x in iterations:
        matriz_gerada[a][0] = x['node_count'][0]
        matriz_gerada[a][1] = x['node_count'][1]
        matriz_gerada[a][2] = x['node_count'][2]
        Igerado.append(x['node_count'][1])
        Rgerado.append(x['node_count'][2])
        a = a + 1

    print(matriz_gerada)
    print(Igerado)
    print(iterations)

    mseI = mean_squared_error(sirI, Igerado)
    mseR = mean_squared_error(sirR, Rgerado)
    rmseI = math.sqrt(mseI)
    rmseR = math.sqrt(mseR)
    f = (rmseI + rmseR) / 2
    return f

GaModel= ga(function= fitness,dimension=2,variable_type='real',variable_boundaries=varbound)

GaModel.run()


"""
座右铭:如果现在的生活不是你想要的,那就是你自找的.
@project:yuke
@author:Si_jin_hui
@file:Spider.PY
@ide:PyCharm
@time:2018-08-17 10:46:15
"""
from bs4 import BeautifulSoup
import requests

import sqlite3

class DBManger(object):
    connect = None
    cursor = None
    @classmethod
    def create_connect_and_cursor(cls):
        cls.connect = sqlite3.connect('kanshu.db')
        cls.cursor = cls.connect.cursor()
    @classmethod
    def create_table(cls):
        cls.cursor.execute(
            "create table if not exists paihang(id integer primary key unique, paiming text, fenlei text, shuming text, lianjie text, zuozhe text, zongzishu text, gengxin text, souquan text, jincheng text, zongdianji text, benyuedianji text)")
    @classmethod
    def insert_data(cls,result):
        cls.cursor.execute("insert into paihang(paiming,fenlei,shuming,lianjie,zuozhe,zongzishu,gengxin,souquan,jincheng,zongdianji,benyuedianji)VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')" % (result["paiming"], result["fenlei"], result["shuming"], result["lianjie"], result["zuozhe"], result["zongzishu"],result["gengxin"],result["souquan"],result["jincheng"],result["zongdianji"],result["benyuedianji"]))
    @classmethod
    def close(cls):
        cls.connect.commit()
        cls.cursor.close()
        cls.connect.close()

class Spider(object):
    def __init__(self):
        self.proxies = {"http":"http://175.155.24.17:808"}
        self.headers = {"User-Agent":"Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11",}
        self.session = requests.session()
        self.result_list = []

    def get_book_name(self):
        base_url = "http://top.kanshu.com/list_7_1.html"
        # abs_url = "http://top.kanshu.com/more/list_7_1.html?is_ajax=1&page=3&timeType=week&big_id=7"

        for i in range(1,7):
            params = {
                "is_ajax": "1",
                "page": i,
                "timeType": "week",
                "big_id": "7"
            }
            try:
                response = requests.get(url=base_url,params=params,headers=self.headers).json()
            except Exception as e:
                print("连接失败,原因: ", e)
            else:
                html = response['result']['data']['html']
                bs_soup = BeautifulSoup(html,"lxml")

                paiming = bs_soup.select("li .sp_01")
                fenlei =  bs_soup.select("li .sp_02")
                shuming = bs_soup.select("li .sp_03 a ")
                zuozhe =  bs_soup.select("li .sp_04")
                # dianji =  bs_soup.select("li .sp_05")
                zongzishu = bs_soup.select("li .sp_06")
                gengxin = bs_soup.select("li .sp_07")
                for i in range(0,len(shuming)):
                    result = {"paiming":paiming[i].string,"fenlei":fenlei[i].string,"shuming":shuming[i].string,"lianjie":shuming[i]["href"],"zuozhe":zuozhe[i].string,"zongzishu":zongzishu[i].string,"gengxin":gengxin[i].string}
                    self.result_list.append(result)

    # 定义一个函数获取子链接的内容,并将数据添加到子字典当中
    def get_info(self):
        for result_num in range(0, len(self.result_list)):
            url = self.result_list[result_num]['lianjie']

            try:
                print("正在请求子网页,url = ",url)
                response = requests.get(url,headers=self.headers).content
            except Exception as e:
                print("子网页连接错误,原因: ", e)
            else:
                bs_soup = BeautifulSoup(response,'lxml')
                result_info = bs_soup.select("#main1 .xx_xinx li .org")
                print("result_num=====",result_num)
                try:
                    self.result_list[result_num].setdefault("souquan",result_info[1].string)
                    self.result_list[result_num].setdefault('jincheng',result_info[2].string)
                    self.result_list[result_num].setdefault('zongdianji',result_info[4].string)
                    self.result_list[result_num].setdefault('benyuedianji',result_info[5].string)
                except Exception as e:
                    print("错误原因:  ", e)
                else:
                    DBManger.create_connect_and_cursor()
                    DBManger.insert_data(self.result_list[result_num])
                    DBManger.close()
                # 数据保存成功

if __name__ == '__main__':
    spider = Spider()

    DBManger.create_connect_and_cursor()
    DBManger.create_table()

    spider.get_book_name()
    spider.get_info()

    # DBManger.close()
    # spider.save_data()


from django.shortcuts import render, get_object_or_404

from django.http import HttpResponse

from .models import StudySpace

def index(request):
    """
    The index page should show a list of study spaces available across all
    departments
    """
    study_space_list = StudySpace.objects.order_by('-department')
    context = {'study_space_list': study_space_list}
    return render(request, 'StudySpaceFinderApp/index.html', context)

def study_space_page(request, slug):
    """
    The Study Space Page should show some more information about a
    specific study space
    """
    study_space = get_object_or_404(StudySpace, slug=slug)
    return render(request, 'StudySpaceFinderApp/study_space_detail.html', {'study_space': study_space})