diff --git a/.gitignore b/.gitignore
index 43514da4..12df06c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,3 +139,5 @@ cython_debug/
# Input files
local/rest_api_gcbm/input/
+GCBM_Demo_Run/
+GCBM_New_Demo_Run/
diff --git a/GCBM_New_Demo_Run.zip b/GCBM_New_Demo_Run.zip
index ec0589f1..250cb646 100644
Binary files a/GCBM_New_Demo_Run.zip and b/GCBM_New_Demo_Run.zip differ
diff --git a/local/rest_api_flint.example/docker-compose.yml b/local/rest_api_flint.example/docker-compose.yml
index ef79283a..c8072d7c 100644
--- a/local/rest_api_flint.example/docker-compose.yml
+++ b/local/rest_api_flint.example/docker-compose.yml
@@ -1,7 +1,11 @@
version: "3.9"
services:
flint.example:
- build: .
+ # - when developing use local builds
+ # build: .
+ # - or deploy using our CI
+ image: ghcr.io/moja-global/rest_api_flint.example:master
+ container_name: flint.example
ports:
- "8080:8080"
volumes:
diff --git a/local/rest_api_gcbm/app.py b/local/rest_api_gcbm/app.py
index a52fb5cd..ce5a3b3c 100644
--- a/local/rest_api_gcbm/app.py
+++ b/local/rest_api_gcbm/app.py
@@ -147,9 +147,9 @@ def gcbm_new():
title = request.form.get("title") or "simulation"
# Sanitize title
title = "".join(c for c in title if c.isalnum())
- project_dir = f"{title}"
- if not os.path.exists(f"{os.getcwd()}/input/{project_dir}"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}")
+ input_dir = f"{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."
@@ -181,105 +181,110 @@ def gcbm_upload():
title = "".join(c for c in title if c.isalnum())
# Create project directory
- project_dir = f"{title}"
- if not os.path.exists(f"{os.getcwd()}/input/{project_dir}"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}")
+ input_dir = f"{os.getcwd()}/input/{title}"
+ if not os.path.exists(f"{input_dir}"):
+ os.makedirs(f"{input_dir}")
logging.debug(os.getcwd())
- if os.path.exists(f"{os.getcwd()}/input/{project_dir}") and not os.path.exists(f"{os.getcwd()}/input/{project_dir}/disturbances"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}/disturbances")
- if os.path.exists(f"{os.getcwd()}/input/{project_dir}") and not os.path.exists(f"{os.getcwd()}/input/{project_dir}/classifiers"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}/classifiers")
- if os.path.exists(f"{os.getcwd()}/input/{project_dir}") and not os.path.exists(f"{os.getcwd()}/input/{project_dir}/db"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}/db")
- if os.path.exists(f"{os.getcwd()}/input/{project_dir}") and not os.path.exists(f"{os.getcwd()}/input/{project_dir}/miscellaneous"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}/miscellaneous")
- if os.path.exists(f"{os.getcwd()}/input/{project_dir}") and not os.path.exists(f"{os.getcwd()}/input/{project_dir}/templates"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}/templates")
-
- # Function to flatten paths
- def fix_path(path):
- return os.path.basename(path.replace("\\", "/"))
-
+ # input files follow a strict structure
+ if not os.path.exists(f"{input_dir}/disturbances"):
+ os.makedirs(f"{input_dir}/disturbances")
+ if not os.path.exists(f"{input_dir}/classifiers"):
+ os.makedirs(f"{input_dir}/classifiers")
+ if not os.path.exists(f"{input_dir}/db"):
+ os.makedirs(f"{input_dir}/db")
+ if not os.path.exists(f"{input_dir}/miscellaneous"):
+ os.makedirs(f"{input_dir}/miscellaneous")
+
+
+ # store files following structure defined in curl.md
if "disturbances" in request.files:
for file in request.files.getlist("disturbances"):
- file.save(f"{os.getcwd()}/input/{project_dir}/disturbances/{file.filename}")
+ file.save(f"{input_dir}/disturbances/{file.filename}")
else:
return{"error": "Missing configuration file"}, 400
if "classifiers" in request.files:
for file in request.files.getlist("classifiers"):
- file.save(f"{os.getcwd()}/input/{project_dir}/classifiers/{file.filename}")
+ file.save(f"{input_dir}/classifiers/{file.filename}")
else:
return{"error": "Missing configuration file"}, 400
if "db" in request.files:
for file in request.files.getlist("db"):
- file.save(f"{os.getcwd()}/input/{project_dir}/db/{file.filename}")
+ file.save(f"{input_dir}/db/{file.filename}")
else:
return{"error": "Missing configuration file"}, 400
if "miscellaneous" in request.files:
for file in request.files.getlist("miscellaneous"):
- file.save(f"{os.getcwd()}/input/{project_dir}/miscellaneous/{file.filename}")
- else:
- return{"error": "Missing configuration file"}, 400
-
- if "templates" in request.files:
- for file in request.files.getlist("templates"):
- file.save(f"{os.getcwd()}/input/{project_dir}/templates/{file.filename}")
+ file.save(f"{input_dir}/miscellaneous/{file.filename}")
else:
return{"error": "Missing configuration file"}, 400
-
- get_modules_cbm(project_dir)
- get_provider_config(project_dir)
- # layers(project_dir)
+ get_config_templates(input_dir)
+ get_modules_cbm_config(input_dir)
+ get_provider_config(input_dir)
return {
"data": "All files uploaded succesfully. Proceed to the next step of the API at gcbm/dynamic."
}
-def get_modules_cbm(project_dir):
- with open(f"{os.getcwd()}/input/{project_dir}/templates/modules_cbm.json", "r+") as pcf:
+def get_config_templates(input_dir):
+ if not os.path.exists(f"{input_dir}/templates"):
+ shutil.copytree(f"{os.getcwd()}/templates", f"{input_dir}/templates", dirs_exist_ok=False)
+
+
+# TODO: there needs to be a link between the files configured here append
+# the ["vars"] attribute of modules_cbm.json -> CBMDisturbanceListener
+# current hack is to drop the last five characters, but thats very fragile
+def get_modules_cbm_config(input_dir):
+ with open(f"{input_dir}/templates/modules_cbm.json", "r+") as pcf:
disturbances = []
data = json.load(pcf)
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/disturbances/"):
- disturbances.append(file.split('.')[0])
+ for file in os.listdir(f"{input_dir}/disturbances/"):
+ disturbances.append(file.split('.')[0][:-5]) # drop `_moja` to match modules_cbm.json template
pcf.seek(0)
data["Modules"]["CBMDisturbanceListener"]["settings"]["vars"] = disturbances
json.dump(data, pcf, indent=4)
pcf.truncate()
-def get_provider_config(project_dir):
- with open(f"{os.getcwd()}/input/{project_dir}/templates/provider_config.json", "r+") as gpc:
+def get_provider_config(input_dir):
+ with open(f"{input_dir}/templates/provider_config.json", "r+") as gpc: # why gpc?
lst = []
data = json.load(gpc)
-
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/disturbances/"):
+
+ for file in os.listdir(f"{input_dir}/db/"):
+ d = dict()
+ d["path"] = file
+ d["type"] = "SQLite"
+ data["Providers"]["SQLite"] = d
+ gpc.seek(0)
+
+ for file in os.listdir(f"{input_dir}/disturbances/"):
d = dict()
d["name"] = file[:-10]
- d["layer_path"] = "../layers/tiles" + file
+ d["layer_path"] = file
d["layer_prefix"] = file[:-5]
- lst.append(d)
+ lst.append(d)
gpc.seek(0)
data["Providers"]["RasterTiled"]["layers"] = lst
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/classifiers/"):
+ for file in os.listdir(f"{input_dir}/classifiers/"):
d = dict()
d["name"] = file[:-10]
- d["layer_path"] = "../layers/tiles" + file
+ d["layer_path"] = file
d["layer_prefix"] = file[:-5]
- lst.append(d)
+ lst.append(d)
gpc.seek(0)
data["Providers"]["RasterTiled"]["layers"] = lst
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/miscellaneous/"):
+ for file in os.listdir(f"{input_dir}/miscellaneous/"):
d = dict()
d["name"] = file[:-10]
- d["layer_path"] = "../layers/tiles" + file
+ d["layer_path"] = file
d["layer_prefix"] = file[:-5]
- lst.append(d)
+ lst.append(d)
gpc.seek(0)
data["Providers"]["RasterTiled"]["layers"] = lst
@@ -291,13 +296,13 @@ def get_provider_config(project_dir):
cellLonSize = []
paths = []
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/disturbances/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/disturbances/")):
for file in files:
fp = os.path.join(root, file)
Rasters.append(fp)
paths.append(fp)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/classifiers/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/classifiers/")):
for file in files:
fp1 = os.path.join(root, file)
Rasters.append(fp1)
@@ -312,7 +317,7 @@ def get_provider_config(project_dir):
cellLatSize.append(x)
cellLonSize.append(y)
nodata.append(n)
-
+
result = all(element == cellLatSize[0] for element in cellLatSize)
if(result):
cellLat = x
@@ -324,7 +329,7 @@ def get_provider_config(project_dir):
tileLon = y*4000
else:
print("Corrupt files")
-
+
gpc.seek(0)
data["Providers"]["RasterTiled"]["cellLonSize"] = cellLon
@@ -332,7 +337,7 @@ def get_provider_config(project_dir):
data["Providers"]["RasterTiled"]["blockLonSize"] = blockLon
data["Providers"]["RasterTiled"]["blockLatSize"] = blockLat
data["Providers"]["RasterTiled"]["tileLatSize"] = tileLat
- data["Providers"]["RasterTiled"]["LonSize"] = tileLon
+ data["Providers"]["RasterTiled"]["tileLonSize"] = tileLon
json.dump(data, gpc, indent=4)
gpc.truncate()
@@ -349,7 +354,10 @@ def get_provider_config(project_dir):
"cellLonSize": cellLon,
}
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/miscellaneous/")):
+ # TODO: refactor into get_input_layer_config
+ # should be able to accept variable number of inputs, but requires
+ # means for user to specify/verify correct ["attributes"]
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/miscellaneous/")):
for file in files:
fp2 = os.path.join(root, file)
Rastersm.append(fp2)
@@ -359,114 +367,120 @@ def get_provider_config(project_dir):
d = img.nodata
nodatam.append(d)
-
- with open(f"{os.getcwd()}/input/{project_dir}/miscellaneous/intial_age_moja.json", 'w', encoding ='utf8') as json_file1:
+ with open(f"{input_dir}/initial_age_moja.json", 'w', encoding ='utf8') as json_file1:
dictionary["layer_type"] = "GridLayer"
dictionary["layer_data"] = "Int16"
dictionary["nodata"] = nodatam[1]
json.dump(dictionary, json_file1, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/miscellaneous/mean_annual_temperature_moja.json", 'w', encoding ='utf8') as json_file2:
+ with open(f"{input_dir}/mean_annual_temperature_moja.json", 'w', encoding ='utf8') as json_file2:
dictionary["layer_type"] = "GridLayer"
dictionary["layer_data"] = "Float32"
dictionary["nodata"] = nodatam[0]
json.dump(dictionary, json_file2, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/classifiers/Classifier1_moja.json", 'w', encoding ='utf8') as json_file3:
- dictionary["attributes"] = {"1": "TA", "2": "BP", "3": "BS", "4": "JP", "5": "WS", "6": "WB", "7": "BF", "8": "GA"}
+ with open(f"{input_dir}/Classifier1_moja.json", 'w', encoding ='utf8') as json_file3:
+ dictionary["layer_type"] = "GridLayer"
+ dictionary["layer_data"] = "Byte"
+ dictionary["nodata"] = nd
+ dictionary["attributes"] = {"1": "TA", "2": "BP", "3": "BS", "4": "JP", "5": "WS", "6": "WB", "7": "BF", "8": "GA"}
json.dump(dictionary, json_file3, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/classifiers/Classifier2_moja.json", 'w', encoding ='utf8') as json_file4:
+ with open(f"{input_dir}/Classifier2_moja.json", 'w', encoding ='utf8') as json_file4:
+ dictionary["layer_type"] = "GridLayer"
+ dictionary["layer_data"] = "Byte"
+ dictionary["nodata"] = nd
dictionary["attributes"] = {"1": "5", "2": "6","3": "7",
- "4": "8"}
+ "4": "8"}
json.dump(dictionary, json_file4, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2011_moja.json", 'w', encoding ='utf8') as json_file5:
+ with open(f"{input_dir}/disturbances_2011_moja.json", 'w', encoding ='utf8') as json_file5:
dictionary["layer_data"] = "Byte"
dictionary["nodata"] = nd
dictionary["attributes"] = {
- "1": {
- "year": 2011,
- "disturbance_type": "Wildfire",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2011,
+ "disturbance_type": "Wildfire",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file5, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2012_moja.json", 'w', encoding ='utf8') as json_file6:
+ with open(f"{input_dir}/disturbances_2012_moja.json", 'w', encoding ='utf8') as json_file6:
dictionary["attributes"] = {
- "1": {
- "year": 2012,
- "disturbance_type": "Wildfire",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2012,
+ "disturbance_type": "Wildfire",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file6, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2013_moja.json", 'w', encoding ='utf8') as json_file7:
+ with open(f"{input_dir}/disturbances_2013_moja.json", 'w', encoding ='utf8') as json_file7:
dictionary["attributes"] = {
- "1": {
- "year": 2013,
- "disturbance_type": "Mountain pine beetle — Very severe impact",
- "transition": 1
- },
- "2": {
- "year": 2013,
- "disturbance_type": "Wildfire",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2013,
+ "disturbance_type": "Mountain pine beetle — Very severe impact",
+ "transition": 1
+ },
+ "2": {
+ "year": 2013,
+ "disturbance_type": "Wildfire",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file7, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2014_moja.json", 'w', encoding ='utf8') as json_file8:
+ with open(f"{input_dir}/disturbances_2014_moja.json", 'w', encoding ='utf8') as json_file8:
dictionary["attributes"] = {
- "1": {
- "year": 2014,
- "disturbance_type": "Mountain pine beetle — Very severe impact",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2014,
+ "disturbance_type": "Mountain pine beetle — Very severe impact",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file8, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2015_moja.json", 'w', encoding ='utf8') as json_file9:
+ with open(f"{input_dir}/disturbances_2015_moja.json", 'w', encoding ='utf8') as json_file9:
dictionary["attributes"] = {
- "1": {
- "year": 2016,
- "disturbance_type": "Wildfire",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2016,
+ "disturbance_type": "Wildfire",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file9, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2016_moja.json", 'w', encoding ='utf8') as json_file10:
+ with open(f"{input_dir}/disturbances_2016_moja.json", 'w', encoding ='utf8') as json_file10:
dictionary["attributes"] = {
- "1": {
- "year": 2016,
- "disturbance_type": "Wildfire",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2016,
+ "disturbance_type": "Wildfire",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file10, indent = 4)
- with open(f"{os.getcwd()}/input/{project_dir}/disturbances/disturbances_2018_moja.json", 'w', encoding ='utf8') as json_file11:
+ with open(f"{input_dir}/disturbances_2018_moja.json", 'w', encoding ='utf8') as json_file11:
dictionary["attributes"] = {
- "1": {
- "year": 2018,
- "disturbance_type": "Mountain pine beetle — Low impact",
- "transition": 1
- }
- }
+ "1": {
+ "year": 2018,
+ "disturbance_type": "Mountain pine beetle — Low impact",
+ "transition": 1
+ }
+ }
json.dump(dictionary, json_file11, indent = 4)
+ # TODO: Refactor into get_study_area_config
study_area = {
"tile_size": tileLat,
"block_size": blockLat,
"tiles": [{
- "x": t[2],
- "y": t[5],
- "index": 12674
+ "x": int(t[2]), # FLINT is strongly typed, but maybe it doesnt matter, just following format in GCBM_Demo_Run
+ "y": int(t[5]),
+ "index": 12674 # verify source of this number
}],
"pixel_size": cellLat,
"layers": [
@@ -474,18 +488,17 @@ def get_provider_config(project_dir):
]
}
- with open(f"{os.getcwd()}/input/{project_dir}/miscellaneous/study_area.json", 'w', encoding = 'utf') as json_file:
-
+ with open(f"{input_dir}/study_area.json", 'w', encoding = 'utf') as json_file:
list = []
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/miscellaneous/"):
+ for file in os.listdir(f"{input_dir}/miscellaneous/"):
d1 = dict()
d1["name"] = file[:-10]
d1["type"] = "VectorLayer"
list.append(d1)
study_area["layers"] = list
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/classifiers/"):
+ for file in os.listdir(f"{input_dir}/classifiers/"):
d1 = dict()
d1["name"] = file[:-10]
d1["type"] = "VectorLayer"
@@ -493,7 +506,7 @@ def get_provider_config(project_dir):
list.append(d1)
study_area["layers"] = list
- for file in os.listdir(f"{os.getcwd()}/input/{project_dir}/disturbances/"):
+ for file in os.listdir(f"{input_dir}/disturbances/"):
d1 = dict()
d1["name"] = file[:-10]
d1["type"] = "DisturbanceLayer"
@@ -501,47 +514,45 @@ def get_provider_config(project_dir):
list.append(d1)
study_area["layers"] = list
-
-
json.dump(study_area, json_file, indent=4)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/disturbances/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/disturbances/")):
for file in files:
fp = os.path.join(root, file)
Rasters.append(fp)
paths.append(fp)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/classifiers/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/classifiers/")):
for file in files:
fp1 = os.path.join(root, file)
Rasters.append(fp1)
paths.append(fp1)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/miscellaneous/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/miscellaneous/")):
for file in files:
fp2 = os.path.join(root, file)
paths.append(fp2)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/templates/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/templates/")):
for file in files:
fp3 = os.path.join(root, file)
paths.append(fp3)
- for root, dirs, files in os.walk(os.path.abspath(f"{os.getcwd()}/input/{project_dir}/db/")):
+ for root, dirs, files in os.walk(os.path.abspath(f"{input_dir}/db/")):
for file in files:
fp4 = os.path.join(root, file)
paths.append(fp4)
for i in paths:
print(i)
- shutil.copy2(i, (f"{os.getcwd()}/input/{project_dir}"))
+ shutil.copy2(i, (f"{input_dir}"))
- shutil.rmtree((f"{os.getcwd()}/input/{project_dir}/disturbances/"))
- shutil.rmtree((f"{os.getcwd()}/input/{project_dir}/templates/"))
- shutil.rmtree((f"{os.getcwd()}/input/{project_dir}/classifiers/"))
- shutil.rmtree((f"{os.getcwd()}/input/{project_dir}/miscellaneous/"))
- shutil.rmtree((f"{os.getcwd()}/input/{project_dir}/db/"))
+ shutil.rmtree((f"{input_dir}/disturbances/"))
+ shutil.rmtree((f"{input_dir}/templates/"))
+ shutil.rmtree((f"{input_dir}/classifiers/"))
+ shutil.rmtree((f"{input_dir}/miscellaneous/"))
+ shutil.rmtree((f"{input_dir}/db/"))
@app.route("/gcbm/dynamic", methods=["POST"])
def gcbm_dynamic():
@@ -562,28 +573,29 @@ def gcbm_dynamic():
"""
# Default title = simulation
title = request.form.get("title") or "simulation"
+
# Sanitize title
title = "".join(c for c in title if c.isalnum())
- project_dir = f"{title}"
+ input_dir = f"{os.getcwd()}/input/{title}"
gcbm_config_path = "gcbm_config.cfg"
provider_config_path = "provider_config.json"
- if not os.path.exists(f"{os.getcwd()}/input/{project_dir}"):
- os.makedirs(f"{os.getcwd()}/input/{project_dir}")
+ if not os.path.exists(f"{input_dir}"):
+ os.makedirs(f"{input_dir}")
thread = Thread(
- target=launch_run, kwargs={"title": title, "project_dir": project_dir}
+ target=launch_run, kwargs={"title": title, "input_dir": input_dir}
)
thread.start()
# subscriber_path = create_topic_and_sub(title)
return {"status": "Run started"}, 200
-def launch_run(title, project_dir):
+def launch_run(title, input_dir):
s = time.time()
logging.debug("Starting run")
- with open(f"{os.getcwd()}/input/{project_dir}/gcbm_logs.csv", "w+") as f:
+ with open(f"{input_dir}/gcbm_logs.csv", "w+") as f:
res = subprocess.Popen(
[
"/opt/gcbm/moja.cli",
@@ -593,20 +605,23 @@ def launch_run(title, project_dir):
"provider_config.json",
],
stdout=f,
- cwd=f"{os.getcwd()}/input/{project_dir}",
+ cwd=f"{input_dir}",
)
logging.debug("Communicating")
(output, err) = res.communicate()
logging.debug("Communicated")
- if not os.path.exists(f"{os.getcwd()}/input/{project_dir}/output"):
+
+ # TODO: this should go in `output/title/` but will need updating in
+ # get_modules_cbm_config and download()
+ if not os.path.exists(f"{input_dir}/output"):
logging.error(err)
return "OK"
logging.debug("Output exists")
- # returncode = final_run(title, gcbm_config_path, provider_config_path, project_dir)
+ # returncode = final_run(title, gcbm_config_path, provider_config_path, input_dir)
shutil.make_archive(
- f"{os.getcwd()}/input/{project_dir}/output",
+ f"{input_dir}/output",
"zip",
- f"{os.getcwd()}/input/{project_dir}/output",
+ f"{input_dir}/output",
)
logging.debug("Made archive")
e = time.time()
@@ -640,9 +655,9 @@ def gcbm_download():
title = request.form.get("title") or "simulation"
# Sanitize title
title = "".join(c for c in title if c.isalnum())
- project_dir = f"{title}"
+ input_dir = f"{title}"
return send_file(
- f"{os.getcwd()}/input/{project_dir}/output.zip",
+ f"{input_dir}/output.zip",
attachment_filename="output.zip",
)
diff --git a/local/rest_api_gcbm/curl.md b/local/rest_api_gcbm/curl.md
index 5737d90a..2565fa41 100644
--- a/local/rest_api_gcbm/curl.md
+++ b/local/rest_api_gcbm/curl.md
@@ -1,6 +1,6 @@
Endpoints
-1. `/gcbm/new/`
+1. `/gcbm/new/`
The title of a new simulation can be passed or the default title `simulation` will be used. (i.e the default title of the simulation is `simulation`, here the title `run4` is used)
@@ -31,15 +31,6 @@
-F db='@db/gcbm_input.db' \
-F miscellaneous='@miscellaneous/initial_age_moja.tiff' \
-F miscellaneous='@miscellaneous/mean_annual_temperature_moja.tiff' \
- -F templates='@templates/internal_variables.json' \
- -F templates='@templates/localdomain.json' \
- -F templates='@templates/modules_cbm.json' \
- -F templates='@templates/modules_output.json' \
- -F templates='@templates/pools_cbm.json' \
- -F templates='@templates/provider_config.json' \
- -F templates='@templates/spinup.json' \
- -F templates='@templates/variables.json' \
- -F templates='@templates/gcbm_config.cfg' \
-F title="run4" \
http://localhost:8080/gcbm/upload
@@ -56,7 +47,7 @@
```
5. `/gcbm/download`
A file named `output.zip` will be obtained. This file contains the outputs generated, which can be analysed on unzipping.
-
+
```
curl -d "title=run4" -X POST http://localhost:8080/gcbm/download -L -o output.zip
```
diff --git a/local/rest_api_gcbm/docker-compose.yml b/local/rest_api_gcbm/docker-compose.yml
index e11802f6..03ffdbe6 100644
--- a/local/rest_api_gcbm/docker-compose.yml
+++ b/local/rest_api_gcbm/docker-compose.yml
@@ -1,9 +1,12 @@
version: "3.9"
services:
gcbm:
+ # - when developing use local builds
build: .
+ # - or deploy using our CI
+ # image: ghcr.io/moja-global/rest_api_gcbm:master
+ container_name: flint.gcbm
ports:
- "8080:8080"
volumes:
- .:/app
-
diff --git a/local/rest_api_gcbm/run4/gcbm_logs.csv b/local/rest_api_gcbm/run4/gcbm_logs.csv
new file mode 100644
index 00000000..e69de29b
diff --git a/local/rest_api_gcbm/templates/gcbm_config.cfg b/local/rest_api_gcbm/templates/gcbm_config.cfg
new file mode 100644
index 00000000..e6640ac9
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/internal_variables.json b/local/rest_api_gcbm/templates/internal_variables.json
new file mode 100644
index 00000000..d9f71537
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/localdomain.json b/local/rest_api_gcbm/templates/localdomain.json
new file mode 100644
index 00000000..5bb04f33
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/logging.conf b/local/rest_api_gcbm/templates/logging.conf
new file mode 100644
index 00000000..2da5fec5
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/modules_cbm.json b/local/rest_api_gcbm/templates/modules_cbm.json
new file mode 100644
index 00000000..4db5d37b
--- /dev/null
+++ b/local/rest_api_gcbm/templates/modules_cbm.json
@@ -0,0 +1,65 @@
+{
+ "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": [
+ "disturbances_2012_moja",
+ "disturbances_2015_moja",
+ "disturbances_2014_moja",
+ "disturbances_2018_moja",
+ "disturbances_2016_moja",
+ "disturbances_2013_moja",
+ "disturbances_2011_moja"
+ ]
+ }
+ },
+ "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_gcbm/templates/modules_output.json b/local/rest_api_gcbm/templates/modules_output.json
new file mode 100644
index 00000000..cad01b28
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/pools_cbm.json b/local/rest_api_gcbm/templates/pools_cbm.json
new file mode 100644
index 00000000..35979d38
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/provider_config.json b/local/rest_api_gcbm/templates/provider_config.json
new file mode 100644
index 00000000..1d2a9987
--- /dev/null
+++ b/local/rest_api_gcbm/templates/provider_config.json
@@ -0,0 +1,75 @@
+{
+ "Providers": {
+ "SQLite": {
+ "path": "../input_database/gcbm_input.db",
+ "type": "SQLite"
+ },
+ "RasterTiled": {
+ "layers": [
+ {
+ "name": "disturbances_2012",
+ "layer_path": "../layers/tilesdisturbances_2012_moja.tiff",
+ "layer_prefix": "disturbances_2012_moja"
+ },
+ {
+ "name": "disturbances_2015",
+ "layer_path": "../layers/tilesdisturbances_2015_moja.tiff",
+ "layer_prefix": "disturbances_2015_moja"
+ },
+ {
+ "name": "disturbances_2014",
+ "layer_path": "../layers/tilesdisturbances_2014_moja.tiff",
+ "layer_prefix": "disturbances_2014_moja"
+ },
+ {
+ "name": "disturbances_2018",
+ "layer_path": "../layers/tilesdisturbances_2018_moja.tiff",
+ "layer_prefix": "disturbances_2018_moja"
+ },
+ {
+ "name": "disturbances_2016",
+ "layer_path": "../layers/tilesdisturbances_2016_moja.tiff",
+ "layer_prefix": "disturbances_2016_moja"
+ },
+ {
+ "name": "disturbances_2013",
+ "layer_path": "../layers/tilesdisturbances_2013_moja.tiff",
+ "layer_prefix": "disturbances_2013_moja"
+ },
+ {
+ "name": "disturbances_2011",
+ "layer_path": "../layers/tilesdisturbances_2011_moja.tiff",
+ "layer_prefix": "disturbances_2011_moja"
+ },
+ {
+ "name": "Classifier1",
+ "layer_path": "../layers/tilesClassifier1_moja.tiff",
+ "layer_prefix": "Classifier1_moja"
+ },
+ {
+ "name": "Classifier2",
+ "layer_path": "../layers/tilesClassifier2_moja.tiff",
+ "layer_prefix": "Classifier2_moja"
+ },
+ {
+ "name": "mean_annual_temperature",
+ "layer_path": "../layers/tilesmean_annual_temperature_moja.tiff",
+ "layer_prefix": "mean_annual_temperature_moja"
+ },
+ {
+ "name": "initial_age",
+ "layer_path": "../layers/tilesinitial_age_moja.tiff",
+ "layer_prefix": "initial_age_moja"
+ }
+ ],
+ "blockLonSize": 0.1,
+ "tileLatSize": 1.0,
+ "tileLonSize": 1.0,
+ "cellLatSize": 0.00025,
+ "cellLonSize": 0.00025,
+ "blockLatSize": 0.1,
+ "type": "RasterTiledGDAL",
+ "library": "moja.modules.gdal"
+ }
+ }
+}
diff --git a/local/rest_api_gcbm/templates/spinup.json b/local/rest_api_gcbm/templates/spinup.json
new file mode 100644
index 00000000..1365b141
--- /dev/null
+++ b/local/rest_api_gcbm/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_gcbm/templates/variables.json b/local/rest_api_gcbm/templates/variables.json
new file mode 100644
index 00000000..f2d8bc2f
--- /dev/null
+++ b/local/rest_api_gcbm/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