Comis Project Website logo Comis Project Website

As described in the "Method" section, the calibration process is applied with a bottom-up approach. The process start with the calibration of each components then by the calibration of the whole system. The script needed for the system calibration is given below.

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 12 09:35:40 2017

@author: wthomare
"""
import buildingspy.simulate.Simulator as si
import numpy  as np
from buildingspy.io.outputfile import Reader
import pandas as pd
import os
import shutil
import copy

parametres=[]
parametres = {'kPipe':[0.036,0.044],
              'kTank':[0.036,0.044],
              'lesThrTRoo.threshold':[273.15+16,273.15+20],
              'mixingCircuit_Tset.KvReturn':[40,60],
              'TSup_nominal':[42,47],
              'TRet_Min':[58,62]}

order =['kPipe','kTank','lesThrTRoo.threshold','mixingCircuit_Tset.KvReturn','TSup_nominal','TRet_Min']

centroide_initial = [0.5] * len(parametres.items())
initial_guess = np.array(centroide_initial)

line     = []
expected = []
saw      = []
cont     = True

while cont == True:
    try:
        mesures = pd.read_table(os.path.join("//media","wthomare","DONNEES","comis","FBM","Utilities","Tutorial","FirstTutorial.txt"), skiprows=line)

        CPT_tags = u"integrator"
        t_tags    = u"t(s)"

        cont = False
        t_mesure    = np.array(mesures[t_tags])
        CPT_mesure = np.column_stack(mesures[CPT_tags])

        t0 = 0
        TSimulation = 604800
        cut = np.flatnonzero(t_mesure == TSimulation)+1
        CPT_mesure = CPT_mesure[:,range(cut)]

        t_mesure  = t_mesure[:cut]

        N = len(t_mesure)
        C = 1
        resol_CPT  = [0.1] * C
        w_CPT = 1. / np.array(resol_CPT)**2

    except Exception as e:
        errortype = e.message.split('.')[0].strip()
        if errortype == u"Error tokenizing data":
            cerror      = e.message.split(':')[1].strip().replace(',','')
            nums        = [n for n in cerror.split(' ') if str.isdigit(n)]
            expected.append(int(nums[0]))
            saw.append(int(nums[2]))
            line.append(int(nums[1])-1)
        else:
            cerror      = u"Unknown"
            print u"Unknown Error - 222"

model = u"Comis.Helios.Validation.ValidationPan"
s = si.Simulator(model,u"dymola",u"case", packagePath="//home//wthomare//Bureau//NouveauDossier")
s.setStopTime(TSimulation)
s.setSolver('dassl')
s.translate()
s1=copy.deepcopy(s)

def simulateCase(s):
    s.setStartTime(t0)
    s.setStopTime(TSimulation)
    s.setTimeOut(600)
    s.showProgressBar(False)
    s.printModelAndTime()
    s.simulate_translated()

def evaluation(individual):

	p = [ parametres[order[_]][0] + individual[_]*(parametres[order[_]][1]-parametres[order[_]][0]) for _ in range(len(order))]

	s1.setOutputDirectory('//media//wthomare//DONNEES//FyPy//case %d %d %d %d %d' % (100*p[0],100*p[1],100*p[2],100*p[3],100*p[4]))
	s1.addParameters({"kPipe":p[0]})
	s1.addParameters({"kTank":p[1]})
	s1.addParameters({"lesThrTRoo.threshold":p[2]})
  s1.addParameters({"'mixingCircuit_Tset.KvReturn'":p[3]})
  s1.addParameters({u"TSup_nominal":p[i,4]})
  s1.addParameters({u"TRet_Min":p[i,5]})
 	simulateCase(s1)

	if not os.path.exists(os.path.join("//media","wthomare","DONNEES","FyPy",'case %d %d %d %d %d' % (100*p[0],100*p[1],100*p[2],100*p[3],100*p[4]),u"FirstTuto.mat")):

	 print u"no file"
	 return (np.inf, )

	else:

	 resultFile = os.path.join("//media","wthomare","DONNEES","FyPy",'case %d %d %d %d %d' % (100*p[0],100*p[1],100*p[2],100*p[3],100*p[4]),u"FirstTuto.mat")
	 r=Reader(resultFile, u"dymola")

	 (t2,CPT_Calculer)=r.values("integrator.y")

	 CPT_calcul = np.column_stack ((t2,CPT_Calculer))
	 CPT_Init    = np.array([[0,0]])
	 CPT_Init[[0,0]] = CPT_calcul[[0,0]]

	 index=np.zeros((len(CPT_calcul)),dtype='i')

	 for i in range(len(CPT_calcul)):
          if CPT_calcul[i][0] in t_mesure:
              index [i]=i

	 CPT_calcul = CPT_calcul[index]

	 CPT_calcul =CPT_calcul[~(CPT_calcul[:,0] == 0)]

	 CPT_calcul = CPT_calcul[0:len(CPT_calcul):2]
	 CPT_calcul =  np.concatenate((CPT_Init,CPT_calcul), axis=0)

	 CPT_calcul = np.delete(CPT_calcul,(0), axis = 1)
	 CPT_calculbis = np.transpose(CPT_calcul)

	 CPT_mesurebis = np.transpose(CPT_mesure)

	 if  (len(CPT_mesurebis) == len(CPT_calcul)) :

          mc_CPT  = 1./N * np.sum( (CPT_mesure  - CPT_calculbis)**2, axis=0 )
          R_CPT  = 1./C * np.sum( w_CPT * mc_CPT )

          alpha = 0
          normX = np.sum( (np.array(individual)-initial_guess)**2 ) / len(individual)
          shutil.rmtree('//media//wthomare//DONNEES//FyPy//case %d %d %d %d %d' % (100*p[0],100*p[1],100*p[2],100*p[3],100*p[4]))

          return (R_CPT + alpha*normX, )

	 else :
          shutil.rmtree('//media//wthomare//DONNEES//FyPy//case %d %d %d %d %d' % (100*p[0],100*p[1],100*p[2],100*p[3],100*p[4]))
          return (np.inf, )

from deap import creator, base, tools, cma

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

toolbox = base.Toolbox()
toolbox.register("evaluate", evaluation)

def main():

    NGENMAX = 500
    NPOP = 12

    strategy = cma.Strategy(centroide_initial, sigma=0.3, lambda_=NPOP)
    toolbox.register(u"generate", strategy.generate, creator.Individual)
    toolbox.register(u"update", strategy.update)

    import multiprocessing
    pool = multiprocessing.Pool(processes=4)
    toolbox.register("map", pool.map)

    hof   = tools.HallOfFame(1)
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register(u"avg", np.mean, axis=0)
    stats.register(u"std", np.std, axis=0)
    stats.register(u"min", np.min, axis=0)
    stats.register(u"max", np.max, axis=0)
    hof_complet = np.zeros( (NGENMAX,len(centroide_initial)) )
    ecartypes   = np.zeros( (NGENMAX,len(centroide_initial)) )

    toutlemonde = np.zeros( (NGENMAX, NPOP, len(centroide_initial)) )
    touslesfits = np.zeros( (NGENMAX, NPOP) )

    column_names = [u"gen", u"evals"]
    if stats is not None:
        column_names += stats.functions.keys()
    logbook = tools.Logbook()
    logbook.header = column_names

    STOP = False
    gen = 0
    while not STOP:

        population = toolbox.generate()
        foo = np.array(population)
        ecartypes[gen] = np.abs( np.std(foo,axis=0) / np.mean(foo,axis=0) )
        toutlemonde[gen] = foo

        fitnesses = toolbox.map(toolbox.evaluate, population)
        k = 0
        for ind, fit in zip(population, fitnesses):
            ind.fitness.values = fit
            touslesfits[gen, k] = fit[0]
            k += 1

        hof.update(population)
        hof_complet[gen] = hof.items[0]
        toolbox.update(population)
        record = stats.compile(population)
        logbook.record(gen=gen, evals=len(population), **record)
        print(logbook.stream)

        gen +=1
        conv_paras   = np.max(ecartypes[gen-1]) < 1e-3
        conv_fitness = (record[u"std"][-1] / record[u"avg"][-1]) < 1e-5
        if (conv_paras and conv_fitness) or gen >= NGENMAX:
            STOP = True

    return logbook, ecartypes, toutlemonde, touslesfits, hof, hof_complet

if __name__ == "__main__":

    logbook, ecartypes, toutlemonde, touslesfits, hof, hof_complet = main()

    Ecartypes = ecartypes
    toutlemonde_2 = np.column_stack( [np.ravel(toutlemonde[:,:,_]) for _ in range(len(centroide_initial))] )
    OptGlobal = np.zeros_like(centroide_initial)
    OptParGen = np.zeros_like(hof_complet)
    ToutLeMonde = np.zeros_like(toutlemonde_2)
    for i in range(len(centroide_initial)):
        OptGlobal[i]     = parametres[order[i]][0] + hof.items[0][i]   *(parametres[order[i]][1]-parametres[order[i]][0])
        OptParGen[:,i]   = parametres[order[i]][0] + hof_complet[:,i]   *(parametres[order[i]][1]-parametres[order[i]][0])
        ToutLeMonde[:,i] = parametres[order[i]][0] + toutlemonde_2[:,i] *(parametres[order[i]][1]-parametres[order[i]][0])

    sigma_f = np.array( logbook.select(u"std") )
    minimum = np.array( logbook.select(u"min") )
    ngen = len(sigma_f)

    np.savetxt(u"CMA_bestfit.txt", OptGlobal)

    total = np.column_stack((sigma_f, minimum, OptParGen[:ngen], Ecartypes[:ngen]))
    np.savetxt(u"CMA_stats.txt", total)

    TousLesFits = np.ravel(touslesfits)
    np.savetxt(u"CMA_population.txt", np.column_stack((ToutLeMonde, TousLesFits)))
    normX = np.sum( (np.array(hof.items[0])-initial_guess)**2 ) / len(hof.items[0])
    print(normX)

The calibrations give following results :

Control and Monitoring control
Parameters name Calibrated value
Minimal temperature at the bottom of the tank 48,6°C
Minimal return temperature to the wood stove 61.3°C
Test to block boiler if room air temperature is sufficiently high 17.1°C
Wood stove parameters
Parameters name Calibrated value
Nominal Heating Power 5886 W
Nominal efficiency 0.86%
LHV of the wood 4.71 kWh/kg
Boiler pump and mixing circuit parameters
Parameters name Calibrated value
Thermal conductivity ( lambda/thickness) 0.08 / 4 cm
KV of the 3-Way valve 82 (m3/h.Bar)^(1/2)
Hot water Tank parameters
Parameters name Calibrated value
Thermal conductivity ( lambda/thickness) 0.04 / 0.10 cm

Results :

All parameters have change slowly from there nominal values but three are more outstanding :

The KV of the 3 way valve that controled the minimal return temperature to the stoove as increase of 60%. This may indicate that the valve controller fails to open/close the valve properly or that the installed model is oversized (or a mix ...). With a heat source wich risk to explose if the return temperature is not hot enough this can lead to a major problem ... The decrease of 6% of the LHV shows a poor stockage condition of the fuel (with an increase of the humidity of the wood) or initial characteristics not corresponding to wood pellet with a DIN + certification

Thermal conductivity are also strongly migrated to poorer values in terms of thermal insulation. However, thermal losses are difficult to analyze. Indeed, even if this indicates a poor performance of the systems, losses at these levels are often released within the building. It is, therefore, possible that the performance of the system is affected without the comfort in the building being so.

Calibration curve

However, we can see that the calibration don't give us a perfect adequacy between the measured on the calibrated model. This can be due to a too low number of simulations (500*12 in the previous script), too few parameters taken into account or any other sources of errors exposed in the other sections of the site. This doubt can be lifted by a conclusive validation phase