Skip to content

Ontkoppelde bestanden

Jip Claassens edited this page Nov 11, 2026 · 28 revisions

Terug naar Home


Een deel van de berekeningen in RSopen wordt niet elke run opnieuw gedaan, maar eenmalig weggeschreven naar een bestand dat een volgende run terugleest. Dat heet in dit model een ontkoppeld bestand. Deze pagina beschrijft wanneer dat gebeurt, hoe het model bepaalt of zo'n bestand nog bruikbaar is, en wat je moet doen als je iets verandert dat de inhoud ervan bepaalt.

Waarom ontkoppelen

Sommige stappen kosten veel rekentijd en veranderen zelden: de BGT-afgeleiden op 2,5 meter, de pandtypering van de hele BAG, de opbrengsten per ontwikkelpakket. Die hoeven niet bij elke run opnieuw.

GeoDMS houdt zelf niet bij welke uitkomsten door een configuratiewijziging ongeldig zijn geworden. Ontkoppelen is daarom handwerk: de configuratie bepaalt zelf wanneer een bestand hergebruikt mag worden. Het voordeel is snelheid, het risico is dat het model stilzwijgend met een verouderd bestand rekent. De fingerprint hieronder is er om dat risico af te dekken.

De drieslag

Een ontkoppeld item heeft drie takken, gestuurd door een schakelaar:

attribute<...> X := =!ModelParameters/<Iets>Ontkoppeld ? 'Calc_X' : Decoupling/MayReuse ? 'Read_X' : 'Make_X';
  • Calc_X rekent zonder tussenbestand, voor wie het ontkoppelen helemaal uit wil zetten.
  • Read_X leest het bestaande bestand.
  • Make_X levert het bestand plus zijn zijbestand. Het rekenen en schrijven zelf staat in Write_X, dat de StorageName draagt; Make_X := Write_X heeft Decoupling/Write_Fingerprint als ExplicitSupplier.

