4HSXLC3CAM6KCESNNF3FF4BN5PUP3ZBFDDKLO7A2GO7NDINT3RIAC WIWZX2VC2HUKDT4HMQMCAZR5D2TPMR4VSNXCA65SZDDOELT23J6QC 56GM5G2QA5STMUGEGQSUOHJ33R46TUA5KUGQ7L47APXAZB3P6NSAC QWHL7S5MW7TZMJOBHNC22UU3FSH5CHL6LJ7VAZ5TTGOAWE22PB3AC VXUN2ELCS6FPZXKYXCACGUHLLS6M4SOS3BHSDWP3ZERFYSG3LHNQC 6OZI57U6GCISXB3AIS6FKNPYCVTU73Q6BOHDC3LKP5UMWRKDWXXAC BH23G7KVGRV5KI7T24OONO3BQGWIOOORIBGEJSZQ2MUECZNO6T3QC 6HLUKGVAXT4LRM3QIA5KGJ23KPFEWCF72QOYH7L2RDLVQH73ESDAC I7ZQ7SD37MTRJNRCUK5L52VUHJA6F5TU3VLO6MRMWRSYANG3X6UAC HHB3EDC2CAWBDMUYY2VQPJVDM5HRUDX5EECSSYHXYSO4AAZOUZXAC SMEDDJKY7PW7FWSG4QEWPAZBQK3SA3MK6JXG5XLF7MTPY23CBYIAC REQ25X7QQUEWPLPCEG6NOZXUEULXMTYD6WU4VSHASGSNFRMATAMQC 6NB2PU2F64XDSURKYMBECKEN7ZQ63RMDN2GL5CP74YA6HE4K3TTAC 7MCTB5G2W6IB7JQXGO2HCMRHBUYIOKXI4MBODKLAJIK66EMLC5ZQC 3O3IMVFKGSXMVLPLZR3H6MIG3EE5PS4632QE4JMK5SVX2PVSSKDAC FWV2VPFI3VIQXMY4LZ266AHP7PKBSKVMSJ6ERABTUFXCTFVEMFZQC P7KZ25R4CNS4PZITRWPBVXRFSLY5TKCOFO6U3SDKX45ITNVU773QC QHVOZBISIQ3E3P5F6GGKWVDSXC4OA23HCIH2OMXEVGXKSF5W4APAC E3CFBYSDSBRXG2USHXIFWSCDVFRYUDWJBPUFTEEB3ZPMN3NT6PIAC LX2ZVNAYX2FRCEIJ6XBCBILB3O7YT52AP56QDWCCGLATFCEB7KHQC 33TN2LIIJXVIE42DPWV7VZRGKF2RM4ELXGWAO36DER7CFSWIFKHAC O4ALNQWBOXUOZRVT6J7C64I4BNJMHIO44ZWNEWIOUBCLE2C7JBAQC 3WWWPCD6BDUHGDTIQHSVUSETNZCM56FYV5EDE2XIH3BNSXBUIKLQC C56DYYC72SFNR6BSKCOVDY2QW6XNP66EUGGKCBROTCFJVQDB4FUAC VNWG7QG3VM3JCF3QQ4OJAY2RFBKBWZ7JJNAISIP6YIIX6L2LGBUQC 5FNNIOUNDS5SG75A4ZR6VY7DS6WU2GNNCOSSHX34RFTRB7LJ3D2QC 2UH4OD6TI5TAIIV2N2HQ2MWAWGJ7IELMZIMHORKL2237ENT7V3AAC O63TXA57OHFIPUDT4QQBDVXRQA64CUIT7XU4G6MSQPMDRFJPM7IAC DB6B3MEDBTEEIS6KOSJH7L5JFXKDMATJARZ6AR7TF2HCCKTFRZJQC CALQZ74ABIY2S35P4EHAX6NY6G7YXCCVVUMTFGIWGYZQ45XFT7OQC UWD234SIIBCA45TXXSOSZEWLUF66NFPWET257C3WZQYX3L5EJPCAC PQXDAWT2RRUZ3YCV77U4VOHJ576MPY3OZEU6ZO4RV6UKWQKP3OUAC FWTPFLCKH6V2JGGALMTFH4YUZM7I6VL7PMC62QXP4VY2ZTH26E2QC O22SKNQ6LUA45DZ7QFM3RFAMC2X64WMRITU4N5K22CWNGHIYFLJAC KABVEJWT5CZRUR7DPBZHLMN75F4EEMKQF4BT57SV7XPO3USH42QQC 6NRS3ZPPZ6A42IEDMRLQ7LZ5TPPLFQ6AGYVS32TQRGHBIJQW4WBAC FHKSWRLS3UBAU6AMQTNZTCLKDUUJVMYRX6EUY5YDDHOITLQLQEFQC KNH5OGCTL3YCOQQPA32M76SGWHGHAPQRIZ7S2CBC5DGIEV32SOYQC XTPX4PYLPGJAEK52LYOYHLVRCL7N5FFAEY4E3OL23LOWLYPLCILQC FERLNXU2QISSKOUBSPABB2ERHOWHQRI2GVKDJ352Y4B2FUXBRGRQC AFTBFAXJMQ6SFDHO3X4725EQG64BVQYMTXRPFV6JO6IWCQSI5T3QC E6LXIE7VBUGCR762DFTHYZISEWYFV5E3NM3MGLT5Z7YFQQ5GTYRQC 5R7SS5AWSCPT4WWCS5WUBRFULLXATBZW4FFPBT6S5EYJVEWKL5NQC V3QTRVNR5EVDZ2O2WRK7ZCVKSGGYBSNILH44OWXKOJK2ME5JC7UQC CF23CLXE24SNMD7YLQ4OHNNVIRIK4FY25Z2Q5N42B7IDLINPE44QC PI6D6Y5EHSXHSILBYHKRKXWXZ6H6JOR5ZTP44CXBW4LUUIREY7OQC LU257USNNJW57H5M5E46IB2E3IBFNYBXB6EPEM63BYC23NNVHCFQC WFOI5DN6JBBPNX7T3RCENHAHMHSZMO6MNCSNH7276AYS2REGK23QC 64D3E3ZOPPF3UFDFYWGBCKS5NTBR34J27FGESDZSSYMUEPD5ZMLQC 5FPD6WH3Z6WVWVHWSU276I2JF7VRJZJB7GC76UY6MDRFJ7YGUMCQC RLLNOBJM5LB446HWBUNDLNMG35PTUFRBRRVNHMFTX7CMQC4JSXUQC FUATUEJRPVGPYL54DSQR5RCDD4FA6RN3GQQDYGUGOJSBV33JFI7AC UR5RFMWCD455OQZMTDQ2MSVJUPBNEUQHOBJ2UJBDWVHRJ4SOA5NAC 5B42RKMDCXT74BWXB7OVBMWVAEZAVFKV6T4I3KBESZIWSNQLPQCAC YLOKW6ERT2XEQG4T6GBPSBCQWVIHWAKBESCXJBKMQBSDXV3C2ACQC Y62XTAEHAC5MNJELNKACRLEVBUU2MKYKFPHB5M2S5X46B4EI2JJQC TLRGOVFX6KIWQSWRPXS73WW4EHJQ5L5W5NYMO6UM2EF2H3EPAHHQC GBEGPEQZPTMSSEHTK5MKHFYCA5ZFGYCYURMQGWC4SJSWIPHNSPHAC 5LXKHEZNPK7RBJ33RTHN4Q3V5OUTM4WXZ477UOHTA34RNBPUN5DAC 632SZPUQC6KX3CDZLYWV22OSFIOG66CJ7PONRNTXYTFLQX3JFFXQC UPEYNW7CF54F2XHS3SZ7NDZTFAUGJL4OJ6FHLKC7M6XLXL3M2L4QC GNIA6BK2TG2WOBCSLDBMX4MQ26YMFTIYQFH2XPSKWOBMWSUWOQIAC WXJSE2H5CZ4NAI5PAWGAZCAB2XCEO2LIJR2QCW3JAK7ZZGIHRJLQC WPNVVCX5GDWRL65VWBSU3B2JTBRHQL5DZZWG4Z6DUGIMILQYRHVQC J47EV2H73JKATJDKBZZNSIGAPC7G5X5DCWZ7YDN55XUNPYPS54TQC R5TAB7OOEDIU75AKTUZMU2PDNQTENUYQ3UMWDRVQF7SYHLHEEXKAC 5NKW4FOUZN2IXLASSQZVV5RE23ERNIEWK57IU6WW67WIN5NOD5DQC "use strict";export const SimulationCommunaute = validate10;const schema11 = {"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/Grain.SimulationCommunaute","definitions":{"Grain.SimulationCommunaute":{"type":"object","properties":{"puissance":{"type":"number"},"economies":{"type":"number"},"autoconso":{"type":"number"},"autoprod":{"type":"number"},"fraisDivers":{"type":"number"},"prix":{"type":"number"},"apport":{"type":"number"},"interet":{"type":"number"},"echeances":{"type":"number"},"consoMoyenneFoyer":{"type":"number"},"productible":{"type":"number"},"degradation":{"type":"number"},"inflation":{"type":"number"},"ratio":{"type":"number"},"enedis":{"type":"number"},"tarifCRE":{"type":"object","properties":{"limites":{"type":"array","items":{"type":"number"}},"prix":{"type":"array","items":{"type":"number"}},"inflation":{"type":"number"}},"required":["limites","prix","inflation"],"additionalProperties":false},"coutElec":{"type":"number"},"inflationElec":{"type":"number"},"maintenance":{"type":"number"},"turpe":{"type":"number"},"turpeInjection":{"type":"number"},"provisionOnduleurs":{"type":"number"},"assurance":{"type":"number"},"divers":{"type":"number"},"ratioDcAc":{"type":"number"},"dureeAmortissement":{"type":"number"},"tauxIS":{"type":"number"},"tauxDSRA":{"type":"number"}},"required":["puissance","autoconso","autoprod","fraisDivers","prix","apport","interet","echeances","consoMoyenneFoyer","productible","degradation","inflation","ratio","enedis","tarifCRE","coutElec","inflationElec","maintenance","turpe","turpeInjection","provisionOnduleurs","assurance","divers","ratioDcAc","dureeAmortissement","tauxIS","tauxDSRA"],"additionalProperties":false}},"$id":"#/definitions/SimulationCommunaute"};const schema12 = {"type":"object","properties":{"puissance":{"type":"number"},"economies":{"type":"number"},"autoconso":{"type":"number"},"autoprod":{"type":"number"},"fraisDivers":{"type":"number"},"prix":{"type":"number"},"apport":{"type":"number"},"interet":{"type":"number"},"echeances":{"type":"number"},"consoMoyenneFoyer":{"type":"number"},"productible":{"type":"number"},"degradation":{"type":"number"},"inflation":{"type":"number"},"ratio":{"type":"number"},"enedis":{"type":"number"},"tarifCRE":{"type":"object","properties":{"limites":{"type":"array","items":{"type":"number"}},"prix":{"type":"array","items":{"type":"number"}},"inflation":{"type":"number"}},"required":["limites","prix","inflation"],"additionalProperties":false},"coutElec":{"type":"number"},"inflationElec":{"type":"number"},"maintenance":{"type":"number"},"turpe":{"type":"number"},"turpeInjection":{"type":"number"},"provisionOnduleurs":{"type":"number"},"assurance":{"type":"number"},"divers":{"type":"number"},"ratioDcAc":{"type":"number"},"dureeAmortissement":{"type":"number"},"tauxIS":{"type":"number"},"tauxDSRA":{"type":"number"}},"required":["puissance","autoconso","autoprod","fraisDivers","prix","apport","interet","echeances","consoMoyenneFoyer","productible","degradation","inflation","ratio","enedis","tarifCRE","coutElec","inflationElec","maintenance","turpe","turpeInjection","provisionOnduleurs","assurance","divers","ratioDcAc","dureeAmortissement","tauxIS","tauxDSRA"],"additionalProperties":false};const func2 = Object.prototype.hasOwnProperty;function validate10(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){/*# sourceURL="#/definitions/SimulationCommunaute" */;let vErrors = null;let errors = 0;const _errs0 = errors;if(errors === _errs0){if(data && typeof data == "object" && !Array.isArray(data)){let missing0;if((((((((((((((((((((((((((((data.puissance === undefined) && (missing0 = "puissance")) || ((data.autoconso === undefined) && (missing0 = "autoconso"))) || ((data.autoprod === undefined) && (missing0 = "autoprod"))) || ((data.fraisDivers === undefined) && (missing0 = "fraisDivers"))) || ((data.prix === undefined) && (missing0 = "prix"))) || ((data.apport === undefined) && (missing0 = "apport"))) || ((data.interet === undefined) && (missing0 = "interet"))) || ((data.echeances === undefined) && (missing0 = "echeances"))) || ((data.consoMoyenneFoyer === undefined) && (missing0 = "consoMoyenneFoyer"))) || ((data.productible === undefined) && (missing0 = "productible"))) || ((data.degradation === undefined) && (missing0 = "degradation"))) || ((data.inflation === undefined) && (missing0 = "inflation"))) || ((data.ratio === undefined) && (missing0 = "ratio"))) || ((data.enedis === undefined) && (missing0 = "enedis"))) || ((data.tarifCRE === undefined) && (missing0 = "tarifCRE"))) || ((data.coutElec === undefined) && (missing0 = "coutElec"))) || ((data.inflationElec === undefined) && (missing0 = "inflationElec"))) || ((data.maintenance === undefined) && (missing0 = "maintenance"))) || ((data.turpe === undefined) && (missing0 = "turpe"))) || ((data.turpeInjection === undefined) && (missing0 = "turpeInjection"))) || ((data.provisionOnduleurs === undefined) && (missing0 = "provisionOnduleurs"))) || ((data.assurance === undefined) && (missing0 = "assurance"))) || ((data.divers === undefined) && (missing0 = "divers"))) || ((data.ratioDcAc === undefined) && (missing0 = "ratioDcAc"))) || ((data.dureeAmortissement === undefined) && (missing0 = "dureeAmortissement"))) || ((data.tauxIS === undefined) && (missing0 = "tauxIS"))) || ((data.tauxDSRA === undefined) && (missing0 = "tauxDSRA"))){validate10.errors = [{instancePath,schemaPath:"#/definitions/Grain.SimulationCommunaute/required",keyword:"required",params:{missingProperty: missing0},message:"must have required property '"+missing0+"'",schema:schema12.required,parentSchema:schema12,data}];return false;}else {const _errs2 = errors;for(const key0 in data){if(!(func2.call(schema12.properties, key0))){validate10.errors = [{instancePath,schemaPath:"#/definitions/Grain.SimulationCommunaute/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties",schema:false,parentSchema:schema12,data}];return false;break;}}if(_errs2 === errors){if(data.puissance !== undefined){let data0 = data.puissance;const _errs3 = errors;if(!((typeof data0 == "number") && (isFinite(data0)))){validate10.errors = [{instancePath:instancePath+"/puissance",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/puissance/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.puissance.type,parentSchema:schema12.properties.puissance,data:data0}];return false;}var valid1 = _errs3 === errors;}else {var valid1 = true;}if(valid1){if(data.economies !== undefined){let data1 = data.economies;const _errs5 = errors;if(!((typeof data1 == "number") && (isFinite(data1)))){validate10.errors = [{instancePath:instancePath+"/economies",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/economies/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.economies.type,parentSchema:schema12.properties.economies,data:data1}];return false;}var valid1 = _errs5 === errors;}else {var valid1 = true;}if(valid1){if(data.autoconso !== undefined){let data2 = data.autoconso;const _errs7 = errors;if(!((typeof data2 == "number") && (isFinite(data2)))){validate10.errors = [{instancePath:instancePath+"/autoconso",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/autoconso/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.autoconso.type,parentSchema:schema12.properties.autoconso,data:data2}];return false;}var valid1 = _errs7 === errors;}else {var valid1 = true;}if(valid1){if(data.autoprod !== undefined){let data3 = data.autoprod;const _errs9 = errors;if(!((typeof data3 == "number") && (isFinite(data3)))){validate10.errors = [{instancePath:instancePath+"/autoprod",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/autoprod/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.autoprod.type,parentSchema:schema12.properties.autoprod,data:data3}];return false;}var valid1 = _errs9 === errors;}else {var valid1 = true;}if(valid1){if(data.fraisDivers !== undefined){let data4 = data.fraisDivers;const _errs11 = errors;if(!((typeof data4 == "number") && (isFinite(data4)))){validate10.errors = [{instancePath:instancePath+"/fraisDivers",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/fraisDivers/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.fraisDivers.type,parentSchema:schema12.properties.fraisDivers,data:data4}];return false;}var valid1 = _errs11 === errors;}else {var valid1 = true;}if(valid1){if(data.prix !== undefined){let data5 = data.prix;const _errs13 = errors;if(!((typeof data5 == "number") && (isFinite(data5)))){validate10.errors = [{instancePath:instancePath+"/prix",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/prix/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.prix.type,parentSchema:schema12.properties.prix,data:data5}];return false;}var valid1 = _errs13 === errors;}else {var valid1 = true;}if(valid1){if(data.apport !== undefined){let data6 = data.apport;const _errs15 = errors;if(!((typeof data6 == "number") && (isFinite(data6)))){validate10.errors = [{instancePath:instancePath+"/apport",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/apport/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.apport.type,parentSchema:schema12.properties.apport,data:data6}];return false;}var valid1 = _errs15 === errors;}else {var valid1 = true;}if(valid1){if(data.interet !== undefined){let data7 = data.interet;const _errs17 = errors;if(!((typeof data7 == "number") && (isFinite(data7)))){validate10.errors = [{instancePath:instancePath+"/interet",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/interet/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.interet.type,parentSchema:schema12.properties.interet,data:data7}];return false;}var valid1 = _errs17 === errors;}else {var valid1 = true;}if(valid1){if(data.echeances !== undefined){let data8 = data.echeances;const _errs19 = errors;if(!((typeof data8 == "number") && (isFinite(data8)))){validate10.errors = [{instancePath:instancePath+"/echeances",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/echeances/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.echeances.type,parentSchema:schema12.properties.echeances,data:data8}];return false;}var valid1 = _errs19 === errors;}else {var valid1 = true;}if(valid1){if(data.consoMoyenneFoyer !== undefined){let data9 = data.consoMoyenneFoyer;const _errs21 = errors;if(!((typeof data9 == "number") && (isFinite(data9)))){validate10.errors = [{instancePath:instancePath+"/consoMoyenneFoyer",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/consoMoyenneFoyer/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.consoMoyenneFoyer.type,parentSchema:schema12.properties.consoMoyenneFoyer,data:data9}];return false;}var valid1 = _errs21 === errors;}else {var valid1 = true;}if(valid1){if(data.productible !== undefined){let data10 = data.productible;const _errs23 = errors;if(!((typeof data10 == "number") && (isFinite(data10)))){validate10.errors = [{instancePath:instancePath+"/productible",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/productible/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.productible.type,parentSchema:schema12.properties.productible,data:data10}];return false;}var valid1 = _errs23 === errors;}else {var valid1 = true;}if(valid1){if(data.degradation !== undefined){let data11 = data.degradation;const _errs25 = errors;if(!((typeof data11 == "number") && (isFinite(data11)))){validate10.errors = [{instancePath:instancePath+"/degradation",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/degradation/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.degradation.type,parentSchema:schema12.properties.degradation,data:data11}];return false;}var valid1 = _errs25 === errors;}else {var valid1 = true;}if(valid1){if(data.inflation !== undefined){let data12 = data.inflation;const _errs27 = errors;if(!((typeof data12 == "number") && (isFinite(data12)))){validate10.errors = [{instancePath:instancePath+"/inflation",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/inflation/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.inflation.type,parentSchema:schema12.properties.inflation,data:data12}];return false;}var valid1 = _errs27 === errors;}else {var valid1 = true;}if(valid1){if(data.ratio !== undefined){let data13 = data.ratio;const _errs29 = errors;if(!((typeof data13 == "number") && (isFinite(data13)))){validate10.errors = [{instancePath:instancePath+"/ratio",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/ratio/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.ratio.type,parentSchema:schema12.properties.ratio,data:data13}];return false;}var valid1 = _errs29 === errors;}else {var valid1 = true;}if(valid1){if(data.enedis !== undefined){let data14 = data.enedis;const _errs31 = errors;if(!((typeof data14 == "number") && (isFinite(data14)))){validate10.errors = [{instancePath:instancePath+"/enedis",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/enedis/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.enedis.type,parentSchema:schema12.properties.enedis,data:data14}];return false;}var valid1 = _errs31 === errors;}else {var valid1 = true;}if(valid1){if(data.tarifCRE !== undefined){let data15 = data.tarifCRE;const _errs33 = errors;if(errors === _errs33){if(data15 && typeof data15 == "object" && !Array.isArray(data15)){let missing1;if((((data15.limites === undefined) && (missing1 = "limites")) || ((data15.prix === undefined) && (missing1 = "prix"))) || ((data15.inflation === undefined) && (missing1 = "inflation"))){validate10.errors = [{instancePath:instancePath+"/tarifCRE",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'",schema:schema12.properties.tarifCRE.required,parentSchema:schema12.properties.tarifCRE,data:data15}];return false;}else {const _errs35 = errors;for(const key1 in data15){if(!(((key1 === "limites") || (key1 === "prix")) || (key1 === "inflation"))){validate10.errors = [{instancePath:instancePath+"/tarifCRE",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties",schema:false,parentSchema:schema12.properties.tarifCRE,data:data15}];return false;break;}}if(_errs35 === errors){if(data15.limites !== undefined){let data16 = data15.limites;const _errs36 = errors;if(errors === _errs36){if(Array.isArray(data16)){var valid3 = true;const len0 = data16.length;for(let i0=0; i0<len0; i0++){let data17 = data16[i0];const _errs38 = errors;if(!((typeof data17 == "number") && (isFinite(data17)))){validate10.errors = [{instancePath:instancePath+"/tarifCRE/limites/" + i0,schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/properties/limites/items/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.tarifCRE.properties.limites.items.type,parentSchema:schema12.properties.tarifCRE.properties.limites.items,data:data17}];return false;}var valid3 = _errs38 === errors;if(!valid3){break;}}}else {validate10.errors = [{instancePath:instancePath+"/tarifCRE/limites",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/properties/limites/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema12.properties.tarifCRE.properties.limites.type,parentSchema:schema12.properties.tarifCRE.properties.limites,data:data16}];return false;}}var valid2 = _errs36 === errors;}else {var valid2 = true;}if(valid2){if(data15.prix !== undefined){let data18 = data15.prix;const _errs40 = errors;if(errors === _errs40){if(Array.isArray(data18)){var valid4 = true;const len1 = data18.length;for(let i1=0; i1<len1; i1++){let data19 = data18[i1];const _errs42 = errors;if(!((typeof data19 == "number") && (isFinite(data19)))){validate10.errors = [{instancePath:instancePath+"/tarifCRE/prix/" + i1,schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/properties/prix/items/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.tarifCRE.properties.prix.items.type,parentSchema:schema12.properties.tarifCRE.properties.prix.items,data:data19}];return false;}var valid4 = _errs42 === errors;if(!valid4){break;}}}else {validate10.errors = [{instancePath:instancePath+"/tarifCRE/prix",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/properties/prix/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema12.properties.tarifCRE.properties.prix.type,parentSchema:schema12.properties.tarifCRE.properties.prix,data:data18}];return false;}}var valid2 = _errs40 === errors;}else {var valid2 = true;}if(valid2){if(data15.inflation !== undefined){let data20 = data15.inflation;const _errs44 = errors;if(!((typeof data20 == "number") && (isFinite(data20)))){validate10.errors = [{instancePath:instancePath+"/tarifCRE/inflation",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/properties/inflation/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.tarifCRE.properties.inflation.type,parentSchema:schema12.properties.tarifCRE.properties.inflation,data:data20}];return false;}var valid2 = _errs44 === errors;}else {var valid2 = true;}}}}}}else {validate10.errors = [{instancePath:instancePath+"/tarifCRE",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tarifCRE/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema12.properties.tarifCRE.type,parentSchema:schema12.properties.tarifCRE,data:data15}];return false;}}var valid1 = _errs33 === errors;}else {var valid1 = true;}if(valid1){if(data.coutElec !== undefined){let data21 = data.coutElec;const _errs46 = errors;if(!((typeof data21 == "number") && (isFinite(data21)))){validate10.errors = [{instancePath:instancePath+"/coutElec",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/coutElec/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.coutElec.type,parentSchema:schema12.properties.coutElec,data:data21}];return false;}var valid1 = _errs46 === errors;}else {var valid1 = true;}if(valid1){if(data.inflationElec !== undefined){let data22 = data.inflationElec;const _errs48 = errors;if(!((typeof data22 == "number") && (isFinite(data22)))){validate10.errors = [{instancePath:instancePath+"/inflationElec",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/inflationElec/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.inflationElec.type,parentSchema:schema12.properties.inflationElec,data:data22}];return false;}var valid1 = _errs48 === errors;}else {var valid1 = true;}if(valid1){if(data.maintenance !== undefined){let data23 = data.maintenance;const _errs50 = errors;if(!((typeof data23 == "number") && (isFinite(data23)))){validate10.errors = [{instancePath:instancePath+"/maintenance",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/maintenance/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.maintenance.type,parentSchema:schema12.properties.maintenance,data:data23}];return false;}var valid1 = _errs50 === errors;}else {var valid1 = true;}if(valid1){if(data.turpe !== undefined){let data24 = data.turpe;const _errs52 = errors;if(!((typeof data24 == "number") && (isFinite(data24)))){validate10.errors = [{instancePath:instancePath+"/turpe",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/turpe/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.turpe.type,parentSchema:schema12.properties.turpe,data:data24}];return false;}var valid1 = _errs52 === errors;}else {var valid1 = true;}if(valid1){if(data.turpeInjection !== undefined){let data25 = data.turpeInjection;const _errs54 = errors;if(!((typeof data25 == "number") && (isFinite(data25)))){validate10.errors = [{instancePath:instancePath+"/turpeInjection",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/turpeInjection/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.turpeInjection.type,parentSchema:schema12.properties.turpeInjection,data:data25}];return false;}var valid1 = _errs54 === errors;}else {var valid1 = true;}if(valid1){if(data.provisionOnduleurs !== undefined){let data26 = data.provisionOnduleurs;const _errs56 = errors;if(!((typeof data26 == "number") && (isFinite(data26)))){validate10.errors = [{instancePath:instancePath+"/provisionOnduleurs",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/provisionOnduleurs/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.provisionOnduleurs.type,parentSchema:schema12.properties.provisionOnduleurs,data:data26}];return false;}var valid1 = _errs56 === errors;}else {var valid1 = true;}if(valid1){if(data.assurance !== undefined){let data27 = data.assurance;const _errs58 = errors;if(!((typeof data27 == "number") && (isFinite(data27)))){validate10.errors = [{instancePath:instancePath+"/assurance",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/assurance/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.assurance.type,parentSchema:schema12.properties.assurance,data:data27}];return false;}var valid1 = _errs58 === errors;}else {var valid1 = true;}if(valid1){if(data.divers !== undefined){let data28 = data.divers;const _errs60 = errors;if(!((typeof data28 == "number") && (isFinite(data28)))){validate10.errors = [{instancePath:instancePath+"/divers",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/divers/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.divers.type,parentSchema:schema12.properties.divers,data:data28}];return false;}var valid1 = _errs60 === errors;}else {var valid1 = true;}if(valid1){if(data.ratioDcAc !== undefined){let data29 = data.ratioDcAc;const _errs62 = errors;if(!((typeof data29 == "number") && (isFinite(data29)))){validate10.errors = [{instancePath:instancePath+"/ratioDcAc",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/ratioDcAc/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.ratioDcAc.type,parentSchema:schema12.properties.ratioDcAc,data:data29}];return false;}var valid1 = _errs62 === errors;}else {var valid1 = true;}if(valid1){if(data.dureeAmortissement !== undefined){let data30 = data.dureeAmortissement;const _errs64 = errors;if(!((typeof data30 == "number") && (isFinite(data30)))){validate10.errors = [{instancePath:instancePath+"/dureeAmortissement",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/dureeAmortissement/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.dureeAmortissement.type,parentSchema:schema12.properties.dureeAmortissement,data:data30}];return false;}var valid1 = _errs64 === errors;}else {var valid1 = true;}if(valid1){if(data.tauxIS !== undefined){let data31 = data.tauxIS;const _errs66 = errors;if(!((typeof data31 == "number") && (isFinite(data31)))){validate10.errors = [{instancePath:instancePath+"/tauxIS",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tauxIS/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.tauxIS.type,parentSchema:schema12.properties.tauxIS,data:data31}];return false;}var valid1 = _errs66 === errors;}else {var valid1 = true;}if(valid1){if(data.tauxDSRA !== undefined){let data32 = data.tauxDSRA;const _errs68 = errors;if(!((typeof data32 == "number") && (isFinite(data32)))){validate10.errors = [{instancePath:instancePath+"/tauxDSRA",schemaPath:"#/definitions/Grain.SimulationCommunaute/properties/tauxDSRA/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema12.properties.tauxDSRA.type,parentSchema:schema12.properties.tauxDSRA,data:data32}];return false;}var valid1 = _errs68 === errors;}else {var valid1 = true;}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}else {validate10.errors = [{instancePath,schemaPath:"#/definitions/Grain.SimulationCommunaute/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema12.type,parentSchema:schema12,data}];return false;}}validate10.errors = vErrors;return errors === 0;}
<script lang="ts"></script><div class="chart-container"><!-- Dots (if enabled) -->{#if showDots && !dotInfo}{#each I as i}<circlecx={xScale(xVals[i])}cy={yScale(yVals[i])}stroke={colors[colorVals[i]]}</g>{/each}{/if}<!-- Chart lines -->{#each lines as subsetLine, i}{#if dotInfo && false}{:else}{/if}</g>{/each}<!-- Y-axis and horizontal grid lines -->{#each yTicks as tick}<g class="tick" transform="translate(0, {yScale(tick)})">{#if horizontalGrid}{/if}<text x="-10" y="5">{tick + yFormat}</text></g>{/each}<text text-anchor="middle" x="0" y={marginTop - 10}>{yLabel}</text></g><!-- X-axis and vertical grid lines -->{#each xTicks as tick, i}<g class="tick" transform="translate({xScale(tick)}, 0)">{#if verticalGrid}{/if}</g>{/each}</g>{#each pointsScaled as point, i}<pathstroke="none"fill-opacity="0"class="voronoi-cell"d={voronoiGrid.renderCell(i)}{/each}</svg></div><!-- Tooltip -->{#if dotInfo}{points[dotInfo[1]].x}: {points[dotInfo[1]].y.toFixed(2)}{yFormat}</div>{/if}<style></style>.tooltip {border-radius: 5px;padding: 5px;box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px,rgba(0, 0, 0, 0.3) 0px 7px 13px -3px,rgba(0, 0, 0, 0.2) 0px -3px 0px inset;opacity: 1;}@media (prefers-color-scheme: dark) {.y-axis text {fill: white;}.x-axis text {fill: white;}.tick-start {stroke: white;}.tick-grid {stroke: white;}.tick text {fill: white;}.domain {stroke: white;}}.y-axis .tick text {text-anchor: end !important;}.chart-container {justify-content: center;align-items: center;margin-top: 50px;margin-left: 8 0px;}svg {max-width: 100%;height: auto;height: 'intrinsic';margin: auto;}path {fill: 'green';}.y-axis {font-size: '10px';font-family: sans-serif;text-anchor: 'end';}.x-axis {font-size: '10px';font-family: sans-serif;text-anchor: 'end';}.tick text {font-size: 80%;fill: white !important;}.tick {opacity: 1;}.tick-start {stroke: black;stroke-opacity: 1;}.tick-grid {stroke: black;stroke-opacity: 0.2;font-size: '11px';color: black;}.tick text {fill: black;}<divclass="tooltip"style="position:absolute; left:{dotInfo[2].pageX +12}px; top:{dotInfo[2].pageY +12}px; pointer-events:none; background-color:{tooltipBackground}; color:{tooltipTextColor}">on:mouseover={(e) => (dotInfo = [point, i, e])}on:focus={(e) => (dotInfo = [point, i, e])} /><text x={width - marginLeft - marginRight - 40} y={marginBottom}>{xLabel}</text><text font-size="8px" x={-marginLeft / 4} y="20">{xTicksFormatted[i] + xFormat}</text><lineclass="tick-grid"y2={-height + insetTop + marginTop} /><line class="tick-start" stroke="black" y2="6" /><gclass="x-axis"transform="translate(0,{height - marginBottom - insetBottom})"pointer-events="none"><pathclass="domain"stroke="black"d="M{marginLeft},0.5 H{width - marginRight}" /><lineclass="tick-grid"x1={insetLeft}x2={width - marginLeft - marginRight} /><lineclass="tick-start"x1={insetLeft - 6}x2={insetLeft} /><gclass="y-axis"transform="translate({marginLeft}, 0)"pointer-events="none"><pathclass="domain"stroke="black"d="M{insetLeft}, {marginTop} V{height - marginBottom + 6}" /><pathclass="line"fill="none"stroke={colors[i]}d={subsetLine}stroke-opacity={strokeOpacity[i]}stroke-width={strokeWidth}stroke-linecap={strokeLinecap}stroke-linejoin={strokeLinejoin} /><pathclass="line"fill="none"stroke-opacity={points[dotInfo[1]].color === i? '1': '0.1'}stroke={colors[i]}d={subsetLine}stroke-width={strokeWidth}stroke-linecap={strokeLinecap}stroke-linejoin={strokeLinejoin} /><circlecx={xScale(points[dotInfo[1]].x)}cy={yScale(points[dotInfo[1]].y)}{r}stroke={colors[points[dotInfo[1]].color]}fill={dotsFilled} /><g class="chartlines" pointer-events="none">fill={dotsFilled ? colors[colorVals[i]] : 'none'} />{r}<g class="dot" pointer-events="none"><svg{width}{height}viewBox="0 0 {width} {height}"cursor="crosshair"on:mouseout={() => (dotInfo = null)}on:blur={() => (dotInfo = null)}>xTicks = xScale.ticks(xScalefactor)xTicksFormatted = xTicks.map((el) => el)yTicks = niceY.ticks(yScalefactor)}pointsScaled = points.map((el) => [xScale(el.x),yScale(el.y),el.color,])delaunayGrid = Delaunay.from(pointsScaled)voronoiGrid = delaunayGrid.voronoi([0, 0, width, height])lines = []colors.forEach((_color, j) => {const filteredI = I.filter((_el, i) => colorVals[i] === j)lines.push(chartLine(filteredI))})console.log('lines', lines)chartLine = line().defined((i) => cleanData[i]).curve(curve).x((i) => xScale(xVals[i])).y((i) => yScale(yVals[i]))xDomain = [xVals[0], xVals[xVals.length - 1]]yDomain = [Math.min(...yVals), Math.max(...yVals)]xScale = xType(xDomain, xRange)yScale = yType(yDomain, yRange)niceY = scaleLinear().domain([Math.min(...yVals), Math.max(...yVals)]).nice()I = range(xVals.length)gaps = (_d, i) => !isNaN(xVals[i]) && !isNaN(yVals[i])cleanData = points.map(gaps)$: {// For a single set of dataxVals = []yVals = []if (!('data' in data[0])) {x = Object.keys(data[0])[0]y = Object.keys(data[0])[1]xVals = data.map((el: Record<string, any>) => el[x])yVals = data.map((el: Record<string, any>) => el[y])colorVals = data.map((_) => 0)points = data.map((el) => ({x: el[x],y: el[y],color: 0,}))}// For data with subsets (NOTE: expects 'id' and 'data' keys)else {x = Object.keys(data[0]?.data[0])[0]y = Object.keys(data[0]?.data[0])[1]data.forEach((subset, i) => {subset.data.forEach((coordinate) => {xVals.push(coordinate[x])yVals.push(coordinate[y])colorVals.push(i)points.push({x: coordinate[x],y: coordinate[y],color: i,})})subsets.push(subset.id)})}let I,xScale,gaps,cleanData,xDomain,yDomain,yScale,niceY,chartLine,pointsScaled,delaunayGrid,voronoiGrid,xTicks,xTicksFormatted,yTickslet x: string,y: string,dotInfo,lines,xVals = [],yVals = [],points = [],subsets = [],colorVals = []const marginTop = 30 // the top margin, in pixelsconst marginRight = 30 // the right margin, in pixelsconst marginBottom = 30 // the bottom margin, in pixelsconst marginLeft = 100 // the left margin, in pixelsconst inset = 0 // inset the default range, in pixelsconst width = 600 // the outer width of the chart, in pixelsconst height = 400 // the outer height of the chart, in pixelsconst xLabel = '' // a label for the y-axisconst yLabel = 'Résultat net' // a label for the y-axisconst xFormat = '' // a format specifier string for the y-axisconst yFormat = '€' // a format specifier string for the y-axisconst horizontalGrid = true // show horizontal grid linesconst verticalGrid = true // show vertical grid linesconst colors = ['#b81111', '#ffbf00'] // fill color for dots && number of colors in fill array MUST match number of subsets in dataconst showDots = false // whether dots should be displayedconst dotsFilled = true // whether dots should be filled or outlinedconst r = 0 // (fixed) radius of dots, in pixelsconst strokeWidth = 1 // stroke width of line, in pixelsconst strokeOpacity = [1] // stroke opacity of lineconst tooltipBackground = 'white' // background color of tooltipconst tooltipTextColor = 'black' // text color of tooltipconst strokeLinecap = 'round' // stroke line cap of the lineconst strokeLinejoin = 'round' // stroke line join of the lineconst xScalefactor = width / 180 //y-axis number of valuesconst yScalefactor = height / 40 //y-axis number of valuesconst curve = curveLinear // method of interpolation between pointsconst xType = scaleLinear // type of x-scaleconst insetTop = 50 // inset from topconst insetRight = inset // inset from rightconst insetBottom = inset // inset fro bottomconst insetLeft = inset // inset from leftconst xRange = [marginLeft + insetLeft, width - marginRight - insetRight] // [left, right]const yType = scaleLinear // type of y-scaleconst yRange = [height - marginBottom - insetBottom, marginTop + insetTop] // [bottom, top]export let dataimport { line, curveLinear, Delaunay, range, scaleLinear } from 'd3'//@ts-nocheck
export let pvgis_loading = falselet prm_loading = falselet initialised = falselet puissance = 0let communaute: null | (Grain.Communaute & { isMoving?: boolean }) = nulllet Plotly: anylet erreur = ''function addProfil(_ev: Event) {const prt = Object.keys(profils_)data.profils.push({ type: prt[0], conso: 0 })data.profils = data.profils}async function delProfil(i: number) {data.profils.splice(i, 1)data.profils = data.profilsawait updatePlot(puissance, communaute)}const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));var lastRequest = performance.now()async function refresh(event: SubmitEvent) {event.preventDefault()if (data.prms) {prm_loading = trueawait tick()for(let i = 0; i < data.prms.length; i++) {var file = document.getElementById(`releve-${i}`) as HTMLInputElement | null;if (file?.files?.length) {var reader = new FileReader();reader.readAsText(file.files[0], "UTF-8");let r: string | undefined = await new Promise((resolve) => {reader.onload = function (evt) {console.log(typeof (evt.target?.result))let result = evt.target?.result?.toString()if(result) {resolve(result)} else {resolve(undefined)}}})data.prms[i].releve = r}let siret = document.getElementById(`siret-${i}`) as HTMLInputElement | null;if(siret?.value) {let now = performance.now();// Rate-limiting: pas plus de 7 requêtes par seconde.if(now - lastRequest < 150) {await sleep(150 - (now - lastRequest))}lastRequest = nowconst resp = await fetch(`https://recherche-entreprises.api.gouv.fr/search?q=${siret.value}`)if(resp.status == 200) {type Ent = {results: {dirigeants: {nom: string,prenoms: string,}[],matching_etablissements: {libelle_voie: string,commune: string,}[]}[]}let ent: Ent = await resp.json()console.log(ent.results[0].matching_etablissements[0].commune)if(ent.results.length) {data.prms[i].nom = ent.results[0].dirigeants[0].nomdata.prms[i].prenom = ent.results[0].dirigeants[0].prenomsdata.prms[i].codeinsee = ent.results[0].matching_etablissements[0].communeconsole.log(data.prms[i])}}}}console.log(data.prms);const resp = await fetch(`${server}/api/grain/projet/${data.id || 'nouveau'}/prms`,{method: 'POST',body: JSON.stringify(data.prms),})if (resp.ok) {annee = await resp.json()}prm_loading = falseawait tick()} else {erreur = 'La liste des PRMs est vide'}await updatePlot(puissance, communaute)}</div><style>input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {-webkit-appearance: none;margin: 0;}input[type=number] {appearance: none;-moz-appearance:textfield; /* Firefox */}</style>var dataProd = [{values: [Math.round(auto), Math.round(totalProd - auto)],labels: ['Autoconsommé', 'Surplus'],marker: { colors: ['#ffbf00dd', '#b81111dd'] },type: 'pie',sort: false,hole: 0.5,},]var dataConso = [{values: [Math.round(auto), Math.round(totalConso - auto)],labels: ['Autoproduit', 'Fournisseur'],marker: { colors: ['#ffbf00dd', '#b81111dd'] },type: 'pie',sort: false,hole: 0.5,},]<div class="tab-content" id="simuTabContent"><divclass="tab-pane fade active show p-3"id="simu-tab-pane"role="tabpanel"aria-labelledby="simu-tab"tabindex="0"><h3 class="my-3 fs-1 fw-bold">Production… <span class="text-primary">Consommation</span></h3><form method="POST" action="/api/grain" id="pdl" on:submit={refresh} />{#if erreur}<divid="erreur"class="alert alert-danger fade d-flex"class:show={erreur}role="alert">{erreur}<buttontype="button"class="btn-close"style="padding:20px;margin:-16px -16px -16px auto"on:click={() => (erreur = '')}aria-label="Close" /></div>{/if}<h2 class="my-5">Profils de consommation</h2>{#if data.profils.length}{#if $expert}<div>Vous êtes en mode expert. Dans ce mode, vous avez un accès direct à tous les profils utilisés par les opérateurs du réseau pour simuler les consommations. Voir <a href="https://www.enedis.fr/responsable-dequilibre-profilage-et-profils">la documentation</a>.</div>{/if}<table class="table"><thead><tr><th /><th>Profil</th><th>Consommation annuelle (kWh)</th><th /></tr></thead><tbody>{#each data.profils as pr, i}<tr><td class="px-3 align-middle">Profil</td><td><selectclass="form-select"bind:value={pr.type}on:change={(_ev) =>updatePlot(puissance,communaute,)}>{#each Object.entries(profils_) as [p, _]}<option value={p}>{p}</option>{/each}</select></td><td><inputtype="number"class="form-control"placeholder="Abonnement (kW)"min="0"step="500"bind:value={pr.conso}on:change={(_ev) =>updatePlot(puissance,communaute,)} /></td><td style="width:1%;white-space:nowrap;text-align:center"><buttonclass="btn btn-link"on:click={(_ev) => delProfil(i)}><i class="bi bi-x-circle text-primary" /></button></td></tr>{/each}</tbody></table>{/if}<div class="text-center"><button class="btn btn-primary" on:click={addProfil}><i class="bi bi-plus-circle" /> Ajouter un profil</button></div>if(totalProd && totalConso) {plotStyle = 'min-height:450px'Plotly.react('autoProd',dataProd,{title: "Autoconsommation sur l'année",font: {color: darkMode ? '#fff' : '#000',},plot_bgcolor: '#fff0',paper_bgcolor: '#fff0',autosize: true,automargin: true,legend: {orientation: 'h',},},{ responsive: true })Plotly.react('autoConso',dataConso,{title: "Autoproduction sur l'année",font: {color: darkMode ? '#fff' : '#000',},plot_bgcolor: '#fff0',paper_bgcolor: '#fff0',autosize: true,automargin: true,legend: {orientation: 'h',},},{ responsive: true })} else {plotStyle = ''}}
import Simulation from './Simulation.svelte'const data = $props()
<h2 class="my-5">Relevés de compteurs</h2>{#if data.active && data.id && data.id != 'nouveau'}<div class="mb-5">Vous pouvez ajouter des compteurs d'entreprises ou d'associations par leur numéro de compteur et leur numéro de SIRET.</div>{#if data.prms.length}{#each data.prms as prm, i}<div class="row my-2"><div class="col-3 d-flex align-middle"><label class="ms-auto form-label" for="prm-{i}">PRM<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Un PRM, aussi appelé PDL, est l'identifiant d'un compteur électrique. On peut le trouver sur les factures d'électricité, ou en appuyant sur le bouton + du compteur Linky."><i class="bi bi-question-circle" /></button></label></div><div class="col d-flex align-items-center"><inputclass="form-control form-control-sm"id="prm-{i}"bind:value={prm.prm}on:keydown={(e) => (e.key == 'ArrowUp' || e.key == 'ArrowDown') && e.preventDefault() }type="number" /></div><div class="col col-auto d-flex align-items-center"><buttonclass="btn btn-outline-primary btn-sm"on:click={(e) => { e.preventDefault(); data.prms.splice(i, 1); data.prms = data.prms; }}><i class="bi bi-trash"/></button></div></div><div class="row my-2"><div class="col-3 d-flex align-middle"><label class="ms-auto form-label" for="prm-{i}">Relevé au format CSV</label></div><div class="col d-flex align-items-center"><inputclass="form-control form-control-sm"id="releve-{i}"type="file" />{#if prm.releve?.length}<i class="ms-3 bi bi-check-circle"/>{/if}</div></div><div class="row my-2"><div class="col-9 ms-auto"><input type="radio" class="btn-check" id="particulier" value={false} bind:group={prm.pro}><label class="btn btn-sm" for="particulier">Particulier</label>
<input type="radio" class="btn-check" id="pro" value={true} bind:group={prm.pro}><label class="btn btn-sm" for="pro">Professionnel</label></div></div>{#if prm.pro}<div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="siret-{i}">SIRET du titulaire du compteur</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="siret-{i}"bind:value={prm.siret} /></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="prenom-{i}">Prénom du titulaire du compteur</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="prenom-{i}"bind:value={prm.prenom}/></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="nom-{i}">Nom du titulaire du compteur</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="nom-{i}"bind:value={prm.nom}/></div></div>{:else}<div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="prenom-{i}">Prénom du titulaire du compteur</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="prenom-{i}"bind:value={prm.prenom} /></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="nom-{i}">Nom du titulaire du compteur</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="nom-{i}"bind:value={prm.nom} /></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="numerorue-{i}">Numéro et rue</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="numerorue-{i}"bind:value={prm.numerorue} /></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="codepostal-{i}">Code INSEE de la commune</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="codepostal-{i}"bind:value={prm.codeinsee} /></div></div><div class="row my-2"><div class="col-3 d-flex text-end align-items-center"><label class="ms-auto form-label" for="serie-{i}">Numéro de série</label></div><div class="col-9 d-flex align-items-center"><inputclass="form-control form-control-sm"id="serie-{i}"bind:value={prm.serie} /></div></div>{/if}<div class="my-3 form-check d-flex"><inputclass="form-check-input ms-auto me-2"type="checkbox"id="consentement-{i}"bind:checked={prm.consentement} /><label class="form-check-label me-auto" for="consentement-{i}">Cet abonné consent à ce que j'accède à ses données.</label></div><hr class="my-4" />{/each}<div class="my-3">Ce service ne consulte la courbe de charge du compteur communiquant qu'une seule fois, et ce consentement expire dès que ces données pour l'année écoulée sont récupérées. Les données collectées depuis les compteurs communiquants sont stockées temporairement sur nos serveurs pour des raisons de performance, ne sont utilisées que pour afficher cette page et produire le rapport, et ne sont jamais conservées plus de 30 jours.</div><div class="my-3">Les données envoyées via un fichier sont conservées jusqu'à ce que vous supprimiez ce projet.</div>{/if}<div class="d-flex justify-content-center"><button class="mx-2 btn btn-primary" on:click={addPrm}><i class="bi bi-plus-circle" /> Ajouter un compteur</button>{#if data.prms.length}<buttondisabled={!!data.prms.find((p) => !p.releve?.length && !p.consentement)}class="mx-2 btn btn-primary"form="pdl">Mettre à jour</button><divclass="mx-2 spinner-border text-primary"class:d-none={!prm_loading} />{/if}</div>{:else if data.active}<div class="my-3">Sauvegardez ce projet pour avoir accès aux relevés de compteurs détaillés.</div>{:else}<div class="my-3">Vous devez être abonné pour avoir accès aux relevés de compteurs détaillés.</div>{/if}<h2 class="mt-5">Simulation</h2><table class="table table-bordered d-inline-block"><tbody><tr><td>Production totale:</td><td>{Math.round(totalProd)}kWh</td></tr><tr><td>Consommation totale:</td><td>{Math.round(totalConso)}kWh</td></tr></tbody></table>{#if pvgis_loading}<div class="my-3 d-flex align-items-center text-primary"><div class="spinner-border text-primary me-3" />Chargement de la production solaire</div>{/if}<div class="my-3"><div class="mx-auto" style="min-height:450px" id="plot" /></div><div class="row"><div class="col-12 col-sm-6 p-0" style={plotStyle} id="autoProd" /><div class="col-12 col-sm-6 p-0" style={plotStyle} id="autoConso" /></div></div>let auto = 0let totalProd = 0let totalConso = 0let somme: Sample = {hourly: {x: [],y: [],},daily: {x: [],y: [],},weekly: {x: [],y: [],},x: [],y: [],type: 'bar',line: {color: '#b81111',width: 1,},marker: {color: '#b81111',width: 1,},name: 'Consommation totale',bucket: 1,}async function updatePv(puissance: number,communaute: (Grain.Communaute&{isMoving?: boolean}) | null,) {if(communaute?.isMoving) {return pvgis}pvgis_loading = trueawait calcul.updatePv(puissance, communaute, pvgis, soleil, base)pvgis_loading = falseawait tick()}async function updatePlot(puissance: number,communaute: (Grain.Communaute & { isMoving?: boolean }) | null,) {console.log("isMoving", communaute?.isMoving)if(communaute?.isMoving) {return}if (!browser) {return}await updatePv(puissance, communaute)console.log("updated")prm_loading = true;let auto_ = await calcul.updatePlot(assets,annee,data.profils,profils_,somme,soleil,)prm_loading = false;auto = auto_.autototalProd = auto_.totalProdtotalConso = auto_.totalConsoconsole.log("updated auto", auto, totalProd, totalConso)if (!Plotly)//@ts-ignorePlotly = await import('plotly.js-dist')redraw()}let has_plot = { has_plot: false };let layout = {};function relayout_(event: any) {console.log('relayout_')const plot = document.getElementById('plot')!relayout(event, plot, Plotly, layout, has_plot, get(soleil), somme)}function redraw() {console.log("redraw")const plot = document.getElementById('plot')if (!plot) returnlet soleil_ = get(soleil)chooseScale(soleil_)chooseScale(somme)let unite: stringif (soleil_.bucket == 24) {unite = 'kWh/jour'} else if (soleil_.bucket == 24 * 7) {unite = 'kWh/semaine'} else {unite = 'kWh'}layout = {title: 'Autoconsommation',autosize: true,automargin: true,plot_bgcolor: '#fff0',paper_bgcolor: '#fff0',font: {color: darkMode ? '#fff' : '#000',},xaxis: {gridcolor: darkMode ? '#444' : '#bbb',ticklabeloverflow: 'allow',ticklabelstep: 4,tickangle: 45,tickformat: soleil_.bucket < 24 ? '%x %X': '%x',type: 'datetime',},yaxis: {title: { text: unite },gridcolor: darkMode ? '#444' : '#bbb',color: darkMode ? '#fff' : '#000',},showlegend: true,legend: {xanchor: 'center',x: 0.5,y: -0.4,orientation: 'h',},}if (has_plot.has_plot) {Plotly!.update(plot, [soleil_, somme], layout)} else {Plotly!.newPlot(plot, [soleil_, somme], layout, {responsive: true,modeBarButtonsToRemove: modeBarButtonsToRemove,})//@ts-ignoreplot.on('plotly_relayout', relayout_)has_plot.has_plot = true}let plotStyle = ''let darkMode = falseif (browser) {darkMode =window.matchMedia &&window.matchMedia('(prefers-color-scheme: dark)').matcheswindow.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => {darkMode = !!event.matchesredraw()})}let profils_ = Grain.profils($expert)expert.subscribe((value) => profils_ = Grain.profils(value))onMount(async () => {//@ts-ignorePlotly = await import('plotly.js-dist')s.p.puissance.subscribe((value) => {puissance = valueinitialised && updatePlot(puissance, communaute)})_communaute.subscribe((value) => {communaute = valueinitialised && updatePlot(puissance, communaute)})pvgis.subscribe((pvgis) => {console.log("pvgis updated")if(initialised && (pvgis.pvgis?.inputs != pvgis_)) {pvgis_ = pvgis.pvgis?.inputs || nullupdatePlot(puissance, communaute)}})for(let p of data.prms) {p.consentement = false}initialised = trueupdatePlot(puissance, communaute)})function addPrm(_ev: Event) {data.prms = data.prms}const pvgis: Writable<{ pvgis: null | PVGIS, loading: boolean }> = getContext("pvgis")let pvgis_: null | PVGISInputs = nulldata.prms.push({ prm: null, nom: '', prenom: '', siret: '', pro: true })import { browser } from '$app/environment'import { onMount, tick } from 'svelte'import { dev } from '$app/environment';import { assets as a } from '$app/paths'import type { Writable }from 'svelte/store'import { get }from 'svelte/store'import { getContext } from 'svelte'import { Grain } from '../../../../grain-types'import { base } from '$app/paths'import { chooseScale, relayout, modeBarButtonsToRemove } from '../../../../plot'import type { Sample } from '../../../../plot'import type {Derived, PVGIS, PVGISInputs} from '../calcul'import * as calcul from '../calcul'export let data: {id: string,accesParticuliers: boolean,prms: Grain.Prm[],active: boolean,profils: Grain.Profil[],};export let annee: Record<number, number[]> = {}console.log(data)export let assets: string = a;let s: Derived = getContext("simulation")const soleil: Writable<Sample> = getContext("soleil")const expert: Writable<boolean> = getContext("expert")let _communaute: Writable<(Grain.Communaute & {isMoving?: boolean}) | null> = getContext("communaute")const server = dev ? 'http://localhost:5173' : 'https://coturnix.fr'
<Simulation {data} />
<div class="titreligne tcellt">Autoproduction (€)</div><div class="titreligne tcellt">Vente locale (€)</div><div class="titreligne tcellt">Vente de surplus (€)</div>
<div class="titreligne tcellt">Autoproduction (€)</div><div class="titreligne tcellt">Vente locale (€)</div><div class="titreligne tcellt">Vente de surplus (€)</div>
type="button"class="btn btn-sm btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Dans un emprunt, compte bancaire qui permettra de payer le service de la dette si jamais l'entité emprunteuse n'est plus en mesure de le faire."><i class="bi bi-question-circle" /></button>
type="button"class="btn btn-sm btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Dans un emprunt, compte bancaire qui permettra de payer le service de la dette si jamais l'entité emprunteuse n'est plus en mesure de le faire."aria-label="Dans un emprunt, compte bancaire qui permettra de payer le service de la dette si jamais l'entité emprunteuse n'est plus en mesure de le faire."><i class="bi bi-question-circle"></i></button>
<div class="titreligne tcellt">Résultat fiscal</div><div class="titreligne tcellt">Impôt sur les sociétés</div><div class="titreligne tcellt">Résultat net</div>
<div class="titreligne tcellt">Résultat fiscal</div><div class="titreligne tcellt">Impôt sur les sociétés</div><div class="titreligne tcellt">Résultat net</div>
import type { Grain } from '../../../../grain-types.ts';import type { Writable } from 'svelte/store'import { getContext, tick } from 'svelte'export let zoom: number = 5import { onMount, onDestroy } from 'svelte'export let assets: string = '/grain/static'import { browser } from '$app/environment'let redIcon: any = nulllet srv =import.meta.env.MODE == 'production'? 'https://coturnix.fr': 'http://localhost:5173'type Compteur_ = Grain.Compteur & { dot?: any };type Communaute_ = Grain.Communaute & { compteurs?: Compteur_[], circle?: any, isMoving?: boolean };let communaute: Writable<Communaute_ | null> = getContext("communaute")export let save: () => Promise<void> = async () => { };let derogation = $communaute?.derogation ?? "non"let map: any = nulllet circleOpts = {radius: 1000,stroke: true,fillOpacity: 0,color: '#b81413',weight: 3,}let leaflet: any = null;function changeDerogation (e: any) {console.log('Changederogation', derogation, $communaute, e)if($communaute) {$communaute.derogation = derogation;let d = derogationRayonKm() * 1000checkRayon($communaute, d)if ($communaute?.circle) {$communaute.circle.setRadius(d)} else {circleOpts.radius = d$communaute.circle = leaflet.circle($communaute, circleOpts)$communaute.circle.addTo(map!)}save()}}function derogationRayonKm(): number {if ($communaute?.derogation == "20") {return 10} else if ($communaute?.derogation == "10") {return 5} else {return 1}}type Commune = {nom: String,densite: number,}let communes: null | Commune[] = nullasync function checkRayon(latlng: Grain.LatLng| null, rayon: number) {if(latlng) {console.log("checkRayon");let resp = await fetch(`${srv}/api/intersect?lat=${latlng.lat}&lng=${latlng.lng}&rayon=${rayon}`, {credentials: 'include',})if (resp.status == 200) {communes = await resp.json()}}}let mapContainer: HTMLElement;onDestroy(() => {console.log("destroy", map);if(browser ) {delete (<any>document).coturnixMap;}// map && map.off && map.off(); map && map.remove && map.remove()});onMount(async () => {checkRayon($communaute, derogationRayonKm())console.log('map onload', browser)if (!browser) {return}const L = await import('leaflet')leaflet = L;await import('leaflet.fullscreen')const G = await import('leaflet-gesture-handling')// @ts-ignoreL.Map.addInitHook('addHandler', 'gestureHandling', G.GestureHandling)await tick();console.log("Map.svelte")map = L.map(L.DomUtil.create('div'), {// @ts-ignorefullscreenControl: true,fullscreenControlOptions: {position: 'topleft',},attributionControl: false,// @ts-ignoregestureHandling: true,});(<any>document).coturnixMap = mapmapContainer.appendChild(map.getContainer());map.getContainer().style.width = '100%';map.getContainer().style.height = '100%';map.invalidateSize();if ($communaute) {derogation = $communaute.derogation;circleOpts.radius = derogationRayonKm() * 1000;$communaute.circle = L.circle($communaute, circleOpts).addTo(map)map.setView($communaute, zoom)} else {map.setView({ lat: 46, lng: 3 }, 5)}let layer = L.tileLayer(`https://tile.openstreetmap.org/{z}/{x}/{y}.png`,{minZoom: 0,maxZoom: 18,attribution: 'IGN-F/Geoportail',tileSize: 256,noWrap: true,}).addTo(map)layer.on('tileerror', (e) => {console.log(e)})if (!redIcon) {redIcon = L.icon({iconUrl: `${assets}/signal-red.png`,iconRetinaUrl: `${assets}/signal-red.png`,iconAnchor: [12, 41],} as L.IconOptions)}if($communaute?.compteurs) {for(let c of $communaute.compteurs) {c.dot = L.marker(c, {icon: redIcon!,draggable: false,})c.dot.addTo(map)}}map.on('zoomend', function (_: any) {zoom = map.getZoom()})let initialCentre: null | { lat: number; lng: number } = nulllet invalidDrag = falsemap.on('mousemove', function (e: any) {if (invalidDrag) {return}if ($communaute?.circle && e.originalEvent.shiftKey) {// let m = document.getElementById('descrmap')// m!.focus()let d = derogationRayonKm() * 1000if (initialCentre) {let testCentre = {lat: e.latlng.lat - initialCentre.lat,lng: e.latlng.lng - initialCentre.lng,}if (!checkDistance(testCentre, $communaute.compteurs ?? [], d)) {invalidDrag = truereturn}$communaute.lat = testCentre.lat$communaute.lng = testCentre.lng$communaute.circle.setLatLng($communaute);} else {if (map.distance($communaute, e.latlng) <= d) {$communaute.isMoving = true;initialCentre = {lat: e.latlng.lat - $communaute.lat,lng: e.latlng.lng - $communaute.lng,}}}}})map.on('keyup', async (e: KeyboardEvent) => {console.log("KEYUP", e);if (e.originalEvent.key == 'Shift') {if($communaute) {delete $communaute.isMoving;checkRayon($communaute, derogationRayonKm() * 1000)save()}console.log("invalidDrag");invalidDrag = falseinitialCentre = null}})map.on('click', function (e: any) {console.log(e);if(!$communaute) {communaute.set({lat: e.latlng.lat,lng: e.latlng.lng,compteurs: [],derogation,})circleOpts.radius = derogationRayonKm() * 1000;$communaute!.circle = L.circle(e.latlng,circleOpts).addTo(map)checkRayon($communaute, derogationRayonKm() * 1000)}if(map.distance($communaute!, e.latlng) <= derogationRayonKm() * 1000) {let dot = {lat: e.latlng.lat,lng: e.latlng.lng,dot: L.marker(e.latlng, {icon: redIcon!,draggable: false,}),azimuth: 0,inclinaison: 0,puissance: 0,};dot.dot.addTo(map)if(!$communaute!.compteurs) {$communaute!.compteurs = []}$communaute!.compteurs.push(dot);$communaute = $communaute;}save()});recentrer()})function recentrer(zoom?: number) {if (!$communaute || !map) {return}let lng0 = 180let lng1 = -180let lat0 = 90let lat1 = -90let mar = 0.5let dy = (mar + (derogationRayonKm())) / 111let lat2 = $communaute.lat - dylet lat3 = $communaute.lat + dylet dx = dy / Math.cos(($communaute.lat * Math.PI) / 180)let lng2 = $communaute.lng - dxlet lng3 = $communaute.lng + dxlng0 = Math.min(lng0, lng2)lng1 = Math.max(lng1, lng3)lat0 = Math.min(lat0, lat2)lat1 = Math.max(lat1, lat3)if (zoom === undefined && lng0 < lng1 && lat0 < lat1) {console.log([[lat0, lng0],[lat1, lng1],])map.fitBounds([[lat0, lng0],[lat1, lng1],],)} else {map.setView($communaute, zoom)}}function reset() {if (!$communaute || !map) {return}$communaute.circle.removeFrom(map)for(let m of $communaute?.compteurs || []) {m.dot.removeFrom(map);}$communaute = null}function checkDistance(e: { lat: number; lng: number },compteurs: { lat: number, lng: number }[],d: number): boolean {for (let v of compteurs) {let dist = map.distance(e, v)if (dist > d) {return false}}return true}function deleteCompteur(event: any,i: number,) {event.preventDefault();$communaute!.compteurs![i].dot.removeFrom(map);$communaute!.compteurs!.splice(i, 1);$communaute = $communaute;save()}let geoc = false;let endroit: string = ""function diff(a: string, b: string): number {const m = a.length, n = b.length;const dp = Array(m + 1).fill(0).map(() => Array(n + 1).fill(0));dp[0] = dp[0].map((_, j) => j);dp.forEach((row, i) => row[0] = i);for (let i = 1; i <= m; i++) {for (let j = 1; j <= n; j++) {if (a[i - 1] === b[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);}}}return dp[m][n];}async function geocoding(e: Event) {e.preventDefault()geoc = trueawait tick()let resp = await fetch(`https://data.geopf.fr/geocodage/search?q=${endroit}`)geoc = falseif (resp.status == 200) {const b = await resp.json()console.log("features", b);if('features' in b && b.features.length) {let min = -1;let argmin = 0;for(let i = 0; i < b.features.length; i++) {const d = diff(b.features[i].properties.label, endroit)if(min < 0 || d < min) {min = d;argmin = i}}console.log("diff", min, argmin);if(!$communaute) {communaute.set({lat: b.features[argmin].geometry.coordinates[1],lng: b.features[argmin].geometry.coordinates[0],compteurs: [],derogation,})}$communaute!.lng = b.features[argmin].geometry.coordinates[0]$communaute!.lat = b.features[argmin].geometry.coordinates[1]}if ($communaute) {let d = derogationRayonKm() * 1000await checkRayon($communaute, d)circleOpts.radius = dif($communaute.circle) {$communaute.circle.setLatLng($communaute)} else {$communaute.circle = leaflet.circle($communaute, circleOpts).addTo(map!)}recentrer(d == 10000 ? 10 : (d == 5000 ? 11 : 12))}}return null}
import Description from './Description.svelte'
<svelte:head><link rel="stylesheet" href="{assets}/leaflet.css" /><link rel="stylesheet" href="{assets}/leafletfs.css" /><link rel="stylesheet" href="{assets}/leaflet-gesture-handling.min.css" /></svelte:head><divclass="tab-pane fade active show p-3"id="description-tab-pane"role="tabpanel"aria-labelledby="description-tab"tabindex="0"><h3 class="my-3 fs-1 fw-bold">Quelques <span class="text-primary">détails</span> de plus.</h3><div class="my-3">Cliquez sur la carte ci-dessous pour ajouter des compteurs, ou cliquez en maintenant la touche Shift pour positionner la communauté.</div><div class="my-3"><form on:submit={geocoding}><div class="input-group"><input type="text" class="form-control" bind:value={endroit}/><button class="btn btn-sm btn-outline-primary" on:click={geocoding}>Recherche{#if geoc}<div class="spinner-border" style="margin-left:0.2em; width:1em;height:1em"></div>{/if}</button></div></form></div><div bind:this={mapContainer} class="w-100" style="height:500px"></div><div class="d-flex flex-column"><buttonclass="btn btn-sm btn-outline-secondary my-2 ms-auto"on:click={(_) => recentrer(zoom)}>Recentrer</button><buttonclass="btn btn-sm btn-outline-secondary my-2 ms-auto"on:click={reset}>Reset</button>{#if $communaute?.compteurs?.length}<div class="my-3"><table class="table"><thead><tr><th>Puissance</th><th>Azimuth (le Sud est à 0°, l'Est à -90°, l'Ouest à 90°)</th><th>Inclinaison</th><th></th></tr></thead><tbody>{#each $communaute.compteurs as c, i}<tr><td><inputtype="number"class="form-control"bind:value={c.puissance} /></td><td><inputtype="number"class="form-control"bind:value={c.azimuth} /></td><td><inputtype="number"class="form-control"bind:value={c.inclinaison} /></td><td><button class="btn btn-sm btn-outline-primary" on:click={(e) => deleteCompteur(e, i)}><i class="bi bi-trash"/></button></td></tr>{/each}</tbody></table></div>{/if}<div class="p-3 overflow-auto"><label for="derog" class="form-label">Extension de périmètre (habitat rural et/ou dispersé)</label> <button type="button"class="btn btn-link align-baseline p-0"id="ext-popover"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Par dérogation, le rayon de la communauté peut être étendu à 5km ou 10km."><i class="bi bi-question-circle" /></button><selectid="derog"class="form-select form-select-sm w-auto d-inline"name="derog"bind:value={derogation}on:change={changeDerogation}><option value="non">Non</option><option value="10">10km</option><option value="20">20km</option></select>{#if communes && communes.length}<h4 class="mt-5">Communes concernées</h4><table class="table"><thead><tr><th>Nom</th><th>Éligibilité</th></tr></thead><tbody>{#each communes as c}<tr><td>{c.nom}</td><td>{#if c.densite >= 5}20km{:else if c.densite >= 3}10km{#if derogation=='20' }<i class="ms-3 text-danger bi bi-exclamation-triangle"/>{/if}{:else}2km{#if derogation!='non' }<i class="ms-3 text-danger bi bi-exclamation-triangle"/>{/if}{/if}</td></tr>{/each}</tbody></table>{/if}</div></div></div>
<Description zoom={5} save={() => {}} />
import { readable, writable, derived, get } from 'svelte/store';import type { Readable, Writable } from 'svelte/store';
import { readable, writable, derived, get } from 'svelte/store'import type { Readable, Writable } from 'svelte/store'import { asset, resolve } from '$app/paths'
s: Grain.SimulationCommunaute
constructor(s: Grain.SimulationCommunaute) {this.s = sthis.p = <_SimulationCommunaute>Object.fromEntries(Object.entries(s).map(([k, v]) => {/* eslint-disable @typescript-eslint/no-explicit-any */const w = writable(v)w.subscribe((value) =>(this.s[k as keyof Grain.SimulationCommunaute] =value as any))return [k, w]}))
constructor(s: Grain.SimulationCommunaute) {this.s = sthis.p = <_SimulationCommunaute>Object.fromEntries(Object.entries(s).map(([k, v], _) => {let w = writable(v);w.subscribe((value) => this.s[k as keyof Grain.SimulationCommunaute] = value as any)return [k, w]}));this.N = writable(30);this.investissement = derived([this.p.puissance, this.p.ratio, this.p.enedis],([$puissance, $ratio, $enedis]) => $puissance ? $puissance * 1000 * $ratio + $enedis : 0)
this.N = writable(30)
this.apport = derived([this.investissement, this.p.apport],([$investissement, $apport]) => Math.min($investissement, $apport))this.primeInvestissement = derived(this.p.puissance,($puissance) => ($puissance <= 3 ? 0.30: $puissance <= 9 ? 0.23: $puissance <= 36 ? 0.20: $puissance <= 100 ? 0.10: 0) * 1000 * $puissance
this.investissement = derived([this.p.puissance, this.p.ratio, this.p.enedis],([$puissance, $ratio, $enedis]) =>$puissance ? $puissance * 1000 * $ratio + $enedis : 0)
function tarifSurplus_(tarifCRE: any, puissance: number): number {let resultat = tarifCRE.prix[0]for (let i = 0; i < tarifCRE.limites.length; i++) {if (puissance < tarifCRE.limites[i]) {return resultat} else {resultat = tarifCRE.prix[i]
function tarifSurplus_(tarifCRE: any, puissance: number): number {let resultat = tarifCRE.prix[0]for (let i = 0; i < tarifCRE.limites.length; i++) {if (puissance < tarifCRE.limites[i]) {return resultat} else {resultat = tarifCRE.prix[i]}}return resultat
this.tarifSurplus = derived([this.p.tarif_cre, this.p.puissance, this.N],([$tarifCRE, $puissance, $N],_,update) => {update((tarifSurplus) => {if (!tarifSurplus || tarifSurplus.length < $N) {tarifSurplus = Array($N);}let t = tarifSurplus_($tarifCRE, $puissance);for (let i = 0; i < $N; i++) {tarifSurplus[i] = t * Math.pow(1 + $tarifCRE.inflation / 100, i)}return tarifSurplus})});
this.tarifSurplus = derived([this.p.tarif_cre, this.p.puissance, this.N],
this.productionAnnuelle = derived([this.p.productible, this.p.puissance, this.p.degradation, this.N],([$productible, $puissance, $degradation, $N], _, update) => {update((prod) => {if (!prod || prod.length < $N) {prod = Array($N);}for (let i = 0; i < $N; i++) {prod[i] = H.productionAnnuelle($productible, $puissance, $degradation, i)}return prod})})
([$tarifCRE, $puissance, $N], _, update) => {update((tarifSurplus) => {if (!tarifSurplus || tarifSurplus.length < $N) {tarifSurplus = Array($N)}const t = tarifSurplus_($tarifCRE, $puissance)for (let i = 0; i < $N; i++) {tarifSurplus[i] =t * Math.pow(1 + $tarifCRE.inflation / 100, i)}return tarifSurplus})})
this.tarifLocal = derived([this.p.prix, this.p.inflation, this.N],([$prix, $inflation, $N], _, update) => {update((tarif) => {if (!tarif || tarif.length < $N) {tarif = Array($N);}for (let i = 0; i < $N; i++) {tarif[i] = $prix * Math.pow(1 + $inflation / 100, i)}return tarif})})
this.productionAnnuelle = derived([this.p.productible, this.p.puissance, this.p.degradation, this.N],([$productible, $puissance, $degradation, $N], _, update) => {update((prod) => {if (!prod || prod.length < $N) {prod = Array($N)}for (let i = 0; i < $N; i++) {prod[i] = H.productionAnnuelle($productible,$puissance,$degradation,i)}return prod})})
this.tarifAllo = derived([this.p.cout_elec, this.p.inflation_elec, this.N],([$coutElec, $inflationElec, $N], _, update) => {update((tarif) => {if (!tarif || tarif.length < $N) {tarif = Array($N);}for (let i = 0; i < $N; i++) {tarif[i] = $coutElec * Math.pow(1 + $inflationElec / 100, i)}return tarif})})
this.tarifLocal = derived([this.p.prix, this.p.inflation, this.N],([$prix, $inflation, $N], _, update) => {update((tarif) => {if (!tarif || tarif.length < $N) {tarif = Array($N)}for (let i = 0; i < $N; i++) {tarif[i] = $prix * Math.pow(1 + $inflation / 100, i)}return tarif})})
this.chiffreAffaires = derived([this.primeInvestissement, this.productionAnnuelle,this.p.autoconso, this.tarifLocal, this.tarifSurplus,this.p.autoprod, this.tarifAllo, this.N],([$primeInvestissement, $productionAnnuelle, $autoconso, $tarifLocal, $tarifSurplus, $autoprod, $tarifAllo, $N], _, update) => {update((ca) => {if (!ca || ca.length < $N) {ca = Array($N);}for (let i = 0; i < $N; i++) {ca[i] = (i == 0 ? $primeInvestissement : 0)+ $productionAnnuelle[i] * ($autoconso / 100 * $tarifLocal[i] +(1 - $autoconso / 100) * $tarifSurplus[i] +($autoprod / 100 * $tarifAllo[i]))}return ca})})
this.tarifAllo = derived([this.p.cout_elec, this.p.inflation_elec, this.N],([$coutElec, $inflationElec, $N], _, update) => {update((tarif) => {if (!tarif || tarif.length < $N) {tarif = Array($N)}for (let i = 0; i < $N; i++) {tarif[i] =$coutElec * Math.pow(1 + $inflationElec / 100, i)}return tarif})})
this.turpe = derived([this.p.puissance, this.p.turpe, this.p.autoconso, this.productionAnnuelle, this.p.turpe_injection, this.p.inflation, this.N],([$puissance, $turpe, $autoconso, $productionAnnuelle, $turpeInjection, $inflation, $N], _, update) => {update((turpe) => {if (!turpe || turpe.length < $N) {turpe = Array($N);}for (let i = 0; i < $N; i++) {turpe[i] = ($puissance * $turpe +(1 - $autoconso / 100) * $productionAnnuelle[i] * $turpeInjection) * Math.pow(1 + $inflation / 100, i)}return turpe})})
this.chiffreAffaires = derived([this.primeInvestissement,this.productionAnnuelle,this.p.autoconso,this.tarifLocal,this.tarifSurplus,this.p.autoprod,this.tarifAllo,this.N,],([$primeInvestissement,$productionAnnuelle,$autoconso,$tarifLocal,$tarifSurplus,$autoprod,$tarifAllo,$N,],_,update) => {update((ca) => {if (!ca || ca.length < $N) {ca = Array($N)}for (let i = 0; i < $N; i++) {ca[i] =(i == 0 ? $primeInvestissement : 0) +$productionAnnuelle[i] *(($autoconso / 100) * $tarifLocal[i] +(1 - $autoconso / 100) * $tarifSurplus[i] +($autoprod / 100) * $tarifAllo[i])}return ca})})
this.assurance = derived([this.investissement, this.p.assurance, this.p.inflation, this.N],([$investissement, $assurance, $inflation, $N], _, update) => {update((assurance) => {if (!assurance || assurance.length < $N) {assurance = Array($N);}for (let i = 0; i < $N; i++) {assurance[i] = (($investissement * $assurance) / 100)* Math.pow(1 + $inflation / 100, i)}return assurance})})
this.turpe = derived([this.p.puissance,this.p.turpe,this.p.autoconso,this.productionAnnuelle,this.p.turpe_injection,this.p.inflation,this.N,],([$puissance,$turpe,$autoconso,$productionAnnuelle,$turpeInjection,$inflation,$N,],_,update) => {update((turpe) => {if (!turpe || turpe.length < $N) {turpe = Array($N)}for (let i = 0; i < $N; i++) {turpe[i] =($puissance * $turpe +(1 - $autoconso / 100) *$productionAnnuelle[i] *$turpeInjection) *Math.pow(1 + $inflation / 100, i)}return turpe})})
this.exploitation = derived([this.p.puissance, this.p.maintenance, this.p.inflation, this.N],([$puissance, $maintenance, $inflation, $N], _, update) => {update((expl) => {if (!expl || expl.length < $N) {expl = Array($N);}for (let i = 0; i < $N; i++) {expl[i] = $puissance * $maintenance* Math.pow(1 + $inflation / 100, i)}return expl})})
this.assurance = derived([this.investissement, this.p.assurance, this.p.inflation, this.N],([$investissement, $assurance, $inflation, $N], _, update) => {update((assurance) => {if (!assurance || assurance.length < $N) {assurance = Array($N)}for (let i = 0; i < $N; i++) {assurance[i] =(($investissement * $assurance) / 100) *Math.pow(1 + $inflation / 100, i)}return assurance})})
this.divers = derived([this.p.divers, this.p.puissance, this.p.inflation, this.N],([$divers, $puissance, $inflation, $N], _, update) => {update((divers) => {if (!divers || divers.length < $N) {divers = Array($N);}for (let i = 0; i < $N; i++) {divers[i] = $divers * $puissance* Math.pow(1 + $inflation / 100, i)}return divers})})
this.exploitation = derived([this.p.puissance, this.p.maintenance, this.p.inflation, this.N],([$puissance, $maintenance, $inflation, $N], _, update) => {update((expl) => {if (!expl || expl.length < $N) {expl = Array($N)}for (let i = 0; i < $N; i++) {expl[i] =$puissance *$maintenance *Math.pow(1 + $inflation / 100, i)}return expl})})
this.charges = derived([this.investissement, this.p.frais_divers, this.exploitation, this.turpe, this.assurance, this.divers, this.N],([$investissement, $fraisDivers, $exploitation, $turpe, $assurance, $divers, $N], _, update) => {update((charges) => {if (!charges || charges.length < $N) {charges = Array($N);}for (let i = 0; i < $N; i++) {charges[i] = ($investissement && i == 0 ? $fraisDivers : 0) + $exploitation[i] + $turpe[i] + $assurance[i] + $divers[i]}return charges})})
this.divers = derived([this.p.divers, this.p.puissance, this.p.inflation, this.N],([$divers, $puissance, $inflation, $N], _, update) => {update((divers) => {if (!divers || divers.length < $N) {divers = Array($N)}for (let i = 0; i < $N; i++) {divers[i] =$divers *$puissance *Math.pow(1 + $inflation / 100, i)}return divers})})
this.valeurAjoutee = derived([this.chiffreAffaires, this.charges, this.N],([$chiffreAffaires, $charges, $N], _, update) => {update((va) => {if (!va || va.length < $N) {va = Array($N);}for (let i = 0; i < $N; i++) {va[i] = $chiffreAffaires[i] - $charges[i]}return va})})
this.charges = derived([this.investissement,this.p.frais_divers,this.exploitation,this.turpe,this.assurance,this.divers,this.N,],([$investissement,$fraisDivers,$exploitation,$turpe,$assurance,$divers,$N,],_,update) => {update((charges) => {if (!charges || charges.length < $N) {charges = Array($N)}for (let i = 0; i < $N; i++) {charges[i] =($investissement && i == 0 ? $fraisDivers : 0) +$exploitation[i] +$turpe[i] +$assurance[i] +$divers[i]}return charges})})
this.amortissement = derived([this.p.duree_amortissement, this.investissement, this.N],([$dureeAmortissement, $investissement, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {if (i < $dureeAmortissement) {a[i] = $investissement / $dureeAmortissement} else {a[i] = 0
this.valeurAjoutee = derived([this.chiffreAffaires, this.charges, this.N],([$chiffreAffaires, $charges, $N], _, update) => {update((va) => {if (!va || va.length < $N) {va = Array($N)}for (let i = 0; i < $N; i++) {va[i] = $chiffreAffaires[i] - $charges[i]}return va})
this.provisionOnduleurs = derived([this.p.puissance, this.p.provision_onduleurs, this.p.inflation, this.N],([$puissance, $provision, $inflation, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $puissance * 1000 * $provision * Math.pow(1 + $inflation / 100, i) / 10}return a})});
this.amortissement = derived([this.p.duree_amortissement, this.investissement, this.N],([$dureeAmortissement, $investissement, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {if (i < $dureeAmortissement) {a[i] = $investissement / $dureeAmortissement} else {a[i] = 0}}return a})})
// Accise: taux dérogatoire d'1€/MWh jusqu'au 31/1/2025this.accise = derived([this.productionAnnuelle, this.N],([$productionAnnuelle, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $productionAnnuelle[i] * 0.001}return a})});
this.provisionOnduleurs = derived([this.p.puissance,this.p.provision_onduleurs,this.p.inflation,this.N,],([$puissance, $provision, $inflation, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] =($puissance *1000 *$provision *Math.pow(1 + $inflation / 100, i)) /10}return a})})
// Exonération de taxe foncière: https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000044996150this.taxeFonciere = readable(0)
// Accise: taux dérogatoire d'1€/MWh jusqu'au 31/1/2025this.accise = derived([this.productionAnnuelle, this.N],([$productionAnnuelle, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] = $productionAnnuelle[i] * 0.001}return a})})
this.ifer = derived([this.p.puissance, this.p.ratio_dc_ac, this.N],([$puissance, $ratio, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $puissance < 100 ? 0 : 3.394 * $puissance * $ratio}return a})});
// Formule compliquée, exonéré sur les cas concretsthis.cfe = readable(0)
this.impots = derived([this.ifer, this.taxeFonciere, this.cfe, this.N],([$ifer, $taxeFonciere, $cfe, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $ifer[i] + $taxeFonciere + $cfe}return a})});
this.ifer = derived([this.p.puissance, this.p.ratio_dc_ac, this.N],([$puissance, $ratio, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] =$puissance < 100 ? 0 : 3.394 * $puissance * $ratio}return a})})
this.ebe = derived([this.valeurAjoutee, this.impots, this.N],([$va, $impots, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $va[i] - $impots[i]}return a})});
this.impots = derived([this.ifer, this.taxeFonciere, this.cfe, this.N],([$ifer, $taxeFonciere, $cfe, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] = $ifer[i] + $taxeFonciere + $cfe}return a})})
this.dette = derived([this.investissement, this.p.apport],([$inv, $app]) => Math.max(0, $inv - $app))
this.ebe = derived([this.valeurAjoutee, this.impots, this.N],([$va, $impots, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] = $va[i] - $impots[i]}return a})})
this.dette.subscribe(this.banque.dette.set)this.p.echeances.subscribe(this.banque.duree.set)this.p.interet.subscribe(($interet) => this.banque.taux.set($interet/100))
this.dette = derived([this.investissement, this.p.apport],([$inv, $app]) => Math.max(0, $inv - $app))
this.interetsDetteSenior = derived([this.banque.resultat, this.N],([$banque, $N], _, update) => {update((ids) => {if (!ids || ids.length < $N) {ids = Array($N);}for (let i = 0; i < $N; i++) {ids[i] = i < $banque.interetsAnnuels.length ? $banque.interetsAnnuels[i] : 0}return ids})})
this.dette.subscribe(this.banque.dette.set)this.p.echeances.subscribe(this.banque.duree.set)this.p.interet.subscribe(($interet) =>this.banque.taux.set($interet / 100))
this.interetsDSRA = derived([this.interetsDetteSenior, this.p.taux_dsra, this.N],([$ids, $taux, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N);}for (let i = 0; i < $N; i++) {a[i] = $ids[i] * $taux / 100}return a})});
this.interetsDetteSenior = derived([this.banque.resultat, this.N],([$banque, $N], _, update) => {update((ids) => {if (!ids || ids.length < $N) {ids = Array($N)}for (let i = 0; i < $N; i++) {ids[i] =i < $banque.interetsAnnuels.length? $banque.interetsAnnuels[i]: 0}return ids})})
this.resultatFiscal = derived([this.ebe, this.amortissement, this.provisionOnduleurs, this.interetsDetteSenior, this.interetsDSRA, this.N],([$ebe, $amortissement, $provision, $ids, $dsra, $N], _, update) => {update((rf) => {if (!rf || rf.length < $N) {rf = Array($N);}for (let i = 0; i < $N; i++) {rf[i] = $ebe[i] - $amortissement[i] - $provision[i] - $ids[i] - $dsra[i]}return rf})})
this.interetsDSRA = derived([this.interetsDetteSenior, this.p.taux_dsra, this.N],([$ids, $taux, $N], _, update) => {update((a) => {if (!a || a.length < $N) {a = Array($N)}for (let i = 0; i < $N; i++) {a[i] = ($ids[i] * $taux) / 100}return a})})
this.is = derived([this.resultatFiscal, this.p.taux_is, this.N],([$r, $taux, $N], _, update) => {update((is) => {if (!is || is.length < $N) {is = Array($N);}for (let i = 0; i < $N; i++) {is[i] = $r[i] <= 0 ? 0 : ($r[i] * $taux / 100)}return is})})
this.resultatFiscal = derived([this.ebe,this.amortissement,this.provisionOnduleurs,this.interetsDetteSenior,this.interetsDSRA,this.N,],([$ebe, $amortissement, $provision, $ids, $dsra, $N],_,update) => {update((rf) => {if (!rf || rf.length < $N) {rf = Array($N)}for (let i = 0; i < $N; i++) {rf[i] =$ebe[i] -$amortissement[i] -$provision[i] -$ids[i] -$dsra[i]}return rf})})
this.resultatNet = derived([this.resultatFiscal, this.is, this.N],([$r, $is, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N);}for (let i = 0; i < $N; i++) {r[i] = $r[i] - $is[i]}return r})})
this.is = derived([this.resultatFiscal, this.p.taux_is, this.N],([$r, $taux, $N], _, update) => {update((is) => {if (!is || is.length < $N) {is = Array($N)}for (let i = 0; i < $N; i++) {is[i] = $r[i] <= 0 ? 0 : ($r[i] * $taux) / 100}return is})})
this.tresorerieDisponibleDetteSenior = derived([this.ebe, this.is, this.N],([$ebe, $is, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N);}for (let i = 0; i < $N; i++) {r[i] = $ebe[i] - $is[i]}return r})})
this.resultatNet = derived([this.resultatFiscal, this.is, this.N],([$r, $is, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N)}for (let i = 0; i < $N; i++) {r[i] = $r[i] - $is[i]}return r})})
this.serviceDetteSenior = derived([this.interetsDSRA, this.interetsDetteSenior, this.banque.resultat, this.N],([$dsra, $ids, $b, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N);}for (let i = 0; i < $N; i++) {r[i] = $dsra[i] + $ids[i] + $b.remboursementAnnuel[i]}return r})})
this.tresorerieDisponibleDetteSenior = derived([this.ebe, this.is, this.N],([$ebe, $is, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N)}for (let i = 0; i < $N; i++) {r[i] = $ebe[i] - $is[i]}return r})})
this.dscr = derived([this.banque.resultat, this.tresorerieDisponibleDetteSenior,this.serviceDetteSenior, this.N],([$b, $treso, $service, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N);}for (let i = 0; i < $N; i++) {if (i < $b.remboursementAnnuel.length) {r[i] = $treso[i] / $service[i]} else {r[i] = 0
this.serviceDetteSenior = derived([this.interetsDSRA,this.interetsDetteSenior,this.banque.resultat,this.N,],([$dsra, $ids, $b, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N)}for (let i = 0; i < $N; i++) {r[i] = $dsra[i] + $ids[i] + $b.remboursementAnnuel[i]}return r})
}
this.dscr = derived([this.banque.resultat,this.tresorerieDisponibleDetteSenior,this.serviceDetteSenior,this.N,],([$b, $treso, $service, $N], _, update) => {update((r) => {if (!r || r.length < $N) {r = Array($N)}for (let i = 0; i < $N; i++) {if (i < $b.remboursementAnnuel.length) {r[i] = $treso[i] / $service[i]} else {r[i] = 0}}return r})})}
tarifSurplus: Readable<Array<number>>;productionAnnuelle: Readable<Array<number>>;tarifLocal: Readable<Array<number>>;tarifAllo: Readable<Array<number>>;chiffreAffaires: Readable<Array<number>>;turpe: Readable<Array<number>>;assurance: Readable<Array<number>>;exploitation: Readable<Array<number>>;divers: Readable<Array<number>>;charges: Readable<Array<number>>;valeurAjoutee: Readable<Array<number>>;accise: Readable<Array<number>>;taxeFonciere: Readable<number>;cfe: Readable<number>;ifer: Readable<Array<number>>;impots: Readable<Array<number>>;ebe: Readable<Array<number>>;amortissement: Readable<Array<number>>;resultatFiscal: Readable<Array<number>>;provisionOnduleurs: Readable<Array<number>>;interetsDetteSenior: Readable<Array<number>>;interetsDSRA: Readable<Array<number>>;is: Readable<Array<number>>;dette: Readable<number>;resultatNet: Readable<Array<number>>;dscr: Readable<Array<number>>;tresorerieDisponibleDetteSenior: Readable<Array<number>>;serviceDetteSenior: Readable<Array<number>>;
tarifSurplus: Readable<Array<number>>productionAnnuelle: Readable<Array<number>>tarifLocal: Readable<Array<number>>tarifAllo: Readable<Array<number>>chiffreAffaires: Readable<Array<number>>turpe: Readable<Array<number>>assurance: Readable<Array<number>>exploitation: Readable<Array<number>>divers: Readable<Array<number>>charges: Readable<Array<number>>valeurAjoutee: Readable<Array<number>>accise: Readable<Array<number>>taxeFonciere: Readable<number>cfe: Readable<number>ifer: Readable<Array<number>>impots: Readable<Array<number>>ebe: Readable<Array<number>>amortissement: Readable<Array<number>>resultatFiscal: Readable<Array<number>>provisionOnduleurs: Readable<Array<number>>interetsDetteSenior: Readable<Array<number>>interetsDSRA: Readable<Array<number>>is: Readable<Array<number>>dette: Readable<number>resultatNet: Readable<Array<number>>dscr: Readable<Array<number>>tresorerieDisponibleDetteSenior: Readable<Array<number>>serviceDetteSenior: Readable<Array<number>>
remboursement: Array<number>,remboursementAnnuel: number[],crd: number[],crdAnnuel: number[],interets: number[],interetsAnnuels: number[]
remboursement: Array<number>remboursementAnnuel: number[]crd: number[]crdAnnuel: number[]interets: number[]interetsAnnuels: number[]
prorataPeriodique = derived(this.nombrePeriodesParAn, (n) => 1 / n)// V6dureeAns = derived([this.duree, this.nombrePeriodesParAn], ([$a, $b]) => $a / $b);dureeAns_ = derived(this.dureeAns, Math.ceil)
// V6dureeAns = derived([this.duree, this.nombrePeriodesParAn],([$a, $b]) => $a / $b)
resultat: Readable<Resultat> = derived([this.duree, this.dureeAns_, this.dette,this.periodeRemboursementCapital,this.nombreEcheancesPeriodeTronquee,this.taux_,this.prorataPeriodique,this.periodeRemboursementCapital,this.totalPeriodes,this.nombreEcheances,this.nombrePeriodesParAn,], ([$duree, $dureeAns_, $dette, $periode,$nombreEcheancesPeriodeTronquee,$taux_,$prorataPeriodique,$periodeRemboursementCapital,$totalPeriodes,$nombreEcheances,$nombrePeriodesParAn,], _, update) => {update((resultat) => {if (resultat.remboursement.length != $duree + 1) {
// X11periodeRemboursementCapital = this.dureeDifferee
resultat.remboursement = new Array($duree + 1)resultat.crd = new Array($duree + 1)resultat.interets = new Array($duree + 1)
resultat: Readable<Resultat> = derived([this.duree,this.dureeAns_,this.dette,this.periodeRemboursementCapital,this.nombreEcheancesPeriodeTronquee,this.taux_,this.prorataPeriodique,this.periodeRemboursementCapital,this.totalPeriodes,this.nombreEcheances,this.nombrePeriodesParAn,],([$duree,$dureeAns_,$dette,$periode,$nombreEcheancesPeriodeTronquee,$taux_,$prorataPeriodique,$periodeRemboursementCapital,$totalPeriodes,$nombreEcheances,$nombrePeriodesParAn,],_,update) => {update((resultat) => {if (resultat.remboursement.length != $duree + 1) {resultat.remboursement = new Array($duree + 1)resultat.crd = new Array($duree + 1)resultat.interets = new Array($duree + 1)
resultat.remboursementAnnuel = new Array($dureeAns_)resultat.crdAnnuel = new Array($dureeAns_)resultat.interetsAnnuels = new Array($dureeAns_)}
resultat.remboursementAnnuel = new Array($dureeAns_)resultat.crdAnnuel = new Array($dureeAns_)resultat.interetsAnnuels = new Array($dureeAns_)}
resultat.crd[0] = $detteresultat.remboursement[0] = 0resultat.interets[0] = 0resultat.crdAnnuel[0] = $detteresultat.remboursementAnnuel[0] = 0resultat.interetsAnnuels[0] = 0for (let i = 1; i <= $duree; i++) {if (i <= $periode) {resultat.remboursement[i] = 0} else if (i < $nombreEcheancesPeriodeTronquee) {resultat.remboursement[i] = ppmt($taux_ * $prorataPeriodique,i - $periodeRemboursementCapital,$totalPeriodes,-$dette)} else if (i == $nombreEcheances) {resultat.remboursement[i] = resultat.crd[i - 1]} else {resultat.remboursement[i] = 0}resultat.crd[i] = resultat.crd[i - 1] - resultat.remboursement[i]resultat.interets[i] = resultat.crd[i - 1] * $taux_ * $prorataPeriodiqueif (i % $nombrePeriodesParAn == 0) {resultat.crdAnnuel[i / $nombrePeriodesParAn] = resultat.crd[i]resultat.remboursementAnnuel[i / $nombrePeriodesParAn] = 0resultat.interetsAnnuels[i / $nombrePeriodesParAn] = 0
resultat.crd[0] = $detteresultat.remboursement[0] = 0resultat.interets[0] = 0resultat.crdAnnuel[0] = $detteresultat.remboursementAnnuel[0] = 0resultat.interetsAnnuels[0] = 0for (let i = 1; i <= $duree; i++) {if (i <= $periode) {resultat.remboursement[i] = 0} else if (i < $nombreEcheancesPeriodeTronquee) {resultat.remboursement[i] = ppmt($taux_ * $prorataPeriodique,i - $periodeRemboursementCapital,$totalPeriodes,-$dette)} else if (i == $nombreEcheances) {resultat.remboursement[i] = resultat.crd[i - 1]} else {resultat.remboursement[i] = 0}resultat.crd[i] =resultat.crd[i - 1] - resultat.remboursement[i]resultat.interets[i] =resultat.crd[i - 1] * $taux_ * $prorataPeriodiqueif (i % $nombrePeriodesParAn == 0) {resultat.crdAnnuel[i / $nombrePeriodesParAn] =resultat.crd[i]resultat.remboursementAnnuel[i / $nombrePeriodesParAn] =0resultat.interetsAnnuels[i / $nombrePeriodesParAn] = 0}resultat.remboursementAnnuel[Math.floor(i / $nombrePeriodesParAn)] += resultat.remboursement[i]resultat.interetsAnnuels[Math.floor(i / $nombrePeriodesParAn)] += resultat.interets[i]}return resultat})},{remboursement: new Array(0),remboursementAnnuel: new Array(0),crd: new Array(0),crdAnnuel: new Array(0),interets: new Array(0),interetsAnnuels: new Array(0),
resultat.remboursementAnnuel[Math.floor(i / $nombrePeriodesParAn)] +=resultat.remboursement[i]resultat.interetsAnnuels[Math.floor(i / $nombrePeriodesParAn)] += resultat.interets[i]}return resultat})}, {remboursement: new Array(0),remboursementAnnuel: new Array(0),crd: new Array(0),crdAnnuel: new Array(0),interets: new Array(0),interetsAnnuels: new Array(0),});
)
inputs: PVGISInputs,outputs: {hourly: {time: string'G(i)': numberP: numberT2m: numberH_sun: numberInt: number}[],},
inputs: PVGISInputsoutputs: {hourly: {time: string'G(i)': numberP: numberT2m: numberH_sun: numberInt: number}[]}
puissance: number,communaute: (Grain.Communaute & { isMoving?: boolean }) | null,pvgis: Writable<{ pvgis: PVGIS | null, loading: boolean }>,soleil_: Writable<Sample>,base: string,
puissance: number,communaute: (Grain.Communaute & { isMoving?: boolean }) | null,pvgis: Writable<{ pvgis: PVGIS | null; loading: boolean }>,soleil_: Writable<Sample>
if (communaute?.isMoving) {return}console.log("updatePv", puissance);let azimuth = 0;let p_total = 0;let inclinaison = 0;
if (communaute?.isMoving) {return}console.log('updatePv', puissance)let azimuth = 0let p_total = 0let inclinaison = 0
console.log("com", communaute)if (communaute?.compteurs) {for (let c of communaute.compteurs) {azimuth += c.azimuth * c.puissance;inclinaison += c.inclinaison * c.puissance;p_total += c.puissance;}if (p_total <= puissance) {inclinaison += lat * (puissance - p_total)} else {azimuth *= puissance / p_total;inclinaison *= puissance / p_total;}
console.log('com', communaute)if (communaute?.compteurs) {for (const c of communaute.compteurs) {azimuth += c.azimuth * c.puissanceinclinaison += c.inclinaison * c.puissancep_total += c.puissance}if (p_total <= puissance) {inclinaison += lat * (puissance - p_total)} else {azimuth *= puissance / p_totalinclinaison *= puissance / p_total}
if (puissance > 0) {azimuth /= puissanceinclinaison /= puissance} else {azimuth = 0;inclinaison = lat;
if (puissance > 0) {azimuth /= puissanceinclinaison /= puissance} else {azimuth = 0inclinaison = lat}azimuth = Math.round(azimuth)inclinaison = Math.round(inclinaison)
azimuth = Math.round(azimuth)inclinaison = Math.round(inclinaison)}let d = new Date()let min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000let max_t = min_t + 364 * 24 * 3600let pvgis_ = get(pvgis);if (!pvgis_.pvgis ||pvgis_.pvgis.inputs.location.latitude != lat ||pvgis_.pvgis.inputs.location.longitude != lng ||pvgis_.pvgis.inputs.mounting_system.fixed.slope['value'] != inclinaison ||pvgis_.pvgis.inputs.mounting_system.fixed.azimuth['value'] != azimuth) {console.log("Updating PVGIS", lat, lng, inclinaison, azimuth);pvgis_.loading = truepvgis.set(pvgis_)await tick()console.log(inclinaison, azimuth, p_total);let annuelle = await fetch(`${base}/pvgis?lat=${lat}&lng=${lng}&azimuth=${azimuth}&inclinaison=${inclinaison}`)pvgis_.pvgis = await annuelle.json()pvgis_.loading = false;pvgis.set(pvgis_)}console.log(pvgis);let soleil = get(soleil_)soleil.hourly = { x: [], y: [] };soleil.daily = { x: [], y: [] };soleil.weekly = { x: [], y: [] };const start = new Date(min_t * 1000)const janvier = new Date(start.getFullYear(), 0, 1)console.log("UP")for (let t = min_t; t < max_t; t += 3600) {let tt = new Date(t * 1000)// let tts = tt.toLocaleString()// let tds = tt.toLocaleDateString()let pp = 0if (pvgis_.pvgis) {let len = pvgis_.pvgis.outputs.hourly.lengthlet n = ((t * 1000 - janvier.getTime()) / 3600000) % lenconst pvvar = 'P'pp =(pvgis_.pvgis.outputs.hourly[Math.floor(n)][pvvar] * puissance) /1000
const d = new Date()const min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000const max_t = min_t + 364 * 24 * 3600const pvgis_ = get(pvgis)if (!pvgis_.pvgis ||pvgis_.pvgis.inputs.location.latitude != lat ||pvgis_.pvgis.inputs.location.longitude != lng ||pvgis_.pvgis.inputs.mounting_system.fixed.slope['value'] !=inclinaison ||pvgis_.pvgis.inputs.mounting_system.fixed.azimuth['value'] != azimuth) {console.log('Updating PVGIS', lat, lng, inclinaison, azimuth)pvgis_.loading = truepvgis.set(pvgis_)await tick()console.log(inclinaison, azimuth, p_total)const annuelle = await fetch(resolve(`/pvgis?lat=${lat}&lng=${lng}&azimuth=${azimuth}&inclinaison=${inclinaison}`,{}))pvgis_.pvgis = await annuelle.json()pvgis_.loading = falsepvgis.set(pvgis_)}console.log(pvgis)const soleil = get(soleil_)soleil.hourly = { x: [], y: [] }soleil.daily = { x: [], y: [] }soleil.weekly = { x: [], y: [] }const start = new Date(min_t * 1000)const janvier = new Date(start.getFullYear(), 0, 1)console.log('UP')for (let t = min_t; t < max_t; t += 3600) {const tt = new Date(t * 1000)// let tts = tt.toLocaleString()// let tds = tt.toLocaleDateString()let pp = 0if (pvgis_.pvgis) {const len = pvgis_.pvgis.outputs.hourly.lengthconst n = ((t * 1000 - janvier.getTime()) / 3600000) % lenconst pvvar = 'P'pp =(pvgis_.pvgis.outputs.hourly[Math.floor(n)][pvvar] *puissance) /1000
soleil.hourly.x.push(tt)soleil.hourly.y.push(pp)if ((t - min_t) % (24 * 3600) == 0) {if ((t - min_t) % (24 * 7 * 3600) == 0) {soleil.weekly.x.push(tt)soleil.weekly.y.push(pp)} else {soleil.weekly.y[soleil.weekly.y.length - 1] += pp
soleil.hourly.x.push(tt)soleil.hourly.y.push(pp)if ((t - min_t) % (24 * 3600) == 0) {if ((t - min_t) % (24 * 7 * 3600) == 0) {soleil.weekly.x.push(tt)soleil.weekly.y.push(pp)} else {soleil.weekly.y[soleil.weekly.y.length - 1] += pp}soleil.daily.x.push(tt)soleil.daily.y.push(pp)} else {soleil.daily.y[soleil.daily.y.length - 1] += ppsoleil.weekly.y[soleil.weekly.y.length - 1] += pp}
export async function profile_(assets: string, profils_: Record<string, { profils: string[] }>, name: string, _fetch?: Fetch): Promise<{ coefs: number[], total: number }> {await tick();let profiles = await Promise.all(profils_[name].profils.map(async (x) => {let url = `${assets}/profiles/${x}.csv`let resp = await (_fetch? _fetch:fetch)(url)return await resp.text()}))
export async function profile_(profils_: Record<string, { profils: string[] }>,name: string,_fetch?: Fetch): Promise<{ coefs: number[]; total: number }> {await tick()const profiles = await Promise.all(profils_[name].profils.map(async (x) => {const url = asset(`/profiles/${x}.csv`)const resp = await (_fetch ? _fetch : fetch)(url)return await resp.text()}))
let annee = []let total = 0let file = 0for (let p of profiles) {let l = 0for (let line of p.split('\n')) {if (!line) {continue}const col = line.split(',')// const week = parseInt(col[0])// const dow = parseInt(col[1])const cs = parseFloat(col[2])const cj = parseFloat(col[3])for (let i = 0; i < 48; i++) {let ch = parseFloat(col[5 + i])const c = cs * cj * chif (file == 0) {annee.push(c)} else {annee[l] += c
const annee = []let total = 0let file = 0for (const p of profiles) {let l = 0for (const line of p.split('\n')) {if (!line) {continue}const col = line.split(',')// const week = parseInt(col[0])// const dow = parseInt(col[1])const cs = parseFloat(col[2])const cj = parseFloat(col[3])for (let i = 0; i < 48; i++) {const ch = parseFloat(col[5 + i])const c = cs * cj * chif (file == 0) {annee.push(c)} else {annee[l] += c}total += c}l += 1
assets: string,annee: Record<number, number[]>,profils: Grain.Profil[],profils_: Record<string, { profils: string[] }>,somme: Sample,
annee: Record<number, number[]>,profils: Grain.Profil[],profils_: Record<string, { profils: string[] }>,somme: Sample,
fetch?: Fetch,): Promise<{auto: number, totalProd: number, totalConso: number}> {let annee_: Record<string, { t: number[]; y: number[]; i: number }> = {}
fetch?: Fetch): Promise<{ auto: number; totalProd: number; totalConso: number }> {const annee_: Record<string, { t: number[]; y: number[]; i: number }> = {}
let d = new Date()const min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000const max_t = min_t + 364 * 24 * 3600for (let [prm, r] of Object.entries(annee)) {let d: { t: number[]; y: number[]; i: number } = {t: [],y: [],i: 0,}let i = 0for (let t = min_t; t < max_t; t += 1800) {d.t.push(t)d.y.push(r[i] / 1000)i += 1
const d = new Date()const min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000const max_t = min_t + 364 * 24 * 3600for (const [prm, r] of Object.entries(annee)) {const d: { t: number[]; y: number[]; i: number } = {t: [],y: [],i: 0,}let i = 0for (let t = min_t; t < max_t; t += 1800) {d.t.push(t)d.y.push(r[i] / 1000)i += 1}annee_[prm] = d
if (profils.length > 0) {let pi = 0;for (let p of profils) {let d: { t: number[]; y: number[]; i: number } = {t: [],y: [],i: 0,}let i = 0let pp = profil_cache.get(p.type)if (!pp) {pp = await profile_(assets, profils_, p.type, fetch)profil_cache.set(p.type, pp)}for (let t = min_t; t <= max_t; t += 1800) {d.t.push(t)if (pp) {d.y.push((pp.coefs[i] * p.conso) / pp.total)
if (profils.length > 0) {let pi = 0for (const p of profils) {const d: { t: number[]; y: number[]; i: number } = {t: [],y: [],i: 0,}let i = 0let pp = profil_cache.get(p.type)if (!pp) {pp = await profile_(profils_, p.type, fetch)profil_cache.set(p.type, pp)}for (let t = min_t; t <= max_t; t += 1800) {d.t.push(t)if (pp) {d.y.push((pp.coefs[i] * p.conso) / pp.total)}i += 1}annee_[pi] = dpi += 1
}let auto = {auto: 0, totalProd: 0, totalConso: 0}let sol = get(soleil)console.log("update soleil")auto = sample(min_t, max_t, annee_, somme, sol);
let auto = { auto: 0, totalProd: 0, totalConso: 0 }const sol = get(soleil)console.log('update soleil')auto = sample(min_t, max_t, annee_, somme, sol)
const _simulation: Derived = getContext("simulation")const soleil: Writable<Sample> = getContext("soleil")const pvgis: Writable<{ pvgis: PVGIS | null, loading: boolean }> = getContext("pvgis")let maxProd = 0
const _simulation: Derived = getContext('simulation')const soleil: Writable<Sample> = getContext('soleil')const pvgis: Writable<{ pvgis: PVGIS | null; loading: boolean }> =getContext('pvgis')let maxProd = $state(0)
$: consoMoyenneFoyer = (i: number) => Math.min($_consoMoyenneFoyer, H.productionAnnuelle($productible, $puissance, $degradation, i) / $autoprod)
const consoMoyenneFoyer = $derived((i: number) =>Math.min($_consoMoyenneFoyer,H.productionAnnuelle($productible, $puissance, $degradation, i) /$autoprod))
($_coutElec *Math.pow(1 + $inflationElec / 100, i) *consoMoyenneFoyer(i) *(100 - $autoprod)) /100
($_coutElec *Math.pow(1 + $inflationElec / 100, i) *consoMoyenneFoyer(i) *(100 - $autoprod)) /100
$: coutElec_ = coutElec()$: coutElecAuto_ = coutElecAuto()
function format(x: number) {let f = 0let s = ''if (Math.abs(x) <= 1000) {s = ' €'f = x} else if (Math.abs(x) < 1000000) {s = ' k€'f = x / 1000} else if (Math.abs(x) < 1000000000) {s = ' M€'f = x / 1000000} else {s = ' mds€'f = x / 1000000000}return fmt2.format(f) + s}function rentabiliteTaux(resultat: number): string {return (fmt0.format($investissement ? (resultat * 100) / $investissement - 100 : 0) + '%')}let maxa = $state(0)let mina = $state(0)let margin = $state(1)function traceArray(f: Array<number>, n: number) {let c = ''let ai = 0maxa = -1 / 0mina = 1 / 0for (let i = 0; i < n; i++) {ai += f[i]maxa = Math.max(maxa, ai)mina = Math.min(mina, ai)c += ` ${c ? 'L' : 'M'} ${i.toFixed(arr)}, ${-ai.toFixed(arr)}`}if (maxa == -1 / 0) {maxa = 0mina = 0}margin = Math.max(1, (maxa - mina) / 20)return c}const roiDate = $derived.by(() => {let sum = 0let lastNeg = 0for (let i = 0; i < $N; i += 1) {sum += $resultatNet[i]if (sum < 0) lastNeg = i}lastNeg += 1if (lastNeg < $N) {if (lastNeg <= 1 && sum >= 0) {return `Tout de suite`} else if (lastNeg == 1) {return `1 an`} else {return `${lastNeg} ans`}} else {return 'À la saint Glinglin'}})const rembPret = $derived((n: number) => {let totalRembAnnuel_n = $banque.remboursementAnnuel.slice(0, n).reduce((a, b) => a + b, 0)let totalInteret_n = sum_($interetsDetteSenior, n)let totalRembAnnuel = $banque.remboursementAnnuel.reduce((a, b) => a + b,0)let totalInteret = sum_($interetsDetteSenior, n)return fmt0.format(totalRembAnnuel + totalInteret? ((totalRembAnnuel_n + totalInteret_n) * 100) /(totalRembAnnuel + totalInteret): 0)})
viewBox="{Math.floor(-$N * 0.05)} {Math.floor(-maxa - margin)} {Math.ceil($N * 1.1)} {Math.ceil(maxa - mina + 2 * margin)}"
viewBox="{Math.floor(-$N * 0.05)} {Math.floor(-maxa - margin)} {Math.ceil($N * 1.1)} {Math.ceil(maxa - mina + 2 * margin)}"
function format(x: number) {let f = 0let s = ''if (Math.abs(x) <= 1000) {s = ' €'f = x} else if (Math.abs(x) < 1000000) {s = ' k€'f = x / 1000} else if (Math.abs(x) < 1000000000) {s = ' M€'f = x / 1000000} else {s = ' mds€'f = x / 1000000000}return fmt2.format(f) + s}function rentabiliteTaux(resultat: number): string {return (fmt0.format($investissement ? (resultat * 100) / $investissement - 100 : 0) + '%')}let maxa = 0let mina = 0let margin = 1function traceArray(f: Array<number>, n: number) {let c = ''let ai = 0maxa = -1 / 0mina = 1 / 0for (let i = 0; i < n; i++) {ai += f[i]maxa = Math.max(maxa, ai)mina = Math.min(mina, ai)c += ` ${c ? 'L' : 'M'} ${i.toFixed(arr)}, ${-ai.toFixed(arr)}`}if (maxa == -1 / 0) {maxa = 0mina = 0}margin = Math.max(1, (maxa - mina) / 20)return c}$: roiDate = () => {let sum = 0let lastNeg = 0for (let i = 0; i < $N; i += 1) {sum += $resultatNet[i]if (sum < 0) lastNeg = i}lastNeg += 1if (lastNeg < $N) {if (lastNeg <= 1 && sum >= 0) {return `Tout de suite`} else if (lastNeg == 1) {return `1 an`} else {return `${lastNeg} ans`}} else {return 'À la saint Glinglin'}}$: rembPret = (n: number) => {let totalRembAnnuel_n = $banque.remboursementAnnuel.slice(0, n).reduce((a, b) => a + b, 0)let totalInteret_n = sum_($interetsDetteSenior, n)let totalRembAnnuel = $banque.remboursementAnnuel.reduce((a, b) => a + b, 0)let totalInteret = sum_($interetsDetteSenior, n)return fmt0 .format(totalRembAnnuel + totalInteret? ((totalRembAnnuel_n + totalInteret_n) * 100) /(totalRembAnnuel + totalInteret): 0)}$: economieFoyerMois = fmt2.format(coutElec_ ? (coutElec_ - coutElecAuto_) / (coutElec_ / ($N * 12)) : 0)
save: async ({ params, request, platform }) => {if (!platform) {return null}const id_ = platform.env.USER.idFromName('grain')return await save(id_, params, request, platform)
save: async () => {console.log('Pas de sauvegarde configurée')
del: async ({ params, platform }) => {if (!platform) {return null}const id_ = platform.env.USER.idFromName('grain')return await del(id_, params, platform)
del: async () => {console.log('Pas de sauvegarde configurée')
setContext("simulation", simulation)setContext("banque", simulation.banque)setContext("communaute", writable(null))
let simulation = new Derived(data.simulation)setContext('simulation', simulation)setContext('banque', simulation.banque)setContext('communaute', writable(null))
setContext("expert", expert)setContext("pvgis", writable({ pvgis: null, loading: false }))setContext("soleil", writable({hourly: {x: <string[]>[],y: <number[]>[],},daily: {x: <string[]>[],y: <number[]>[],},weekly: {
setContext('expert', expert)setContext('pvgis', writable({ pvgis: null, loading: false }))setContext('soleil',writable({hourly: {x: <string[]>[],y: <number[]>[],},daily: {x: <string[]>[],y: <number[]>[],},weekly: {x: <string[]>[],y: <number[]>[],},
},x: <string[]>[],y: <number[]>[],type: 'bar',line: {color: '#ffbf00',width: 1,},marker: {color: '#ffbf00',width: 1,},name: 'Production solaire',bucket: 1,}))
type: 'bar',line: {color: '#ffbf00',width: 1,},marker: {color: '#ffbf00',width: 1,},name: 'Production solaire',bucket: 1,}))
export let root = "/grain/projet/"$: compteActive = $page.route.id?.endsWith("/finances") ?? false$: descriptionActive = $page.route.id?.endsWith("/description") ?? false$: banqueActive = $page.route.id?.endsWith("/banque") ?? false$: expertActive = $page.route.id?.endsWith("/expert") ?? false$: simuActive = $page.route.id?.endsWith("/simulation") ?? false$: syntheseActive = !compteActive && !descriptionActive && !banqueActive && !expertActive && !simuActive
const compteActive = page.route.id?.endsWith('/finances') ?? falseconst descriptionActive = page.route.id?.endsWith('/description') ?? falseconst banqueActive = page.route.id?.endsWith('/banque') ?? falseconst expertActive = page.route.id?.endsWith('/expert') ?? falseconst simuActive = page.route.id?.endsWith('/simulation') ?? falseconst syntheseActive =!compteActive &&!descriptionActive &&!banqueActive &&!expertActive &&!simuActive
on:change={onPuissanceChange} />{#if data.simulation.puissance > 3000}<span class="text-warning"><iclass="bi bi-exclamation-circle-fill me-2" /> Unecommunauté d'autoconsommation ne peut dépasserplus de 3MWc. Les résultats obtenus seront doncpurement hypothétiques.</span>{/if}
onchange={onPuissanceChange} />{#if data.simulation.puissance > 3000}<spanclass="text-warning"><i class="bi bi-exclamation-circle-fill me-2"></i> Une communauté d'autoconsommation ne peutdépasser plus de 3MWc. Les résultats obtenusseront donc purement hypothétiques.</span>{/if}
>Surface totale (m²)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Estimation de la surface de modules photovoltaïques en fonction de la puissance et du ratio (configurable en mode expert)."><i class="bi bi-question-circle" /></button></label>
>Surface totale (m²)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Estimation de la surface de modules photovoltaïques en fonction de la puissance et du ratio (configurable en mode expert)."aria-label="Estimation de la surface de modules photovoltaïques en fonction de la puissance et du ratio (configurable en mode expert)."><i class="bi bi-question-circle"></i></button></label>
>Taux d'autoconsommation (%)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Pourcentage de la production consommée localement, à valider plus finement dans l'onglet Simulation. C'est la valeur que l'application Coturnix optimise."><i class="bi bi-question-circle" /></button>
>Taux d'autoconsommation (%)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Pourcentage de la production consommée localement, à valider plus finement dans l'onglet Simulation. C'est la valeur que l'application Coturnix optimise."aria-label="Pourcentage de la production consommée localement, à valider plus finement dans l'onglet Simulation. C'est la valeur que l'application Coturnix optimise."><i class="bi bi-question-circle"></i></button>
>Taux d'autoproduction (%)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Pourcentage des consommations venant de sources locales, à valider plus finement dans l'onglet Simulation."><i class="bi bi-question-circle" /></button></label>
>Taux d'autoproduction (%)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Pourcentage des consommations venant de sources locales, à valider plus finement dans l'onglet Simulation."aria-label="Pourcentage des consommations venant de sources locales, à valider plus finement dans l'onglet Simulation."><i class="bi bi-question-circle"></i></button></label>
>Prix d'achat fournisseur (€/kWh)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Prix d'achat moyen des consommateurs de la communauté à leur fournisseur d'électricité habituel (par exemple EDF)."><i class="bi bi-question-circle" /></button></label>
>Prix d'achat fournisseur (€/kWh)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Prix d'achat moyen des consommateurs de la communauté à leur fournisseur d'électricité habituel (par exemple EDF)."aria-label="Prix d'achat moyen des consommateurs de la communauté à leur fournisseur d'électricité habituel (par exemple EDF)."><i class="bi bi-question-circle"></i></button></label>
>Prix de vente local (€/kWh)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Hypothèse sur le prix de vente moyen. Dans Coturnix, les producteurs et les consommateurs choisissent leurs prix acceptables, et Coturnix calcule à chaque instant le prix qui maximise la valeur totale créée par la communauté."><i class="bi bi-question-circle" /></button></label>
>Prix de vente local (€/kWh)<buttontype="button"class="btn btn-link align-baseline p-0 ms-2"data-bs-toggle="popover"data-bs-trigger="hover focus"data-bs-content="Hypothèse sur le prix de vente moyen. Dans Coturnix, les producteurs et les consommateurs choisissent leurs prix acceptables, et Coturnix calcule à chaque instant le prix qui maximise la valeur totale créée par la communauté."aria-label="Hypothèse sur le prix de vente moyen. Dans Coturnix, les producteurs et les consommateurs choisissent leurs prix acceptables, et Coturnix calcule à chaque instant le prix qui maximise la valeur totale créée par la communauté."><i class="bi bi-question-circle"></i></button></label>
export let data: PageData & {donnees?: {projets: numberpuissance: numbereconomies: number}}export let base = bexport let assets: string = a
import type { PageProps } from './$types'let { data }: PageProps = $props()
export const load: PageServerLoad = async ({ platform }) => {if (platform && 'env' in platform) {let id_ = platform!.env.USER.idFromName('grain')let projets = await userForm(platform!.env, id_, {ListProjets: null,})return { projets, email: 'grain@coturnix.fr' }} else {return { projets: [], email: '' }}
export const load: PageServerLoad = async () => {return { projets: [], email: '' }
let x0 = Date.parse(event['xaxis.range[0]']) / 1000let x1 = Date.parse(event['xaxis.range[1]']) / 1000let w = x1 - Math.max(0, x0)let layout_ = JSON.parse(JSON.stringify(layout))
const x0 = Date.parse(event['xaxis.range[0]']) / 1000const x1 = Date.parse(event['xaxis.range[1]']) / 1000const w = x1 - Math.max(0, x0)const layout_ = JSON.parse(JSON.stringify(layout))
import { error, redirect } from '@sveltejs/kit'import { base } from '$app/paths'interface EnvUser {USER: DurableObjectNamespace}
export * as Grain from './grain-types'
import type { Grain } from './grain-types'export { Grain } from './grain-types'import { SimulationCommunaute } from './simulation_communaute.js'export { SimulationCommunaute } from './simulation_communaute.js'
export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.CreateProjet): Promise<Grain.CreateProjetResp>export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.SaveProjet): Promise<null>export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.ListProjets): Promise<Grain.ListProjetsResp>export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.DelProjet): Promise<null>export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.GetProjet): Promise<Grain.GetProjetResp>export async function userForm(env: EnvUser,id: DurableObjectId,body: Grain.Cmd): Promise<any> {let headers = new Headers()headers.set('Content-Type', 'application/json')let stub = env.USER.get(id)let x = await (await stub.fetch('https://y.coturnix.fr', {method: 'POST',body: JSON.stringify(body),headers,})).text()console.log('userForm json', x)return JSON.parse(x)}export async function save(id_: DurableObjectId,params: { id?: string },request: Request,platform: Readonly<App.Platform>) {const f = await request.formData()const data_ = f.get('data')let dataif (data_) {console.log('data', data_)data = JSON.parse(data_ as string)if (!SimulationCommunaute(data)) {throw error(400, 'Bad request')}} else {throw error(400, 'Bad request')}const prms = JSON.parse(<string>f.get('prms') || '[]')const centrales = JSON.parse(<string>f.get('centrales') || '[]')const nom = <string>f.get('nom') || ''const porteur = <string>f.get('porteur') || ''const adresse = <string>f.get('adresse') || ''const tel = <string>f.get('tel') || ''const photo = <string | null>f.get('photo')console.log('params!', params)let pidif (params['id'] == 'nouveau') {pid = await userForm(platform.env, id_, {CreateProjet: {nom,porteur,tel,adresse,simulation: data,prms,centrales,},})} else if (params['id']) {pid = params['id']await userForm(platform.env, id_, {SaveProjet: {id: pid,nom,porteur,tel,adresse,simulation: data,prms,centrales,},})}console.log(pid, !!photo)/*if (photo) {console.log('photo')try {console.log('f')console.log(photo)await platform.env.projets.put(`photo.${id_.toString()}.${pid}`,photo)console.log('put')} catch (e) {console.log('Error', JSON.stringify(e))}}*/console.log('redirect', `${base}/projet/${pid}`)throw redirect(302, `${base}/projet/${pid}`)}export async function del(id_: DurableObjectId,params: { id?: string },platform: Readonly<App.Platform>) {if (params.id) {await userForm(platform.env, id_, {DelProjet: {id: params['id'],},})throw redirect(302, `${base}`)}}
export type SimulationCommunaute = {puissance: numbereconomies?: numberautoconso: numberautoprod: numberfrais_divers: numberprix: numberapport: numberinteret: numberecheances: numberconso_moyenne_foyer: numberproductible: numberdegradation: number
export type SimulationCommunaute = {puissance: numbereconomies?: numberautoconso: numberautoprod: numberfrais_divers: numberprix: numberapport: numberinteret: numberecheances: numberconso_moyenne_foyer: numberproductible: numberdegradation: numberinflation: numberratio: numberenedis: numbertarif_cre: {limites: number[]prix: number[]
ratio: numberenedis: numbertarif_cre: {limites: number[]prix: number[]inflation: number}cout_elec: numberinflation_elec: numbermaintenance: numberturpe: numberturpe_injection: numberprovision_onduleurs: numberassurance: numberdivers: numberratio_dc_ac: numberduree_amortissement: numbertaux_is: numbertaux_dsra: number
export function newSimulationCommunaute(): SimulationCommunaute {return {puissance: 0,autoconso: 90,autoprod: 10,frais_divers: 1000,prix: 0.13,apport: 10000,interet: 4.5,echeances: 96,conso_moyenne_foyer: 2500, //Kwh/anproductible: 1100,degradation: 0.6,
export function newSimulationCommunaute(): SimulationCommunaute {return {puissance: 0,autoconso: 90,autoprod: 10,frais_divers: 1000,prix: 0.13,apport: 10000,interet: 4.5,echeances: 96,conso_moyenne_foyer: 2500, //Kwh/anproductible: 1100,degradation: 0.6,inflation: 1,ratio: 1.1, // €/Wcenedis: 1500,tarif_cre: {limites: [0, 9, 100],prix: [0.1301, 0.781, 0.1141],
ratio: 1.1, // €/Wcenedis: 1500,tarif_cre: {limites: [0, 9, 100],prix: [0.1301, 0.781, 0.1141],inflation: 1,},cout_elec: 0.24, // €inflation_elec: 3, // %maintenance: 7, // €/kWcturpe: 16, // €/kWcturpe_injection: 0.0278,provision_onduleurs: 0.1, // €/Wcassurance: 1, // % des travaux estimé entre 0.5% et 0.8%divers: 12,ratio_dc_ac: 0.8,duree_amortissement: 10, // durée fiscale en annéestaux_is: 25,taux_dsra: 1.7, // %}}export type SaveFunction = (e: Event, nom: string, simulation: SimulationCommunaute, prms: Prm[], profils: Profil[], communaute?: Communaute) => Promise<void>export type Rapport = {id: string,nom: string,simulation: SimulationCommunaute,communaute?: Communaute,production?: number[]charge?: Record<string, number[]>interets_annuel: number[],remboursement_annuel: number[],};export type RapportFunction = (r: Rapport) => Promise<void>export type ListProjets = { ListProjets: null }export type ListProjetsResp = {id: stringnom: stringpuissance: numbert: number}[]export type CreateProjet = {CreateProjet: {nom?: stringporteur?: stringtel?: stringadresse?: stringcentrales: Centrale[]simulation?: SimulationCommunauteprms: Prm[]}
},cout_elec: 0.24, // €inflation_elec: 3, // %maintenance: 7, // €/kWcturpe: 16, // €/kWcturpe_injection: 0.0278,provision_onduleurs: 0.1, // €/Wcassurance: 1, // % des travaux estimé entre 0.5% et 0.8%divers: 12,ratio_dc_ac: 0.8,duree_amortissement: 10, // durée fiscale en annéestaux_is: 25,taux_dsra: 1.7, // %
export type Centrale = {position?: { lat: number; lng: number }azimuth?: numberinclinaison?: number}
export type SaveFunction = (e: Event,nom: string,simulation: SimulationCommunaute,prms: Prm[],profils: Profil[],communaute?: Communaute) => Promise<void>
export type CreateProjetResp = null | string
export type Rapport = {id: stringnom: stringsimulation: SimulationCommunautecommunaute?: Communauteproduction?: number[]charge?: Record<string, number[]>interets_annuel: number[]remboursement_annuel: number[]}
export type SaveProjet = {SaveProjet: {id: stringnom?: stringporteur?: stringtel?: stringadresse?: stringcommunaute?: Communaute,simulation?: SimulationCommunauteprms: Prm[]profils: Profil[]centrales: Centrale[]}}
export type RapportFunction = (r: Rapport) => Promise<void>
export type Prm = {prm: number | nullnom: stringprenom: stringsiret?: stringserie?: stringcodeinsee?: stringnumerorue?: stringpro?: booleanreleve?: stringconsentement?: boolean}
export type ListProjets = { ListProjets: null }export type ListProjetsResp = {id: stringnom: stringpuissance: numbert: number}[]
export type DelProjet = {DelProjet: {id: string}}
export type Prm = {prm: number | nullnom: stringprenom: stringsiret?: stringserie?: stringcodeinsee?: stringnumerorue?: stringpro?: booleanreleve?: stringconsentement?: boolean}
export type Cmd =| ListProjets| CreateProjet| SaveProjet| DelProjet| GetProjet
export type Profil = {type: stringconso: number}export type GetProjet = { GetProjet: string }export type GetProjetResp = null | {id: stringnom?: stringporteur?: stringtel?: stringadresse?: stringcommunaute?: Communautesimulation?: SimulationCommunauteimg?: stringprms: Prm[]profils: Profil[]expert: boolean}
export type LatLng = { lat: number; lng: number }export type Derogation = 'non' | '10' | '20'export type Compteur = {lat: numberlng: numberpuissance: numberazimuth: numberinclinaison: number
export type DelProjet = {DelProjet: {id: string
export function profils(expert: boolean) {let profils_: Record<string, { profils: string[] }> = {
export type LatLng = { lat: number; lng: number }export type Derogation = 'non' | '10' | '20'export type Compteur = {lat: numberlng: numberpuissance: numberazimuth: numberinclinaison: number}export type Communaute = {lat: numberlng: numberderogation: Derogationcompteurs?: Compteur[]}export function profils(expert: boolean) {const profils_: Record<string, { profils: string[] }> = {
}if(expert) {for (let p of ["ENT1-P1","ENT1-P2","ENT1-P3","ENT1-P4","ENT2-P1","ENT2-P2","ENT2-P3","ENT2-P4","ENT3-P1","ENT3-P2","ENT3-P3","ENT3-P4","ENT3-P5","ENT4-P1","ENT4-P2","ENT4-P3","ENT4-P4","ENT5-P1","ENT5-P2","ENT5-P3","ENT5-P4","ENT5-P5","ENT5-P6","ENT5-P7","ENT5-P8","ENT6-P1","ENT6-P2","ENT6-P3","ENT6-P4","ENT6-P5","ENT6-P6","ENT7-P1","ENT7-P2","ENT7-P3","ENT7-P4","ENT7-P5","PRD1-P1","PRD2-P1","PRD3-P1","PRD4-P1","PRO1-P1","PRO1WE-P1","PRO1WE-P2","PRO22WE-P1","PRO22WE-P2","PRO22WE-P3","PRO22WE-P4","PRO2-P1","PRO2-P2","PRO3-P1","PRO3-P2","PRO3-P3","PRO3-P4","PRO3-P5","PRO3-P6","PRO4-P1","PRO4-P2","PRO5-P1","PRO6-P1","PRO6-P2","PRO6-P3","PRO6-P4","RES11-P1","RES11WE-P1","RES11WE-P2","RES1-P1","RES1WE-P1","RES1WE-P2","RES22WE-P1","RES22WE-P2","RES22WE-P3","RES22WE-P4","RES2-P1","RES2-P2","RES2WE-P1","RES2WE-P2","RES2WE-P3","RES3-P1","RES3-P2","RES3-P3","RES3-P4","RES3-P5","RES3-P6","RES4-P1","RES4-P2","RES5-P1","RES5-P2","RES5-P3","RES5-P4",]) {profils_[p] = {profils: [p]
}if (expert) {for (const p of ['ENT1-P1','ENT1-P2','ENT1-P3','ENT1-P4','ENT2-P1','ENT2-P2','ENT2-P3','ENT2-P4','ENT3-P1','ENT3-P2','ENT3-P3','ENT3-P4','ENT3-P5','ENT4-P1','ENT4-P2','ENT4-P3','ENT4-P4','ENT5-P1','ENT5-P2','ENT5-P3','ENT5-P4','ENT5-P5','ENT5-P6','ENT5-P7','ENT5-P8','ENT6-P1','ENT6-P2','ENT6-P3','ENT6-P4','ENT6-P5','ENT6-P6','ENT7-P1','ENT7-P2','ENT7-P3','ENT7-P4','ENT7-P5','PRD1-P1','PRD2-P1','PRD3-P1','PRD4-P1','PRO1-P1','PRO1WE-P1','PRO1WE-P2','PRO22WE-P1','PRO22WE-P2','PRO22WE-P3','PRO22WE-P4','PRO2-P1','PRO2-P2','PRO3-P1','PRO3-P2','PRO3-P3','PRO3-P4','PRO3-P5','PRO3-P6','PRO4-P1','PRO4-P2','PRO5-P1','PRO6-P1','PRO6-P2','PRO6-P3','PRO6-P4','RES11-P1','RES11WE-P1','RES11WE-P2','RES1-P1','RES1WE-P1','RES1WE-P2','RES22WE-P1','RES22WE-P2','RES22WE-P3','RES22WE-P4','RES2-P1','RES2-P2','RES2WE-P1','RES2WE-P2','RES2WE-P3','RES3-P1','RES3-P2','RES3-P3','RES3-P4','RES3-P5','RES3-P6','RES4-P1','RES4-P2','RES5-P1','RES5-P2','RES5-P3','RES5-P4',]) {profils_[p] = {profils: [p],}
Grain est conçu pour être facile à héberger. Si vous n'avez pas besoin de la partie serveur de Coturnix (rapports et historique de PDLs), vous pouvez souscrire à un compte "Workers Paid" chez Cloudflare (5$/mois), puis déployer votre version en trois commandes seulement:
Grain est conçu pour être facile à héberger: