diff --git a/local/rest_api_skeleton/Endpoints/__init__.py b/local/rest_api_skeleton/Endpoints/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/local/rest_api_skeleton/Endpoints/gcbm_endpoints.py b/local/rest_api_skeleton/Endpoints/gcbm_endpoints.py new file mode 100644 index 00000000..a5582bca --- /dev/null +++ b/local/rest_api_skeleton/Endpoints/gcbm_endpoints.py @@ -0,0 +1,155 @@ +from flask_restful import Resource +import os +from threading import Thread +from Helpers.preprocess import ( + DisturbanceConfig, + launch_run, + ClassifierConfig, + MiscellaneousConfig, +) +from Helpers.for_requests import ( + title_query, + miscellaneous_query, + disturbance_query, + classifier_query, +) + + +class disturbance(Resource): + def post(self): + title = title_query().get("title") or "simulation" + input_dir = f"{os.getcwd()}/input/{title}" + if not os.path.exists(f"{input_dir}"): + os.makedirs(f"{input_dir}") + if not os.path.exists(f"{input_dir}/disturbances"): + os.makedirs(f"{input_dir}/disturbances") + + # store disturbances file in a new folder + disturbances = disturbance_query() + if not disturbances: + return {"error": "Missing disturbances file"}, 400 + for file in disturbances.get("disturbances"): + file.save(f"{input_dir}/disturbances/{file.filename}") + try: + disturb = DisturbanceConfig( + input_dir, file.filename, disturbances.get("attributes") + ) + disturb() + except Exception as e: + return e + disturb.flatten_directory("disturbances") + return { + "data": "Disturbances file uploaded succesfully. Proceed to the next step." + } + + +class classifier(Resource): + def post(self): + # Get the title from the payload + title = title_query().get("title") or "simulation" + + # Check for project directory else create one + input_dir = f"{os.getcwd()}/input/{title}" + if not os.path.exists(f"{input_dir}"): + os.makedirs(f"{input_dir}") + + # input files follow a strict structure + if not os.path.exists(f"{input_dir}/classifiers"): + os.makedirs(f"{input_dir}/classifiers") + + # store disturbances file in a new folder + classifiers = classifier_query() + if not classifiers: + return {"error": "Missing classifiers file"}, 400 + + for file in classifiers.get("classifiers"): + file.save(f"{input_dir}/classifiers/{file.filename}") + try: + classify = ClassifierConfig( + input_dir, file.filename, classifiers.get("attributes") + ) + classify() + except Exception as e: + return e + classify.flatten_directory("classifiers") + return { + "data": "Classifiers file uploaded succesfully. Proceed to the next step." + } + + +class Database(Resource): + def post(self): + pass + + +class miscellaneous(Resource): + def post(self): + # Get the title from the payload + title = title_query().get("title") or "simulation" + + # Check for project directory else create one + input_dir = f"{os.getcwd()}/input/{title}" + if not os.path.exists(f"{input_dir}"): + os.makedirs(f"{input_dir}") + + # input files follow a strict structure + if not os.path.exists(f"{input_dir}/miscellaneous"): + os.makedirs(f"{input_dir}/miscellaneous") + + # store miscellaneous file in a new folder + mis = miscellaneous_query() + if not mis: + return {"error": "Missing classifiers file"}, 400 + + for file in mis.get("miscellaneous"): + file.save(f"{input_dir}/miscellaneous/{file.filename}") + try: + miscel = MiscellaneousConfig( + input_dir, file.filename, mis.get("attributes") + ) + miscel() + except Exception as e: + return e + miscel.flatten_directory("miscellaneous") + return { + "data": "Classifiers file uploaded succesfully. Proceed to the next step." + } + + +class title(Resource): + def post(self): + # Default title = simulation + title = title_query().get("title") or "simulation" + # Sanitize title + title = "".join(c for c in title if c.isalnum()) + # input_dir = f"{title}" + input_dir = f"{os.getcwd()}/input/{title}" + if not os.path.exists(f"{input_dir}"): + os.makedirs(f"{input_dir}") + message = "New simulation started. Please move on to the next stage for uploading files at /gcbm/upload." + else: + message = "Simulation already exists. Please check the list of simulations present before proceeding with a new simulation at gcbm/list. You may also download the input and output files for this simulation at gcbm/download sending parameter title in the body." + + return {"data": message}, 200 + + +class Run(Resource): + """THIS ENDPOINT WILL BE ABLE TO RUN A SIMULATION + GOAL IS TO EQUIP IT TO BE ABLE TO RUN MORE THAN ONE SIMULATIONS AT A TIME""" + + def post(self): + title = title_query().get("title") or "simulation" + + # Sanitize title + title = "".join(c for c in title if c.isalnum()) + input_dir = f"{os.getcwd()}/input/{title}" + + if not os.path.exists(f"{input_dir}"): + os.makedirs(f"{input_dir}") + + thread = Thread( + target=launch_run, kwargs={"title": title, "input_dir": input_dir} + ) + thread.start() + + return {"status": "Run started"}, 200 diff --git a/local/rest_api_skeleton/Helpers/__init__.py b/local/rest_api_skeleton/Helpers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/local/rest_api_skeleton/Helpers/for_requests.py b/local/rest_api_skeleton/Helpers/for_requests.py new file mode 100644 index 00000000..9851264f --- /dev/null +++ b/local/rest_api_skeleton/Helpers/for_requests.py @@ -0,0 +1,47 @@ +from flask_restful import reqparse +from werkzeug.datastructures import FileStorage + + +def title_query(): + query = reqparse.RequestParser() + query.add_argument("title", required=True, location="form") + return query.parse_args() + + +def classifier_query(): + query = reqparse.RequestParser() + query.add_argument( + "classifiers", + type=FileStorage, + required=True, + action="append", + location="files", + ) + query.add_argument("attributes", location="form") + return query.parse_args() + + +def disturbance_query(): + query = reqparse.RequestParser() + query.add_argument( + "disturbances", + type=FileStorage, + required=True, + action="append", + location="files", + ) + query.add_argument("attributes", location="form") + return query.parse_args() + + +def miscellaneous_query(): + query = reqparse.RequestParser() + query.add_argument( + "miscellaneous", + type=FileStorage, + required=True, + action="append", + location="files", + ) + query.add_argument("attributes", location="form") + return query.parse_args() diff --git a/local/rest_api_skeleton/Helpers/preprocess.py b/local/rest_api_skeleton/Helpers/preprocess.py new file mode 100644 index 00000000..a496b64a --- /dev/null +++ b/local/rest_api_skeleton/Helpers/preprocess.py @@ -0,0 +1,304 @@ +import os, time, subprocess +import shutil +import json +import rasterio as rst + + +def launch_run(title, input_dir): + s = time.time() + with open(f"{input_dir}/gcbm_logs.csv", "w+") as f: + res = subprocess.Popen( + [ + "/opt/gcbm/moja.cli", + "--config_file", + "gcbm_config.cfg", + "--config_provider", + "provider_config.json", + ], + stdout=f, + cwd=f"{input_dir}", + ) + (_, err) = res.communicate() + + if not os.path.exists(f"{input_dir}/output"): + return "OK" + + # cut and paste output folder to app/output/simulation_name + shutil.copytree(f"{input_dir}/output", (f"{os.getcwd()}/output/{title}")) + shutil.make_archive( + f"{os.getcwd()}/output/{title}", "zip", f"{os.getcwd()}/output/{title}" + ) + shutil.rmtree((f"{input_dir}/output")) + e = time.time() + + response = { + "exitCode": res.returncode, + "execTime": e - s, + "response": "Operation executed successfully. Downloadable links for input and output are attached in the response. Alternatively, you may also download this simulation input and output results by making a request at gcbm/download with the title in the body.", + } + + +class Configs: + def __init__(self, input_dir) -> None: + self.input_dir = input_dir + self.Rasters = [] + self.Rastersm = [] + self.nodatam = [] + self.nodata = [] + self.cellLatSize = [] + self.cellLonSize = [] + self.paths = [] + self.lst = [] + self.provider_config = open( + f"{os.getcwd()}/templates/provider_config.json", "r+" + ) + + def get_config_templates(self): + if not os.path.exists(f"{self.input_dir}/templates"): + shutil.copytree( + f"{os.getcwd()}/templates", + f"{self.input_dir}/templates", + dirs_exist_ok=False, + ) + self.provider_config = open( + f"{self.input_dir}/templates/provider_config.json", "r+" + ) + + def get_modules_cbm_config(self): + with open( + f"{self.input_dir}/templates/modules_cbm.json", "r+" + ) as modules_cbm_config: + data = json.load(modules_cbm_config) + disturbances = [ + file.split(".")[0][:-5] + for file in os.listdir(f"{self.input_dir}/disturbances/") + ] # drop `_moja` to match modules_cbm.json template + modules_cbm_config.seek(0) + data["Modules"]["CBMDisturbanceListener"]["settings"]["vars"] = disturbances + json.dump(data, modules_cbm_config, indent=4) + modules_cbm_config.truncate() + + # for database input + def database_writes(self): + data = json.load(self.provider_config) + for file in os.listdir(f"{self.input_dir}/db/"): + data["Providers"]["SQLite"] = {"type": "SQLite", "path": file} + self.provider_config.seek(0) + + def write_configs(self, config_type: str): + data = json.load(self.provider_config) + for file in os.listdir(f"{self.input_dir}/{config_type}/"): + d = dict() + d["name"] = file[:-10] + d["layer_path"] = file + d["layer_prefix"] = file[:-5] + self.lst.append(d) + if config_type == "disturbances" or config_type == "classifiers": + for root, _, files in os.walk( + os.path.abspath(f"{self.input_dir}/{config_type}/") + ): + for file in files: + fp = os.path.join(root, file) + self.Rasters.append(fp) + self.paths.append(fp) + for self.nd in self.Rasters: + img = rst.open(self.nd) + t = img.transform + x = t[0] + y = -t[4] + n = img.nodata + self.cellLatSize.append(x) + self.cellLonSize.append(y) + self.nodata.append(n) + result = all(element == self.cellLatSize[0] for element in self.cellLatSize) + if result: + cellLat = x + cellLon = y + self.nd = n + blockLat = x * 400 + blockLon = y * 400 + tileLat = x * 400 + tileLon = y * 4000 + else: + print("Corrupt files") + + self.provider_config.seek(0) + new_values = { + "cellLonSize": cellLon, + "cellLatSize": cellLat, + "blockLonSize": blockLon, + "blockLatSize": blockLat, + "tileLatSize": tileLat, + "tileLonSize": tileLon, + } + data["Providers"]["RasterTiled"]["layers"] = self.lst + data["Providers"]["RasterTiled"].update(new_values) + + json.dump(data, self.provider_config, indent=4) + self.provider_config.truncate() + + self.dictionary = { + "layer_type": "GridLayer", + "layer_data": "Byte", + "nodata": self.nd, + "tileLatSize": tileLat, + "tileLonSize": tileLon, + "blockLatSize": blockLat, + "blockLonSize": blockLon, + "cellLatSize": cellLat, + "cellLonSize": cellLon, + } + + self.study_area = { + "tile_size": tileLat, + "block_size": blockLat, + "tiles": [ + { + "x": int(t[2]), + "y": int(t[5]), + "index": 12674, + } + ], + "pixel_size": cellLat, + "layers": [], + } + + def add_file_to_path(self, config_type): + for root, _, files in os.walk( + os.path.abspath(f"{self.input_dir}/{config_type}/") + ): + for file in files: + fp = os.path.join(root, file) + self.paths.append(fp) + + def copy_directory(self): + for i in self.paths: + shutil.copy2(i, (f"{self.input_dir}")) + + def flatten_directory(self, config_type): + shutil.rmtree((f"{self.input_dir}/{config_type}/")) + + +class DisturbanceConfig(Configs): + def __init__(self, input_dir, config_file: str, attribute: dict = None) -> None: + super().__init__(input_dir) + self.config_file = config_file + self.attribute = attribute + + def disturbances_special(self): + with open( + f"{self.input_dir}/{self.config_file}", "w", encoding="utf8" + ) as json_file: + self.dictionary["attributes"] = self.attribute + json.dump(self.dictionary, json_file, indent=4) + with open( + f"{self.input_dir}/study_area.json", "w", encoding="utf" + ) as json_file: + study_area = [] + self.study_area["layers"] = study_area + json.dump(self.study_area, json_file, indent=4) + for file in os.listdir(f"{self.input_dir}/disturbances/"): + study_area.append( + { + "name": file[:10], + "type": "DisturbanceLayer", + "tags": ["disturbance"], + } + ) + + self.study_area["layers"] = study_area + json.dump(self.study_area, json_file, indent=4) + + def __call__(self): + self.get_config_templates() + self.get_modules_cbm_config() + self.write_configs("disturbances") + self.disturbances_special() + self.add_file_to_path("disturbances") + self.copy_directory() + + +class ClassifierConfig(Configs): + def __init__(self, input_dir, config_file: str, attribute: dict) -> None: + super().__init__(input_dir) + self.config_file = config_file + self.attribute = attribute + + def classifier_special(self): + with open( + f"{self.input_dir}/{self.config_file}", "w", encoding="utf8" + ) as json_file: + self.dictionary["attributes"] = self.attribute + json.dump(self.dictionary, json_file, indent=4) + + with open( + f"{self.input_dir}/study_area.json", "w", encoding="utf" + ) as json_file: + study_area = [] + for file in os.listdir(f"{self.input_dir}/classifiers/"): + study_area.append( + {"name": file[:10], "type": "VectorLayer", "tags": ["classifier"]} + ) + + self.study_area["layers"] = study_area + json.dump(self.study_area, json_file, indent=4) + + def __call__(self): + self.get_config_templates() + self.get_modules_cbm_config() + self.write_configs("classifiers") + self.classifier_special() + self.add_file_to_path("classifiers") + self.copy_directory() + + +class MiscellaneousConfig(Configs): + def __init__(self, input_dir, config_file: str, attribute: dict) -> None: + super().__init__(input_dir) + self.config_file = config_file + self.attribute = attribute + + def miscellaneous_special(self): + for root, _, files in os.walk( + os.path.abspath(f"{self.input_dir}/miscellaneous/") + ): + for file in files: + fp2 = os.path.join(root, file) + self.Rastersm.append(fp2) + + for i in self.Rastersm: + img = rst.open(i) + d = img.nodata + self.nodatam.append(d) + """this is an experimental thing""" + with open( + f"{self.input_dir}/{self.config_file}", "w", encoding="utf8" + ) as json_file: + self.dictionary["layer_type"] = "GridLayer" + if self.config_file == "mean_annual_temperature_moja.json": + self.dictionary["layer_data"] = "Float32" + else: + self.dictionary["layer_data"] = "Int16" + self.dictionary["nodata"] = 32767 + json.dump(self.dictionary, json_file, indent=4) + + # for study area + with open( + f"{self.input_dir}/study_area.json", "w", encoding="utf" + ) as json_file: + study_area = [] + + for file in os.listdir(f"{self.input_dir}/miscellaneous/"): + study_area.append({"name": file[:10], "type": "VectorLayer"}) + + self.study_area["layers"] = study_area + json.dump(self.study_area, json_file, indent=4) + + def __call__(self): + self.get_config_templates() + self.get_modules_cbm_config() + self.write_configs("miscellaneous") + self.classifier_special() + self.add_file_to_path("miscellaneous") + self.copy_directory() + self.flatten_directory("miscellaneous") diff --git a/local/rest_api_skeleton/Helpers/routes.py b/local/rest_api_skeleton/Helpers/routes.py new file mode 100644 index 00000000..0a002789 --- /dev/null +++ b/local/rest_api_skeleton/Helpers/routes.py @@ -0,0 +1,8 @@ +from Endpoints.gcbm_endpoints import disturbance, Run, title, classifier, miscellaneous + +def endpoints(api): + api.add_resource(disturbance, "/gcbm/upload/disturbances") + api.add_resource(title, "/gcbm/create") + api.add_resource(classifier, "/gcbm/upload/classifies") + api.add_resource(miscellaneous, "/gcbm/upload/miscellaneous") + api.add_resource(Run, "/gcbm/run") diff --git a/local/rest_api_skeleton/__init__.py b/local/rest_api_skeleton/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/local/rest_api_skeleton/app.py b/local/rest_api_skeleton/app.py new file mode 100644 index 00000000..bc201d42 --- /dev/null +++ b/local/rest_api_skeleton/app.py @@ -0,0 +1,13 @@ +from flask import Flask +from flask_restful import Api +from Helpers.routes import endpoints + + +app = Flask(__name__) +api = Api() + + +endpoints(api=api) + +if __name__ == "__main__": + app.run(debug=True) diff --git a/local/rest_api_skeleton/models/__init__.py b/local/rest_api_skeleton/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/local/rest_api_skeleton/templates/__init__.py b/local/rest_api_skeleton/templates/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/local/rest_api_skeleton/templates/gcbm_config.cfg b/local/rest_api_skeleton/templates/gcbm_config.cfg new file mode 100644 index 00000000..e6640ac9 --- /dev/null +++ b/local/rest_api_skeleton/templates/gcbm_config.cfg @@ -0,0 +1,7 @@ +config=localdomain.json +config=pools_cbm.json +config=modules_cbm.json +config=modules_output.json +config=spinup.json +config=variables.json +config=internal_variables.json diff --git a/local/rest_api_skeleton/templates/internal_variables.json b/local/rest_api_skeleton/templates/internal_variables.json new file mode 100644 index 00000000..d9f71537 --- /dev/null +++ b/local/rest_api_skeleton/templates/internal_variables.json @@ -0,0 +1,34 @@ +{ + "Variables": { + "spatialLocationInfo": { + "flintdata": { + "type": "SpatialLocationInfo", + "library": "internal.flint", + "settings": {} + } + }, + "simulateLandUnit": true, + "is_decaying": true, + "spinup_moss_only": false, + "run_peatland": false, + "peatlandId": -1, + "is_forest": true, + "run_moss": false, + "run_delay": false, + "landUnitBuildSuccess": true, + "regen_delay": 0, + "age": 0, + "tileIndex": 0, + "blockIndex": 0, + "cellIndex": 0, + "LandUnitId": -1, + "landUnitArea": 0, + "classifier_set": {}, + "localDomainId": 0, + "LocalDomainId": 1, + "age_class": 0, + "historic_land_class": "FL", + "current_land_class": "FL", + "unfccc_land_class": "UNFCCC_FL_R_FL" + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/localdomain.json b/local/rest_api_skeleton/templates/localdomain.json new file mode 100644 index 00000000..5bb04f33 --- /dev/null +++ b/local/rest_api_skeleton/templates/localdomain.json @@ -0,0 +1,31 @@ +{ + "Libraries": { + "moja.modules.cbm": "external", + "moja.modules.gdal": "external" + }, + "LocalDomain": { + "start_date": "2010/01/01", + "end_date": "2021/01/01", + "landUnitBuildSuccess": "landUnitBuildSuccess", + "simulateLandUnit": "simulateLandUnit", + "sequencer_library": "moja.modules.cbm", + "sequencer": "CBMSequencer", + "timing": "annual", + "type": "spatial_tiled", + "landscape": { + "provider": "RasterTiled", + "num_threads": 4, + "tiles": [ + { + "x": -106, + "y": 55, + "index": 12674 + } + ], + "x_pixels": 4000, + "y_pixels": 4000, + "tile_size_x": 1.0, + "tile_size_y": 1.0 + } + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/logging.conf b/local/rest_api_skeleton/templates/logging.conf new file mode 100644 index 00000000..2da5fec5 --- /dev/null +++ b/local/rest_api_skeleton/templates/logging.conf @@ -0,0 +1,17 @@ +[Core] +DisableLogging=false + +[Sinks.console] +Destination=Console +Asynchronous=false +AutoFlush=true +Format="<%TimeStamp%> (%Severity%) - %Message%" +Filter="%Severity% >= info" + +[Sinks.file] +Destination=TextFile +FileName="output/simulation.log" +Asynchronous=false +AutoFlush=true +Format="<%TimeStamp%> (%Severity%) - %Message%" +Filter="%Severity% >= debug" diff --git a/local/rest_api_skeleton/templates/modules_cbm.json b/local/rest_api_skeleton/templates/modules_cbm.json new file mode 100644 index 00000000..0b237195 --- /dev/null +++ b/local/rest_api_skeleton/templates/modules_cbm.json @@ -0,0 +1,59 @@ +{ + "Modules": { + "CBMBuildLandUnitModule": { + "order": 1, + "library": "moja.modules.cbm" + }, + "CBMSequencer": { + "order": 2, + "library": "moja.modules.cbm" + }, + "CBMDisturbanceListener": { + "enabled": true, + "order": 3, + "library": "moja.modules.cbm", + "settings": { + "vars": [ + + ] + } + }, + "CBMDisturbanceEventModule": { + "enabled": true, + "order": 4, + "library": "moja.modules.cbm" + }, + "CBMTransitionRulesModule": { + "enabled": true, + "order": 5, + "library": "moja.modules.cbm" + }, + "CBMLandClassTransitionModule": { + "enabled": true, + "order": 6, + "library": "moja.modules.cbm" + }, + "CBMGrowthModule": { + "enabled": true, + "order": 7, + "library": "moja.modules.cbm" + }, + "CBMDecayModule": { + "enabled": true, + "order": 8, + "library": "moja.modules.cbm", + "settings": { + "extra_decay_removals": false + } + }, + "CBMAgeIndicators": { + "enabled": true, + "order": 9, + "library": "moja.modules.cbm" + }, + "TransactionManagerAfterSubmitModule": { + "order": 10, + "library": "internal.flint" + } + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/modules_output.json b/local/rest_api_skeleton/templates/modules_output.json new file mode 100644 index 00000000..cad01b28 --- /dev/null +++ b/local/rest_api_skeleton/templates/modules_output.json @@ -0,0 +1,816 @@ +{ + "Modules": { + "WriteVariableGeotiff": { + "enabled": true, + "order": 11, + "library": "moja.modules.gdal", + "settings": { + "items": [ + { + "data_name": "Age", + "enabled": true, + "variable_data_type": "Int16", + "on_notification": "OutputStep", + "variable_name": "age" + }, + { + "pool_name": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther" + ], + "data_name": "AG_Biomass_C", + "enabled": true, + "variable_data_type": "float", + "on_notification": "OutputStep" + }, + { + "pool_name": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "data_name": "Total_Ecosystem_C", + "enabled": true, + "variable_data_type": "float", + "on_notification": "OutputStep" + }, + { + "pool_name": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "data_name": "Total_Biomass_C", + "enabled": true, + "variable_data_type": "float", + "on_notification": "OutputStep" + }, + { + "pool_name": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "data_name": "Dead_Organic_Matter_C", + "enabled": true, + "variable_data_type": "float", + "on_notification": "OutputStep" + }, + { + "pool_name": [ + "BelowGroundVeryFastSoil", + "BelowGroundSlowSoil" + ], + "data_name": "Soil_C", + "enabled": true, + "variable_data_type": "float", + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "from": [ + "Atmosphere" + ] + }, + "data_name": "NPP", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "to": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "from": [ + "Atmosphere" + ] + }, + { + "subtract": true, + "from": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "to": [ + "CO2", + "CH4", + "CO" + ], + "flux_source": "annual_process" + } + ], + "data_name": "NEP", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "flux_source": "annual_process", + "from": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "to": [ + "CO2", + "CH4", + "CO" + ] + } + ], + "data_name": "Decomp_Releases", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "to": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "from": [ + "Atmosphere" + ] + }, + { + "subtract": true, + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "to": [ + "Products" + ], + "flux_source": "disturbance" + }, + { + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "subtract": true, + "to": [ + "CO2", + "CH4", + "CO" + ] + } + ], + "data_name": "NBP", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "to": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "from": [ + "Atmosphere" + ] + }, + { + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "subtract": true, + "to": [ + "CO2", + "CH4", + "CO" + ] + }, + { + "subtract": true, + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "to": [ + "Products" + ], + "flux_source": "disturbance" + } + ], + "data_name": "Delta_Total_Ecosystem", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "to": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "from": [ + "Atmosphere" + ] + }, + { + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "subtract": true, + "to": [ + "CO2", + "CH4", + "CO" + ] + }, + { + "subtract": true, + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "to": [ + "Products" + ], + "flux_source": "disturbance" + }, + { + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "subtract": true, + "to": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + } + ], + "data_name": "Delta_Total_Biomass", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "to": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + { + "from": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "subtract": true, + "to": [ + "CO2", + "CH4", + "CO", + "Products" + ] + } + ], + "data_name": "Delta_Total_DOM", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CO2", + "CH4", + "CO" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Total_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CO2", + "CH4", + "CO" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ] + }, + "data_name": "Total_Biomass_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CO2", + "CH4", + "CO" + ], + "from": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Total_DOM_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CO2" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Total_CO2_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CO" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Total_CO_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "to": [ + "CH4" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Total_CH4_Emissions", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": [ + { + "to": [ + "CO2", + "CH4", + "CO" + ], + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + { + "flux_source": "disturbance", + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ], + "to": [ + "Products" + ] + } + ], + "data_name": "Ecosystem_Removals", + "enabled": true, + "on_notification": "OutputStep" + }, + { + "variable_data_type": "float", + "flux": { + "flux_source": "disturbance", + "from": [ + "SoftwoodMerch", + "SoftwoodFoliage", + "SoftwoodOther", + "SoftwoodCoarseRoots", + "SoftwoodFineRoots", + "HardwoodMerch", + "HardwoodFoliage", + "HardwoodOther", + "HardwoodCoarseRoots", + "HardwoodFineRoots" + ], + "to": [ + "AboveGroundVeryFastSoil", + "BelowGroundVeryFastSoil", + "AboveGroundFastSoil", + "BelowGroundFastSoil", + "MediumSoil", + "AboveGroundSlowSoil", + "BelowGroundSlowSoil", + "SoftwoodStemSnag", + "SoftwoodBranchSnag", + "HardwoodStemSnag", + "HardwoodBranchSnag" + ] + }, + "data_name": "Bio_To_DOM_From_Disturbances", + "enabled": true, + "on_notification": "OutputStep" + } + ], + "output_path": "output" + } + }, + "CBMAggregatorLandUnitData": { + "enabled": true, + "order": 12, + "library": "moja.modules.cbm", + "settings": { + "reporting_classifier_set": "reporting_classifiers" + } + }, + "CBMAggregatorSQLiteWriter": { + "enabled": true, + "order": 13, + "library": "moja.modules.cbm", + "settings": { + "databasename": "output/simulation_output.db" + } + } + } +} diff --git a/local/rest_api_skeleton/templates/pools_cbm.json b/local/rest_api_skeleton/templates/pools_cbm.json new file mode 100644 index 00000000..35979d38 --- /dev/null +++ b/local/rest_api_skeleton/templates/pools_cbm.json @@ -0,0 +1,34 @@ +{ + "Pools": { + "AboveGroundFastSoil": 0.0, + "AboveGroundSlowSoil": 0.0, + "AboveGroundVeryFastSoil": 0.0, + "Atmosphere": 0.0, + "BelowGroundFastSoil": 0.0, + "BelowGroundSlowSoil": 0.0, + "BelowGroundVeryFastSoil": 0.0, + "BlackCarbon": 0.0, + "CH4": 0.0, + "CO": 0.0, + "CO2": 0.0, + "DissolvedOrganicCarbon": 0.0, + "HardwoodBranchSnag": 0.0, + "HardwoodCoarseRoots": 0.0, + "HardwoodFineRoots": 0.0, + "HardwoodFoliage": 0.0, + "HardwoodMerch": 0.0, + "HardwoodOther": 0.0, + "HardwoodStemSnag": 0.0, + "MediumSoil": 0.0, + "NO2": 0.0, + "Peat": 0.0, + "Products": 0.0, + "SoftwoodBranchSnag": 0.0, + "SoftwoodCoarseRoots": 0.0, + "SoftwoodFineRoots": 0.0, + "SoftwoodFoliage": 0.0, + "SoftwoodMerch": 0.0, + "SoftwoodOther": 0.0, + "SoftwoodStemSnag": 0.0 + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/provider_config.json b/local/rest_api_skeleton/templates/provider_config.json new file mode 100644 index 00000000..0888f9fc --- /dev/null +++ b/local/rest_api_skeleton/templates/provider_config.json @@ -0,0 +1,55 @@ +{ + "Providers": { + "SQLite": { + "path": "../input_database/gcbm_input.db", + "type": "SQLite" + }, + "RasterTiled": { + "layers": [ + { + "name": "disturbances_2011", + "layer_path": "disturbances_2011_moja.tiff", + "layer_prefix": "disturbances_2011_moja" + }, + { + "name": "disturbances_2012", + "layer_path": "disturbances_2012_moja.tiff", + "layer_prefix": "disturbances_2012_moja" + }, + { + "name": "disturbances_2013", + "layer_path": "disturbances_2013_moja.tiff", + "layer_prefix": "disturbances_2013_moja" + }, + { + "name": "disturbances_2014", + "layer_path": "disturbances_2014_moja.tiff", + "layer_prefix": "disturbances_2014_moja" + }, + { + "name": "disturbances_2015", + "layer_path": "disturbances_2015_moja.tiff", + "layer_prefix": "disturbances_2015_moja" + }, + { + "name": "disturbances_2016", + "layer_path": "disturbances_2016_moja.tiff", + "layer_prefix": "disturbances_2016_moja" + }, + { + "name": "disturbances_2018", + "layer_path": "disturbances_2018_moja.tiff", + "layer_prefix": "disturbances_2018_moja" + } + ], + "blockLonSize": 0.1, + "tileLatSize": 0.1, + "tileLonSize": 1.0, + "cellLatSize": 0.00025, + "cellLonSize": 0.00025, + "blockLatSize": 0.1, + "type": "RasterTiledGDAL", + "library": "moja.modules.gdal" + } + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/spinup.json b/local/rest_api_skeleton/templates/spinup.json new file mode 100644 index 00000000..1365b141 --- /dev/null +++ b/local/rest_api_skeleton/templates/spinup.json @@ -0,0 +1,56 @@ +{ + "Spinup": { + "enabled": true, + "sequencer_library": "moja.modules.cbm", + "simulateLandUnit": "simulateLandUnit", + "landUnitBuildSuccess": "landUnitBuildSuccess", + "sequencer": "CBMSpinupSequencer" + }, + "SpinupVariables": { + "delay": 0, + "minimum_rotation": 10, + "run_delay": false + }, + "Variables": { + "spinup_parameters": { + "transform": { + "queryString": "SELECT s.return_interval AS return_interval, s.max_rotations AS max_rotations, dt.name AS historic_disturbance_type, dt.name AS last_pass_disturbance_type, s.mean_annual_temperature AS mean_annual_temperature, 0 as delay FROM spinup_parameter s INNER JOIN disturbance_type dt ON s.historic_disturbance_type_id = dt.id INNER JOIN spatial_unit spu ON spu.spinup_parameter_id = s.id INNER JOIN admin_boundary a ON spu.admin_boundary_id = a.id INNER JOIN eco_boundary e ON spu.eco_boundary_id = e.id WHERE a.name = {var:admin_boundary} AND e.name = {var:eco_boundary}", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + } + }, + "SpinupModules": { + "CBMSpinupSequencer": { + "create_new": true, + "library": "moja.modules.cbm", + "order": 1 + }, + "CBMBuildLandUnitModule": { + "create_new": true, + "library": "moja.modules.cbm", + "order": 2 + }, + "CBMGrowthModule": { + "create_new": true, + "library": "moja.modules.cbm", + "order": 3 + }, + "CBMDecayModule": { + "create_new": true, + "library": "moja.modules.cbm", + "order": 4 + }, + "TransactionManagerAfterSubmitModule": { + "create_new": true, + "library": "internal.flint", + "order": 5 + }, + "CBMSpinupDisturbanceModule": { + "create_new": true, + "library": "moja.modules.cbm", + "order": 6 + } + } +} \ No newline at end of file diff --git a/local/rest_api_skeleton/templates/variables.json b/local/rest_api_skeleton/templates/variables.json new file mode 100644 index 00000000..f2d8bc2f --- /dev/null +++ b/local/rest_api_skeleton/templates/variables.json @@ -0,0 +1,257 @@ +{ + "Variables": { + "enable_peatland": false, + "enable_moss": false, + "admin_boundary": "British Columbia", + "eco_boundary": "Taiga Plains", + "initial_age": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "initial_age" + } + }, + "initial_historic_land_class": "FL", + "initial_current_land_class": "FL", + "age_class_range": 20, + "age_maximum": 300, + "slow_ag_to_bg_mixing_rate": 0.006, + "disturbance_matrices": { + "transform": { + "queryString": "SELECT dm.id AS disturbance_matrix_id, source_pool.name as source_pool_name, dest_pool.name as dest_pool_name, dv.proportion FROM disturbance_matrix dm INNER JOIN disturbance_matrix_value dv ON dm.id = dv.disturbance_matrix_id INNER JOIN pool source_pool ON dv.source_pool_id = source_pool.id INNER JOIN pool dest_pool ON dv.sink_pool_id = dest_pool.id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "softwood_yield_table": { + "transform": { + "queryString": "SELECT gcv.age AS age, SUM(gcv.merchantable_volume) AS merchantable_volume FROM (SELECT CASE WHEN gc.id IS NOT NULL THEN gc.id ELSE -1 END AS growth_curve_component_id FROM growth_curve_component gc INNER JOIN species s ON s.id = gc.species_id INNER JOIN forest_type ft ON ft.id = s.forest_type_id WHERE gc.growth_curve_id = {var:growth_curve_id} AND LOWER(ft.name) LIKE LOWER('Softwood')) AS gc INNER JOIN growth_curve_component_value gcv ON gc.growth_curve_component_id = gcv.growth_curve_component_id GROUP BY gcv.age", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "reporting_classifiers": { + "transform": { + "allow_nulls": true, + "type": "CompositeTransform", + "library": "internal.flint", + "vars": [ + "classifier_set" + ] + } + }, + "land_class_transitions": { + "transform": { + "queryString": "SELECT dt.name AS disturbance_type, lc.code AS land_class_transition, lc.is_forest, lc.years_to_permanent FROM disturbance_type dt INNER JOIN land_class lc ON dt.transition_land_class_id = lc.id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "transition_rules": { + "transform": { + "queryString": "SELECT t.id AS id, age, regen_delay, description, tt.name AS reset_type FROM transition t INNER JOIN transition_type tt ON t.transition_type_id = tt.id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "transition_rule_matches": { + "transform": { + "classifier_set_var": "classifier_set", + "type": "TransitionRuleTransform", + "library": "moja.modules.cbm", + "provider": "SQLite" + } + }, + "spatial_unit_id": { + "transform": { + "queryString": "SELECT spu.id FROM spatial_unit spu INNER JOIN admin_boundary a ON spu.admin_boundary_id = a.id INNER JOIN eco_boundary e ON spu.eco_boundary_id = e.id WHERE a.name = {var:admin_boundary} AND e.name = {var:eco_boundary}", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "hardwood_yield_table": { + "transform": { + "queryString": "SELECT gcv.age AS age, SUM(gcv.merchantable_volume) AS merchantable_volume FROM (SELECT CASE WHEN gc.id IS NOT NULL THEN gc.id ELSE -1 END AS growth_curve_component_id FROM growth_curve_component gc INNER JOIN species s ON s.id = gc.species_id INNER JOIN forest_type ft ON ft.id = s.forest_type_id WHERE gc.growth_curve_id = {var:growth_curve_id} AND LOWER(ft.name) LIKE LOWER('Hardwood')) AS gc INNER JOIN growth_curve_component_value gcv ON gc.growth_curve_component_id = gcv.growth_curve_component_id GROUP BY gcv.age", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "turnover_rates": { + "transform": { + "queryString": "SELECT COALESCE(sw_turnover.foliage, 0) AS sw_foliage_turnover, COALESCE(hw_turnover.foliage, 0) AS hw_foliage_turnover, COALESCE(sw_turnover.stem, 0) AS sw_stem_turnover, COALESCE(hw_turnover.stem, 0) AS hw_stem_turnover, COALESCE(sw_turnover.branch, 0) AS sw_branch_turnover, COALESCE(hw_turnover.branch, 0) AS hw_branch_turnover, COALESCE(sw_turnover.branch_snag_split, 0) AS sw_other_to_branch_snag_split, COALESCE(hw_turnover.branch_snag_split, 0) AS hw_other_to_branch_snag_split, COALESCE(sw_turnover.stem_snag, 0) AS sw_stem_snag_turnover, COALESCE(hw_turnover.stem_snag, 0) AS hw_stem_snag_turnover, COALESCE(sw_turnover.branch_snag, 0) AS sw_branch_snag_turnover, COALESCE(hw_turnover.branch_snag, 0) AS hw_branch_snag_turnover, COALESCE(sw_turnover.coarse_ag_split, 0) AS sw_coarse_root_split, COALESCE(hw_turnover.coarse_ag_split, 0) AS hw_coarse_root_split, COALESCE(sw_turnover.coarse_root, 0) AS sw_coarse_root_turnover, COALESCE(hw_turnover.coarse_root, 0) AS hw_coarse_root_turnover, COALESCE(sw_turnover.fine_ag_split, 0) AS sw_fine_root_ag_split, COALESCE(hw_turnover.fine_ag_split, 0) AS hw_fine_root_ag_split, COALESCE(sw_turnover.fine_root, 0) AS sw_fine_root_turnover, COALESCE(hw_turnover.fine_root, 0) AS hw_fine_root_turnover FROM growth_curve gc LEFT JOIN ( SELECT growth_curve_id, foliage, stem, branch, branch_snag_split, stem_snag, branch_snag, coarse_ag_split, coarse_root, fine_ag_split, fine_root FROM turnover_parameter_association tpa INNER JOIN eco_boundary e ON tpa.eco_boundary_id = e.id INNER JOIN genus g ON tpa.genus_id = g.id INNER JOIN species s ON s.genus_id = g.id INNER JOIN forest_type f ON s.forest_type_id = f.id INNER JOIN growth_curve_component gcc ON gcc.species_id = s.id INNER JOIN turnover_parameter t ON tpa.turnover_parameter_id = t.id WHERE gcc.growth_curve_id = {var:growth_curve_id} AND e.name = {var:eco_boundary} AND f.name = 'Softwood' ORDER BY gcc.id LIMIT 1 ) AS sw_turnover ON gc.id = sw_turnover.growth_curve_id LEFT JOIN ( SELECT growth_curve_id, foliage, stem, branch, branch_snag_split, stem_snag, branch_snag, coarse_ag_split, coarse_root, fine_ag_split, fine_root FROM turnover_parameter_association tpa INNER JOIN eco_boundary e ON tpa.eco_boundary_id = e.id INNER JOIN genus g ON tpa.genus_id = g.id INNER JOIN species s ON s.genus_id = g.id INNER JOIN forest_type f ON s.forest_type_id = f.id INNER JOIN growth_curve_component gcc ON gcc.species_id = s.id INNER JOIN turnover_parameter t ON tpa.turnover_parameter_id = t.id WHERE gcc.growth_curve_id = {var:growth_curve_id} AND e.name = {var:eco_boundary} AND f.name = 'Hardwood' ORDER BY gcc.id LIMIT 1 ) AS hw_turnover ON gc.id = hw_turnover.growth_curve_id WHERE gc.id = {var:growth_curve_id}", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "disturbance_type_codes": { + "transform": { + "queryString": "SELECT dt.name AS disturbance_type, dt.code AS disturbance_type_code FROM disturbance_type dt", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "transition_rule_classifiers": { + "transform": { + "queryString": "SELECT t.id, c.name AS classifier_name, cv.value AS classifier_value FROM transition t INNER JOIN transition_classifier_value tcv ON t.id = tcv.transition_id INNER JOIN classifier_value cv ON tcv.classifier_value_id = cv.id INNER JOIN classifier c ON cv.classifier_id = c.id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "initial_classifier_set": { + "transform": { + "type": "CompositeTransform", + "library": "internal.flint", + "vars": [ + "Classifier2", + "Classifier1" + ] + } + }, + "disturbance_matrix_associations": { + "transform": { + "queryString": "SELECT dt.name AS disturbance_type, dma.spatial_unit_id, dma.disturbance_matrix_id FROM disturbance_matrix_association dma INNER JOIN disturbance_type dt ON dma.disturbance_type_id = dt.id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "other_to_branch_snag_split": { + "transform": { + "queryString": "SELECT t.branch_snag_split AS slow_mixing_rate FROM eco_boundary e INNER JOIN turnover_parameter t ON e.turnover_parameter_id = t.id WHERE e.name LIKE {var:eco_boundary}", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "growth_curve_id": { + "transform": { + "classifier_set_var": "classifier_set", + "type": "GrowthCurveTransform", + "library": "moja.modules.cbm", + "provider": "SQLite" + } + }, + "volume_to_biomass_parameters": { + "transform": { + "queryString": "SELECT ft.name AS forest_type, f.a as a, f.b as b, f.a_nonmerch as a_non_merch, f.b_nonmerch as b_non_merch, f.k_nonmerch as k_non_merch, f.cap_nonmerch as cap_non_merch, f.a_sap as a_sap, f.b_sap as b_sap, f.k_sap as k_sap, f.cap_sap as cap_sap, f.a1 as a1, f.a2 as a2, f.a3 as a3, f.b1 as b1, f.b2 as b2, f.b3 as b3, f.c1 as c1, f.c2 as c2, f.c3 as c3, f.min_volume as min_volume, f.max_volume as max_volume, f.low_stemwood_prop as low_stemwood_prop, f.high_stemwood_prop as high_stemwood_prop, f.low_stembark_prop as low_stembark_prop, f.high_stembark_prop as high_stembark_prop, f.low_branches_prop AS low_branches_prop, f.high_branches_prop as high_branches_prop, f.low_foliage_prop AS low_foliage_prop, f.high_foliage_prop AS high_foliage_prop, sp.sw_top_proportion AS softwood_top_prop, sp.sw_stump_proportion AS softwood_stump_prop, sp.hw_top_proportion AS hardwood_top_prop, sp.hw_stump_proportion AS hardwood_stump_prop, rp.hw_a AS hw_a, rp.hw_b AS hw_b, rp.sw_a AS sw_a, rp.frp_a AS frp_a, rp.frp_b AS frp_b, rp.frp_c AS frp_c FROM vol_to_bio_factor_association fa INNER JOIN vol_to_bio_factor f ON f.id = fa.vol_to_bio_factor_id INNER JOIN species s ON fa.species_id = s.id INNER JOIN growth_curve_component gcc ON s.id = gcc.species_id INNER JOIN forest_type ft ON s.forest_type_id = ft.id INNER JOIN spatial_unit spu ON fa.spatial_unit_id = spu.id INNER JOIN admin_boundary a ON spu.admin_boundary_id = a.id INNER JOIN stump_parameter sp ON a.stump_parameter_id = sp.id INNER JOIN root_parameter rp ON rp.id = fa.root_parameter_id WHERE gcc.growth_curve_id = {var:growth_curve_id} AND spu.id = {var:spatial_unit_id} ORDER BY gcc.id DESC", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "spu": { + "transform": { + "queryString": "select s.id AS spu_id from spatial_unit s inner join admin_boundary a on s.admin_boundary_id = a.id inner join eco_boundary e on s.eco_boundary_id = e.id where a.name like {var:admin_boundary} and e.name like {var:eco_boundary}", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "land_class_data": { + "transform": { + "queryString": "SELECT code AS land_class, is_forest, years_to_permanent FROM land_class lc", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "mean_annual_temperature": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "mean_annual_temperature" + } + }, + "decay_parameters": { + "transform": { + "queryString": "SELECT p.name AS pool, dp.base_decay_rate AS organic_matter_decay_rate, dp.prop_to_atmosphere AS prop_to_atmosphere, dp.q10 AS q10, dp.reference_temp AS reference_temp, dp.max_rate AS max_decay_rate_soft FROM decay_parameter dp INNER JOIN dom_pool dom ON dp.dom_pool_id = dom.id INNER JOIN pool p ON p.id = dom.pool_id", + "type": "SQLQueryTransform", + "library": "internal.flint", + "provider": "SQLite" + } + }, + "disturbances_2012": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2012" + } + }, + "disturbances_2011": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2011" + } + }, + "disturbances_2015": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2015" + } + }, + "disturbances_2014": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2014" + } + }, + "disturbances_2018": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2018" + } + }, + "disturbances_2016": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2016" + } + }, + "Classifier2": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "Classifier2" + } + }, + "Classifier1": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "Classifier1" + } + }, + "disturbances_2013": { + "transform": { + "library": "internal.flint", + "type": "LocationIdxFromFlintDataTransform", + "provider": "RasterTiled", + "data_id": "disturbances_2013" + } + } + } +} \ No newline at end of file