UNPKG

solar-scores

Version:

Compute scores for solar decathlon competition - Cali 2015

314 lines (270 loc) 9.16 kB
'use strict'; const clone = require('lodash.clone'); const moment = require('moment'); var periods = require('./periods').all; var periodsByDay = require('./periods').byDay; const oneByDay = require('./periods').oneByDay; exports.filterValues = function (arr, param) { // We expect defined values return arr.filter(function (val) { return val[param] !== null && val[param] !== undefined; }); }; exports.getSingleScoringFunction = function (fullPointThreshold, noPointThreshold) { const fraction = 1 / (fullPointThreshold - noPointThreshold); const constant = -fraction * noPointThreshold; if (fullPointThreshold < noPointThreshold) { return function (value) { if (value <= fullPointThreshold) return 1; if (value >= noPointThreshold) return 0; return value * fraction + constant; }; } else { return function (value) { if (value >= fullPointThreshold) return 1; if (value <= noPointThreshold) return 0; return value * fraction + constant; }; } }; exports.getDoubleScoringFunction = function (noPoint1, fullPointStart, fullPointEnd, noPoint2) { const fraction1 = 1 / (fullPointStart - noPoint1); const constant1 = -fraction1 * noPoint1; const fraction2 = 1 / (fullPointEnd - noPoint2); const constant2 = -fraction2 * noPoint2; return function (value) { if (value <= noPoint1 || value >= noPoint2) return 0; if (value >= fullPointStart && value <= fullPointEnd) return 1; if (value < fullPointStart) return value * fraction1 + constant1; if (value > fullPointEnd) return value * fraction2 + constant2; }; }; //exports.getResampledMax = function(series, resolution) { // if(series.length === 1) return series[0]; // //}; exports.getElapsedFraction = function (scoreType, date) { var now = date || new Date(); if (typeof scoreType === 'string') { var p = periods[scoreType]; } else { p = scoreType; } var elapsedDuration = 0; var totalDuration = 0; for (var i = 0; i < p.length; i++) { totalDuration += p[i].duration; if (now < p[i].begin) { continue; } else if (now < p[i].end) { elapsedDuration += moment.duration(moment(now).diff(p[i].begin)).asSeconds(); } else { elapsedDuration += p[i].duration; } } return elapsedDuration / totalDuration; }; exports.filterByEpoch = function (arr, scoreType) { var period; if (typeof scoreType === 'string') { period = periods[scoreType]; } else { period = scoreType; } if (period.length > 0) { arr = arr.filter(function (val) { return new Date(val.epoch) >= period[0].begin; }); } for (let i = 1; i < period.length; i++) { arr = arr.filter(function (val) { let e = new Date(val.epoch); return e <= period[i - 1].end || e >= period[i].begin; }); } if (period.length > 0) { arr = arr.filter(function (val) { return new Date(val.epoch) <= period[period.length - 1].end; }); } return arr; }; exports.filterByEpochPerDay = function (arr, scoreType) { var byDay; if (typeof scoreType === 'string') { byDay = periodsByDay[scoreType]; } else { byDay = scoreType; } //console.log(byDay[0].periods[0]); var byDay = clone(byDay, true); for (let i = 0; i < byDay.length; i++) { byDay[i].data = new Array(byDay[i].periods.length); for (let j = 0; j < byDay[i].periods.length; j++) { byDay[i].data[j] = exports.filterByEpoch(arr, [byDay[i].periods[j]]) } //byDay[i].data = exports.filterByEpoch(arr, byDay[i].periods); } return byDay; }; // Series must be asc // periods must be asc exports.resampleWithMax = function (series, params, scoreType, resolution) { // Resolution is 5 minutes var period; if (typeof scoreType === 'string') { period = periods[scoreType] } else { period = scoreType; } resolution = resolution || 60 * 5 * 1000; var semiRes = resolution / 2; var res1000 = resolution / 1000; let l = 0; let pl = new Array(period.length); for (let i = 0; i < period.length; i++) { pl[i] = Math.floor(period[i].duration / res1000) + 1; l += pl[i]; } var epochs = new Array(l); let count = 0; for (let i = 0; i < period.length; i++) { for (let j = 0; j < pl[i]; j++) { epochs[count] = period[i].begin.getTime() + j * resolution; count++; } } var result = epochs.map(function (epoch) { return { value: null, epoch: epoch }; }); // Series are assumed to be ordered asc for (let i = 0; i < series.length; i++) { let currentIdx = 0; for (let j = 0; j < series[i].length; j++) { let ediff; do { var diff = epochs[currentIdx] - series[i][j].epoch; ediff = Math.abs(diff); currentIdx++; } while ((ediff > semiRes) && (currentIdx < epochs.length) && diff < semiRes ); currentIdx = currentIdx - 1; if (ediff <= semiRes) { let newValue = series[i][j][params[i]]; if (result[currentIdx].value === null || result[currentIdx].value < newValue) { result[currentIdx].value = newValue; } } } } return result; }; exports.finalizeScores = function (byDay) { var result = { points: 0, max: 0, maxUntilNow: 0 }; var perDay = new Array(byDay.length); for (let i = 0; i < byDay.length; i++) { perDay[i] = {}; perDay[i].day = byDay[i].day; let l = byDay[i].periods.length; perDay[i].points = 0; perDay[i].maxUntilNow = 0; perDay[i].max = 0; for (let j = 0; j < l; j++) { perDay[i].max += byDay[i].periods[j].points; perDay[i].points += byDay[i].points[j]; perDay[i].maxUntilNow += byDay[i].maxUntilNow[j]; perDay[i].fraction = byDay[i].fraction[j]; } perDay[i].projected = perDay[i].points * (perDay[i].max / perDay[i].maxUntilNow); result.points += perDay[i].points; result.max += perDay[i].max; result.maxUntilNow += perDay[i].maxUntilNow; } result.projected = result.points * (result.max / result.maxUntilNow); result.perDay = perDay; return result; }; exports.interpolate = function (data) { var idx = 0; var last; while (idx < data.length) { while (data[idx] === null && idx < data.length) { idx++; } var lastIdx = (last || 0) + 1; if (last === undefined && data[0] === null) { for (let i = 0; i < idx; i++) { data[i] = data[idx] || null; } } else if ((data[idx] !== null && idx !== data.length) || (data[idx - 1] !== null && idx === data.length)) { var slope = (data[idx] - data[last]) / (idx - last); for (let i = lastIdx; i < idx; i++) { var a = i - lastIdx + 1; data[i] = data[last] + a * slope; } } else { for (let i = lastIdx; i < idx; i++) { data[i] = data[last]; } } last = idx; idx++; } return data; }; exports.average = function (data) { data = data.filter(function (val) { return val !== null; }); if (!data.length) return null; var avg = 0; for (let i = 0; i < data.length; i++) { avg += data[i]; } return avg / data.length; }; exports.diff = function (data) { if (data.length <= 1) return []; let diff = new Array(data.length - 1); for(let i=1; i<data.length; i++) { diff[i-1] = data[i] - data[i-1]; } return diff; }; exports.getRefTemperature = function (values, param, date) { // Each day we need to recalculate the periods var periods = []; for(let j=6; j>=0; j--) { periods.push({ begin: moment(date).add(-1*j-1, 'days').hours(6).minutes(0).seconds(0).toDate(), end: moment(date).add(-1*j-1, 'days').hours(18).minutes(0).seconds(0).toDate(), duration: 3600 * 12 }); } periods = oneByDay(periods); var extPerDay = exports.filterByEpochPerDay(values, periods); var extAvg = extPerDay.map(function(day) { var temp = day.data[0].map(function(val) { return val[param]; }); return exports.average(temp); }); var coefficients = [1, 0.8, 0.6, 0.5, 0.4, 0.3, 0.2]; var tMax = 0; var factor = 0; for(let i=0; i<coefficients.length; i++) { if(extAvg[i] !== null) { tMax += coefficients[i] * extAvg[i]; factor += coefficients[i]; } } tMax /= factor; tMax = 19.9 + 0.255 * tMax; return tMax; };