Die opsplitsing legt de volgorde vast en is geen vormkwestie. Het sjabloon krijgt als derde argument Writers, de naam of namen van de schrijvende items, en hangt die onder Write_Fingerprint. GeoDMS werkt een leverancier bij voordat het item zelf wordt uitgerekend, dus staat het bestand er voordat het zijbestand ontstaat. Andersom, met Write_Fingerprint als leverancier van het schrijvende item, komt het zijbestand als eerste, en een run die afbreekt terwijl het bestand nog wordt uitgerekend laat dan een nieuwe fingerprint naast een oud bestand achter, dat de volgende run als geldig leest (#837).

Vraag daarom altijd Make_X en nooit Write_X: dat laatste schrijft het bestand zonder zijbestand. Een naam in Writers die niet oplost valt op bij het rekenen, met exit 1 en de melding dat de ExplicitSupplier niet is gevonden, voordat er een zijbestand ontstaat.

De schakelaars staan in ModelParameters:

Schakelaar Betekenis
BaseDataOntkoppeld Voorbereidende data die voor alle varianten gelijk is
VariantDataOntkoppeld Voorbereidende data per variant; in batchmodus gestuurd via de omgevingsvariabele met dezelfde naam
StandAllocatieOntkoppeld De standbestanden per zichtjaar; idem via omgevingsvariabele
IndicatorenOntkoppeld Wat een zichtjaar in de indicatoren van zijn voorganger nodig heeft, uit de ketentifs in plaats van uit de levende container van dat zichtjaar; idem via omgevingsvariabele
TabellenUitExport De regionale en landelijke tabellen lezen de kaarten terug die de export van hetzelfde zichtjaar heeft geschreven, in plaats van het levende item te berekenen; idem via omgevingsvariabele
OpbrengstdervingOntkoppeld De opbrengstdervingskaarten van de landbouw als tif, in plaats van ze opnieuw af te leiden uit de WWL-relatiedatabase
BAG_WP5_rel_Ontkoppeld De pandtypering van de BAG
AlwaysRemakeDecoupledFiles Zet alle hergebruik in een keer uit, ongeacht de fingerprints

De fingerprint

Naast een ontkoppeld bestand staat een zijbestand met dezelfde naam plus .params.txt. Daarin staat de lijst waarden die de uitkomst bepalen, als sleutel=waarde gescheiden door puntkomma's, met Engelse sleutelnamen:

bgt_date=20260819;study_area=Nederland;variant=BAU;class_set=Default;...

De fingerprint bepaalt ook de naam van het bestand, zie De hash in de naam hieronder. Staat er een bestand onder de naam die bij de huidige fingerprint hoort, met een zijbestand waarin diezelfde fingerprint staat, dan mag het teruggelezen worden. Anders wordt het gemaakt. Het mechanisme staat in Templates/DecoupledFile_T.dms en wordt aangeroepen als Templates/DecoupledFile_T(FileName, Fingerprint, Writers), met het pad zonder hash, de fingerprint en de schrijvende items uit De drieslag.

Vier regels bij het samenstellen van een fingerprint:

  1. Zet er alle waarden in die de uitkomst bepalen, ook de waarden die al in de bestandsnaam zitten. Dat is bewust dubbelop: zo blijft de regel zonder uitzonderingen en is het zijbestand een leesbaar verslag van waar het bestand vandaan komt.
  2. Het gaat niet alleen om ModelParameters, maar ook om variantinstellingen, klassenindelingen en de datum of versie van de brondata.
  3. Neem bij een klassenset niet alleen de naam op maar ook de inhoud. Een wijziging binnen de set Default verandert de naam niet, dus zonder de vlaggenreeks zelf zou die wijziging onopgemerkt blijven.
  4. Zet er alleen waarden in die zonder rekenen bekend zijn: parameters, paden, de inhoud van een klassentabel en de fingerprints van andere ontkoppelde bestanden, nooit een som of telling over een kaart. De keuze tussen lezen en maken en de bestandsnaam staan in een meta-expressie, en die wordt opgelost bij elke aanroep die het item raakt, ook bij een naamcontrole en bij het uitklappen van de boom in de GUI. Een fingerprint die data vraagt, rekent die data dan elke keer door. Hangt een bestand aan een uitkomst die zelf gerekend wordt, zet dan de invoer van die berekening erin, met een versiesleutel voor haar regels.

Een waarde die vast in de code staat en niet als parameter, zoals een kernelstraal die via het itempad wordt gekozen of een drempel in een expressie, staat als letterlijke waarde in de fingerprint. Verandert die regel in de code, dan hoort de sleutel mee te veranderen, anders blijft een verouderd bestand geldig ogen.

Het mechanisme faalt de goede kant op. Ontbreekt het zijbestand, dan valt het model terug op cfg/no_fingerprint.txt, klopt de vergelijking nooit en wordt er opnieuw gerekend. Ontbreekt het bestand zelf, idem. Wie wil weten waarom een bestand wel of niet opnieuw gemaakt wordt, vraagt het item Decoupling/Explanation op: dat geeft het pad, of het bestand bestaat, de opgeslagen en de huidige fingerprint, en de uitkomst.

De hash in de naam

De naam van een ontkoppeld bestand draagt voor de extensie een hash van 8 hexadecimale tekens over de fingerprint, bijvoorbeeld Sloopkosten_Woningen_Y2023_Nederland_0c47820a.tif met het zijbestand Sloopkosten_Woningen_Y2023_Nederland_0c47820a.tif.params.txt. Elke stand van de invoer krijgt zo een eigen bestand. Een wissel van variant of instelling maakt een nieuw bestand naast het oude, en wie terugwisselt leest het oude bestand terug in plaats van het opnieuw te rekenen (#878).

Het sjabloon krijgt het pad zonder hash en geeft het pad met hash terug als StorageFile; daar wijzen de schrijver en de lezer naar. Een set bestanden onder een fingerprint, zoals de basisjaarstand en de zonneladder, geeft het pad van een van de bestanden mee en zet StorageSuffix in de naam van alle bestanden van de set. De hash is de som over de tekens van de fingerprint van hun code maal 16807 tot de macht van hun positie, modulo 2^31 - 1. Dat zijn alleen gehele getallen, dus de hash is gelijk over GeoDMS-versies en na te rekenen buiten het model; het is dezelfde formule als in NetworkModel_PBL.

Twee controles houden een run tegen voordat er iets gelezen of geschreven wordt. PathGate geeft een fout als het pad, met de langste naam die eronder kan komen (ModelParameters/MaxSubPathLength), langer wordt dan ModelParameters/MaxPathLength; kort dan de naam van de map boven cfg in, want die bepaalt de LocalData. NameGate geeft een fout als er onder dezelfde naam een zijbestand met een andere fingerprint staat. Dat is een botsing van de hash of een met de hand gewijzigd zijbestand; verwijder dan het bestand en zijn zijbestand.

Elke wijziging in de tekst van een fingerprint, ook een nieuwe sleutel die de uitkomst niet verandert, geeft een nieuwe naam en dus een nieuw bestand. Een schakelaar die vast in de code wordt ingebouwd houdt daarom zijn sleutel als letterlijke waarde in de fingerprint. Lees een ontkoppeld bestand buiten het model niet op zijn naam: een patroon met een joker op de plek van de hash vindt ook een oudere stand, en zegt dus dat er iets staat en niet dat de huidige stand er staat.

Een LocalData die gevuld is door een tak zonder dit mechanisme, heeft bestanden zonder hash in hun naam. Een tak met de hash leest die niet en maakt alles opnieuw. batch/OntkoppeldNaarHash.py <LocalData> --uitvoeren hernoemt die bestanden eenmalig. Het rekent de hash uit het zijbestand, dus een bestand komt nooit onder een verkeerde fingerprint terecht.

Oudere standen opruimen

Een oudere stand blijft staan tot iemand hem weghaalt, en een extra volledige stand voor Nederland kost ongeveer 5 GB. batch/OntkoppeldOpruimen.py <LocalData> zet per naam de standen onder elkaar, met hun datum, hun omvang en de sleutels waarin hun fingerprint verschilt van die van de nieuwste stand. Aan dat verschil is te zien of een stand nog terug kan komen, zoals bij een andere variant of instelling, of door de code is ingehaald, zoals bij een hogere versiesleutel of een nieuwe levering. De nieuwste stand per naam blijft altijd staan. Met --in-gebruik en de bestandenlijst van de naamcontrole (.claude/skills/rs-draaien/scripts/naamcontrole.ps1 -Bestanden) blijft ook elke stand staan die de configuratie op dat moment leest. De rest komt in een lijst in <LocalData>/logs.

Verwijderen gaat in een tweede aanroep met die lijst, --verwijderen <lijst>. Het script verwijdert dan precies de paden uit de lijst, met hun bijbestanden, en niets als een pad sindsdien van omvang of datum veranderd is of als er een GeoDMS-proces op die LocalData draait. Wat verwijderd wordt is zo gelijk aan wat er getoond en goedgekeurd is.

Wat een fingerprint heeft

De namen in deze tabel staan zonder hash.

Bestand Sleutels
BaseData/Grondgebruik/EvidentBenutKaart/Klasse_BGT<datum>_BRT<datum>_<studyarea>_25m (de evident-benut-kaart) bgt_date, brt_date, start_year, bag_table, study_area, admin_grid, grid_size, rule (de versiesleutel van de rekenregel), big_water_ha, min_footprint, de BGT-groepen als vlaggen per klasse (bgt_water tot en met bgt_used) en de BRT-tabellen voor functie en terrein
VariantData/<variant>/EvidentBenut, de BGT-kaart van zon bgt_date, study_area, variant, class_set, class_count, class_flags, grid_size
BaseData/Zonneladder/PerAdminDomain bgt_date, brt_date, bbg_year, study_area, admin_grid, step_count, steps
BaseData/StartState/Verblijfsrecreatie_Trends/Trends regio_unit, object_years, area_years, study_area, max_objects_beta, max_area_beta, bag_year, bbg_year
BaseData/Omgeving/BebouwdGebiedMetRand_<peiljaar>_<buffer>m_kern<inwoners>_<studyarea>_<grid>.tif (de stedelijke zone van het stedelijke vrijstaande pakket: het bebouwde gebied van de kernen vanaf een inwonergrens met een rand eromheen) bbg_boundary_year, buffer_m, min_inwoners_kern, inwoners (de jaargang van de CBS-vierkanten), zone (de afbakening), quad_segments, admin_grid, study_area
BaseData/Vastgoed/WoningtypeEengezins/<regio>_<van>_<tot>_BAG<jaar>_<studyarea>.mmd (gebouwd aandeel per woningtype binnen eengezins, voor het quotum in de woonallocatie) alloc_region, cbs_year, build_years, bag_year, bag_date, study_area, min_count, groups, rule
LogitCoef_toegepast_<studyarea>.mmd (herschatting logit verblijfsrecreatie) terms, y, study_area, admin_ref, bbg_year, iters
Verwervingskosten_Woningen_AdminDomain_<studyarea>.tif start_year, bag_recent_year, bag_date, nvm_date, nvm_coeff_year, constr_period_in_price, constr_period_count, constr_period_breaks, wp4_classes, trunc_upper_woononly, trunc_upper, trunc_lower, admin_grid, grid_size, study_area, spread
Verwervingskosten_Niet_Woningen_AdminDomain_<studyarea>.tif woz_year, growth_office, growth_industry, growth_retail, woz_ratio_hall, woz_ratio_other, hall_fraction_default, unit_price_2017, max_storeys_per_cell, unit_price_start_year, start_year, bag_recent_year, bag_date, trunc_upper_woononly, trunc_upper, trunc_lower, combi_split, storey_height_nonres_cm, tolerance_nonres, admin_grid, grid_size, study_area
BaseData/Vastgoed/Vervangingskans_Woningen_AdminDomain_<studyarea>.tif (jaarlijkse kans dat een woning op dezelfde plek wordt vervangen, uit de bouwperiode van haar pand; nul op een perceel met een rijksmonument) start_year, bag_date, brk_date, parcel_coupling, erfgoed_date, heritage_rule, constr_period_count, constr_period_breaks, replacement_rates, admin_grid, grid_size, study_area, spread
BaseData/Vastgoed/Vervanging_Waardefactor_AdminDomain_<studyarea>.tif (hedonische waarde van de vervangen voorraad gedeeld door die van de huidige) start_year, bag_recent_year, bag_date, nvm_date, nvm_coeff_year, constr_period_count, constr_period_breaks, wp4_classes, maintenance_uplift, trunc_upper, trunc_lower, admin_grid, grid_size, study_area, spread
BaseData/Vastgoed/Sloopkosten_Woningen start_year, bag_date, wp4_classes, de vier sloopkentallen per woningtype (rijtjes, twee-onder-een-kap, vrijstaand, appartement), de truncatiegrenzen, wp5_decoupled, pand_inflate_size, grid en study_area
BaseData/Vastgoed/Sloopkosten_Niet_Woningen start_year, bag_date, bag_recent_year, lisa_start_year, bag_logistics_dynamic, logistics_pipeline_heuristic, de kentallen voor hal, overige utiliteit en asbest met drempeljaar, hall_fraction_default, max_storeys_per_cell, de truncatiegrenzen, storey_height_nonres_cm, tolerance_nonres, grid en study_area
BaseData/Grondgebruik/BGT/Fractie_Verhard_<bgt_date>_<kaartjaar>_<studyarea>.mmd (gemiddelde verharding per BGT-klasse uit de verhardingskaart van Copernicus) bgt_date, imperviousness_year, study_area, classes (de klassenlijst, want het bestand heeft een waarde per klasse op rijvolgorde)
BaseData/Grondgebruik/BGT/<soort>Capaciteit_<bgt_date>_Per_AdminDomain_<studyarea>.tif (de zes capaciteitskaarten voor piekbuiberging: halfverharding, holle weg, wadi en halfverharding van wijkweg, woonerf en inrit) bgt_date, study_area, admin_domain, capacity_rule (de versiesleutel voor de rekenregel en de capaciteitsklassen) en avg_paving (de fingerprint van Fractie_Verhard)
BaseData/Grondgebruik/BRT/IsWoonkern brt_date, source_layers, het selectielabel, selection_codes, grid en study_area
BaseData/Grondgebruik/IBIS: IsBedrijfsmatigTerrein, IsVol_grid, RestrictiefWonen, RestrictiefGevoeligeWerkfuncties ibis_year, ibis_sources, stacked_years, grid en study_area, plus per kaart wat haar selectie bepaalt: vol_fraction voor IsVol_grid; buffer_wonen_m, milieucat_count en milieucat_aanvulling voor de twee restrictiekaarten, met min_cat voor de gevoelige werkfuncties; bedrijfsmatig_types, ibis_class_codes en wloc_type_norm voor IsBedrijfsmatigTerrein
BaseData/Grondgebruik/LGN: fr_natuur_tot2500m, fr_water_500m en de twee n_gedekt-noemers lgn_year, de kernelstralen en resoluties, denominator_floor, covered, de klassenlijst met natuur- en watervlaggen, study_area
BaseData/Suitabilities/Werken_raw_<sector> (zes tifs) sector, coeff_date, bag_recent_year, bag_date, bbg_year, uai, de jaartallen van de zes afstandslagen, land_price_year, nodata_fill, grid en study_area
BaseData/Suitabilities/Waterberging: Depth_Norm, IsDiepGenoeg, IsMeer_Nabij_Norm, IsVeen_Nabij_Norm, Kwel_Norm, Wegzijging_Norm, InvUAI_Norm per kaart de bronversie (liwo, kwel, bofek, bag), de normerings- en nabijheidsparameters, bbg_year en lake_classes waar van toepassing, grid en study_area
BaseData/Grondgebruik/Natuur/Ring_rel (NNN-ringkaart) nnn_date, ring_resolution_m, ring_kernels_m, ring_count, ring_names, study_area
BaseData/Omgeving/N2K1000mBuffer en GrootWater1500mBuffer n2k_date respectievelijk bbg_year, buffer_m, grootwater_flags, grid en study_area; de N2K-buffer sluit groot water uit en draagt daarom de volledige fingerprint van de grootwaterbuffer genest mee
BaseData/Omgeving/Netcongestie_Capaciteitskaart<datum>_<studyarea>_<grid>.tif (per cel het jaar waarin de afnamecongestie volgens de capaciteitskaart van Netbeheer Nederland is opgelost, overgenomen van de dichtstbijzijnde postcode; 0 waar geen wachtrij is, 1 bij een wachtrij zonder jaartal) capaciteitskaart_date, bag_date, pc6_year (het BAG-jaar waaruit de ligging van de postcodes komt), nearest_grid, rule, admin_grid, study_area
BaseData/Grondgebruik/NWB/StichtseRotonde nwb_date, street_name, buffer_out_m, buffer_in_m, grid en study_area
BaseData/Grondgebruik/NBP/nbp<jaargang>_INL_Beheertype_<studyarea>_<resolutie>.tif (Natuurbeheerplan) bron, laag, sql, landschapselementen, beheertypen, study_area, admin_domain
BaseData/StandBasisjaar/Landgebruik/Type en JaarVerandering (stand-administratie basisjaar) beheertype_bron, gaten_vullen, beheertype_passend, beheertype_masker, nbp (de fingerprint van de NBP-tif), mnp (die van de MNP-kaart), lgn_year, brp (die van de BRP-gewascodetif), bbg_year, start_year, bag_tabel (de store van de volledige BAG, met de levering in de naam, want die bepaalt in welk pand en dus in welke cel een woning staat), study_area, admin_domain, landgebruik_set, de koppelkolommen lgn_hoofdklasse, lgn_bebouwd, lgn_landbouwtype en brp_landbouwtype, en de drie heuristiektabellen
BaseData/Grondgebruik/MNP/mnp_bau_INL_Beheertype_25m_dekking<d>_<studyarea>.tif (MNP-planpotentieelkaart op 25 meter) bron, minimum_dekking, mnp_val, beheertypen, study_area
BaseData/Landbouw/BRP_Gewascode_25m_<jaar>_<studyarea>.tif (gewascode per cel) brp_year, sql (de letterlijke SqlString, want die bepaalt bij overlap wie wint), study_area, grid_size
BaseData/Landbouw/WWL_Opbrengstderving/<levering>_<anker>_<gewas>_<studyarea>.tif (opbrengstderving per hydrologische levering, klimaatanker en gewas) hydrology, anchor, crop, crop_code, study_area, admin_domain, wwl_db (de netcdf), climate en climate_band, crop_codes en soil_codes (de volgorde waarin de banden van de netcdf zijn ingedeeld), ghg, glg en gxg_fill (de grondwaterstanden van de levering en het anker met hun vulling), soil en soil_fill (BOFEK met de vulling), irrigation en irrigation_map, gxg_scale, gxg_sign en lookup (de opzoeklogica); bij een levering met een veenoplegging daarbij veen_rule, veen_table, bouwsteen_rule, natuurdeel, levering_pv, levering_zpv, trekking, water_mag_land, claim_excl_bebouwd, basisjaar en mnp (de fingerprints van de basisjaarstand en de MNP-kaart), depth, mask, study_area en admin_grid

De fingerprint van de basisjaarstand staat naast de Type-tif van het landgebruik, maar de leeskant van alle 31 standbestanden van het basisjaar toetst hem in haar IntegrityCheck, want die set wordt door Write/Generate in een keer geschreven (#776). Faalt die toets, vraag dan Decoupling_Landgebruik/Explanation op en draai Write/Generate opnieuw, niet een los item, want het zijbestand hangt aan Generate.

Bij de verwervingskosten van niet-woningen is een deel van de fingerprint een benadering. De halfractie per cel komt uit de samenstelling van het vloeroppervlak en hangt aan de BAG-pandset en de hoogteregel op de vbo-oppervlakte, een keten die in geen parameterlijst zit. De sleutels bag_date, bag_recent_year, start_year en de truncatieparameters dekken een nieuwe BAG-levering of een andere truncatie, maar een wijziging in de hal-gewichten of de toedelingsmatrix zelf verandert de fingerprint niet. Zie de Descr bij de fingerprint in BaseData/Suitabilities/Verwervingskosten.dms.

Bij de opbrengstdervingskaarten staan er twee soorten sleutels in die niet uit een parameterlijst komen. De eerste zijn versiesleutels voor de rekenregels: lookup voor de opzoeking in de WWL-relatiedatabase, gxg_fill en soil_fill voor de vulling van de grondwaterstanden en van BOFEK waar de levering niets geeft. Een reparatie aan zo'n regel verandert de uitkomst zonder dat er een invoer verandert, en daarom verandert de sleutel mee met de regel. De tweede is de herkomst van de veenoplegging. Waar een levering de grondwaterstand laat afhangen van de gealloceerde veenbouwsteen (in de NL2120-toepassing NbSGenuanceerd), hangt de kaart aan een allocatie. Volgens regel 4 draagt de fingerprint dan niet die allocatie maar haar invoer: de regels en de opgelegde grondwaterstanden per bouwsteen, de versiesleutel van de bouwsteenallocatie (Veen_T/Regel_Versie), het natuurdeel per bouwsteen, de twee leveringen met hun selectie, de trekkingsparameters, de twee veenkeuzes, de fingerprints van de basisjaarstand en van de MNP-kaart, de LIWO-dieptekaarten, de jaren van het opleggingsmasker, het studiegebied en het raster (#837). De keerzijde is dat een invoer die in die lijst ontbreekt stil een oude kaart laat staan; de lijst in SourceData/Water.dms (Oplegging_Herkomst) hoort daarom mee te veranderen met elke wijziging in de veenallocatie.

Bij de zes capaciteitskaarten bevat de fingerprint alleen parameters. De capaciteitsfractie per klasse zelf hangt aan de gemiddelde verharding per klasse, een ontkoppeld bestand dat uit alle BGT-categorieen wordt gerekend, en de keuze tussen lezen en maken staat in een meta-expressie die geen data mag vragen: in een verse LocalData viel daar elke lezer op om. Daarom staat de fingerprint van Fractie_Verhard erin, en dekt capacity_rule de rekenregel en de capaciteitsklassen in Classifications/Grondgebruik/BGT. Die sleutel draagt het issue van de laatste wijziging en gaat met elke wijziging daaraan omhoog (#757, #769).

Ook de vervangingskans draagt twee versiesleutels voor rekenregels: parcel_coupling voor de koppeling van cel en perceel (SourceData/Vastgoed/BRK/Koppeling_Versie) en heritage_rule voor de regel die een perceel als monumentperceel aanmerkt (SourceData/Omgevingsrecht/Rijksmonumenten/Regel_Versie). Beide bepalen welke woningen nooit vervangen worden, en geen van beide hangt aan een levering.

Hoe lang het duurt voordat het zijbestand op de kaart volgt, verschilt per bestand: het is het deel van de fingerprint dat niet al voor de kaart zelf is uitgerekend. Een fingerprint van alleen parameters en paden kost vrijwel niets. Bij de MNP-planpotentieelkaart staat de fingerprint naast de kaart en wordt hij apart uitgerekend, en daar is het een merkbaar deel van de rekentijd.

Wat nog geen fingerprint heeft

Deze bestanden worden wel ontkoppeld maar zonder fingerprint. Hieronder staat per bestand welke invoer de uitkomst bepaalt en dus niet vergeten mag worden bij een wijziging:

  • Opbrengsten per ontwikkelpakket (Templates/VariantData_T/Geschiktheden.dms): NVM_filedate, NVM_coeff_Year, Model_StartYear, de eigenschappen van de ontwikkelpakketten (dichtheid, woonoppervlakte, kamers, hoogbouw, wegingen), het perceeloppervlak per pakket, de locatievariabelen, en via de correctie op het gemiddelde wegingseffect ook de restricties- en stimuliselectie voor wonen.
  • Stand basisjaar (BaseData/StateBasisjaar.dms) voor wonen, werken en de andere sectoren: LISA_StartYear, LISA_FileYear, de AltLISA-schakelaar en -varianten, en de klassenindelingen WP2xVSSH en Jobs6 zitten in geen fingerprint. De set draagt wel de fingerprint van de landgebruikstand hierboven, die de leeskant van alle standbestanden toetst: een ander basisjaar, een andere BAG-levering, beheertypenkaart of BRP-jaargang maakt de hele basisjaarstand ongeldig, een nieuwe LISA-levering niet.
  • De pandtypering WP5 (SourceData/Vastgoed/BAG/AfleidingPandtype.dms): het aantal tegels, de inflate-grootte, de criteria voor functioneel pand en de WP5-indeling. Het bestand staat in een map met de BAG-levering in de naam, dus een nieuwe levering krijgt een eigen typering. Het is bovendien een positionele reeks over de pandenset van dat jaar: hoort het bij een andere pandenset, dan schuift de typering op. De integriteitscontrole op pand/WP5_rel vangt dat af.
  • De BGT-afgeleiden in BaseData/Grondgebruik/BGT.dms (groen, water, verhard, spoor, autoweg); de capaciteitskaarten voor piekbuiberging hebben wel een fingerprint (#769).
  • De geaggregeerde TIGRIS-claims per allocatieregio (Templates/Claims/Claims_TargetUnits_T.dms, geschreven door WriteBasedata/Generate_Run3 als BaseData/Beleid/Claims/TXL_<versie>/<scenario>/<variant>/<zichtjaar>/<regio>/Wonen.csv en Werken.csv): de TIGRIS-versie zit in de mapnaam, de regio-indeling waarop is gesommeerd niet. Die staat als TIGRIS_claims_CBSjaar in ModelParameters, met een integriteitscontrole op ClaimDir die het model laat stoppen zodra die jaargang afwijkt van RegioIndelingen_CBSjaar (#691). De bestanden schrijven bovendien een kolom regio mee als regiosleutel.
  • Het proxybestand WP2xVSSH_Proxy per allocatieregio (BaseData/Verdeling_VSSH.dms), waarmee de claim eengezins en meergezins naar vrije sector en sociale huur wordt gesplitst: geen sleutelkolom, geen controle en geen fingerprint, terwijl de inhoud aan de regio-indeling hangt.
  • De logistieke pandenaanvulling (WritePrivData/LogistiekAanvulling.dms, bestand LogistiekPandenAanvulling_BAG<jaar>_LISA<jaar>_<versie>.mmd): BAG_RecentYear, LISA_StartYear en een versienummer zitten in de bestandsnaam. Let op: die naam staat niet als parameter in ModelParameters maar wordt aan beide kanten uitgeschreven, in SourceData/Vastgoed.dms en in WritePrivData/LogistiekAanvulling.dms, met het versienummer hard in de string. De versie moet worden opgehoogd bij elke wijziging aan de regeldrempels (kernaandeel, footprint-ondergrenzen, zoekafstand vanaf de pandrand): op de gedeelde opslag mag een eenmaal geplaatst bestand niet worden overschreven, dus elke inhoudelijke wijziging krijgt een nieuwe naam. Bijzonderheid: hergenereren kan alleen met BAG_LogistiekDynamisch op FALSE, omdat het pand-domein anders het nog te schrijven bestand als supplier meetrekt; een integriteitscontrole op de schrijf-unit dwingt dat af. Zie BAG-verwerking voor wat het bestand doet.

Let bij een ontkoppeld bestand per regio op een tweede vorm van veroudering, naast de inhoud. Een csv of mmd over een regio-eenheid draagt geen rijlabels, dus de koppeling loopt op rijvolgorde. Verandert de regio-indeling terwijl het aantal regio's gelijk blijft, en dat blijft het: NVM staat al jaren op 76, COROP op 40 en provincie op 12, dan hangen de waarden aan verschoven regio's zonder dat er iets fout gaat (#585). Er is geen foutmelding en geen kanarie. Wat daar wel tegen helpt is de indeling als parameter vastleggen in plaats van hem uit de brondata af te leiden, en de gebruikte jaargang naast het bestand registreren en bij het inlezen toetsen. Voor de claims is dat de opzet met TIGRIS_claims_CBSjaar en de kolom regio; voor het proxybestand nog niet.

De standbestanden per zichtjaar hebben bewust geen fingerprint en dus ook geen hash in hun naam; ze lopen niet via DecoupledFile_T, maar krijgen hun naam van ModelParameters/Advanced/AllocatieFileName. Die hangen af van vrijwel de hele configuratie, inclusief alle bestanden hierboven, dus een fingerprint zou daar de hele configuratie moeten omvatten. Ze worden per run beheerd met StandAllocatieOntkoppeld. Hetzelfde geldt voor de ketentifs en de kaarten van de indicatorenexport: die worden per run beheerd met IndicatorenOntkoppeld en TabellenUitExport, een bestaande tif wordt gelezen, en de batch toetst alleen of ze er staan en of ze jonger zijn dan de stand van dat zichtjaar (#824). Zie Batchrun draaien.

Het pad van een standbestand draagt de casus, het zichtjaar, het studiegebied en het aantal subsectoren (SS-<n>). Een andere variant schrijft dus in een eigen map, maar een nieuwe run van dezelfde casus in dezelfde LocalData overschrijft de vorige. Wie een stand wil bewaren, zet hem opzij of draait in een kopie met een eigen mapnaam boven cfg, en dus een eigen LocalData.

Wat te doen bij een wijziging

Verander je iets dat de uitkomst van een ontkoppeld bestand bepaalt, dan moet die invoer in de fingerprint staan, of moet het bestand op een andere manier ongeldig worden gemaakt: een nieuwe bestandsnaam, het bestand weggooien, of AlwaysRemakeDecoupledFiles aanzetten voor die run.

Dat geldt ook voor bestanden zonder fingerprint. Een voorbeeld: het peiljaar van de begrenzing bebouwd gebied (BBG_Year) werkt via de grondproductiekosten door in de residuele waarde en dus in de allocatie zelf, terwijl de standbestanden per zichtjaar geen fingerprint hebben. Zo'n wijziging vraagt dus een volledige herberekening van alle zichtjaren.

Twee GeoDMS-valkuilen

  • ExplicitSuppliers op een container lift niet mee wanneer je een los kind opvraagt. Bij containers die met for_each worden opgebouwd kan het schrijven van het zijbestand dus niet aan de container hangen. Vraag je zo'n item rechtstreeks op, dan wordt het wel gerekend en geschreven maar komt er geen zijbestand, en rekent de volgende run het opnieuw uit.
  • PropValue(item, 'StorageName') geeft de expressietekst terug, niet de uitkomst. Dat werkt wanneer je hem weer als StorageName gebruikt, maar niet als invoer voor ExistingFile. Zet het pad dan als eigen parameter<String> neer en verwijs daar vanuit beide kanten naar.

Clone this wiki locally