Module: GrassCookbook
- Defined in:
- lib/grassgis/cookbook.rb
Overview
Recipes can only be defined when input parameters, files and maps are specific (although an input file can be a directory with an indetermninate number of files inside) and there’s no dependency between input parameters/files/maps and which products are generated. (so the generated products are also specific, except, again, for the contents of directories). Also, recipes shouldn’t generate any non-declared maps, i.e. temporary or auxiliary maps should be removed before the recipe ends.
Temporary maps & files support, e.g.: temporaries are declared, then recipe is executed in a block with a ensure which removes temporary maps
Example:
GrassCookbook.recipe :dem_base_from_mdt05 do
description %{
Generate a DEM for the interest area at fixed 5m resolution
from CNIG's MDT05 data.
}
required_files 'data/MDT05'
generated_raster_maps 'dem_base'
process do |mdt05_sheets|
...
end
end
GrassCookbook.recipe :dem_base_derived do
description %{
Generate DEM-derived maps from the 5m dem base:
slope, aspect and relief shading
}
required_raster_maps 'dem_base'
generated_raster_maps 'shade_base', 'slope_base', 'aspect_base'
process do
r.relief input: 'dem_base', output: 'shade_base'
r.slope.aspect elevation: 'dem_base',
slope: 'slope_base',
aspect: 'aspect_base'
end
end
GrassCookbook.recipe :working_dem do
description %{
Generate DEM data at working resolution
}
required_raster_maps 'dem_base', 'slope_base', 'aspect_base'
generated_raster_maps 'dem', 'slope', 'aspect'
process do |resolution|
...
end
end
# Now use our recipes to compute some permanent base maps and
# alternative scenario mapsheets varying some parameter.
GrassGis.session grass_config do
# First generate maps using fixed parameters and move them to PERMANENT
fixed_parameters = { mdt05_sheets: %w(0244 0282) }
fixed_data = primary = GrassCookbook::Data[
parameters: fixed_parameters.keys,
files: GrassCookbook.existing_external_input_files
]
plan = GrassCookbook.plan(fixed_data)
permanent = plan.last
GrassCookbook.replace_existing_products self, plan
GrassCookbook.execute self, fixed_parameters, plan
permanent.maps.each do |map, type|
move_map(map, type: type, to: 'PERMANENT')
end
# Then define some variations of other parameters and create a mapset
# for each variation, where maps dependent on the varying parameters
# will be put
variants = {
'10m' => { resolucion: 10 },
'25m' => { resolucion: 25 }
}
for variant_name, variant_parameters in variants
data = GrassCookbook::Data[parameters: variant_parameters.keys] + permanent
plan = GrassCookbook.plan(data)
GrassCookbook.replace_existing_products self, plan
GrassCookbook.execute self, fixed_parameters.merge(variant_parameters), plan
variant_maps = (plan.last - data).maps
create_mapset variant_name
variant_maps.each do |map, type|
move_map(map, type: type, to: variant_name)
end
end
end
Defined Under Namespace
Classes: Data, Recipe, RecipeDsl
Class Method Summary collapse
- .[](recipe) ⇒ Object
- .achievable_results(grass, parameters) ⇒ Object
- .all_files_possible ⇒ Object
- .all_files_used ⇒ Object
- .all_maps_possible ⇒ Object
- .all_maps_used ⇒ Object
- .available_data(grass, parameters) ⇒ Object
- .cook(grass, recipe, parameters) ⇒ Object
- .execute(grass, parameters, plan) ⇒ Object
-
.existing_external_input_files ⇒ Object
primary input files input files that exist (and are not generated, so they are externally provided input).
- .existing_input_files ⇒ Object
- .existing_input_maps(grass) ⇒ Object
- .impossible_results(grass, parameters) ⇒ Object
- .missing_input(grass) ⇒ Object
- .permantent_results(grass, fixed_parameters) ⇒ Object
-
.plan(input_data) ⇒ Object
Generate ordered recipes and generated products (output) than can be obtained with available inputdata.
- .recipe(id, &blk) ⇒ Object
- .replace_existing_products(grass, plan, parameters = nil) ⇒ Object
Class Method Details
.[](recipe) ⇒ Object
345 346 347 348 349 350 351 |
# File 'lib/grassgis/cookbook.rb', line 345 def [](recipe) if recipe.is_a? Recipe recipe else @recipes[recipe.to_sym] end end |
.achievable_results(grass, parameters) ⇒ Object
419 420 421 422 |
# File 'lib/grassgis/cookbook.rb', line 419 def achievable_results(grass, parameters) inputs = available_data(grass, parameters) inputs + plan(inputs).last end |
.all_files_possible ⇒ Object
366 367 368 |
# File 'lib/grassgis/cookbook.rb', line 366 def all_files_possible @recipes.values.map(&:generated_files).flatten.uniq end |
.all_files_used ⇒ Object
358 359 360 |
# File 'lib/grassgis/cookbook.rb', line 358 def all_files_used @recipes.values.map(&:required_files).flatten.uniq end |
.all_maps_possible ⇒ Object
370 371 372 |
# File 'lib/grassgis/cookbook.rb', line 370 def all_maps_possible @recipes.values.map(&:generated_maps).flatten(1).uniq end |
.all_maps_used ⇒ Object
362 363 364 |
# File 'lib/grassgis/cookbook.rb', line 362 def all_maps_used @recipes.values.map(&:required_maps).flatten(1).uniq end |
.available_data(grass, parameters) ⇒ Object
411 412 413 414 415 416 417 |
# File 'lib/grassgis/cookbook.rb', line 411 def available_data(grass, parameters) Data[ parameters: parameters, files: existing_input_files, maps: existing_input_maps(grass) ] end |
.cook(grass, recipe, parameters) ⇒ Object
353 354 355 356 |
# File 'lib/grassgis/cookbook.rb', line 353 def cook(grass, recipe, parameters) grass.log "Recipe: #{recipe}" self[recipe].cook grass, parameters end |
.execute(grass, parameters, plan) ⇒ Object
450 451 452 453 454 455 456 |
# File 'lib/grassgis/cookbook.rb', line 450 def execute(grass, parameters, plan) recipes, result = plan recipes.each do |recipe| cook grass, recipe, parameters end result end |
.existing_external_input_files ⇒ Object
primary input files input files that exist (and are not generated, so they are externally provided input)
426 427 428 |
# File 'lib/grassgis/cookbook.rb', line 426 def existing_external_input_files existing_input_files - all_files_possible end |
.existing_input_files ⇒ Object
374 375 376 |
# File 'lib/grassgis/cookbook.rb', line 374 def existing_input_files all_files_used.select { |f| File.exists?(f) } end |
.existing_input_maps(grass) ⇒ Object
378 379 380 381 382 |
# File 'lib/grassgis/cookbook.rb', line 378 def existing_input_maps(grass) # TODO: use mapset PATH here (add as another parameters) path = [] all_maps_used.select { |m, t| grass.map_exists?(m, type: t, mapset: path) } end |
.impossible_results(grass, parameters) ⇒ Object
442 443 444 445 446 447 448 |
# File 'lib/grassgis/cookbook.rb', line 442 def impossible_results(grass, parameters) possibilities = Data[ files: all_files_possible, maps: all_maps_possible ] possibilities - achievable_results(grass, parameters) end |
.missing_input(grass) ⇒ Object
435 436 437 438 439 440 |
# File 'lib/grassgis/cookbook.rb', line 435 def missing_input(grass) Data[ files: all_files_used - existing_input_files, maps: all_maps_used - existing_input_maps(grass) ] end |
.permantent_results(grass, fixed_parameters) ⇒ Object
430 431 432 433 |
# File 'lib/grassgis/cookbook.rb', line 430 def permantent_results(grass, fixed_parameters) primary = Data[parameters: fixed_parameters, files: existing_external_input_files] plan(primary).last end |
.plan(input_data) ⇒ Object
Generate ordered recipes and generated products (output) than can be obtained with available inputdata.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# File 'lib/grassgis/cookbook.rb', line 386 def plan(input_data) input = Data[input_data] existing = input.dup applied_recipes = [] remaining_recipes = @recipes.values - applied_recipes while remaining_recipes.size > 0 progress = false remaining_recipes.each do |recipe| unless recipe.done?(existing) if recipe.doable?(existing) progress = true applied_recipes << recipe existing.merge! recipe.products end end end break unless progress remaining_recipes -= applied_recipes end [applied_recipes, existing - input] end |
.recipe(id, &blk) ⇒ Object
339 340 341 342 343 |
# File 'lib/grassgis/cookbook.rb', line 339 def recipe(id, &blk) dsl = RecipeDsl.new(id) dsl.instance_eval &blk @recipes[id.to_sym] = dsl.recipe end |
.replace_existing_products(grass, plan, parameters = nil) ⇒ Object
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/grassgis/cookbook.rb', line 458 def replace_existing_products(grass, plan, parameters = nil) results = plan.last if parameters results.parameters.each do |parameter| parameters.delete parameter end end results.maps.each do |map, type| mapset = grass.explicit_map_mapset(map) || grass.current_mapset if grass.map_exists?(map, type: type, mapset: mapset) grass.remove_map(map, type: type, mapset: mapset) end end results.files.each do |file| if File.exists?(file) if File.directory?(file) FileUtils.rm_rf file else FileUtils.rm file end end end end |