[GRASS-SVN] r60080 - grass-addons/grass6/general/g.infer

svn_grass at osgeo.org svn_grass at osgeo.org
Sun May 4 15:46:16 PDT 2014


Author: hamish
Date: 2014-05-04 15:46:16 -0700 (Sun, 04 May 2014)
New Revision: 60080

Modified:
   grass-addons/grass6/general/g.infer/g.infer
Log:
fix newlines; only read region, don't alter WIND file (#2230)

Modified: grass-addons/grass6/general/g.infer/g.infer
===================================================================
--- grass-addons/grass6/general/g.infer/g.infer	2014-05-04 21:57:22 UTC (rev 60079)
+++ grass-addons/grass6/general/g.infer/g.infer	2014-05-04 22:46:16 UTC (rev 60080)
@@ -1,996 +1,996 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-############################################################################
-#
-# MODULE:      g.infer.clips  
-# AUTHOR(S):   Peter Loewe loewe at gisix.com
-#              
-# PURPOSE:     GRASS interface to the CLIPS inference engine
-# COPYRIGHT:   (C) 2011,2012,2013 by Peter Loewe
-#
-#              This program is free software under the GNU General Public
-#              License (>=v2). Read the file COPYING that comes with GRASS
-#              for details.
-#############################################################################
-#############################################################################
-#BUGS
-# grass_run / grass_read has problems when executing off-the-shelf shell commands like "sleep 2s"
-#############################################################################
-#TESTED:
-#
-# in/out: RASTER without Labels: WORKS 2012-01-18
-# in/out: RASTER with Labels: WORKS 2012-01-18
-# in/out: VOLUMES without labels: WORKS 2012-01-23
-# in/out: Vector points 2D: WORK 2012-01-23
-# out:    Create new vector point layer 2012-05-08 - broken - reconifmred: 2013-01-15
-# in/out: Vector points 3D: 2012-06-07
-# in/out: facts:
-# in/out: COOL-objects:
-#
-# GRASS modules on RHS:
-# GENERAL
-# g.list: (python-call grass_run_command "g.list" "f" "type=rast,vect")
-# g.version: (python-call grass_run_command "g.version" "c")
-
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## GRASS g.infer module description
-#####################################################
-
-#%module
-#% description: GRASS GIS interface to the CLIPS inference engine
-#% keywords: inference, reseasoning, knowledge-based
-#%end
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## GRASS GUI: Flags
-#####################################################
-
-#%flag
-#% key: d
-#% description: Activate CLIPS dribble option.
-#% guisection: CLIPS
-#%end
-
-#%flag
-#% key: e
-#% description: Traceback of CLIPS error messages.
-#% guisection: CLIPS
-#%end
-
-#%flag
-#% key: i
-#% description: Interactive CLIPS shell
-#% guisection: CLIPS
-#%end
-
-#%flag
-#% key: l
-#% description: Raster input: Ignore raster labels (default: labels are imported).
-#% guisection: Input
-#%end
-
-#DEPRECATED: In most cases this will halt the module as lots and lots of GIS layer derived facts would have to be printed.
-## #%flag
-## #% key: p
-## #% description: Print applicable facts (pre-loaded) for the inference run (default: off).
-## #% guisection: CLIPS
-## #%end
-
-# #%flag
-# #% key: k
-# #% description: Provide a built-in knowledge base of application examples.
-# #% guisection: CLIPS
-# #%end
-
-#%flag
-#% key: x
-#% description: Stop execution just prior to inference run.
-#% guisection: CLIPS
-#%end
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## GRASS GUI: Options
-#####################################################
-
-#%option
-#% key: rulebase
-#% type: string
-#% key_desc: name
-#% description: Rule base file (ASCII).
-#% gisprompt: old_file,file,input
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: load_instances
-#% type: string
-#% key_desc: load_instances
-#% description: Load instances from ASCII file
-#% gisprompt: old_file,file,input
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: bload_instances
-#% type: string
-#% key_desc: bload_instances
-#% description: Load instances from binary file
-#% gisprompt: old_file,file,input
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: rast
-#% type: string
-#% gisprompt: old,cell,raster
-#% description: Raster input map(s)
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: rast3d
-#% type: string
-#% gisprompt: old,raster3,raster3
-#% description: Raster3d input map(s)
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: vector
-#% type: string
-#% gisprompt: old,vector,vector
-#% description: Vector input map(s)
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: facts
-#% type: string
-#% gisprompt: old_file,file,file
-#% description: CLIPS facts input
-#% multiple : no
-#% key_desc : facts
-#% required : no
-#% guisection: Input
-#%end
-
-#%option
-#% key: library
-#% type: string
-#% description: Built-in CLIPS rulebases which are included in g.infer. The spearfish rulebase requires the Spearfish location.  
-#% options: reference,spearfish
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Input
-#%end
-
-#############################################
-##General g.infer output-related options
-
-#%option
-#% key: export
-#% type: string
-#% description: Export of maps (a subset of the maps selected as input layers)
-#% key_desc : name
-#% required : no
-#% multiple : yes
-#% guisection: Output
-#%end
-
-#%option
-#% key: output 
-#% type: string
-#% description: new vector output map
-#% key_desc : name
-#% required : no
-#% multiple : yes
-#% guisection: Output
-#%end
-
-#%option
-#% key: save_instances
-#% type: string
-#% description: ASCII output of COOL instances 
-#% key_desc : instances_ascii_output_name
-#% required : no
-#% guisection: Output
-#%end
-
-#%option
-#% key: bsave_instances
-#% type: string
-#% description: Binary output of COOL instances 
-#% key_desc : instances_binary_output_name
-#% required : no
-#% guisection: Output
-#%end
-
-#%option
-#% key: columns
-#% type: string
-#% description: Attribute column structure for output vector  
-#% key_desc : name
-#% required : no
-#% guisection: Output
-#%end
-
-#%option
-#% key: save_rulebase
-#% type: string
-#% description: CLIPS entities to be saved to ASCII file  
-#% options: constructs,facts,instances
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Output
-#%end
-
-#%option
-#% key: bsave_rulebase
-#% type: string
-#% description: CLIPS entities to be saved to binary file 
-#% options: constructs,facts,instances
-#% multiple : yes
-#% key_desc : name
-#% required : no
-#% guisection: Output
-#%end
-
-
-################################
-## CLIPS-related OPTIONS
-
-#%option
-#% key: strategy
-#% type: string
-#% description: Inference Strategy 
-#% key_desc : Select the inference strategy (default: depth)
-#% options: breadth,complexity,depth,lex,mea,simplicity,random
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: limit
-#% type: string
-#% description: Maximum number of inferences 
-#% key_desc : Upper limit for inference runs
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: salience
-#% type: string
-#% description: Salience behaviour 
-#% key_desc : Select the salience behaviour strategy (default: when-defined)
-#% options: when-defined,when-activated,every-cycle
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: module
-#% type: string
-#% description: Rule base module(s) to be on te focus stack for inference launch (default: MAIN)
-#% key_desc : Module(s) (group(s= of rules) to be specificaly put the focus stack for the inference run.
-#% required : no
-#% multiple : yes
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: watch
-#% type: string
-#% options: activations,compilations,facts,functions,genericfunctions,globals,methods,messagehandlers,messages,rules,slots,statistics,all
-#% multiple : yes
-#% description: Watch options for CLIPS engine
-#% key_desc : Watch options for CLIPS engine.
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: print
-#% type: string
-#% options: agenda,breakpoints,classes,deffacts,definstances,facts,focusstack,functions,generics,globals,instances,messagehandlers,modules,rules,templates
-#% multiple : yes
-#% description: Prints CLIPS items prior to inference run.
-#% key_desc : Prints CLIPS items prior to inference run.
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: config
-#% type: string
-#% options: auto-float-dividend,dynamic-constraint-checking,fact-duplication,incremental-reset,reset-globals,sequence-operator-recognition,static-constraint-checking
-#% multiple : yes
-#% description: Configuration options for CLIPS engine
-#% key_desc : Configuration options for CLIPS engine.
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#%option
-#% key: classdefault
-#% type: string
-#% options: convenience,conservation
-#% multiple : no
-#% description: Class default of CLIPS engine
-#% key_desc : Class default of CLIPS engine.
-#% required : no
-#% guisection: CLIPS
-#%end
-
-#######################################################################
-#######################################################################
-#######################################################################
-## Import Python Modules
-#######################################################################
-
-def module_exists(the_module,as_name = False):
-    """! TBD"""
-    the_module_name = str(the_module)	 
-    try:
-        if as_name:
-	    import the_module_name as as_name	
-	else:
-	    __import__(the_module_name)
-		       
-    except ImportError:
-        error_message=str("[module_exists] Import Error:" + str(the_module))
-	grass.fatal(_(error_message))
-    return True
-
-
-import grass.script as grass
-from grass.lib import vector as grassvect
-
-from grass.lib.gis import * 
-from ctypes import *
-import grass.script.array as garray
-#module_exists("grass.script.array","garray")
-import clips
-#module_exists('clips')
-#ISSUE: see below. same case.
-import sys
-import os
-import atexit
-import random
-import time
-import string as _string
-import types
-#module_exists(str("types"))
-#^^^^ There is some issue: Global name types is not defined.
-module_exists('numpy')
-module_exists(str("os.path"))
-
-#######################################################################
-#######################################################################
-#######################################################################
-## Global Variables
-#######################################################################
-
-##################################################
-#A placeholder for the NULL substitute for vector export
-# must be improved to support FLOATS for NULLS during export.
-FACT_NULL = -2147483648
-FACT_NULL_FLOAT = "nan"
-
-# Reality check: 
-#    Integer maps, NULLs -> (value -2147483648)
-#    Float maps: NULL -> (value nan)
-
-##################################################
-# Set up dictionaries to manage all relevant aspects of GRASS-(input)-layers 
-##################################################
-
-#################################################
-# Dictionary to store v.in.ascii-string for vector layers
-layers_vector_vinascii={}
-
-#################################################
-# Dictionary to store template for vector layer
-layers_template={}
-
-#################################################
-# Dictionary to store attribute column structure for vector layers
-layers_vector_columns={}
-
-#################################################
-# Dictionary to store numeric type of raster layers
-layers_raster_type={}
-
-#################################################
-# Dictionary to store 2D slice names for 3D rast3d volume layers
-layers_raster3d_slices={}
-
-##################################################
-# Access to central dictionaries
-
-def global_layers_template_put(the_layer,the_template):
-    """! Put a layer template in the layer template dictionary under its layer name"""
-    global the_layers_template
-    layers_template[the_layer]=the_template
-
-def global_layers_raster_type_put(the_layer,the_type):
-    """! Put a raster layers typ in the raster type dictionary under its layer name"""
-    global layers_raster_type
-    layers_raster_type[the_layer]=the_type
-    
-def global_layers_vector_vinascii_put(the_layer,the_string):
-    """! Put a vector layer v.in.ascii string in the layer v.in.ascii dictionary under its layer name"""
-    global layers_vector_vinascii
-    layers_vector_vinascii[the_layer]=the_string
-
-def global_layers_vector_columns_put(the_layer,the_columns):
-    """! Put a vector layers columns description in the vector column dictionary under its layer name"""
-    global layers_vector_columns
-    layers_vector_columns[the_layer]=the_columns
-
-def global_layers_rast3d_slices_put(the_layer,the_slices):
-    """! Put a slices info (list?) of a volume layer in the volume layer slices dictionary under its layer name"""
-    global layers_raster3d_slices
-    layers_raster3d_slices[the_layer] = the_slices
-    
-def global_layers_template_get(the_layer):
-    """! Retrieve a layer template from the layer template dictionary by its layer name"""
-    global the_layers_template
-    return layers_template[the_layer]
-
-def global_layers_raster_type_get(the_layer):
-    """! Retrieve a raster layer type from the raster type dictionary by its layer name"""
-    global layers_raster_type
-    return layers_raster_type[the_layer]
-    
-def global_layers_vector_vinascii_get(the_layer):
-    """! Retrieve a vector layer v.in.ascii string from the vector v.in.ascii dictionary by the layer name"""
-    global layers_vector_vinascii
-    return layers_vector_vinascii[the_layer]
-
-def global_layers_vector_columns_get(the_layer):
-    """! Retrieve a vector layer column string from the vector column dictionary by the layer name"""
-    global layers_vector_columns
-    return layers_vector_columns[the_layer]
-    
-    
-def global_layers_rast3d_slices_get(the_layer):
-    """! Retrieve the slices info (list?) of a volume layer from the volume layer slices dictionary by its layer name"""
-    global layers_raster3d_slices
-    return layers_raster3d_slices[the_layer]
-
-
-
-#######################################################################
-#######################################################################
-#######################################################################
-## Program cleanup epilogue
-#######################################################################
-
-
-def cleanup():
-    """!Function: Final cleanup routine of g.infer module"""
-    # tbd: Ensure that all temp files are removed.
-    grass.debug(_("[cleanup] g.infer: completed"))
-
-
-
-    
-#######################################################################
-#######################################################################
-#######################################################################
-## TOOLS
-#######################################################################
-
-
-######################################################################
-# General Sanity Checks for input data: 
-# Ensure that all input parameters are valid and don't contradict each other
-
-def sanity_checks_input_layers(facts_rasters,facts_raster3ds,facts_vectors,facts_file,rulebase_file):
-    """!Ensure that sufficient input layers are provided to process by g.infer"""
-    fact_sources = 4
-    # fact sources can be either raster,volumes, vector layers or fact files.
-    if not facts_rasters: fact_sources = fact_sources -1
-    if not facts_raster3ds: fact_sources = fact_sources -1 
-    if not facts_vectors: fact_sources = fact_sources -1
-    if not facts_file: fact_sources = fact_sources -1
-    if (fact_sources == 0):
-        grass.fatal(_("None of the parameters <raster>, <raster3d> or <vector> is set."))
-    return "ok"
-
-def detect_input_layer(string_list,set_a,set_b):
-    """! Naming conflict detection: Each layer name (coming from vector/raster/voxel input layers) must be unique."""
-    this_count = 0
-    this_list = [] 
-    for this_item in str(string_list).split(','): 
-        this_count = this_count + 1
-        this_list.append(this_item)
-        if (this_item in set_a) or (this_item in set_b):
-            grass.fatal(_("Naming conflict: Layer " + this_item + " can not be used as raster, raster3d and vector input source simultanously. Renaming is recommended."))
-    this_set=set(this_list)
-    return this_count,this_set
-
-def norules_nofacts_noservice():
-    """! A failsafe to stop the g.infer module if neither rules nor facts are available"""
-    #Note:  the built-in reference knowledgebase (2013) contains both rules and facts, which overrides the requirements of this function
-    rules_sum = len(GLOBAL_CLIPS__ENVIRONMENT.RuleList())
-    facts_sum = len(GLOBAL_CLIPS__ENVIRONMENT.FactList())
-    #if not reference_knowledgebase:
-    if (facts_sum < 1):
-        grass.fatal(_("Execution terminated: No facts available "))
-        sys.exit()
-    if (rules_sum < 1):
-        grass.fatal(_("Execution terminated: No rules available "))
-        sys.exit()
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## PyCLips related wrappers (for use at the CLIPS prompt).
-#####################################################
-
-# Scope: The wrappers can be used in PyCLIPS functions and via the CLIPS prompt
-
-#####################################################
-# Wrapper for SendCommand [PyCLIPS-API] for usage in CLIPS shell
-def pyclips_send_command(this_command):
-    """! Wrapper for CLIPS-command execution on the (interactive) PyCLIPS shell"""
-    grass.message(_("[pyclips_send_command]: " + str(this_command)))	
-    clips.SendCommand(str(this_command)) # works.
-
-
-    #works: (python-call pyclips_send_command (assert (foo bar)))
-    #works: (python-call pyclips_send_command "(assert (bar))")
-
-    # Issue:
-    #CLIPS[19/1]> (python-call pyclips_send_command (load 'upload_test.clp'))
-    #[ARGACCES2] Function load was unable to open file 'upload_test.clp'.
-    #nil
-    #CLIPS[20/1]> (python-call pyclips_send_command (load #'/home/loewe/Dokumente/g.infer/2013/upload_test.clp'))
-    #[ARGACCES2] Function load was unable to open file #'/home/loewe/Dokumente/g.infer/2013/upload_test.clp'.
-    # returns nil but thats ok
-
-#####################################################
-# Wrapper for load/Batchstar for usage in CLIPS shell
-def pyclips_batchstar(this_file):
-    """! Wrapper for load/Batchstar [CLIPS-command] for usage in CLIPS shell"""
-    grass.message(_("[pyclips_batchstar: " + str(this_file)))	
-    ingest_rulebase_file(str(this_command)) 
-#  internal name (might change) is mapped to reference name for clips shell use.
-# Works: (python-call ingest_rulebase_file baz.clp)
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## GRASS Python-API related wrappers (for use at the CLIPS prompt).
-#####################################################
-
-#######################################################################
-## GRASS region 3D support: 
-##  (TAKEN and CHANGED from (GRASS) CORE.py)
-def region3():
-    """!Returns the output from running the GRASS command "g.region -g", as a
-    dictionary. Example:
-
-    \code
-    >>> region = grass.region()
-    >>> [region[key] for key in "nsew"]
-    [228500.0, 215000.0, 645000.0, 630000.0]
-    >>> (region['nsres'], region['ewres'])
-    (10.0, 10.0)
-    \endcode
-
-    @return dictionary of region values
-    """
-    s = grass.read_command("g.region", flags='3g')
-    reg = grass.parse_key_val(s, val_type = float)
-    for k in ['rows', 'cols']:
-	reg[k] = int(reg[k])
-    return reg
-
-#####################################################
-# Wrapper for grass.run [GRASS-Python-API] for usage in CLIPS
-def grass_run_command(command,*args):
-    """! Run a GRASS command  on Python level- and return the results"""
-    thekw = {}
-    theargs = ""
-    foo = ""
-    for arg in args:
-        if "=" in str(arg):
-            thekey,thevalue=arg.split('=')
-            thekw[thekey.strip(' ')]=thevalue.strip(' ')   
-        else:
-            theargs += arg.lstrip('-').strip(' ')
-    #argstuple = tuple(theargs)
-    #WORKS: grass.run_command("r.stats","cl",input="geology",fs="_")
-    result = grass.run_command(command,theargs, **thekw)
-
-#
-# WORKS !!! (python-call grass_run_command "g.list" "f" "type=rast,vect")
-# WORKS !!! (python-call grass_run_command "r.stats" "cl" "input=geology" "fs=_")
-
-#works: (python-call grass_run_command "g.version")
-#works: (python-call grass_run_command "g.version" "c")
-
-def grass_read_command(command,*args):
-    """! Read a GRASS command  [GRASS-Python-API] on Python level - and return the results"""
-    thekw = {}
-    theargs = "" 
-    foo = ""
-    for arg in args:
-        if "=" in str(arg):
-            thekey,thevalue=arg.split('=')
-            thekw[thekey.strip(' ')]=thevalue.strip(' ')   
-        else:
-            theargs += arg.lstrip('-').strip(' ')
-    result = grass.read_command(command,theargs, **thekw)
-    return result
-
-#####################################################
-# Wrapper for grass.start for usage in CLIPS
-
-def grass_start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs):
-    """! Start a GRASS command [GRASS-Python-API]  on Python level- and return the results"""
-    grass.start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs) 
-    
- #   @param prog GRASS module
- #   @param flags flags to be used (given as a string)
- #   @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- #   @param quiet True to run quietly (<tt>--q</tt>)
- #   @param verbose True to run verbosely (<tt>--v</tt>)
- #   @param kwargs module's parameters
-
- #Role model:
- #clips.RegisterPythonFunction(pyread)
- #
- #py_printout1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_printout","?logical-name $?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg)))""")
- #
- #bashstar_printout1="(deffunction ginfer_printout (?logical-name $?args)(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg))))"
- #prelude_upload(bashstar_printout1)
-
-# like this:
-#py_grass_run =
-# GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_grassrun","$?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintoutRUN $?args) else (progn$ (?arg $?args)(printoutRUN ?arg)))""")
-# ... triffts nicht.
-
-
-
-#####################################################
-### Raster Layer Category Dictionary:
-def raster_categories(the_raster):
-    """Returns a dictionary of all categories of a GRASS raster layer """
-
-    # the VAL option must be used for FLOAT maps.
-    # evtl stattdessen r.stats -il (mit labeln und floats als int betrachten)
-    
-    #p = grass.pipe_command('r.category',map=the_raster,fs=':', quiet='TRUE')
-    p = grass.pipe_command('r.stats',flags = 'il',input=the_raster,fs=':', quiet='TRUE')
-    result = {}
-    count = 0
-    category_list=""
-    raster_category_dictionary=dict()
-    for line in p.stdout:
-      the_cat = line.split(':')
-      raster_category_dictionary.update({the_cat[0]:the_cat[1].rstrip()})
-    return raster_category_dictionary
-
-
-#####################################################
-# Wrapper for grass.raster.info [GRASS-Python-API] for usage in CLIPS
-def grass_raster_info(the_raster):
-    """! Print info abouta GRASS raster layer  on Python level"""
-    grass.raster_info(the_raster)
-
-
-#####################################################
-# Wrapper for grass.message [GRASS-Python-API] for usage in CLIPS
-def grass_message(the_message):
-    """! Wrapper for GRASS message construct (for use in PYCLIPS/Prompt)"""
-    grass.message(_(the_message))
-
-#####################################################
-# Wrapper for grass.fatal for usage in CLIPS
-def grass_fatal(the_message):
-    """! Wrapper for grass.fatal [GRASS-Python-API] for usage in CLIPS"""
-    grass.fatal(_(the_message))
-
-#####################################################
-# Wrapper for grass.message [GRASS-Python-API] for usage in CLIPS
-def grass_debug(the_message):
-    """! Wrapper for GRASS debug message"""
-    grass.debug(_(the_message))
-
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## Tools for CLIPS-facts
-#####################################################
-
-
-
-def facts_total(atemplate):
-    """! Provide the overall number of facts for a template"""
-    count = 0
-    try:
-        position = fact_first(atemplate)
-        count=count+1
-        while (fact_next_exists(atemplate, position) == 1):
-            count=count+1
-            position=fact_next(atemplate, position)
-           #print count 
-        return count
-    except TypeError:
-        count = (count - 1)
-        # count one down as the first + 1 increment for fact_first seems to be executed even if the rest croaks.
-        return count 
-    except AttributeError:
-        count = (count - 1)
-        return count
-
-def facts_any(atemplate):
-    """! Check whether any facts exist for a specific template """
-    count = 0
-    try:
-        position = fact_first(atemplate)
-        count=count+1
-        return True
-    except TypeError:
-        return False 
-
-def printable_fact(afact):
-    """! PrettyPrint the fact"""
-    return afact.CleanPPForm()
-  
-def fact_first(atemplate):
-    """! Return the first fact of the template"""
-    try:
-        a = atemplate.InitialFact()
-        return a
-    except TypeError:
-        return 0
-
-def fact_first_retract(atemplate):
-    """! Return the content of the first known fact of the template and retract it"""
-    try:
-        a = atemplate.InitialFact()
-        atemplate.InitialFact().Retract()
-        return 1
-    except TypeError:
-        return 0
-  
-def fact_next(atemplate, afact):
-    """! Return the next fact for a template which follows on the provided fact."""
-    try:
-        a = atemplate.NextFact(afact)
-        return a
-        #return atemplate.NextFact(afact)
-    except TypeError:
-        return 0
-
-def fact_next_exists(atemplate, afact):
-    """! Tests for the template whether another fact remains after the provided fact"""
-    try:
-        while atemplate.NextFact(afact):
-            return 1
-    except TypeError:
-        return 0
-
-def get_slot(thefact,theslot):
-    """! Returns the actual value of a given slot for a fact.""" 
-    try:
-        return thefact.Slots[theslot]
-    except TypeError:
-        return False 
-
-def facts_all_integer(atemplate,aslot):
-    """! Check for all facts by the template whether a given slot contains exclusively integer values."""
-    all_integer = True
-    try:
-
-         position = fact_first(atemplate)
-         slotvalue = get_slot(position,aslot)
-         if not is_null_integer(slotvalue):
-	     all_integer = False
-             # printable_fact(position)
-         while (fact_next_exists(atemplate, position) == 1):
-             position=fact_next(atemplate, position)
-             slotvalue = get_slot(position,aslot)
-             if not is_null_integer(slotvalue):
-	         all_integer = False
-             return all_integer
-
-    except TypeError:
-        return False 
-#tbd: Build similar for isfloat and isnumber ! 
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## Tools for strings (Python)
-#####################################################
-
-def cat_filter (catstring):
-    """! Replace all 'cat'-strings by 'cat_' in agiven string and return result """
-    return catstring.replace(' cat ', ' cat_ ')   
-
-def vectorimport_get_name_type_payload(i):
-    """! Split a payload string in three segments (name/type/length) and return these"""
-    i=i.replace('[','')
-    i=i.replace(']','')
-    i=i.strip()
-    attr_name,attr_type,attr_length=i.split(",")
-    attr_name=attr_name.strip("'")
-    attr_type=attr_type.rstrip("'").lstrip(" '")
-    return attr_name,attr_type,attr_length
-
-
-
-
-#####################################################
-#####################################################
-#####################################################
-#####################################################
-## Tools for numbers (Python)
-#####################################################
-
-def is_integer(number):
-    """! Check whether a number is a) a number and b) it's an Integer. Returns True or False."""
-    try:
-        thefloat = float(number)
-        theint = int(number)
-        if thefloat - theint != 0.0:
-            return False
-        else:
-            return True   
-    except ValueError:
-        return False
-
-def is_null_integer(number):
-    """! Check whether a number is a) a number and b) it's an Integer. Returns True or False. If a NULL value is given, INTEGER is considered as true."""
-    if is_null(number):
-        return True
-    else:
-        return is_integer(number)
-
-def is_float(number):
-    """! Check whether a number is a) a number and b) it's an Float. Returns True or False."""
-    try:
-        thefloat = float(number)
-        theint = int(number)
-        if thefloat - theint != 0.0:
-            return True
-        else:
-            return Flase   
-    except ValueError:
-            return False
-
-def is_number(number):
-    """! Check whether a (float) number is a) a number. Returns True or False."""
-    try:
-        thefloat = float(number)
-        return True   
-    except ValueError:
-        return False
-
-def is_null(number):
-    """! Check whether a value is a GRASS NULL valuer ("*"). Returns True or False."""
-    if number == "*":
-        return True   
-    else:
-        return False
-
-
-
-
-###########################################################################
-###########################################################################
-###########################################################################
-###########################################################################
-###########################################################################
-## IMPORT
-###########################################################################
-###########################################################################
-
-
-def import_layer_test(the_layer,the_type):
-    """! Test whether a vector|rast|rast -typed input GRASS layer exists""" 
-    layer_exists=""
-    result = grass.find_file(name = the_layer, element = the_type)
-    layer_exists=str(result['file'])
-    if (layer_exists == ""):
-          grass_fatal("Input map not found: " + str(the_layer))
-    return 0                                                
-
-def import_vector_test(the_layer):
-    """! Test whether a vector input GRASS layer exists"""
-    import_layer_test(the_layer,'vector')
-        
-def import_raster_test(the_layer):    
-    """! Test whether a raster input GRASS layer exists"""  
-    import_layer_test(the_layer,'cell')
-                                                
-# The mechanism used in import_layer|vector test does not work for raster. Here comes a workaround    
-def import_rast3d_test(the_layer):
-    """! Test whether a rast3d input GRASS layer exists"""
-    #import_layer_test(the_layer,'rast3d')
-    gisenv = grass.gisenv()
-    gisenv_mapset = gisenv['MAPSET']
-    listofmaps=grass.list_grouped('rast3d')[gisenv_mapset]
-    if (the_layer) not in listofmaps:
-          grass_fatal("Rast3d layer does not exist:" + str(the_layer))
-          sys.exit(1)
-                                        
-        
-        
-########################################################################
-####VECTOR IMPORT
-########################################################################
-                                          
-
-
-def ingest_facts_vectors(facts_vectors,inference_map):
-    """! Ingestion of all user-provided GRASS vector layers, and (optional) an output vector layer to be created in GRASS"""
-    inference_map_vinascii_string = "" 
-    #^^^^ Failsafe to ensure that no empty string will be returned.
-    vectors_list = str(facts_vectors).split(',')
-    for index in range(0,len(vectors_list)):
-        this_vector = vectors_list[index]
-        import_layer_test(this_vector,'vector')
-                    
-        if grassvector_test_valid(this_vector):          
-            if grassvector_ensure_points(this_vector):              
-                assert_vector_metadata(this_vector)                       
-                voutascii_columns,attribute_list=grassvector2factlayer(this_vector, vector_get_attribute_structure(this_vector))    
-                grassvector2factlayer_assert(this_vector,voutascii_columns,attribute_list)
-                #### This is a potential ISSUE: grassvector2factlayer_assert ingests the real point data.
-                #### What if this is an empty inference-result vector ?
-                #### Outdated logic ?
-                if vectors_list[index] == inference_map:
-                    #Remember ths visnascci_sequence for the output layer.
-                    inference_map_vinascii_string = the_vinascii_string
-        else:
-             grass.message(_("Unable to open vector map "+this_vector+": The map must contain only points-data. " ))
-    return inference_map_vinascii_string  #IS THIS EVER NEEDED ??
-
-
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
 
+############################################################################
+#
+# MODULE:      g.infer.clips  
+# AUTHOR(S):   Peter Loewe loewe at gisix.com
+#              
+# PURPOSE:     GRASS interface to the CLIPS inference engine
+# COPYRIGHT:   (C) 2011,2012,2013 by Peter Loewe
+#
+#              This program is free software under the GNU General Public
+#              License (>=v2). Read the file COPYING that comes with GRASS
+#              for details.
+#############################################################################
+#############################################################################
+#BUGS
+# grass_run / grass_read has problems when executing off-the-shelf shell commands like "sleep 2s"
+#############################################################################
+#TESTED:
+#
+# in/out: RASTER without Labels: WORKS 2012-01-18
+# in/out: RASTER with Labels: WORKS 2012-01-18
+# in/out: VOLUMES without labels: WORKS 2012-01-23
+# in/out: Vector points 2D: WORK 2012-01-23
+# out:    Create new vector point layer 2012-05-08 - broken - reconifmred: 2013-01-15
+# in/out: Vector points 3D: 2012-06-07
+# in/out: facts:
+# in/out: COOL-objects:
+#
+# GRASS modules on RHS:
+# GENERAL
+# g.list: (python-call grass_run_command "g.list" "f" "type=rast,vect")
+# g.version: (python-call grass_run_command "g.version" "c")
 
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## GRASS g.infer module description
+#####################################################
+
+#%module
+#% description: GRASS GIS interface to the CLIPS inference engine
+#% keywords: inference, reseasoning, knowledge-based
+#%end
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## GRASS GUI: Flags
+#####################################################
+
+#%flag
+#% key: d
+#% description: Activate CLIPS dribble option.
+#% guisection: CLIPS
+#%end
+
+#%flag
+#% key: e
+#% description: Traceback of CLIPS error messages.
+#% guisection: CLIPS
+#%end
+
+#%flag
+#% key: i
+#% description: Interactive CLIPS shell
+#% guisection: CLIPS
+#%end
+
+#%flag
+#% key: l
+#% description: Raster input: Ignore raster labels (default: labels are imported).
+#% guisection: Input
+#%end
+
+#DEPRECATED: In most cases this will halt the module as lots and lots of GIS layer derived facts would have to be printed.
+## #%flag
+## #% key: p
+## #% description: Print applicable facts (pre-loaded) for the inference run (default: off).
+## #% guisection: CLIPS
+## #%end
+
+# #%flag
+# #% key: k
+# #% description: Provide a built-in knowledge base of application examples.
+# #% guisection: CLIPS
+# #%end
+
+#%flag
+#% key: x
+#% description: Stop execution just prior to inference run.
+#% guisection: CLIPS
+#%end
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## GRASS GUI: Options
+#####################################################
+
+#%option
+#% key: rulebase
+#% type: string
+#% key_desc: name
+#% description: Rule base file (ASCII).
+#% gisprompt: old_file,file,input
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: load_instances
+#% type: string
+#% key_desc: load_instances
+#% description: Load instances from ASCII file
+#% gisprompt: old_file,file,input
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: bload_instances
+#% type: string
+#% key_desc: bload_instances
+#% description: Load instances from binary file
+#% gisprompt: old_file,file,input
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: rast
+#% type: string
+#% gisprompt: old,cell,raster
+#% description: Raster input map(s)
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: rast3d
+#% type: string
+#% gisprompt: old,raster3,raster3
+#% description: Raster3d input map(s)
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: vector
+#% type: string
+#% gisprompt: old,vector,vector
+#% description: Vector input map(s)
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: facts
+#% type: string
+#% gisprompt: old_file,file,file
+#% description: CLIPS facts input
+#% multiple : no
+#% key_desc : facts
+#% required : no
+#% guisection: Input
+#%end
+
+#%option
+#% key: library
+#% type: string
+#% description: Built-in CLIPS rulebases which are included in g.infer. The spearfish rulebase requires the Spearfish location.  
+#% options: reference,spearfish
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Input
+#%end
+
+#############################################
+##General g.infer output-related options
+
+#%option
+#% key: export
+#% type: string
+#% description: Export of maps (a subset of the maps selected as input layers)
+#% key_desc : name
+#% required : no
+#% multiple : yes
+#% guisection: Output
+#%end
+
+#%option
+#% key: output 
+#% type: string
+#% description: new vector output map
+#% key_desc : name
+#% required : no
+#% multiple : yes
+#% guisection: Output
+#%end
+
+#%option
+#% key: save_instances
+#% type: string
+#% description: ASCII output of COOL instances 
+#% key_desc : instances_ascii_output_name
+#% required : no
+#% guisection: Output
+#%end
+
+#%option
+#% key: bsave_instances
+#% type: string
+#% description: Binary output of COOL instances 
+#% key_desc : instances_binary_output_name
+#% required : no
+#% guisection: Output
+#%end
+
+#%option
+#% key: columns
+#% type: string
+#% description: Attribute column structure for output vector  
+#% key_desc : name
+#% required : no
+#% guisection: Output
+#%end
+
+#%option
+#% key: save_rulebase
+#% type: string
+#% description: CLIPS entities to be saved to ASCII file  
+#% options: constructs,facts,instances
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Output
+#%end
+
+#%option
+#% key: bsave_rulebase
+#% type: string
+#% description: CLIPS entities to be saved to binary file 
+#% options: constructs,facts,instances
+#% multiple : yes
+#% key_desc : name
+#% required : no
+#% guisection: Output
+#%end
+
+
+################################
+## CLIPS-related OPTIONS
+
+#%option
+#% key: strategy
+#% type: string
+#% description: Inference Strategy 
+#% key_desc : Select the inference strategy (default: depth)
+#% options: breadth,complexity,depth,lex,mea,simplicity,random
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: limit
+#% type: string
+#% description: Maximum number of inferences 
+#% key_desc : Upper limit for inference runs
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: salience
+#% type: string
+#% description: Salience behaviour 
+#% key_desc : Select the salience behaviour strategy (default: when-defined)
+#% options: when-defined,when-activated,every-cycle
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: module
+#% type: string
+#% description: Rule base module(s) to be on te focus stack for inference launch (default: MAIN)
+#% key_desc : Module(s) (group(s= of rules) to be specificaly put the focus stack for the inference run.
+#% required : no
+#% multiple : yes
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: watch
+#% type: string
+#% options: activations,compilations,facts,functions,genericfunctions,globals,methods,messagehandlers,messages,rules,slots,statistics,all
+#% multiple : yes
+#% description: Watch options for CLIPS engine
+#% key_desc : Watch options for CLIPS engine.
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: print
+#% type: string
+#% options: agenda,breakpoints,classes,deffacts,definstances,facts,focusstack,functions,generics,globals,instances,messagehandlers,modules,rules,templates
+#% multiple : yes
+#% description: Prints CLIPS items prior to inference run.
+#% key_desc : Prints CLIPS items prior to inference run.
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: config
+#% type: string
+#% options: auto-float-dividend,dynamic-constraint-checking,fact-duplication,incremental-reset,reset-globals,sequence-operator-recognition,static-constraint-checking
+#% multiple : yes
+#% description: Configuration options for CLIPS engine
+#% key_desc : Configuration options for CLIPS engine.
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#%option
+#% key: classdefault
+#% type: string
+#% options: convenience,conservation
+#% multiple : no
+#% description: Class default of CLIPS engine
+#% key_desc : Class default of CLIPS engine.
+#% required : no
+#% guisection: CLIPS
+#%end
+
+#######################################################################
+#######################################################################
+#######################################################################
+## Import Python Modules
+#######################################################################
+
+def module_exists(the_module,as_name = False):
+    """! TBD"""
+    the_module_name = str(the_module)	 
+    try:
+        if as_name:
+	    import the_module_name as as_name	
+	else:
+	    __import__(the_module_name)
+		       
+    except ImportError:
+        error_message=str("[module_exists] Import Error:" + str(the_module))
+	grass.fatal(_(error_message))
+    return True
+
+
+import grass.script as grass
+from grass.lib import vector as grassvect
+
+from grass.lib.gis import * 
+from ctypes import *
+import grass.script.array as garray
+#module_exists("grass.script.array","garray")
+import clips
+#module_exists('clips')
+#ISSUE: see below. same case.
+import sys
+import os
+import atexit
+import random
+import time
+import string as _string
+import types
+#module_exists(str("types"))
+#^^^^ There is some issue: Global name types is not defined.
+module_exists('numpy')
+module_exists(str("os.path"))
+
+#######################################################################
+#######################################################################
+#######################################################################
+## Global Variables
+#######################################################################
+
+##################################################
+#A placeholder for the NULL substitute for vector export
+# must be improved to support FLOATS for NULLS during export.
+FACT_NULL = -2147483648
+FACT_NULL_FLOAT = "nan"
+
+# Reality check: 
+#    Integer maps, NULLs -> (value -2147483648)
+#    Float maps: NULL -> (value nan)
+
+##################################################
+# Set up dictionaries to manage all relevant aspects of GRASS-(input)-layers 
+##################################################
+
+#################################################
+# Dictionary to store v.in.ascii-string for vector layers
+layers_vector_vinascii={}
+
+#################################################
+# Dictionary to store template for vector layer
+layers_template={}
+
+#################################################
+# Dictionary to store attribute column structure for vector layers
+layers_vector_columns={}
+
+#################################################
+# Dictionary to store numeric type of raster layers
+layers_raster_type={}
+
+#################################################
+# Dictionary to store 2D slice names for 3D rast3d volume layers
+layers_raster3d_slices={}
+
+##################################################
+# Access to central dictionaries
+
+def global_layers_template_put(the_layer,the_template):
+    """! Put a layer template in the layer template dictionary under its layer name"""
+    global the_layers_template
+    layers_template[the_layer]=the_template
+
+def global_layers_raster_type_put(the_layer,the_type):
+    """! Put a raster layers typ in the raster type dictionary under its layer name"""
+    global layers_raster_type
+    layers_raster_type[the_layer]=the_type
+    
+def global_layers_vector_vinascii_put(the_layer,the_string):
+    """! Put a vector layer v.in.ascii string in the layer v.in.ascii dictionary under its layer name"""
+    global layers_vector_vinascii
+    layers_vector_vinascii[the_layer]=the_string
+
+def global_layers_vector_columns_put(the_layer,the_columns):
+    """! Put a vector layers columns description in the vector column dictionary under its layer name"""
+    global layers_vector_columns
+    layers_vector_columns[the_layer]=the_columns
+
+def global_layers_rast3d_slices_put(the_layer,the_slices):
+    """! Put a slices info (list?) of a volume layer in the volume layer slices dictionary under its layer name"""
+    global layers_raster3d_slices
+    layers_raster3d_slices[the_layer] = the_slices
+    
+def global_layers_template_get(the_layer):
+    """! Retrieve a layer template from the layer template dictionary by its layer name"""
+    global the_layers_template
+    return layers_template[the_layer]
+
+def global_layers_raster_type_get(the_layer):
+    """! Retrieve a raster layer type from the raster type dictionary by its layer name"""
+    global layers_raster_type
+    return layers_raster_type[the_layer]
+    
+def global_layers_vector_vinascii_get(the_layer):
+    """! Retrieve a vector layer v.in.ascii string from the vector v.in.ascii dictionary by the layer name"""
+    global layers_vector_vinascii
+    return layers_vector_vinascii[the_layer]
+
+def global_layers_vector_columns_get(the_layer):
+    """! Retrieve a vector layer column string from the vector column dictionary by the layer name"""
+    global layers_vector_columns
+    return layers_vector_columns[the_layer]
+    
+    
+def global_layers_rast3d_slices_get(the_layer):
+    """! Retrieve the slices info (list?) of a volume layer from the volume layer slices dictionary by its layer name"""
+    global layers_raster3d_slices
+    return layers_raster3d_slices[the_layer]
+
+
+
+#######################################################################
+#######################################################################
+#######################################################################
+## Program cleanup epilogue
+#######################################################################
+
+
+def cleanup():
+    """!Function: Final cleanup routine of g.infer module"""
+    # tbd: Ensure that all temp files are removed.
+    grass.debug(_("[cleanup] g.infer: completed"))
+
+
+
+    
+#######################################################################
+#######################################################################
+#######################################################################
+## TOOLS
+#######################################################################
+
+
+######################################################################
+# General Sanity Checks for input data: 
+# Ensure that all input parameters are valid and don't contradict each other
+
+def sanity_checks_input_layers(facts_rasters,facts_raster3ds,facts_vectors,facts_file,rulebase_file):
+    """!Ensure that sufficient input layers are provided to process by g.infer"""
+    fact_sources = 4
+    # fact sources can be either raster,volumes, vector layers or fact files.
+    if not facts_rasters: fact_sources = fact_sources -1
+    if not facts_raster3ds: fact_sources = fact_sources -1 
+    if not facts_vectors: fact_sources = fact_sources -1
+    if not facts_file: fact_sources = fact_sources -1
+    if (fact_sources == 0):
+        grass.fatal(_("None of the parameters <raster>, <raster3d> or <vector> is set."))
+    return "ok"
+
+def detect_input_layer(string_list,set_a,set_b):
+    """! Naming conflict detection: Each layer name (coming from vector/raster/voxel input layers) must be unique."""
+    this_count = 0
+    this_list = [] 
+    for this_item in str(string_list).split(','): 
+        this_count = this_count + 1
+        this_list.append(this_item)
+        if (this_item in set_a) or (this_item in set_b):
+            grass.fatal(_("Naming conflict: Layer " + this_item + " can not be used as raster, raster3d and vector input source simultanously. Renaming is recommended."))
+    this_set=set(this_list)
+    return this_count,this_set
+
+def norules_nofacts_noservice():
+    """! A failsafe to stop the g.infer module if neither rules nor facts are available"""
+    #Note:  the built-in reference knowledgebase (2013) contains both rules and facts, which overrides the requirements of this function
+    rules_sum = len(GLOBAL_CLIPS__ENVIRONMENT.RuleList())
+    facts_sum = len(GLOBAL_CLIPS__ENVIRONMENT.FactList())
+    #if not reference_knowledgebase:
+    if (facts_sum < 1):
+        grass.fatal(_("Execution terminated: No facts available "))
+        sys.exit()
+    if (rules_sum < 1):
+        grass.fatal(_("Execution terminated: No rules available "))
+        sys.exit()
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## PyCLips related wrappers (for use at the CLIPS prompt).
+#####################################################
+
+# Scope: The wrappers can be used in PyCLIPS functions and via the CLIPS prompt
+
+#####################################################
+# Wrapper for SendCommand [PyCLIPS-API] for usage in CLIPS shell
+def pyclips_send_command(this_command):
+    """! Wrapper for CLIPS-command execution on the (interactive) PyCLIPS shell"""
+    grass.message(_("[pyclips_send_command]: " + str(this_command)))	
+    clips.SendCommand(str(this_command)) # works.
+
+
+    #works: (python-call pyclips_send_command (assert (foo bar)))
+    #works: (python-call pyclips_send_command "(assert (bar))")
+
+    # Issue:
+    #CLIPS[19/1]> (python-call pyclips_send_command (load 'upload_test.clp'))
+    #[ARGACCES2] Function load was unable to open file 'upload_test.clp'.
+    #nil
+    #CLIPS[20/1]> (python-call pyclips_send_command (load #'/home/loewe/Dokumente/g.infer/2013/upload_test.clp'))
+    #[ARGACCES2] Function load was unable to open file #'/home/loewe/Dokumente/g.infer/2013/upload_test.clp'.
+    # returns nil but thats ok
+
+#####################################################
+# Wrapper for load/Batchstar for usage in CLIPS shell
+def pyclips_batchstar(this_file):
+    """! Wrapper for load/Batchstar [CLIPS-command] for usage in CLIPS shell"""
+    grass.message(_("[pyclips_batchstar: " + str(this_file)))	
+    ingest_rulebase_file(str(this_command)) 
+#  internal name (might change) is mapped to reference name for clips shell use.
+# Works: (python-call ingest_rulebase_file baz.clp)
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## GRASS Python-API related wrappers (for use at the CLIPS prompt).
+#####################################################
+
+#######################################################################
+## GRASS region 3D support: 
+##  (TAKEN and CHANGED from (GRASS) CORE.py)
+def region3():
+    """!Returns the output from running the GRASS command "g.region -gu", as a
+    dictionary. Example:
+
+    \code
+    >>> region = grass.region()
+    >>> [region[key] for key in "nsew"]
+    [228500.0, 215000.0, 645000.0, 630000.0]
+    >>> (region['nsres'], region['ewres'])
+    (10.0, 10.0)
+    \endcode
+
+    @return dictionary of region values
+    """
+    s = grass.read_command("g.region", flags='3gu')
+    reg = grass.parse_key_val(s, val_type = float)
+    for k in ['rows', 'cols']:
+	reg[k] = int(reg[k])
+    return reg
+
+#####################################################
+# Wrapper for grass.run [GRASS-Python-API] for usage in CLIPS
+def grass_run_command(command,*args):
+    """! Run a GRASS command  on Python level- and return the results"""
+    thekw = {}
+    theargs = ""
+    foo = ""
+    for arg in args:
+        if "=" in str(arg):
+            thekey,thevalue=arg.split('=')
+            thekw[thekey.strip(' ')]=thevalue.strip(' ')   
+        else:
+            theargs += arg.lstrip('-').strip(' ')
+    #argstuple = tuple(theargs)
+    #WORKS: grass.run_command("r.stats","cl",input="geology",fs="_")
+    result = grass.run_command(command,theargs, **thekw)
+
+#
+# WORKS !!! (python-call grass_run_command "g.list" "f" "type=rast,vect")
+# WORKS !!! (python-call grass_run_command "r.stats" "cl" "input=geology" "fs=_")
+
+#works: (python-call grass_run_command "g.version")
+#works: (python-call grass_run_command "g.version" "c")
+
+def grass_read_command(command,*args):
+    """! Read a GRASS command  [GRASS-Python-API] on Python level - and return the results"""
+    thekw = {}
+    theargs = "" 
+    foo = ""
+    for arg in args:
+        if "=" in str(arg):
+            thekey,thevalue=arg.split('=')
+            thekw[thekey.strip(' ')]=thevalue.strip(' ')   
+        else:
+            theargs += arg.lstrip('-').strip(' ')
+    result = grass.read_command(command,theargs, **thekw)
+    return result
+
+#####################################################
+# Wrapper for grass.start for usage in CLIPS
+
+def grass_start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs):
+    """! Start a GRASS command [GRASS-Python-API]  on Python level- and return the results"""
+    grass.start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs) 
+    
+ #   @param prog GRASS module
+ #   @param flags flags to be used (given as a string)
+ #   @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ #   @param quiet True to run quietly (<tt>--q</tt>)
+ #   @param verbose True to run verbosely (<tt>--v</tt>)
+ #   @param kwargs module's parameters
+
+ #Role model:
+ #clips.RegisterPythonFunction(pyread)
+ #
+ #py_printout1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_printout","?logical-name $?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg)))""")
+ #
+ #bashstar_printout1="(deffunction ginfer_printout (?logical-name $?args)(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg))))"
+ #prelude_upload(bashstar_printout1)
+
+# like this:
+#py_grass_run =
+# GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_grassrun","$?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintoutRUN $?args) else (progn$ (?arg $?args)(printoutRUN ?arg)))""")
+# ... triffts nicht.
+
+
+
+#####################################################
+### Raster Layer Category Dictionary:
+def raster_categories(the_raster):
+    """Returns a dictionary of all categories of a GRASS raster layer """
+
+    # the VAL option must be used for FLOAT maps.
+    # evtl stattdessen r.stats -il (mit labeln und floats als int betrachten)
+    
+    #p = grass.pipe_command('r.category',map=the_raster,fs=':', quiet='TRUE')
+    p = grass.pipe_command('r.stats',flags = 'il',input=the_raster,fs=':', quiet='TRUE')
+    result = {}
+    count = 0
+    category_list=""
+    raster_category_dictionary=dict()
+    for line in p.stdout:
+      the_cat = line.split(':')
+      raster_category_dictionary.update({the_cat[0]:the_cat[1].rstrip()})
+    return raster_category_dictionary
+
+
+#####################################################
+# Wrapper for grass.raster.info [GRASS-Python-API] for usage in CLIPS
+def grass_raster_info(the_raster):
+    """! Print info abouta GRASS raster layer  on Python level"""
+    grass.raster_info(the_raster)
+
+
+#####################################################
+# Wrapper for grass.message [GRASS-Python-API] for usage in CLIPS
+def grass_message(the_message):
+    """! Wrapper for GRASS message construct (for use in PYCLIPS/Prompt)"""
+    grass.message(_(the_message))
+
+#####################################################
+# Wrapper for grass.fatal for usage in CLIPS
+def grass_fatal(the_message):
+    """! Wrapper for grass.fatal [GRASS-Python-API] for usage in CLIPS"""
+    grass.fatal(_(the_message))
+
+#####################################################
+# Wrapper for grass.message [GRASS-Python-API] for usage in CLIPS
+def grass_debug(the_message):
+    """! Wrapper for GRASS debug message"""
+    grass.debug(_(the_message))
+
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## Tools for CLIPS-facts
+#####################################################
+
+
+
+def facts_total(atemplate):
+    """! Provide the overall number of facts for a template"""
+    count = 0
+    try:
+        position = fact_first(atemplate)
+        count=count+1
+        while (fact_next_exists(atemplate, position) == 1):
+            count=count+1
+            position=fact_next(atemplate, position)
+           #print count 
+        return count
+    except TypeError:
+        count = (count - 1)
+        # count one down as the first + 1 increment for fact_first seems to be executed even if the rest croaks.
+        return count 
+    except AttributeError:
+        count = (count - 1)
+        return count
+
+def facts_any(atemplate):
+    """! Check whether any facts exist for a specific template """
+    count = 0
+    try:
+        position = fact_first(atemplate)
+        count=count+1
+        return True
+    except TypeError:
+        return False 
+
+def printable_fact(afact):
+    """! PrettyPrint the fact"""
+    return afact.CleanPPForm()
+  
+def fact_first(atemplate):
+    """! Return the first fact of the template"""
+    try:
+        a = atemplate.InitialFact()
+        return a
+    except TypeError:
+        return 0
+
+def fact_first_retract(atemplate):
+    """! Return the content of the first known fact of the template and retract it"""
+    try:
+        a = atemplate.InitialFact()
+        atemplate.InitialFact().Retract()
+        return 1
+    except TypeError:
+        return 0
+  
+def fact_next(atemplate, afact):
+    """! Return the next fact for a template which follows on the provided fact."""
+    try:
+        a = atemplate.NextFact(afact)
+        return a
+        #return atemplate.NextFact(afact)
+    except TypeError:
+        return 0
+
+def fact_next_exists(atemplate, afact):
+    """! Tests for the template whether another fact remains after the provided fact"""
+    try:
+        while atemplate.NextFact(afact):
+            return 1
+    except TypeError:
+        return 0
+
+def get_slot(thefact,theslot):
+    """! Returns the actual value of a given slot for a fact.""" 
+    try:
+        return thefact.Slots[theslot]
+    except TypeError:
+        return False 
+
+def facts_all_integer(atemplate,aslot):
+    """! Check for all facts by the template whether a given slot contains exclusively integer values."""
+    all_integer = True
+    try:
+
+         position = fact_first(atemplate)
+         slotvalue = get_slot(position,aslot)
+         if not is_null_integer(slotvalue):
+	     all_integer = False
+             # printable_fact(position)
+         while (fact_next_exists(atemplate, position) == 1):
+             position=fact_next(atemplate, position)
+             slotvalue = get_slot(position,aslot)
+             if not is_null_integer(slotvalue):
+	         all_integer = False
+             return all_integer
+
+    except TypeError:
+        return False 
+#tbd: Build similar for isfloat and isnumber ! 
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## Tools for strings (Python)
+#####################################################
+
+def cat_filter (catstring):
+    """! Replace all 'cat'-strings by 'cat_' in agiven string and return result """
+    return catstring.replace(' cat ', ' cat_ ')   
+
+def vectorimport_get_name_type_payload(i):
+    """! Split a payload string in three segments (name/type/length) and return these"""
+    i=i.replace('[','')
+    i=i.replace(']','')
+    i=i.strip()
+    attr_name,attr_type,attr_length=i.split(",")
+    attr_name=attr_name.strip("'")
+    attr_type=attr_type.rstrip("'").lstrip(" '")
+    return attr_name,attr_type,attr_length
+
+
+
+
+#####################################################
+#####################################################
+#####################################################
+#####################################################
+## Tools for numbers (Python)
+#####################################################
+
+def is_integer(number):
+    """! Check whether a number is a) a number and b) it's an Integer. Returns True or False."""
+    try:
+        thefloat = float(number)
+        theint = int(number)
+        if thefloat - theint != 0.0:
+            return False
+        else:
+            return True   
+    except ValueError:
+        return False
+
+def is_null_integer(number):
+    """! Check whether a number is a) a number and b) it's an Integer. Returns True or False. If a NULL value is given, INTEGER is considered as true."""
+    if is_null(number):
+        return True
+    else:
+        return is_integer(number)
+
+def is_float(number):
+    """! Check whether a number is a) a number and b) it's an Float. Returns True or False."""
+    try:
+        thefloat = float(number)
+        theint = int(number)
+        if thefloat - theint != 0.0:
+            return True
+        else:
+            return Flase   
+    except ValueError:
+            return False
+
+def is_number(number):
+    """! Check whether a (float) number is a) a number. Returns True or False."""
+    try:
+        thefloat = float(number)
+        return True   
+    except ValueError:
+        return False
+
+def is_null(number):
+    """! Check whether a value is a GRASS NULL valuer ("*"). Returns True or False."""
+    if number == "*":
+        return True   
+    else:
+        return False
+
+
+
+
+###########################################################################
+###########################################################################
+###########################################################################
+###########################################################################
+###########################################################################
+## IMPORT
+###########################################################################
+###########################################################################
+
+
+def import_layer_test(the_layer,the_type):
+    """! Test whether a vector|rast|rast -typed input GRASS layer exists""" 
+    layer_exists=""
+    result = grass.find_file(name = the_layer, element = the_type)
+    layer_exists=str(result['file'])
+    if (layer_exists == ""):
+          grass_fatal("Input map not found: " + str(the_layer))
+    return 0                                                
+
+def import_vector_test(the_layer):
+    """! Test whether a vector input GRASS layer exists"""
+    import_layer_test(the_layer,'vector')
+        
+def import_raster_test(the_layer):    
+    """! Test whether a raster input GRASS layer exists"""  
+    import_layer_test(the_layer,'cell')
+                                                
+# The mechanism used in import_layer|vector test does not work for raster. Here comes a workaround    
+def import_rast3d_test(the_layer):
+    """! Test whether a rast3d input GRASS layer exists"""
+    #import_layer_test(the_layer,'rast3d')
+    gisenv = grass.gisenv()
+    gisenv_mapset = gisenv['MAPSET']
+    listofmaps=grass.list_grouped('rast3d')[gisenv_mapset]
+    if (the_layer) not in listofmaps:
+          grass_fatal("Rast3d layer does not exist:" + str(the_layer))
+          sys.exit(1)
+                                        
+        
+        
+########################################################################
+####VECTOR IMPORT
+########################################################################
+                                          
+
+
+def ingest_facts_vectors(facts_vectors,inference_map):
+    """! Ingestion of all user-provided GRASS vector layers, and (optional) an output vector layer to be created in GRASS"""
+    inference_map_vinascii_string = "" 
+    #^^^^ Failsafe to ensure that no empty string will be returned.
+    vectors_list = str(facts_vectors).split(',')
+    for index in range(0,len(vectors_list)):
+        this_vector = vectors_list[index]
+        import_layer_test(this_vector,'vector')
+                    
+        if grassvector_test_valid(this_vector):          
+            if grassvector_ensure_points(this_vector):              
+                assert_vector_metadata(this_vector)                       
+                voutascii_columns,attribute_list=grassvector2factlayer(this_vector, vector_get_attribute_structure(this_vector))    
+                grassvector2factlayer_assert(this_vector,voutascii_columns,attribute_list)
+                #### This is a potential ISSUE: grassvector2factlayer_assert ingests the real point data.
+                #### What if this is an empty inference-result vector ?
+                #### Outdated logic ?
+                if vectors_list[index] == inference_map:
+                    #Remember ths visnascci_sequence for the output layer.
+                    inference_map_vinascii_string = the_vinascii_string
+        else:
+             grass.message(_("Unable to open vector map "+this_vector+": The map must contain only points-data. " ))
+    return inference_map_vinascii_string  #IS THIS EVER NEEDED ??
+
+
+
+
 def grassvector_new(the_vector, attributelist):
     """! Creates (touch) a new empty GRASS vector (to contain inference results)"""
     # v.in.ascii -e 
@@ -998,1892 +998,1892 @@
     grass.run_command("v.in.ascii","e",input='-',output=the_vector, x=1, y=2, columns=attributelist, overwrite='True', quiet='TRUE')
     #grass_message(str("*** GRASSVECTOR: " + str(the_vector) + " HAS BEEN CREATED ***"))
 
-
-def grassvector2factlayer(the_vector,the_attributelist):
-    """! Import a GRASS vector and create a custom fact-template according to the vectors database attributes"""
-
-    #tbd: Extension for an optional attribute as an addtitional paramater needed 1)Name 2)Type 3)Value
-    gisenv = grass.gisenv()
-    gisenv_mapset = gisenv['MAPSET']
+
+def grassvector2factlayer(the_vector,the_attributelist):
+    """! Import a GRASS vector and create a custom fact-template according to the vectors database attributes"""
+
+    #tbd: Extension for an optional attribute as an addtitional paramater needed 1)Name 2)Type 3)Value
+    gisenv = grass.gisenv()
+    gisenv_mapset = gisenv['MAPSET']
          
-    #mymessage="grassvector2factlayer:  " + str(the_vector)+  " columns = " + str(the_attributelist)
-    #grass.message(_(mymessage))
-    voutascii_columns=""
-    vinascii_columns=""
-    columns_list=[]
-
-    if grassvector_test_3d(the_vector):
-      z_column = True   
-    else:
-      z_column = False
-
-    # construct strings to generate templates both on pyclips and clips level:
-    buildtemplate_template = "(slot x)(slot y)"
-    if z_column:
-      buildtemplate_template += "(slot z)"
-    bashstar_template = "(deftemplate " + the_vector + " (slot x)(slot y)"
-
-    if z_column:
-      bashstar_template += "(slot z)"
-
-    attribute_list = []
-    attribute_list.append("x")
-    attribute_list.append("y")
-
-    if z_column:
-      attribute_list.append("z")
-
-    attribute_list.append("numcat") 
-
-    attributes = the_attributelist
-
-    if isinstance(the_attributelist, types.ListType):
-       #iterate over all existing attributes and append them to the template-construction-strings
-       for i in attributes:
-	  i=i.replace('[','')
-	  i=i.replace(']','')
-	  i=i.strip()
-	  attr_name,attr_type,attr_length=i.split(",")
-	  attr_name=attr_name.strip("'")
-	  attr_type=attr_type.rstrip("'").lstrip(" '")
-
-	  if ((attr_name != 'x') and (attr_name != 'y')) and (attr_name != 'z'):
-	    attr_length=attr_length.rstrip("'").lstrip(" '")
-	    buildtemplate_template = buildtemplate_template + "(multislot "+ attr_name +")"
-	    bashstar_template = bashstar_template + "(multislot "+ attr_name +")"
-	    voutascii_columns = voutascii_columns + attr_name + ","
-	    attribute_list.append(attr_name)
-
-	    if attr_type == 'INTEGER':
-	      export_type = 'int'
-	    elif attr_type == 'DOUBLE PRECISION':
-	      export_type = 'double precision'
-	    elif attr_type == 'CHARACTER':
-	      export_type = 'varchar('+attr_length+')'
-	    else:
-	      grass.fatal(_("Unkown attribute type: "+attr_type))
-	  else:
-	    print ""
-            #print "[grassvector2factlayer] Filtered out: " + attr_name + " " + attr_type 
-     
-       vinascii_columns = vinascii_columns + " " + attr_name  + " " + export_type + ","
-       columns_list.append(attr_name)
- 
-    elif isinstance(the_attributelist, types.StringTypes):
-        attributeline=str(attributes).strip("'")
-        attributelist=attributeline.split(',')
-        #^^^ husk single quotes
-
-	for i in attributelist:
-	  attr_name,ignore,attr_type = i.strip().partition(" ")
-	  attr_name.strip()
-	  attr_type.strip()
-	  export_type='double precision'
-	  #^^^--- fallback option: works for x and y
-	  if ((attr_name != 'x') and (attr_name != 'y')) and (attr_name != 'z'):
-	    buildtemplate_template = buildtemplate_template + "(multislot "+ attr_name +")"
-	    bashstar_template = bashstar_template + "(multislot "+ attr_name +")"
-	    voutascii_columns = voutascii_columns + attr_name + ","
-	    attribute_list.append(attr_name)
-	    if attr_type == 'int':
-	      export_type = 'int'
-	    elif attr_type == 'double precision':
-	      export_type = 'double precision'
-	    elif attr_type.startswith('varchar'):
-	      #tbd: filter out actual length !!!!!
-	      export_type = 'varchar(255)'
-	    else:
-	      grass.fatal(_("Unkown attribute type:"+attr_type))
-
-	  else:
-	    grass.message(_(" "))
-	  columns_list.append(attr_name)
-     
-	  vinascii_columns = vinascii_columns + " " + attr_name  + " " + export_type + ","
-
-
-    voutascii_columns = voutascii_columns.rstrip(",")
-    #strip trailing comma
-    #-> is needed to assert cector data wird 
-
-    vinascii_columns = "'"+vinascii_columns.rstrip(",")+"'"
-    #strip trailing comma and add quotation
-    
-    bashstar_template = bashstar_template + ")"
-
-    #Instantiate the new template in PyClips
-    quoted_template = buildtemplate_template
-
-    the_new_template = GLOBAL_CLIPS__ENVIRONMENT.BuildTemplate(the_vector,quoted_template,"GRASS VECTOR")
-
-    #Instantiate the new template in Clips
-    prelude_upload(bashstar_template)
-    # !!! REFACTORING: prelude_upload uses a write to tempfile approach. Better alternative: Use the here document function !
-    
-    global_layers_template_put(the_vector,the_new_template)
-    global_layers_vector_vinascii_put(the_vector,vinascii_columns)
-    global_layers_vector_columns_put(the_vector,columns_list)
-    
-    return voutascii_columns,attribute_list
-   
-
-
-def grassvector2factlayer_internal(the_vector):
-    """! Internal Version: Import a GRASS vector and create a custom fact-template according to the vectors database attributes"""
-    grassvector2factlayer(the_vector,vector_get_attribute_structure(the_vector))
-    return True
-
-
-
-def grassvector_KB_load_vector(the_vector):
-    """! Creates a template and asserts the facts for a GRASS vector - to be used with internal knowledgebases  """ 
-    if grassvector_test_valid(thie_vector):          
-        if grassvector_ensure_points(thie_vector):        
-            assert_vector_metadata(the_vector)
-            print str(vector_get_attribute_structure(the_vector))                                          
-            voutascii_columns,attribute_list = grassvector2factlayer(the_vector, vector_get_attribute_structure(the_vector))
-            grassvector2factlayer_assert(the_vector,voutascii_columns,attribute_list)
-        else:
-            grass.message(_("[grassvector_KB_load_vector]: Unable to open vector map "+this_vector+": The map must contain only points-data. " ))
-    else:
-        grass.message(_("[grassvector_KB_load_vector]: Unable to open vector map "+this_vector+": Invalid vector. " ))
-
-def grassvector_ensure_points(the_vector):
-    """! Checks a GRASS vector layer whether all geometry objects are points. Returns false otherwise """
-#REFACTORING OPPORTUNITY: pipe stuff ...  
-    #p = grass.pipe_command('v.info',flags='t',map=the_vector, quiet='TRUE')
-    #result = {}
-    #count = 0
-    #vinfo={}
-    #for line in p.stdout:
-    #    the_line = line.strip().split("=") 
-    #    vinfo[the_line[0]]=the_line[1]
-    vinfo = grass.vector_info_topo(the_vector)
-    points_count=vinfo['points']
-    primitives_count=vinfo['primitives']
-    if points_count == primitives_count:
-         return True
-    else:
-         return False
-
-def grassvector_test_3d(the_vector):
-    """! Tests a GRASS vector layer for the 3d attribute (-> z column exists) . Returns false otherwise """
-    vinfo = grass.vector_info_topo(the_vector)
+    #mymessage="grassvector2factlayer:  " + str(the_vector)+  " columns = " + str(the_attributelist)
+    #grass.message(_(mymessage))
+    voutascii_columns=""
+    vinascii_columns=""
+    columns_list=[]
+
+    if grassvector_test_3d(the_vector):
+      z_column = True   
+    else:
+      z_column = False
+
+    # construct strings to generate templates both on pyclips and clips level:
+    buildtemplate_template = "(slot x)(slot y)"
+    if z_column:
+      buildtemplate_template += "(slot z)"
+    bashstar_template = "(deftemplate " + the_vector + " (slot x)(slot y)"
+
+    if z_column:
+      bashstar_template += "(slot z)"
+
+    attribute_list = []
+    attribute_list.append("x")
+    attribute_list.append("y")
+
+    if z_column:
+      attribute_list.append("z")
+
+    attribute_list.append("numcat") 
+
+    attributes = the_attributelist
+
+    if isinstance(the_attributelist, types.ListType):
+       #iterate over all existing attributes and append them to the template-construction-strings
+       for i in attributes:
+	  i=i.replace('[','')
+	  i=i.replace(']','')
+	  i=i.strip()
+	  attr_name,attr_type,attr_length=i.split(",")
+	  attr_name=attr_name.strip("'")
+	  attr_type=attr_type.rstrip("'").lstrip(" '")
+
+	  if ((attr_name != 'x') and (attr_name != 'y')) and (attr_name != 'z'):
+	    attr_length=attr_length.rstrip("'").lstrip(" '")
+	    buildtemplate_template = buildtemplate_template + "(multislot "+ attr_name +")"
+	    bashstar_template = bashstar_template + "(multislot "+ attr_name +")"
+	    voutascii_columns = voutascii_columns + attr_name + ","
+	    attribute_list.append(attr_name)
+
+	    if attr_type == 'INTEGER':
+	      export_type = 'int'
+	    elif attr_type == 'DOUBLE PRECISION':
+	      export_type = 'double precision'
+	    elif attr_type == 'CHARACTER':
+	      export_type = 'varchar('+attr_length+')'
+	    else:
+	      grass.fatal(_("Unkown attribute type: "+attr_type))
+	  else:
+	    print ""
+            #print "[grassvector2factlayer] Filtered out: " + attr_name + " " + attr_type 
+     
+       vinascii_columns = vinascii_columns + " " + attr_name  + " " + export_type + ","
+       columns_list.append(attr_name)
+ 
+    elif isinstance(the_attributelist, types.StringTypes):
+        attributeline=str(attributes).strip("'")
+        attributelist=attributeline.split(',')
+        #^^^ husk single quotes
+
+	for i in attributelist:
+	  attr_name,ignore,attr_type = i.strip().partition(" ")
+	  attr_name.strip()
+	  attr_type.strip()
+	  export_type='double precision'
+	  #^^^--- fallback option: works for x and y
+	  if ((attr_name != 'x') and (attr_name != 'y')) and (attr_name != 'z'):
+	    buildtemplate_template = buildtemplate_template + "(multislot "+ attr_name +")"
+	    bashstar_template = bashstar_template + "(multislot "+ attr_name +")"
+	    voutascii_columns = voutascii_columns + attr_name + ","
+	    attribute_list.append(attr_name)
+	    if attr_type == 'int':
+	      export_type = 'int'
+	    elif attr_type == 'double precision':
+	      export_type = 'double precision'
+	    elif attr_type.startswith('varchar'):
+	      #tbd: filter out actual length !!!!!
+	      export_type = 'varchar(255)'
+	    else:
+	      grass.fatal(_("Unkown attribute type:"+attr_type))
+
+	  else:
+	    grass.message(_(" "))
+	  columns_list.append(attr_name)
+     
+	  vinascii_columns = vinascii_columns + " " + attr_name  + " " + export_type + ","
+
+
+    voutascii_columns = voutascii_columns.rstrip(",")
+    #strip trailing comma
+    #-> is needed to assert cector data wird 
+
+    vinascii_columns = "'"+vinascii_columns.rstrip(",")+"'"
+    #strip trailing comma and add quotation
+    
+    bashstar_template = bashstar_template + ")"
+
+    #Instantiate the new template in PyClips
+    quoted_template = buildtemplate_template
+
+    the_new_template = GLOBAL_CLIPS__ENVIRONMENT.BuildTemplate(the_vector,quoted_template,"GRASS VECTOR")
+
+    #Instantiate the new template in Clips
+    prelude_upload(bashstar_template)
+    # !!! REFACTORING: prelude_upload uses a write to tempfile approach. Better alternative: Use the here document function !
+    
+    global_layers_template_put(the_vector,the_new_template)
+    global_layers_vector_vinascii_put(the_vector,vinascii_columns)
+    global_layers_vector_columns_put(the_vector,columns_list)
+    
+    return voutascii_columns,attribute_list
+   
+
+
+def grassvector2factlayer_internal(the_vector):
+    """! Internal Version: Import a GRASS vector and create a custom fact-template according to the vectors database attributes"""
+    grassvector2factlayer(the_vector,vector_get_attribute_structure(the_vector))
+    return True
+
+
+
+def grassvector_KB_load_vector(the_vector):
+    """! Creates a template and asserts the facts for a GRASS vector - to be used with internal knowledgebases  """ 
+    if grassvector_test_valid(thie_vector):          
+        if grassvector_ensure_points(thie_vector):        
+            assert_vector_metadata(the_vector)
+            print str(vector_get_attribute_structure(the_vector))                                          
+            voutascii_columns,attribute_list = grassvector2factlayer(the_vector, vector_get_attribute_structure(the_vector))
+            grassvector2factlayer_assert(the_vector,voutascii_columns,attribute_list)
+        else:
+            grass.message(_("[grassvector_KB_load_vector]: Unable to open vector map "+this_vector+": The map must contain only points-data. " ))
+    else:
+        grass.message(_("[grassvector_KB_load_vector]: Unable to open vector map "+this_vector+": Invalid vector. " ))
+
+def grassvector_ensure_points(the_vector):
+    """! Checks a GRASS vector layer whether all geometry objects are points. Returns false otherwise """
+#REFACTORING OPPORTUNITY: pipe stuff ...  
+    #p = grass.pipe_command('v.info',flags='t',map=the_vector, quiet='TRUE')
+    #result = {}
+    #count = 0
+    #vinfo={}
+    #for line in p.stdout:
+    #    the_line = line.strip().split("=") 
+    #    vinfo[the_line[0]]=the_line[1]
+    vinfo = grass.vector_info_topo(the_vector)
+    points_count=vinfo['points']
+    primitives_count=vinfo['primitives']
+    if points_count == primitives_count:
+         return True
+    else:
+         return False
+
+def grassvector_test_3d(the_vector):
+    """! Tests a GRASS vector layer for the 3d attribute (-> z column exists) . Returns false otherwise """
+    vinfo = grass.vector_info_topo(the_vector)
     #grass_message("GRASSVECTOR_TEST_3D: " +  str(the_vector) + "   " +  str(vinfo))
-    is_map3d = vinfo['map3d']
-
-    #[grassvector_test_3d]:{'kernels': 0, 'lines': 0, 'centroids': 0, 'boundaries': 0, 'points': 25, 'faces': 0, 'primitives': 25, 'islands': 0, 'nodes': 25, 'map3d': False, 'areas': 0}
-
-    if (str(is_map3d) == "False"):
-         return False
-    else:
-         return True
-    #Important: False can indicate a broken vector topology !
-    #Criteria: A vector lacking any nodes would be inavlid 
-
-def grassvector_test_valid(the_vector):
-    """! Tests a GRASS vector layer for the 3d attribute (-> z column exists) . Returns false otherwise """
-    
-    vinfo = grass.vector_info_topo(the_vector)
-    if 'nodes' in vinfo:
-         return True
-    else:
-         grass.message(_("grassvector_test_valid ERROR: "+ str(the_vector)))
-         return False     
-
-def grassvector2factlayer_assert(the_vector,voutascii_columns,attribute_list):
-    """! Asserts facts for a GRASS vector via v.out.ascii (after the custom template for the vector has been previously defined) """
-    #GRASS String attributes concatining whitespaces are correctly asserted. 
-    p = grass.pipe_command('v.out.ascii',columns=voutascii_columns,input=the_vector, quiet='TRUE')
-    result = {}
-    count = 0
-    for line in p.stdout:
-        count = count + 1
-        the_line = line.strip().split("|") 
-        to_assert="(" + the_vector + " "
-        for index in range(len(attribute_list)):
-          if not attribute_list[index] == "numcat":
-          # numcat is a workaround for the dual cat provision by v.out.ascii
-          # it is filtered out as it is not defined (or used) in the template defined above..
-            to_assert=to_assert+"("+attribute_list[index]+" "+the_line[index] + ")"        
-        to_assert=to_assert+" )"
-	GLOBAL_CLIPS__ENVIRONMENT.Assert(to_assert) 
-
-
-def vector_get_attribute_structure(the_vector):
-    """! Return attribute structure of a vector"""
-    dbdescribe = grass.db_describe(the_vector)
-    #ingest the attribute structure information
-    line = str(dbdescribe).strip("{}")
-    nrows,ignore,cdrline = line.partition(",")
-    cdrline,ingore,ncols = cdrline.rpartition(",")
-    ignore,ignore,attributes = cdrline.partition(":")
-    attributes = attributes.split("],")
-    return attributes
-
-
-
-########################################################################
-#### SET VECTOR METADATA FACTS
-########################################################################
-
-    #grass.vector_columns('soils')
-    
-    #grass.vector_db('soils')
-    # Prints the database connection
-    
-    #grass.vector_db_select('soils')
-    # Prints the range of existing values.
-    
-    #grass.db_describe('soils')
-    # Describes the attribute table
-    # >>  grass.db_describe('soils')
-    # >> {'nrows': 54, 'cols': [['cat', 'INTEGER', '11'], ['label', 'CHARACTER', '13']], 'ncols': 2}
-    # !!! For type CHAR the maximum string length is returned. 
-
-
-def assert_vector_metadata(thevector):
-    """!Assert the metadata for a GRASS vector layer as facts in the CLIPS environment
-    #grass.vector_info_topo('soils')
-    # Lists, numbers of  Boundaries, Points, Primitives, Islands, Lines, Centroids, Nodes
-    """
-    if grassvector_test_valid(thevector):
-    
-        topology = grass.vector_info_topo(thevector)
-        topo_nodes = topology['nodes']
-        topo_points = topology['points']
-        #topo_lines = topology['lines']
-        #topo_boundaries = topology['boundaries']
-        #topo_centroids = topology['centroids']
-        #topo_areas = topology['areas']
-        #topo_islands = topology['islands']
-        #topo_faces = topology['faces']
-        #topo_kernels = topology['kernels']
-        topo_primitives = topology['primitives']
-        topo_map3d = topology['map3d']
-        assert_t_nodes = "( TOPOLOGY_NODES " + thevector +" " + str(topo_nodes) + " )" 
-        assert_t_points = "( TOPOLOGY_POINTS " + thevector +" " + str(topo_points) + " )" 
-        #assert_t_lines = "( TOPOLOGY_LINES " + thevector +" " + str(topo_lines) + " )" 
-        #assert_t_boundaries = "( TOPOLOGY_BOUNDARIES " + thevector +" " + str(topo_boundaries) + " )" 
-        #assert_t_centroids = "( TOPOLOGY_CENTROIDS " + thevector +" " + str(topo_centroids) + " )" 
-        #assert_t_areas = "( TOPOLOGY_AREAS " + thevector +" " + str(topo_areas) + " )" 
-        #assert_t_islands = "( TOPOLOGY_ISLANDS " + thevector +" " + str(topo_islands) + " )" 
-        #assert_t_faces = "( TOPOLOGY_FACES " + thevector +" " + str(topo_faces) + " )" 
-        #assert_t_kernels = "( TOPOLOGY_KERNELS " + thevector +" " + str(topo_kernels) + " )" 
-        assert_t_primitives = "( TOPOLOGY_PRIMITIVES " + thevector +" " + str(topo_primitives) + " )" 
-        assert_t_map3d = "( TOPOLOGY_MAP3D " + thevector +" " + str(topo_map3d) + " )" 
-    
-        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_nodes )
-        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_points)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_lines)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_boundaries)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_centroids)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_areas)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_islands)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_faces)
-        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_kernels)
-        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_primitives)
-        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_map3d)
-
-        #dto:
-        dbconnection = grass.vector_db(thevector)
-        mymessage="*** vector_dbconncetion = " + str(dbconnection)
-        grass.debug(_(mymessage))
- 
-        columns = grass.vector_columns(thevector)
-
-        mymessage="*** vector columns = " + str(columns)
-        grass.debug(_(mymessage))
-        #?? Is there a similar API interface to v.info -g (vectors region). ?? 
-    else:
-        #grass.message(_("g.infer: Something really wrong with vector" + str(thevector)))
-        sys.exit(1)
-
-
-
-#######################################################################
-## RASTER IMPORT
-#######################################################################
-
-
-def ingest_facts_rasters(facts_rasters,ignore_raster_labels):
-    """! Ingestion of all user-provided GRASS raster layers. Option: Ignore GRASS raster labels"""
-    facts_rasters_list=[]
-    count_maps = 0
-    gisenv = grass.gisenv()
-    gisenv_mapset = gisenv['MAPSET']                        
-    for this_facts_raster in str(facts_rasters).split(','): 
-        grass.debug(_("Ingesting Raster: "+this_facts_raster))
-        count_maps = count_maps + 1
-        
-        #gisenv = grass.gisenv()
-        #gisenv_mapset = gisenv['MAPSET']         
-        #listofmaps=grass.list_grouped('rast')[gisenv_mapset]
-        #if (this_facts_raster) not in listofmaps:
-        #    grass_fatal("g.infer: Raster layer does not exist:" + str(this_facts_raster))
-        #    sys.exit(1)        
-            
-        import_raster_test(this_facts_raster)
-        
-        is_elevation_level = False
-        facts_rasters_list.append(this_facts_raster)
-        grassraster2factlayer(this_facts_raster,"GRASS RASTER",ignore_raster_labels,is_elevation_level)
-    return set(facts_rasters_list)
-
-
-
-    
-def grassraster2factlayer(the_raster,the_comment_string="GRASS RASTER",ignore_raster_labels=False,elevationlevel=False):
-    """! Generate facts from a GRASS raster layer including the coordinates, the digital number AND the value attribute
-    test for categories: r.category --quiet geology fs=: 0> 1:metamorphic or 1: 
-    """
-
-    #TO BE INCLUDED:
-    ## test for input raster map
-    #result = grass.find_file(name = map_name, element = 'cell', quiet = True)
-    #if not result['file']
-    #grass.fatal("Raster map <%s> not found" % map_name)
-
-    #check for category strings:
-    raster_with_labels = True
-    the_categories = raster_categories(the_raster)
-    if len(the_categories) < 1:
-       raster_with_labels = False
-    # find map in search path
-    mapset = G_find_cell2(the_raster, '') 
-
-    #Attribute recognition doesnt work for rast3d rasters
-
-    # determine the inputmap type (CELL/FCELL/DCELL) 
-    typename = 'undefined'
-    data_type = G_raster_map_type(the_raster, mapset)
-    if data_type == CELL_TYPE:
-       ptype = POINTER(c_int)
-       type_name = 'CELL'
-    elif data_type == FCELL_TYPE:
-       ptype = POINTER(c_float)
-       type_name = 'FCELL'
-    elif data_type == DCELL_TYPE:
-       ptype = POINTER(c_double)
-       type_name = 'DCELL'
-  
-    # construct strings to generate templates both on pyclips and clips level:
- 
-    buildtemplate_template = "(slot x)(slot y)"
-    bashstar_template = "(deftemplate " + the_raster + " (slot x)(slot y)"
-
-    attribute_list = []
-    attribute_list.append("x")
-    attribute_list.append("y")
-
-    if elevationlevel:
-       buildtemplate_template = buildtemplate_template + "(slot z)"
-       bashstar_template = bashstar_template  + "(slot z)"
-       attribute_list.append("z")
-    #Append a column for elevation if this raster layer stems from a rast3d layer, aka has a z-Value constant attached to it
-
-    attr_name_value = 'value'
-
-    attr_name_attribute = 'attribute' 
-
-    if type_name == 'CELL':
-        export_type_value = 'integer'
-      ### UNTESTED !!!! 
-    else:
-        export_type_value = 'double precision'
-    ###^^^--- The datdtype is defined below: CELL/FCELL/DCELL -> fix  !
-
-    #export_type_attribute = "varchar(" + str(GLOBAL_ATTRIBUTE_TYPE) + ")"
-
-    # generate low level GRASS structures 
-
-    infd = G_open_cell_old(the_raster, mapset)
-    inrast = G_allocate_raster_buf(data_type) 
-    inrast = cast(c_void_p(inrast), ptype)
-
-    rows = G_window_rows()
-    cols = G_window_cols()
-
-    hd=struct_Cell_head()
-    G_get_cellhd(the_raster,mapset,byref(hd))
-
-
-    ###############################
-
-    if raster_with_labels and not ignore_raster_labels:    
-        buildtemplate_template = buildtemplate_template + "(slot "+ attr_name_value +")"+ "(multislot "+ attr_name_attribute +")"
-        bashstar_template = bashstar_template + "(slot "+ attr_name_value +")" + "(multislot "+ attr_name_attribute +")"+")" 
-        attribute_list.append(attr_name_value)
-        attribute_list.append(attr_name_attribute)       
-    else:
-        buildtemplate_template = buildtemplate_template + "(slot "+ attr_name_value +")"
-        bashstar_template = bashstar_template + "(slot "+ attr_name_value +") )"
-        attribute_list.append(attr_name_value)
-     
-        
-    #Instantiate the new template in PyClips
-    the_new_template = GLOBAL_CLIPS__ENVIRONMENT.BuildTemplate(the_raster,buildtemplate_template,the_comment_string)
-    #Instantiate the new template in Clips
-    prelude_upload(bashstar_template)
-
-    for rown in xrange(rows):
-        therow = G_get_raster_row(infd, inrast, rown, data_type)
-     
-        for coln in xrange(cols):
-            coo_col = G_col_to_easting(coln, byref(hd))
-            coo_row = G_row_to_northing(rown, byref(hd))
-            the_value=inrast[coln]
-            fallback=''
-            the_category=the_categories.get(str(the_value),fallback)
-            to_assert = "(" + the_raster + " (x " + str(coo_col) + ") (y " + str(coo_row) + ")"
-            if elevationlevel: 
-                to_assert =  to_assert + "(z "+ str (elevationlevel) + ")"
-
-            to_assert =  to_assert + "(value " + str(the_value) + ")"
-            if raster_with_labels and not ignore_raster_labels:
-                to_assert =  to_assert + "(attribute " + str(the_category) + ")"
-
-            to_assert =  to_assert + ")"          
-            GLOBAL_CLIPS__ENVIRONMENT.Assert(to_assert)
-
-    G_close_cell(infd)
-    G_free(inrast)
-
-    global_layers_template_put(the_raster,the_new_template) 
-    global_layers_raster_type_put(the_raster,type_name)
-
-    return
-
-
-def grassraster_KB_load_raster(the_raster):
-    """! Creates a template and asserts the facts for a GRASS raster - to be used with internal knowledgebases  """ 
-    ### !!! Requires a failsafe to test whether the layer exists at all !
-    is_elevation_level = False
-    ignore_raster_labels = FALSE
-    #facts_rasters_set = set(facts_rasters_list.append(the_raster))
-    #^^ is only set otherwise during explicit raster upload in MAIN.
-    # !!!allow for update option
-    grassraster2factlayer(the_raster,"GRASS RASTER",ignore_raster_labels,is_elevation_level)
-
-
-########################################################################
-#### RASTER METADATA FACTS
-########################################################################
-
-#TBD: Provide the metadata for a GRASS raster as CLIPS facts for use in the inference process.
-
-
-# grass.raster_info
-# grass.raster_history
-
-# tbd: Actual region/coverage a raster layer: r.region
-# tbd: r.support
-# tbd: stats: r.median, r.quantile, r.statistics, r.univar
-# tbd: number format (integer, floats, etc)
-# r.info ?
-
-
-#######################################################################
-## VOLUME IMPORT 
-#######################################################################
-
-
-def ingest_factsraster3ds(facts_raster3ds):
-    """! Ingestion of all user-provided GRASS raster3D (volume) layers"""
-    facts_raster3ds_list=[]
-    count_maps = 0
-                     
-    for this_facts_raster3d in str(facts_raster3ds).split(','): 
-        grass.message(_("Ingesting Raster3D: "+this_facts_raster3d))
-        import_rast3d_test(this_facts_raster3d)
-        #listofmaps=grass.list_grouped('rast3')[gisenv_mapset]
-        #if (this_facts_raster) not in listofmaps:
-        #    grass_fatal("g.infer: Raster layer does not exist:" + str(this_facts_raster))
-        #    sys.exit(1)                                                                                
-        count_maps = count_maps + 1
-        facts_raster3ds_list.append(this_facts_raster3d)
-        grassvolume2factlayer(this_facts_raster3d) 
-    return set(facts_raster3ds_list)
-
-
-
-def grassvolume2factlayer(the_volume):
-    """! Generate facts from a GRASS volume layer including the 3d coordinates and the digital number"""
-    the_raster = str(the_volume)+"_slice_"
-
-    #the_layers_template = global_layers_template_get(the_volume)
- 
-    #layers_raster_type = global_layers_raster_type_get(the_volume)
-
-    #global_layers_rast3d_slices_get(the_volume)
-
-    p = grass.pipe_command('r3.to.rast',flags='rm',input=the_volume, output=the_raster.rstrip("_"), quiet='TRUE')
-    # tbd: replace the_raster by a randomly generated name.
-
-    grass.debug("grassvolume2factlayer: Sleeping 10 sec")
-    time.sleep(10) 
-    #SLEEP to ensure that the pipe returns in time. This is ugly and need to be improved.
-    # get height of layerstack
-    region = region3()
-    stack_height=region['depths']
-    stack_res=region['tbres']
-
-    this_raster3d_raster_slices_list = []
-    #create a container for all raster_file_names for this raster3d volume
-
-    #ITERATE OVER THE stack of raster layerswhich were creared
-    for level in range(1, int(stack_height)):
-      if level < 10:
-         levelstring="0000"+str(level)
-      elif level < 100:
-         levelstring="000"+str(level)
-      elif level < 1000:
-         levelstring="00"+str(level)
-      elif level < 10000:
-         levelstring="0"+str(level)  
-      current_raster=the_raster+levelstring
-    #^^ use the real elevations ( not the levels) level*elevationelta=ELEVATIONVARIABLE
-
-
-      grass.debug("Raster-Level: "+current_raster)
-      this_raster3d_raster_slices_list.append(current_raster)
-      this_elevation=stack_res * level 
-      the_ignore_label_flag = True
-      #the_template,raster_type = grassraster2factlayer(current_raster,"GRASS VOLUME",the_ignore_label_flag,this_elevation)
-
-      #the_layers_template[current_raster]=the_template
-      #layers_raster_type[current_raster]=raster_type
-      grassraster2factlayer(current_raster,"GRASS VOLUME",the_ignore_label_flag,this_elevation)
-
-      ###^^ to be returned !
-    #global_layers_template_put(the_volume,the_layers_template)
- 
-    #global_layers_raster_type_put(the_volume,layers_raster_type)
-
-    global_layers_rast3d_slices_put(the_volume,this_raster3d_raster_slices_list)
-    
-    #return the_layers_template, layers_raster_type, this_raster3d_raster_slices_list
-
-
-
-def grassvolume2factlayer_internal(the_volume):
-    """! Internal Use: Generate facts from a GRASS volume layer including the 3d coordinates and the digital number"""
-    grassvolume2factlayer(the_volume) 
-
-########################################################################
-#### VOLUME METADATA FACTS
-########################################################################
-
-#TBD: Provide the metadata for a GRASS raster3D volume as CLIPS facts for use in the inference process.
-
-# r3.timestamp
-# r3.stats
-# r3.univar
-
-
-
-
-##############################################################
-##############################################################
-##############################################################
-##############################################################
-##############################################################
-##############################################################
-## METADATA
-##############################################################
-##############################################################
-
-##########################################################
-## GRASS SESSION METADATA to FACTS
-##########################################################
-    
-def assert_region():
-    """! Creates facts for all GRASS region parameters"""
-    region = region3()
-    region_rows = region['rows']
-    region_cols = region['cols']
-    region_cells = region['cells']
-    region_ewres = region['ewres']
-    region_nsres = region['nsres']
-    region_n = region['n']
-    region_s = region['s']
-    region_e = region['e']
-    region_w = region['w']
-
-    # Accomodate for 3D region parameters:
-    region_t = region['t']
-    region_b = region['b']
-    region_tbres = region['tbres'] 
-    region_ewres3 = region['ewres3']
-    region_nsres3 = region['nsres3']   
-    region_rows3 = region['rows3']
-    region_cols3 = region['cols3']
-    region_depths = region['depths']
-    region_cells3 = region['cells3']
- 
-
-    assert_region_rows = "( REGION_ROWS " + str(region_rows) + " )" 
-    assert_region_cols = "( REGION_COLS " + str(region_cols) + " )"
-    assert_region_cells = "( REGION_CELLS " + str(region_cells) + " )" 
-    assert_region_ewres = "( REGION_EWRES " + str(region_ewres) + " )"
-    assert_region_nsres = "( REGION_NSRES " + str(region_nsres) + " )" 
-    assert_region_n = "( REGION_N " + str(region_n) + " )"
-    assert_region_s = "( REGION_S " + str(region_s) + " )" 
-    assert_region_e = "( REGION_E " + str(region_e) + " )"
-    assert_region_w = "( REGION_W " + str(region_w) + " )"
-
-    #  Region 3D parameters:
-    assert_region_rows3 = "( REGION_ROWS3 " + str(region_rows3) + " )" 
-    assert_region_cols3 = "( REGION_COLS3 " + str(region_cols3) + " )"
-    assert_region_cells3 = "( REGION_CELLS3 " + str(region_cells3) + " )" 
-    assert_region_ewres3 = "( REGION_EWRES3 " + str(region_ewres3) + " )"
-    assert_region_nsres3 = "( REGION_NSRES3 " + str(region_nsres3) + " )" 
-    assert_region_tbres = "( REGION_TBRES " + str(region_tbres) + " )" 
-    assert_region_t = "( REGION_T " + str(region_t) + " )"
-    assert_region_b = "( REGION_B " + str(region_b) + " )" 
-    assert_region_depths = "( REGION_DEPTHS " + str(region_depths) + " )" 
-
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_rows)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cols)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cells)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_nsres)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_ewres)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_n)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_s)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_e)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_w)
-
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_rows3)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cols3)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cells3)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_nsres3)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_ewres3)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_tbres)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_t)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_b)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_depths)
-
-
-   
-def assert_gisenv():
-    """!Assert all GRASS environmental variables (GISENV / Location / Mapset) as facts in the CLIPS environment"""
-    gisenv = grass.gisenv()
-    gisenv_gisdbase = gisenv['GISDBASE']
-    gisenv_location_name = gisenv['LOCATION_NAME']
-    gisenv_mapset = gisenv['MAPSET']
-    gisenv_grass_gui = gisenv['GRASS_GUI']
-  
-    assert_gisdbase = "( GISDBASE " + gisenv_gisdbase + " )" 
-    assert_location_name = "( LOCATION_NAME " + gisenv_location_name + " )" 
-    assert_mapset = "( MAPSET " + gisenv_mapset + " )" 
-    assert_grass_gui= "( GRASS_GUI " + gisenv_grass_gui + " )" 
-
-    # More variables to be included !
-    
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_gisdbase)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_location_name)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_mapset)
-    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_grass_gui)
-
-
-
-
-########################################################################
-#### GRASS7 TEMPORAL METADATA FACTS
-########################################################################
-
-# tbd: no python support yet
-
-########################################################################
-#### DATABASE CONNECTIVITY METADATA FACTS
-########################################################################
-
-#TBD: Integrate this metadata as CLIPS facts for use in the inference process.
-
-# grass.db_connection
-# grass.db_describe
-# grass.db_select
-
-
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## EXPORT from CLIPS constructs to GRASS layers
-##########################################################################
-##########################################################################
-
-
-# Export sanity checks needed ?
-
-
-def fact2rastercell(afact,raster_name,integer_case):
-   """! Returns for  a (raster-) fact the structured content of a GRASS - raster cell"""
-   the_x = float(afact.Slots['x'])
-   the_y = float(afact.Slots['y'])
-   if integer_case:
-      the_value = int(afact.Slots['value'])
-   else:
-      the_value = float(afact.Slots['value'])
-   ###^^ not everything is FLOAT !
-   
-   if 'attribute' in afact.Slots.keys():
-      #the_attribute=afact.Slots['attribute']
-      #alternative to deal with multiple string content - works for vector, untested here.
-      the_attribute=""
-      multifield_list = afact.Slots['attribute']
-      allitems=""
-      for item in multifield_list:
-       the_attribute=the_attribute + str(item).rstrip() + " "
-      the_attribute.rstrip(" ")
-   else: 
-      the_attribute=False
-
-   if 'z' in afact.Slots.keys():
-       the_elevation = float(afact.Slots['z'])
-   else: 
-      the_elevation=False
-   return the_x,the_y,the_value,the_attribute,the_elevation
-
-#######################################################################
-## RASTER EXPORT
-####################################################################### 
-
-def factslayer_fromraster2grassraster_internal(rastername,ignore_labels=False):
-  """! Internal Use: Exports a grassraster facts to GRASS vector (point) layer which are transformed into a GRASS raster layer"""
-  factslayer_fromraster2grassraster(rastername,ignore_labels,False)
-
-
-def factslayer_fromraster2grassraster(rastername,ignore_labels=False,raster_type=False):
-  """! Exports a grassraster facts to GRASS vector (point) layer which are transformed into a GRASS raster layer""" 
-  ### tbd: take care of Z-column for rast3d !
-
-  ### start a dictionary to track all attribute/value pairs 
-
-#  global layers_template
-  thetemplate = global_layers_template_get(rastername) 
-  raster_type = global_layers_raster_type_get(rastername) 
-
-# test: if exists: use ELSE: False
-  layers_raster_type[rastername] = raster_type
-  #??? is this the right ordering ?
-
-  attribute_dict = {}
-
-  #Check for number types:
-  if raster_type:
-     if raster_type == "CELL":
-        integer_case = TRUE
-        grass.debug("[factslayer_fromraster2grassraster] INTEGER LIKE INPUT MAP")
-     else:
-        integer_case = FALSE
-        grass.debug("[factslayer_fromraster2grassraster] FLOAT LIKE INPUT MAP")
-        # we don't care what kind of float it is
-  else:
-     # no raster type provided, we must check the facts to figure it out.
-     grass.message("[factslayer_fromraster2grassraster] No raster map type defined: PROBING FACTS TO DEFINE OUTPUT MAP TYPE")
-     integer_case = facts_all_integer(thetemplate,'value')
-
-  #define array to collect random access info from facts
-  if integer_case:
-     raster_output = garray.array(dtype=numpy.int32)
-     grass.debug("[factslayer_fromraster2grassraster] Integer Array")
-  else:
-     grass.debug("[factslayer_fromraster2grassraster] Float Array")
-     raster_output = garray.array()
-
-  #### GRASS LOW LEVEL COMMANDS start here
-  #setup GRASS helpers to transform coordinates into columns and rows.
-  mapset = G_find_cell2(rastername, '') 
-  hd=struct_Cell_head()
-  G_get_cellhd(rastername,mapset,byref(hd))
-
-  thisfact = fact_first(thetemplate)
-
-  if thisfact:   
-     now_x,now_y,now_value,now_attribute,now_elevation = fact2rastercell(thisfact,rastername,integer_case)
-     # now_elevation is currently not used further. 
-     # the z-component is ignored -> the z/level info is also part of the template name.
-     coo_col = int(G_easting_to_col(now_x, byref(hd)))
-     coo_row = int(G_northing_to_row(now_y, byref(hd)))
-     if now_attribute:
-         attribute_dict.update({str(now_attribute):now_value})
-            # push attribute into attribute dictionary if is does not exist yet. 
-     if integer_case:
-         raster_output[coo_row,coo_col] = numpy.int32(now_value)
-     else:
-         raster_output[coo_row,coo_col] = float(now_value)
-
-     count = 1
-     carry_on = 1
-
-  while carry_on:
-     count = count +1
-     thisfact = fact_next(thetemplate, thisfact)
-     if thisfact:
-         now_x,now_y,now_value,now_attribute,now_elevation = fact2rastercell(thisfact,rastername,integer_case)
-         coo_col = int(G_easting_to_col(now_x, byref(hd)))
-         coo_row = int(G_northing_to_row(now_y, byref(hd)))
-         if now_attribute:
-               attribute_dict.update({str(now_attribute):now_value})
-         if integer_case:
-               raster_output[coo_row,coo_col] = numpy.int32(now_value)
-         else:
-               raster_output[coo_row,coo_col] = float(now_value)
-     else:
-         carry_on = 0
-  #!!! coordinate skew is still there !: add +0.5 ?
-  
-  # Remove previous version of layer in GRASS domain:
-  grass.run_command('g.remove', rast=rastername, quiet='TRUE')
-  
-  #write changed raster out
-  raster_output.write(rastername)
-
-  #writeout attributes if any exist
-  if attribute_dict.keys():
-     grassfeed = grass.feed_command("r.category",rules='-',map=rastername, quiet='TRUE')
-     for key in attribute_dict.keys():
-         this_attribute  = str(int(attribute_dict[key])) + ":" + str(key)+"\n"
-         grassfeed.stdin.write(this_attribute)
-     grassfeed.stdin.close()
-
-  #get rid of NULL values (untested) #FACTNULL ist der UGLY interne Wert !
-  grass.run_command('r.null', map=rastername, setnull=FACT_NULL, quiet='TRUE')
-
-  #IF INTEGER: ^^^^
-  # IF FLOAT: Handle * => nan case for NULL value
-
-
-
-########################################################################
-####VECTOR EXPORT
-########################################################################
-
-
-
-def vector_facts2grassvector_string(afact,thecolumnslist):
-    """!Builds and returns a GRASS-formatted string from the facts associated to a GRASS vector """
-    #(grassraster (name foo) (x 596203) (y 4915149)(hanni 42)(nanni 43))
-
-    myresult = str(afact.Slots['x'])+"|"+ str(afact.Slots['y'])
-    multifield_list = list()
-    #^^dummy-define variable for later use
-     
-    for column in thecolumnslist:
-        if (column != 'x')and( column !='y'):
-            multifield_list = afact.Slots[column]
-            allitems=""    
-        if (len(multifield_list) > 0):
-            for item in multifield_list:
-                allitems=allitems + str(item).rstrip() + " "    
-            myresult = myresult+"|"+ allitems.rstrip(" ")
-
-    grass.debug(_("vector_facts2grassvector_string:" + myresult))
-    myresult = myresult + "\n"
-    return myresult
-
-
-def factslayer2grassvector_internal(vectorname):
-    """! Internal Use: Creates a GRASS vector from a factslayer"""
-    factslayer2grassvector(vectorname) 
-    # ^^^Untested ! 
-
-
-
-def factslayer2grassvector(vectorname):
-    """! Creates a GRASS vector from a factslayer"""
-    #!! To be considered: Shall the name  of a newly to be created  output vector is to be included ?
-    #
-
-    #!! In case that a OUTPUT layer has been created with COLUMNS, but remains empty:
-    #   v.in.ascii -e creates only an empty layer.
-    count = 0
-    thetemplate = global_layers_template_get(vectorname)  # --> Could cause a problem in a "new vector (Xanadu)" case. Otherwise: optional argument ?
-    the_columns = global_layers_vector_vinascii_get(vectorname)
-    the_columns_list = global_layers_vector_columns_get(vectorname)
-    #complete_columns= cat_filter('x double precision, y double precision,' + the_columns.strip("\'"))
-    #^^^ original version: assumes that x/y columns are NOT provided by the user.
-    complete_columns= cat_filter('' + the_columns.strip("\'"))
-    # works for now ^^^
-    #20120508: This must be discussed:
-    # is it a good thing if the user has to define X and Y columns when entering the columns-description ?
-    # con: x/X y/Y can be misleading -> internal import assumes that x/y are the needed coordinates.
-    #!!!
-    #print str(vectorname) +" Facts =>  "+str(facts_total(thetemplate))
-    if (facts_total(thetemplate) < 1):
-        # ^^^^FACTS_TOTAL needs a FAILSAFE for the NULL case !
-        #g.message(_("Export stopped: No facts found for export vector: " + the_template))
-        grass.message(_("[factslayer2grassvector]: No facts found for export vector: " + str(vectorname) + " --> EMPTY VECTOR CREATED"))
-        grass.run_command("v.in.ascii","e",input='-',output=vectorname, x=1, y=2, columns=complete_columns, overwrite='True', quiet='TRUE')
-     
-    else:
-        mystring = str(vectorname) + "-facts-count: "+ str(facts_total(thetemplate))
-        #g.message(_("Export continues: " + mystring))
-        grassfeed = grass.feed_command("v.in.ascii",input='-',output=vectorname, x=1, y=2, columns=complete_columns, overwrite='True',   quiet='TRUE')
-
-     
-        firstfact = fact_first(thetemplate)
-        thisfact = firstfact
-        if thisfact: 
-            carry_on = 1
-            grassfeed.stdin.write(vector_facts2grassvector_string(firstfact,the_columns_list))
-            count = 1
-            while carry_on:
-                count = count +1
-                thisfact = fact_next(thetemplate, thisfact)
-                if thisfact:
-                    grassfeed.stdin.write(vector_facts2grassvector_string(thisfact,the_columns_list))
-                else:
-                  carry_on = 0
-        grassfeed.stdin.close()
-    return count
-
-#######################################################################
-## VOLUME EXPORT
-#######################################################################
-
-### !!! The foofact.Slot.keys() mechanism allows to check whether a Z-value exists  
-### -> for now none is handed over.
-### Volume import/export could not be achieved via 2D rasters otherwise.
-
-def factslayer_fromraster3d2grassraster3d_internal(the_inference_map):
-   """! Internal USe: Update an existing GRASS volume layer from its CLIPS facts representation"""
-   factslayer_fromraster3d2grassraster3d(the_inference_map)
-# ^^ UNTESTED !
-
-
-def factslayer_fromraster3d2grassraster3d(the_inference_map):
-    """! Update an existing GRASS volume layer from its CLIPS facts representation"""
-    # for each item in the slices list: 
-    #   get the corresponding template from the vinasciss/templates list 
-    #   launch GRASSRASTER generation processess
-    # bundle rasters into a raster3d
- 
-    #global_layers_raster_type_get(the_volume)
-    # shouldn't this one be handed over, too ?
-  
-    the_slices_list = global_layers_rast3d_slices_get(the_inference_map)
-    slices_list_string=""
-    for this_slice in the_slices_list:
-        layers_templates = global_layers_template_get(this_slice)   
-        slices_list_string=slices_list_string+","+str(this_slice)
-        #generate raster slice:
-        factslayer_fromraster2grassraster(this_slice,False) 
-
-    slices_list_string.lstrip(',')
-    #^^^remove leading comma 
-    p = grass.pipe_command('r.to.rast3',input=slices_list_string, output=the_inference_map, quiet='TRUE', overwrite='TRUE')
-
-
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## CLIPS Engine Settings
-##########################################################################
-##########################################################################
-
-#######################################################################
-## CLIPS Save options for knowledge items
-
-
-def clips_save(inference_map,save_option):
-    """! Write CLIPS information to file""" 
-     
-    if save_option.find("facts") > -1:
-        grass.debug(_("SAVE: Facts"))
-        forensics_facts=inference_map+"_facts.clips"
-        GLOBAL_CLIPS__ENVIRONMENT.SaveFacts(forensics_facts)
- 
-    if save_option.find("constructs") > -1:
-        grass.debug(_("SAVE: Constructs"))
-        forensics_constructs=inference_map+"_constructs.clips"
-        GLOBAL_CLIPS__ENVIRONMENT.Save(forensics_constructs)
-
-    if save_option.find("instances") > -1:
-        grass.debug(_("SAVE: Instances"))
-        forensics_instances=inference_map+"_instances.clips"
-        GLOBAL_CLIPS__ENVIRONMENT.SaveInstances(forensics_instances)
-
-def clips_bsave(inference_map,save_option):
-    """! Write CLIPS information to file"""      
-    binary_export = 0
-
-    if save_option.find("facts") > -1:
-        grass.debug(_("BSAVE: Facts"))
-        forensics_facts=inference_map+"_facts.clips"
-        GLOBAL_CLIPS__ENVIRONMENT.SaveFacts(forensics_facts)
- 
-    if save_option.find("constructs") > -1:
-        grass.debug(_("BSAVE: Constructs"))
-        forensics_constructs=inference_map+"_constructs.bin"
-        GLOBAL_CLIPS__ENVIRONMENT.BSave(forensics_constructs)
- 
-    if save_option.find("instances") > -1:
-        grass.debug(_("BSAVE: Instances"))     
-        forensics_instances=inference_map+"_instances.bin"
-        GLOBAL_CLIPS__ENVIRONMENT.BSaveInstances(forensics_instances)
-     
-#######################################################################
-## CLIPS Set Config
-
-def clips_config(config_option):
-    """! Set CLIPS engine config-setting"""
-    config_string = "auto-float-dividend,dynamic-constraint-checking,fact-duplication,incremental-reset,reset- globals,sequence-operator-recognition,static-constraint-checking"
-    config_list = str(config_string).split(',')
-    for item in config_list:        
-        if watch_option.find(item) > -1:
-            grass.message(_("(set-"+str(item)+" TRUE )"))
-            now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-"+str(item)+" TRUE )")
-
-#######################################################################
-## CLIPS Set Watch
-
-def clips_watch(watch_option):
-    """! Set CLIPS engine watch-setting"""
-    watch_string = "activations,compilations,facts,functions,genericfunctions,globals,methods,messagehandlers,messages,rules,slots,statistics,all"
-    watch_list = str(watch_string).split(',')
-    for item in watch_list:        
-       if watch_option.find(item) > -1:
-         grass.message(_("(watch "+ str(item)+" )"))
-         now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(watch "+ str(item)+" )")
-
-#######################################################################
-## CLIPS Set list
-
-def clips_list(list_option):
-    """! Set CLIPS engine option-settings"""
-    if list_option.find("agenda") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintAgenda()
-    if list_option.find("breakpoints") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintBreakpoints()
-    if list_option.find("classes") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintClasses()
-    if list_option.find("deffacts") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintDeffacts()
-    if list_option.find("definstances") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintDefinstances()
-    if list_option.find("facts") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintFacts()
-    if list_option.find("focusstack") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintFocusStack()
-    if list_option.find("functions") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintFunctions()
-    if list_option.find("generics") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintGenerics()
-    if list_option.find("globals") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.ShowGlobals()
-      #"show" display the variables AND their values
-    if list_option.find("instances") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintInstances()
-    if list_option.find("messagehandlers") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintMessagehandlers()
-    if list_option.find("modules") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintModules()
-    if list_option.find("rules") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintRules()
-    if list_option.find("templates") > -1:
-      GLOBAL_CLIPS__ENVIRONMENT.PrintTemplates()
-      
-#######################################################################
-## CLIPS Set dribble
-
-def clips_dribble(inference_map,toggle_dribble):
-    """! Set CLIPS engine dribble-setting"""
-    if toggle_dribble:
-      grass.message(_("(dribble-on "+str(inference_map)+".dribble )"))
-      now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(dribble-on "+str(inference_map)+".dribble )")
-
-
-#######################################################################
-## CLIPS Set external traceback
-
-def clips_external_traceback(toggle_external_traceback):
-    """! Toggle CLIPS engine traceback-setting"""
-    if toggle_external_traceback:
-      clips.SetExternalTraceback(True)
-      #WORKS: confirmed 20120302
-
-#######################################################################
-## CLIPS Module stack seeding
-
-def clips_module_stack(inference_focus_module):
-    """! Set CLIPS engine focus-setting on a specific KB module"""
-    if inference_focus_module:
-        #iterate over comma seperated inference_focus_module AAA,BBB,CCCC and build up "focus AAA BBB CCC" string.
-        grass.message(_("clips_module_stack: Under development"))
-        clips.PrintFocusStack()
-        ### clips command: (focus AAA BB CC)
-        focus = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(focus AAA BBB CCC )")
-
-        
-        #FindModule($modulename) !! - finds an existing module 
-        # BuildModule
-        #popFocus
-        #printFocusStack
-        #
-        #clips.SetCurrent() / SetFocus / PopFocus
-        #CLIPS: (list-focus-stack) (clear-focus-stack) (focus fi fa fo)
-        #tbd: strip string "inference_focus_module" off commata ("A,B,C") -> "A B C" and assign GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(focus "+str(STTINGSANSCOMMATA)+".dribble )")
-    else:
-        grass.message(_("CLIPS_MODULE_STACK => ELSE:this should not happen"))
-
-#######################################################################
-## CLIPS Set class-default
-
-def clips_classdefault(classdefault_option):
-    """! Set CLIPS engine class-default-setting"""
-    #(set‑class-defaults-mode <mode>)
-    if classdefault_option.find("convenience") > -1:
-        now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("( set‑class-defaults-mode convenience)")
-    if classdefault_option.find("conservation") > -1:
-        now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("( set‑class-defaults-mode conservation)")
-
-
-####################################################################### 
-###########SET DEBUG SETTING#########################
-    ###?? GLOBAL_CLIPS__ENVIRONMENT.Memory[Options] Object P42 pyclips manual
-    
-    #CLIPS Debug Settings which could be provided to the user for forensics.
-    
-    # Conserve: TRUE / False
-    # EnvironmentErrosEnabled
-    # Free()
-    # PPBuffersize
-    # Requests: readonly!
-    # Used: readonly !
-    # NumberOffEnvironmenst
-    
-
-
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## INFERENCE RUN
-##########################################################################
-##########################################################################
-
-
-##########################################################
-# Interactive mode.
-# code snippet adapted from http://pyclips.sourceforge.net/web/?q=node/19 author: franzg
-##########################################################
-
-# Description: TBD
-
-# needed: uo/down keys to navigate a history similar to the bash shell history.
-
-class interactive_shell(object):
-    """an interactive CLIPS prompt activated via the i-Flag"""
- 
-    def __init__(self):
-        self.__ps1 = "g.infer CLIPS prompt[%(cmdno)s/%(lineno)s] (Exit: Ctrl-D)> "
-        self.__ps2 = "g.infer CLIPS prompt[%(cmdno)s/%(lineno)s] (Exit: Ctrl-D): "
-        self.__cmdno = 1
-        self.__lineno = 1
- 
-    def __cmdcomplete(self, cms):
-        """check if CLIPS command is complete (stolen from 'commline.c')"""
-        def eat_ws(s, i):
-            """eat up whitespace"""
-            while i < len(s) and s[i] in _string.whitespace: i += 1
-            return i
-        def eat_string(s, i):
-            """eat up strings"""
-            if s[i] != '"' or i >= len(s): return i
-            i += 1
-            while i < len(s):
-                if s[i] == '"': return i + 1
-                else:
-                    if s[i] == '\\': i += 1
-                    i += 1
-            if i > len(s): raise ValueError, "non-terminated string"
-            return i
-        def eat_comment(s, i):
-            """eat up comments"""
-            if s[i] != ';' or i >= len(s): return i
-            while i < len(s) and s[i] not in '\n\r': i += 1
-            return i + 1
-        s = cms.strip()
-        if len(s) == 0: return False
-        depth = 0
-        i = 0
-        while i < len(s):
-            c = s[i]
-            if c in '\n\r' and depth == 0: return True
-            elif c == '"': i = eat_string(s, i)
-            elif c == ';': i = eat_comment(s, i)
-            elif c == '(': depth += 1; i += 1
-            elif c == ')': depth -= 1; i += 1
-            elif c in _string.whitespace: i = eat_ws(s, i)
-            else: i += 1
-            if depth < 0: raise ValueError, "invalid command"
-        if depth == 0: return True
-        else: return False
- 
-    def Run(self):
-        """start or resume an interactive CLIPS shell"""
-        exitflag = False
-        while not exitflag:
-            self.__lineno = 1
-            s = ""
-            dic = { 'cmdno': self.__cmdno, 'lineno': self.__lineno }
-            prompt = self.__ps1 % dic
-            try:
-                while not self.__cmdcomplete(s):
-                    if s: s += " "
-                    s += raw_input(prompt).strip()
-                    self.__lineno += 1
-                    dic = { 'cmdno': self.__cmdno, 'lineno': self.__lineno }
-                    prompt = self.__ps2 % dic
-            except ValueError, e:
-                sys.stderr.write("[SHELL] %s\n" % str(e))
-            except EOFError:
-                clips.ErrorStream.Read()
-                exitflag = True
-                # tbd: allow also an "graceful" exit using a (exit) command!
-            try:
-                if not exitflag:
-                    GLOBAL_CLIPS__ENVIRONMENT.SendCommand(s, True)
-            except clips.ClipsError, e:
-                sys.stderr.write("[PYCLIPS] %s\n" % str(e))
-            self.__cmdno += 1
-            r0 = clips.StdoutStream.Read()
-            r1 = clips.DisplayStream.Read()
-            tx = clips.TraceStream.Read()
-            r = ""
-            if r0: r += r0
-            if r1: r += r1
-            t = clips.ErrorStream.Read()
-            if r: r = "%s\n" % r.rstrip()
-            if t: t = "%s\n" % t.rstrip()
-            if tx: t = "%s\n" % tx.rstrip() + t
-            #^^^2013_Feb19: This throws an error if WATCH is not set:
-            # TypeError: cannot concatenate 'str' and 'NoneType' objects
-
-
-            if t: sys.stderr.write(t)
-            if r: sys.stdout.write(r)
- 
-##########################################################################
-# CLI Interface code
-# taken from http://commentsarelies.blogspot.de/2008/07/using-printout-and-readline-in-pyclips.html
-# Author: Johan Lindberg, 2008-07-14
-
-# Description: code to provide an interactive CLIPS shell for g.infer sessions.
-
-def pyprintout(*args):
-    """! TBD"""
-    for arg in args[1]:
-        if arg.cltypename().upper() == "SYMBOL":
-            if arg.upper() == "CRLF":
-               print
-            elif arg.upper() == "TAB":
-               print "\t",
-            else:
-              print arg,
-
-        else:
-            print arg,
-
-
-def pyreadline(*args):
-    """! TBD"""
-    return raw_input()
-
-def pyread(*args):
-    """! TBD"""
-    return raw_input()
-
-#######################################################################
-## CLIPS LAYER BATCHSTAR SEEDING
-
-
-def prelude_upload(the_string):
-    """! CReate a tempfile on the GRASS_level,and announce this file at the CLIPS level for BatchSTar usage?"""
-    #generate prelude for batchstar and write it out to a tempfile
-    tempfile = grass.read_command('g.tempfile',pid=random.randint(1,1000000))
-    file = open(tempfile, 'w')
-    file.write(the_string)
-    file.close()
-    # Make the template definitions available on the BatchStar level.
-    GLOBAL_CLIPS__ENVIRONMENT.BatchStar(tempfile)
-    # Remove the template
-    os.remove(tempfile)
-
-
-#######################################################################	
-## Set CLIPS engine options
-
-def set_inference_strategy(inference_strategy):
-    """! Set CLIPS engine inference strategy accoring to user input"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    strategy_was = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.Strategy
-    istrat = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-strategy "+str(inference_strategy)+")")
-    strategy_is = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.Strategy
-    mymessage = "Inference strategy="+str(inference_strategy)
-    grass.debug(_(mymessage))
-
-def set_salience_evaluation_behaviour(salience_evaluation_behaviour):
-    """! Set CLIPS salience evaluation accoring to user input"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    behaviour_was = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.SalienceEvaluation
-    is_behave = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-salience-evaluation "+str(salience_evaluation_behaviour)+")")
-    mymessage = "Salience evaluation strategy="+str(salience_evaluation_behaviour)
-    grass.debug(_(mymessage))
-
-
-#######################################################################
-## Ingest knowledge data: rulebases, facts, instances
-
-
-def ingest_rulebase_file(rulebase_file):
-    """! Ingestion of a user-provided rulebase file (KB)"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    if os.path.isfile(rulebase_file):
-        GLOBAL_CLIPS__ENVIRONMENT.BatchStar(rulebase_file)
-    else:
-        grass.fatal(_("File does not exist: " + rulebase_file))
-
-def ingest_facts_file(facts_file):
-    """! Ingestion of all user-provided facts file"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    if os.path.isfile(facts_file):
-        GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
-        grass.debug(_("[ingest_facts_file] Facts ingested from: " + facts_file))
-    else:
-        grass.fatal(_("File does not exist: " + facts_file))
-
-def ingest_instances_ascii_file(instances_ascii_file):
-    """! Ingestion of all user-provided ASCII instances (COOL, etc) file"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
-    if os.path.isfile(instances_ascii_file):
-        GLOBAL_CLIPS__ENVIRONMENT.LoadInstances(instances_ascii_file)
-        grass.message(_("Instances (ascii) ingested from: " + instances_ascii_file))
-    else:
-        grass.fatal(_("File does not exist: " + instances_ascii_file))
-
-def ingest_instances_binary_file(instances_binary_file):
-    """! Ingestion of all user-provided binary instances (COOL, etc) file"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
-    if os.path.isfile(instances_binary_file):
-     GLOBAL_CLIPS__ENVIRONMENT.BLoadInstances(instances_binary_file)
-     grass.message(_("Instances (binary) ingested from: " + instances_binary_file))
-    else:
-     grass.fatal(_("File does not exist: " + instances_binary_file))
-
-#######################################################################
-## Invoke inference process
-
-def launch_inference(max_rule_firing=False):
-    """! Invoke inference process, with the option to limit the maximum number of firing rules"""
-    global GLOBAL_CLIPS__ENVIRONMENT
-    grass.debug(_("[launch_inference]-----Inference starts-------"))
-    if max_rule_firing:
-       GLOBAL_CLIPS__ENVIRONMENT.Run(int(max_rule_firing))
-    else:
-       GLOBAL_CLIPS__ENVIRONMENT.Run()
-    grass.debug(_("[launch_inference]-----Inference stops-------"))
-
-
-
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## KNOWLEDGEBASES
-##########################################################################
-##########################################################################
-
-
-#2013-01-16: Exported into seperate files
-# tbd: Provide mechanisms to manage external KB as simple text-files (not *.PY)
-	
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## G.INFER SESSION SETUP
-##########################################################################
-##########################################################################
-	
-####################
-# Clips to Python/GRASS downlink tools:
-
-def register_grass_functions_in_clips():
-    """! Register several GRASS-related functions for use on the Rule level."""
-    #Usage: GLOBAL_CLIPS__ENVIRONMENT.Eval("python-call g.message _(/"hello world/") "))
-
-    # pyCLIPS CLI i/o code: 
-    clips.RegisterPythonFunction(pyprintout)
-    clips.RegisterPythonFunction(pyreadline)
-    clips.RegisterPythonFunction(pyread)
-
-    # !!! Keep an eye on this stuff and how it works (documenatation!) 
-    # The functions (below) rely on the already registered Python functions (right above).
-    ############################################
-    #Build CLIPS function: GINFER_PRINTOUT (on the CLIPS and pyCLIPS levels)
-    py_printout1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_printout","?logical-name $?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg)))""")
-    bashstar_printout1="(deffunction ginfer_printout (?logical-name $?args)(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg))))"
-    prelude_upload(bashstar_printout1)
-
-    ############################################
-    #Build CLIPS function: GINFER_READLINE (on the CLIPS and pyCLIPS levels)
-    py_readline1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_readline","$?logical-name","""(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (funcall python-call pyreadline ?logical-name) else (readline ?logical-name)))  """)
-    bashstar_readline1 = "(deffunction ginfer_readline ($?logical-name)"
-    bashstar_readline1 = bashstar_readline1 + "(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t))" 
-    bashstar_readline1=bashstar_readline1 + "(if (member$ python-call (get-function-list)) then (funcall python-call pyreadline ?logical-name) else (readline ?logical-name)))"
-    prelude_upload(bashstar_readline1)
-
-    ############################################
-    #Build CLIPS function: GINFER_READ (on the CLIPS and pyCLIPS levels)
-    py_read1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_read","$?logical-name","""(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (eval (funcall python-call pyread ?logical-name)) else (read ?logical-name))) """)
-    bashstar_read1="(deffunction ginfer_read ($?logical-name) (if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (eval (funcall python-call pyread ?logical-name)) else (read ?logical-name)))"
-    prelude_upload(bashstar_read1)
-
-    #############################################
-    # Pyclips stuff (to be accessible in rules and on the CLIPS prompt
-    # issue a grass(?) command:
-    clips.RegisterPythonFunction(pyclips_send_command)
-    #upload and execute facts/rules/whatnot from a file
-    clips.RegisterPythonFunction(pyclips_batchstar)
-
-    # GRASS stuff:
-    clips.RegisterPythonFunction(grass_message)
-    clips.RegisterPythonFunction(grass_fatal)
-    #clips.RegisterPythonFunction(grass.message)
-    clips.RegisterPythonFunction(assert_vector_metadata)
-    clips.RegisterPythonFunction(grassvector2factlayer)
-    clips.RegisterPythonFunction(grassvector2factlayer_internal)
-    clips.RegisterPythonFunction(grassraster2factlayer)
-    #clips.RegisterPythonFunction(grassraster2factlayer_internal) #removed 2013-05-16
-    clips.RegisterPythonFunction(grassvolume2factlayer)
-    clips.RegisterPythonFunction(grassvolume2factlayer_internal)
-    #clips.RegisterPythonFunction(factslayer_fromraster2grassraster_internal)
-    #clips.RegisterPythonFunction(factslayer_fromraster3d2grassraster3d_internal)
-    #clips.RegisterPythonFunction(factslayer2grassvector_internal)
-    #^^^ These functions require a central storgae place for INPUT INFORMATION
-    clips.RegisterPythonFunction(assert_region)
-    clips.RegisterPythonFunction(assert_gisenv)
-
-    clips.RegisterPythonFunction(grass.mapcalc)
-    clips.RegisterPythonFunction(grass_raster_info)
-    clips.RegisterPythonFunction(grass_run_command)
-    clips.RegisterPythonFunction(grass_read_command)
-
-    clips.RegisterPythonFunction(grass_start_command)
-    #clips.RegisterPythonFunction(LOADFACTS)
-    #clips.RegisterPythonFunction(ASSERT_RASTER_METADATA)
-    #clips.RegisterPythonFunction(DATENBANKZEUGS)
-    #clips.RegisterPythonFunction(MAPCALC)
-    #clips.RegisterPythonFunction("GRASS_LAMBDA")
-    #tbd:
-    # r.mapcalc
-    # raster/vector layer import
-    # database queries
-
-#####################################################
-## EXPERIMENTAL:
-
-#def KB_layers_spearfish():
-    #these KB layers will be imported BEFORE the rulebase is loaded.
-    #this assures that the rules can become valid as the templates they are referring to
-    #have already been instantiated.
-    #
-    #2013-02-19: Currently the check for the Spearfish location is done as rule #1.
-    # the check needs to be executed BEFORE the Spearfish layers are attempted to be uploaded.
-    #
-    # Maybe a simple failsafe in grassraster_KB_load_raster: Test for existance of layer.
-    #
-
-
-    ################SPEARFISH Raster Layers#########################################
-    #grass.message(_("SPEARFISH RASTER LAYER RUSHMORE: Loading"))            
-    #grassraster_KB_load_raster("geology")
-    #grassraster_KB_load_raster("rushmore")
-    #grassraster_KB_load_raster("landuse")
-    #grassraster_KB_load_raster("soils")
-    #grassraster_KB_load_raster("vegcover")
-
-    ################SPEARFISH Vector Layers#########################################
-    #grass.message(_(""SPEARFISH VECTOR LAYER bugsites: starting...")) 
-    #grassvector_KB_load_vector("archsites")
-    #grassvector_KB_load_vector("bugsites") #Mountain Pine Beetle Damage
-##
-#####################################################
-
+    is_map3d = vinfo['map3d']
 
+    #[grassvector_test_3d]:{'kernels': 0, 'lines': 0, 'centroids': 0, 'boundaries': 0, 'points': 25, 'faces': 0, 'primitives': 25, 'islands': 0, 'nodes': 25, 'map3d': False, 'areas': 0}
 
+    if (str(is_map3d) == "False"):
+         return False
+    else:
+         return True
+    #Important: False can indicate a broken vector topology !
+    #Criteria: A vector lacking any nodes would be inavlid 
 
+def grassvector_test_valid(the_vector):
+    """! Tests a GRASS vector layer for the 3d attribute (-> z column exists) . Returns false otherwise """
+    
+    vinfo = grass.vector_info_topo(the_vector)
+    if 'nodes' in vinfo:
+         return True
+    else:
+         grass.message(_("grassvector_test_valid ERROR: "+ str(the_vector)))
+         return False     
 
+def grassvector2factlayer_assert(the_vector,voutascii_columns,attribute_list):
+    """! Asserts facts for a GRASS vector via v.out.ascii (after the custom template for the vector has been previously defined) """
+    #GRASS String attributes concatining whitespaces are correctly asserted. 
+    p = grass.pipe_command('v.out.ascii',columns=voutascii_columns,input=the_vector, quiet='TRUE')
+    result = {}
+    count = 0
+    for line in p.stdout:
+        count = count + 1
+        the_line = line.strip().split("|") 
+        to_assert="(" + the_vector + " "
+        for index in range(len(attribute_list)):
+          if not attribute_list[index] == "numcat":
+          # numcat is a workaround for the dual cat provision by v.out.ascii
+          # it is filtered out as it is not defined (or used) in the template defined above..
+            to_assert=to_assert+"("+attribute_list[index]+" "+the_line[index] + ")"        
+        to_assert=to_assert+" )"
+	GLOBAL_CLIPS__ENVIRONMENT.Assert(to_assert) 
 
 
+def vector_get_attribute_structure(the_vector):
+    """! Return attribute structure of a vector"""
+    dbdescribe = grass.db_describe(the_vector)
+    #ingest the attribute structure information
+    line = str(dbdescribe).strip("{}")
+    nrows,ignore,cdrline = line.partition(",")
+    cdrline,ingore,ncols = cdrline.rpartition(",")
+    ignore,ignore,attributes = cdrline.partition(":")
+    attributes = attributes.split("],")
+    return attributes
 
 
 
+########################################################################
+#### SET VECTOR METADATA FACTS
+########################################################################
 
+    #grass.vector_columns('soils')
+    
+    #grass.vector_db('soils')
+    # Prints the database connection
+    
+    #grass.vector_db_select('soils')
+    # Prints the range of existing values.
+    
+    #grass.db_describe('soils')
+    # Describes the attribute table
+    # >>  grass.db_describe('soils')
+    # >> {'nrows': 54, 'cols': [['cat', 'INTEGER', '11'], ['label', 'CHARACTER', '13']], 'ncols': 2}
+    # !!! For type CHAR the maximum string length is returned. 
 
 
+def assert_vector_metadata(thevector):
+    """!Assert the metadata for a GRASS vector layer as facts in the CLIPS environment
+    #grass.vector_info_topo('soils')
+    # Lists, numbers of  Boundaries, Points, Primitives, Islands, Lines, Centroids, Nodes
+    """
+    if grassvector_test_valid(thevector):
+    
+        topology = grass.vector_info_topo(thevector)
+        topo_nodes = topology['nodes']
+        topo_points = topology['points']
+        #topo_lines = topology['lines']
+        #topo_boundaries = topology['boundaries']
+        #topo_centroids = topology['centroids']
+        #topo_areas = topology['areas']
+        #topo_islands = topology['islands']
+        #topo_faces = topology['faces']
+        #topo_kernels = topology['kernels']
+        topo_primitives = topology['primitives']
+        topo_map3d = topology['map3d']
+        assert_t_nodes = "( TOPOLOGY_NODES " + thevector +" " + str(topo_nodes) + " )" 
+        assert_t_points = "( TOPOLOGY_POINTS " + thevector +" " + str(topo_points) + " )" 
+        #assert_t_lines = "( TOPOLOGY_LINES " + thevector +" " + str(topo_lines) + " )" 
+        #assert_t_boundaries = "( TOPOLOGY_BOUNDARIES " + thevector +" " + str(topo_boundaries) + " )" 
+        #assert_t_centroids = "( TOPOLOGY_CENTROIDS " + thevector +" " + str(topo_centroids) + " )" 
+        #assert_t_areas = "( TOPOLOGY_AREAS " + thevector +" " + str(topo_areas) + " )" 
+        #assert_t_islands = "( TOPOLOGY_ISLANDS " + thevector +" " + str(topo_islands) + " )" 
+        #assert_t_faces = "( TOPOLOGY_FACES " + thevector +" " + str(topo_faces) + " )" 
+        #assert_t_kernels = "( TOPOLOGY_KERNELS " + thevector +" " + str(topo_kernels) + " )" 
+        assert_t_primitives = "( TOPOLOGY_PRIMITIVES " + thevector +" " + str(topo_primitives) + " )" 
+        assert_t_map3d = "( TOPOLOGY_MAP3D " + thevector +" " + str(topo_map3d) + " )" 
+    
+        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_nodes )
+        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_points)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_lines)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_boundaries)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_centroids)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_areas)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_islands)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_faces)
+        #GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_kernels)
+        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_primitives)
+        GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_t_map3d)
 
-
-
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-##########################################################################
-## MAIN
-##########################################################################
-
-def main():
- 
-                               
-    #################################################
-    ##### Sanity Check 1: Ensure that g.infer is run within a GRASS environment
-    if "GISBASE" not in os.environ:
-      print "You must be in GRASS GIS to run this program."
-      sys.exit(1)
-
-    #################################################
-    #### Import parameters provided from the GRASS GUI
-    
-     
-    #################################################
-    #### GRASS GUI Flags
-    
-    toggle_dribble = flags['d']
-    toggle_external_traceback = flags['e']
-    interactive_mode = flags['i']
-    ignore_raster_labels = flags['l']
-    toggle_suddendeath_mode = flags['x']
-
-    #################################################
-    #### GRASS GUI Options
-        
-    ## GRASS input layers
-    facts_rasters = options['rast']
-    facts_vectors = options['vector']
-    facts_raster3ds = options['rast3d']
-
-    # CLIPS knowledge items
-    facts_file = options['facts']
-    instances_binary_file = options['bload_instances']
-    instances_ascii_file = options['load_instances']
-
-    instances_binary_output = options['bsave_instances']
-    instances_ascii_output = options['save_instances']
-
-    ## GRASS output layers
-    inference_map = options['output']
-    output_maps = options['export'] 
-    result_columns = options['columns']
-
-    ## CLIPS parameters
-    max_rule_firing = options['limit']
-    inference_strategy = options['strategy']
-    salience_evaluation_behaviour = options['salience']
-    inference_focus_module = options['module']
-    #^^^--- tbd: remains to be switched on & tested  
-    # CLIPS: (set-current-module FOO)
-    # (focus module2 module1 )
-    
-    save_option = options['save_rulebase']
-    bsave_option = options['bsave_rulebase']
-    config_option = options['config']
-    watch_option = options['watch']
-    print_option = options['print']
-    classdefault_option = options['classdefault']
-    #^-tbd
-    #structure can be either default (builtin template) or custom (user-provided template - this requries a proper SQL description in the payload file)
-    # even better: remove the XOR option: Its either a deafault with a defined value, OR a STRUCTstring has to be provided
-
-    ## Knowledge bases 
-    rulebase_file = options['rulebase']
-    builtin_rulesbase_files = options['library']
-
-
-    #################################################
-    #Set Variables and Data Structures 
-    #################################################
-    
-    #Initialize dictionary to keep the attribute structures for all vectors:
-    global layers_vector_vinascii
-
-    global layers_template
-    global layers_vector_columns
-    global layers_raster_type
-    global layers_raster3d_slices
-
-    facts_vectors_set={}
-    facts_rasters_set={}
-    facts_raster3ds_set={}
-
-    ###^^^^ REFACTOR !
-
-
-
-    #################################################
-    ##### Invoke GRASS Ctype low level  interface
-    #################################################
-    G_gisinit('g.infer')
-    
-  
-
-    #################################################
-    ## Initialize the CLIPS session 
-    #################################################    
-    global GLOBAL_CLIPS__ENVIRONMENT
-    xps = clips.Environment()
-    GLOBAL_CLIPS__ENVIRONMENT=xps
-
-    #################################################
-    ## Register additional Python modules with CLIPS session 
-    register_grass_functions_in_clips()
-    
-    #################################################
-    ## change inference strategy
-    if inference_strategy:
-       set_inference_strategy(inference_strategy)
-
-    #################################################
-    ## set salience evaluation behaviour 
-    if salience_evaluation_behaviour:
-       set_salience_evaluation_behaviour(salience_evaluation_behaviour)
-
-
-    #################################################
-    ## load knowledge base module stack
-    if inference_focus_module:
-       focus_string = "(focus"
-       for this_module in str(inference_focus_module).split(','): 
-           grass.message(_("> Module: "+this_module))
-           focus_string += " "+this_module
-       focus_string += ")"
-       #GLOBAL_CLIPS__ENVIRONMENT.SendCommand(focus_string)
-    ### ^^^Refactor / Encapsulate
-
-    #################################################
-    ##### CLIPS options
-    clips_dribble(inference_map,toggle_dribble)
-  
-    clips_external_traceback(toggle_external_traceback)
-
-    if save_option: 
-        clips_save(inference_map,save_option)
-
-    if bsave_option: 
-        clips_bsave(inference_map,save_option)
-
-    if config_option: 
-        clips_config(config_option)
-
-    if watch_option: 
-        clips_watch(watch_option)
-
-    if print_option: 
-        clips_list(print_option)
-
-    if classdefault_option: 
-        clips_classdefault(classdefault_option)
-
-
-    #################################################
-    ## Sanity Checks of Input Layers
-    #################################################
-    sanity_checks_input_layers(facts_rasters,facts_raster3ds,facts_vectors,facts_file,rulebase_file)
-    
-
-
-    #################################################
-    ## DETECT VECTORS
-    #################################################
-    #Iterate over all input vector layers (if existing): create a set and count total 
-    if facts_vectors > "":
-        count_vectors,facts_vectors_set=detect_input_layer(facts_vectors,facts_rasters_set,facts_raster3ds_set)
-
-    #################################################
-    ## DETECT RASTER
-    #################################################
-    #Iterate over all input raster layers (if existing): create a set and count total 
-    if facts_rasters > "":
-        count_maps,facts_rasters_set=detect_input_layer(facts_rasters,facts_vectors_set,facts_raster3ds_set)
-
-    #################################################
-    ## DETECT RASTER3D (Volume)
-    #################################################
-    #Iterate over all input raster layers (if existing): create a set and count total 
- 
-    if facts_raster3ds > "":
-        count_maps,facts_raster3ds_set=detect_input_layer(facts_raster3ds,facts_vectors_set,facts_rasters_set)
-
-
-    #################################################
-    # DETECT AND ACCESS OUTPUT MAP  
-    #################################################
-
-    if inference_map:
-        if not result_columns:
-            grass.fatal(_("Unable to create output vector map: Parameter <columns> missing."))
-        else:
-            create_vector=TRUE  
+        #dto:
+        dbconnection = grass.vector_db(thevector)
+        mymessage="*** vector_dbconncetion = " + str(dbconnection)
+        grass.debug(_(mymessage))
+ 
+        columns = grass.vector_columns(thevector)
+
+        mymessage="*** vector columns = " + str(columns)
+        grass.debug(_(mymessage))
+        #?? Is there a similar API interface to v.info -g (vectors region). ?? 
+    else:
+        #grass.message(_("g.infer: Something really wrong with vector" + str(thevector)))
+        sys.exit(1)
+
+
+
+#######################################################################
+## RASTER IMPORT
+#######################################################################
+
+
+def ingest_facts_rasters(facts_rasters,ignore_raster_labels):
+    """! Ingestion of all user-provided GRASS raster layers. Option: Ignore GRASS raster labels"""
+    facts_rasters_list=[]
+    count_maps = 0
+    gisenv = grass.gisenv()
+    gisenv_mapset = gisenv['MAPSET']                        
+    for this_facts_raster in str(facts_rasters).split(','): 
+        grass.debug(_("Ingesting Raster: "+this_facts_raster))
+        count_maps = count_maps + 1
+        
+        #gisenv = grass.gisenv()
+        #gisenv_mapset = gisenv['MAPSET']         
+        #listofmaps=grass.list_grouped('rast')[gisenv_mapset]
+        #if (this_facts_raster) not in listofmaps:
+        #    grass_fatal("g.infer: Raster layer does not exist:" + str(this_facts_raster))
+        #    sys.exit(1)        
+            
+        import_raster_test(this_facts_raster)
+        
+        is_elevation_level = False
+        facts_rasters_list.append(this_facts_raster)
+        grassraster2factlayer(this_facts_raster,"GRASS RASTER",ignore_raster_labels,is_elevation_level)
+    return set(facts_rasters_list)
+
+
+
+    
+def grassraster2factlayer(the_raster,the_comment_string="GRASS RASTER",ignore_raster_labels=False,elevationlevel=False):
+    """! Generate facts from a GRASS raster layer including the coordinates, the digital number AND the value attribute
+    test for categories: r.category --quiet geology fs=: 0> 1:metamorphic or 1: 
+    """
+
+    #TO BE INCLUDED:
+    ## test for input raster map
+    #result = grass.find_file(name = map_name, element = 'cell', quiet = True)
+    #if not result['file']
+    #grass.fatal("Raster map <%s> not found" % map_name)
+
+    #check for category strings:
+    raster_with_labels = True
+    the_categories = raster_categories(the_raster)
+    if len(the_categories) < 1:
+       raster_with_labels = False
+    # find map in search path
+    mapset = G_find_cell2(the_raster, '') 
+
+    #Attribute recognition doesnt work for rast3d rasters
+
+    # determine the inputmap type (CELL/FCELL/DCELL) 
+    typename = 'undefined'
+    data_type = G_raster_map_type(the_raster, mapset)
+    if data_type == CELL_TYPE:
+       ptype = POINTER(c_int)
+       type_name = 'CELL'
+    elif data_type == FCELL_TYPE:
+       ptype = POINTER(c_float)
+       type_name = 'FCELL'
+    elif data_type == DCELL_TYPE:
+       ptype = POINTER(c_double)
+       type_name = 'DCELL'
+  
+    # construct strings to generate templates both on pyclips and clips level:
+ 
+    buildtemplate_template = "(slot x)(slot y)"
+    bashstar_template = "(deftemplate " + the_raster + " (slot x)(slot y)"
+
+    attribute_list = []
+    attribute_list.append("x")
+    attribute_list.append("y")
+
+    if elevationlevel:
+       buildtemplate_template = buildtemplate_template + "(slot z)"
+       bashstar_template = bashstar_template  + "(slot z)"
+       attribute_list.append("z")
+    #Append a column for elevation if this raster layer stems from a rast3d layer, aka has a z-Value constant attached to it
+
+    attr_name_value = 'value'
+
+    attr_name_attribute = 'attribute' 
+
+    if type_name == 'CELL':
+        export_type_value = 'integer'
+      ### UNTESTED !!!! 
+    else:
+        export_type_value = 'double precision'
+    ###^^^--- The datdtype is defined below: CELL/FCELL/DCELL -> fix  !
+
+    #export_type_attribute = "varchar(" + str(GLOBAL_ATTRIBUTE_TYPE) + ")"
+
+    # generate low level GRASS structures 
+
+    infd = G_open_cell_old(the_raster, mapset)
+    inrast = G_allocate_raster_buf(data_type) 
+    inrast = cast(c_void_p(inrast), ptype)
+
+    rows = G_window_rows()
+    cols = G_window_cols()
+
+    hd=struct_Cell_head()
+    G_get_cellhd(the_raster,mapset,byref(hd))
+
+
+    ###############################
+
+    if raster_with_labels and not ignore_raster_labels:    
+        buildtemplate_template = buildtemplate_template + "(slot "+ attr_name_value +")"+ "(multislot "+ attr_name_attribute +")"
+        bashstar_template = bashstar_template + "(slot "+ attr_name_value +")" + "(multislot "+ attr_name_attribute +")"+")" 
+        attribute_list.append(attr_name_value)
+        attribute_list.append(attr_name_attribute)       
+    else:
+        buildtemplate_template = buildtemplate_template + "(slot "+ attr_name_value +")"
+        bashstar_template = bashstar_template + "(slot "+ attr_name_value +") )"
+        attribute_list.append(attr_name_value)
+     
+        
+    #Instantiate the new template in PyClips
+    the_new_template = GLOBAL_CLIPS__ENVIRONMENT.BuildTemplate(the_raster,buildtemplate_template,the_comment_string)
+    #Instantiate the new template in Clips
+    prelude_upload(bashstar_template)
+
+    for rown in xrange(rows):
+        therow = G_get_raster_row(infd, inrast, rown, data_type)
+     
+        for coln in xrange(cols):
+            coo_col = G_col_to_easting(coln, byref(hd))
+            coo_row = G_row_to_northing(rown, byref(hd))
+            the_value=inrast[coln]
+            fallback=''
+            the_category=the_categories.get(str(the_value),fallback)
+            to_assert = "(" + the_raster + " (x " + str(coo_col) + ") (y " + str(coo_row) + ")"
+            if elevationlevel: 
+                to_assert =  to_assert + "(z "+ str (elevationlevel) + ")"
+
+            to_assert =  to_assert + "(value " + str(the_value) + ")"
+            if raster_with_labels and not ignore_raster_labels:
+                to_assert =  to_assert + "(attribute " + str(the_category) + ")"
+
+            to_assert =  to_assert + ")"          
+            GLOBAL_CLIPS__ENVIRONMENT.Assert(to_assert)
+
+    G_close_cell(infd)
+    G_free(inrast)
+
+    global_layers_template_put(the_raster,the_new_template) 
+    global_layers_raster_type_put(the_raster,type_name)
+
+    return
+
+
+def grassraster_KB_load_raster(the_raster):
+    """! Creates a template and asserts the facts for a GRASS raster - to be used with internal knowledgebases  """ 
+    ### !!! Requires a failsafe to test whether the layer exists at all !
+    is_elevation_level = False
+    ignore_raster_labels = FALSE
+    #facts_rasters_set = set(facts_rasters_list.append(the_raster))
+    #^^ is only set otherwise during explicit raster upload in MAIN.
+    # !!!allow for update option
+    grassraster2factlayer(the_raster,"GRASS RASTER",ignore_raster_labels,is_elevation_level)
+
+
+########################################################################
+#### RASTER METADATA FACTS
+########################################################################
+
+#TBD: Provide the metadata for a GRASS raster as CLIPS facts for use in the inference process.
+
+
+# grass.raster_info
+# grass.raster_history
+
+# tbd: Actual region/coverage a raster layer: r.region
+# tbd: r.support
+# tbd: stats: r.median, r.quantile, r.statistics, r.univar
+# tbd: number format (integer, floats, etc)
+# r.info ?
+
+
+#######################################################################
+## VOLUME IMPORT 
+#######################################################################
+
+
+def ingest_factsraster3ds(facts_raster3ds):
+    """! Ingestion of all user-provided GRASS raster3D (volume) layers"""
+    facts_raster3ds_list=[]
+    count_maps = 0
+                     
+    for this_facts_raster3d in str(facts_raster3ds).split(','): 
+        grass.message(_("Ingesting Raster3D: "+this_facts_raster3d))
+        import_rast3d_test(this_facts_raster3d)
+        #listofmaps=grass.list_grouped('rast3')[gisenv_mapset]
+        #if (this_facts_raster) not in listofmaps:
+        #    grass_fatal("g.infer: Raster layer does not exist:" + str(this_facts_raster))
+        #    sys.exit(1)                                                                                
+        count_maps = count_maps + 1
+        facts_raster3ds_list.append(this_facts_raster3d)
+        grassvolume2factlayer(this_facts_raster3d) 
+    return set(facts_raster3ds_list)
+
+
+
+def grassvolume2factlayer(the_volume):
+    """! Generate facts from a GRASS volume layer including the 3d coordinates and the digital number"""
+    the_raster = str(the_volume)+"_slice_"
+
+    #the_layers_template = global_layers_template_get(the_volume)
+ 
+    #layers_raster_type = global_layers_raster_type_get(the_volume)
+
+    #global_layers_rast3d_slices_get(the_volume)
+
+    p = grass.pipe_command('r3.to.rast',flags='rm',input=the_volume, output=the_raster.rstrip("_"), quiet='TRUE')
+    # tbd: replace the_raster by a randomly generated name.
+
+    grass.debug("grassvolume2factlayer: Sleeping 10 sec")
+    time.sleep(10) 
+    #SLEEP to ensure that the pipe returns in time. This is ugly and need to be improved.
+    # get height of layerstack
+    region = region3()
+    stack_height=region['depths']
+    stack_res=region['tbres']
+
+    this_raster3d_raster_slices_list = []
+    #create a container for all raster_file_names for this raster3d volume
+
+    #ITERATE OVER THE stack of raster layerswhich were creared
+    for level in range(1, int(stack_height)):
+      if level < 10:
+         levelstring="0000"+str(level)
+      elif level < 100:
+         levelstring="000"+str(level)
+      elif level < 1000:
+         levelstring="00"+str(level)
+      elif level < 10000:
+         levelstring="0"+str(level)  
+      current_raster=the_raster+levelstring
+    #^^ use the real elevations ( not the levels) level*elevationelta=ELEVATIONVARIABLE
+
+
+      grass.debug("Raster-Level: "+current_raster)
+      this_raster3d_raster_slices_list.append(current_raster)
+      this_elevation=stack_res * level 
+      the_ignore_label_flag = True
+      #the_template,raster_type = grassraster2factlayer(current_raster,"GRASS VOLUME",the_ignore_label_flag,this_elevation)
+
+      #the_layers_template[current_raster]=the_template
+      #layers_raster_type[current_raster]=raster_type
+      grassraster2factlayer(current_raster,"GRASS VOLUME",the_ignore_label_flag,this_elevation)
+
+      ###^^ to be returned !
+    #global_layers_template_put(the_volume,the_layers_template)
+ 
+    #global_layers_raster_type_put(the_volume,layers_raster_type)
+
+    global_layers_rast3d_slices_put(the_volume,this_raster3d_raster_slices_list)
+    
+    #return the_layers_template, layers_raster_type, this_raster3d_raster_slices_list
+
+
+
+def grassvolume2factlayer_internal(the_volume):
+    """! Internal Use: Generate facts from a GRASS volume layer including the 3d coordinates and the digital number"""
+    grassvolume2factlayer(the_volume) 
+
+########################################################################
+#### VOLUME METADATA FACTS
+########################################################################
+
+#TBD: Provide the metadata for a GRASS raster3D volume as CLIPS facts for use in the inference process.
+
+# r3.timestamp
+# r3.stats
+# r3.univar
+
+
+
+
+##############################################################
+##############################################################
+##############################################################
+##############################################################
+##############################################################
+##############################################################
+## METADATA
+##############################################################
+##############################################################
+
+##########################################################
+## GRASS SESSION METADATA to FACTS
+##########################################################
+    
+def assert_region():
+    """! Creates facts for all GRASS region parameters"""
+    region = region3()
+    region_rows = region['rows']
+    region_cols = region['cols']
+    region_cells = region['cells']
+    region_ewres = region['ewres']
+    region_nsres = region['nsres']
+    region_n = region['n']
+    region_s = region['s']
+    region_e = region['e']
+    region_w = region['w']
+
+    # Accomodate for 3D region parameters:
+    region_t = region['t']
+    region_b = region['b']
+    region_tbres = region['tbres'] 
+    region_ewres3 = region['ewres3']
+    region_nsres3 = region['nsres3']   
+    region_rows3 = region['rows3']
+    region_cols3 = region['cols3']
+    region_depths = region['depths']
+    region_cells3 = region['cells3']
+ 
+
+    assert_region_rows = "( REGION_ROWS " + str(region_rows) + " )" 
+    assert_region_cols = "( REGION_COLS " + str(region_cols) + " )"
+    assert_region_cells = "( REGION_CELLS " + str(region_cells) + " )" 
+    assert_region_ewres = "( REGION_EWRES " + str(region_ewres) + " )"
+    assert_region_nsres = "( REGION_NSRES " + str(region_nsres) + " )" 
+    assert_region_n = "( REGION_N " + str(region_n) + " )"
+    assert_region_s = "( REGION_S " + str(region_s) + " )" 
+    assert_region_e = "( REGION_E " + str(region_e) + " )"
+    assert_region_w = "( REGION_W " + str(region_w) + " )"
+
+    #  Region 3D parameters:
+    assert_region_rows3 = "( REGION_ROWS3 " + str(region_rows3) + " )" 
+    assert_region_cols3 = "( REGION_COLS3 " + str(region_cols3) + " )"
+    assert_region_cells3 = "( REGION_CELLS3 " + str(region_cells3) + " )" 
+    assert_region_ewres3 = "( REGION_EWRES3 " + str(region_ewres3) + " )"
+    assert_region_nsres3 = "( REGION_NSRES3 " + str(region_nsres3) + " )" 
+    assert_region_tbres = "( REGION_TBRES " + str(region_tbres) + " )" 
+    assert_region_t = "( REGION_T " + str(region_t) + " )"
+    assert_region_b = "( REGION_B " + str(region_b) + " )" 
+    assert_region_depths = "( REGION_DEPTHS " + str(region_depths) + " )" 
+
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_rows)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cols)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cells)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_nsres)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_ewres)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_n)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_s)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_e)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_w)
+
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_rows3)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cols3)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_cells3)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_nsres3)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_ewres3)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_tbres)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_t)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_b)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_region_depths)
+
+
+   
+def assert_gisenv():
+    """!Assert all GRASS environmental variables (GISENV / Location / Mapset) as facts in the CLIPS environment"""
+    gisenv = grass.gisenv()
+    gisenv_gisdbase = gisenv['GISDBASE']
+    gisenv_location_name = gisenv['LOCATION_NAME']
+    gisenv_mapset = gisenv['MAPSET']
+    gisenv_grass_gui = gisenv['GRASS_GUI']
+  
+    assert_gisdbase = "( GISDBASE " + gisenv_gisdbase + " )" 
+    assert_location_name = "( LOCATION_NAME " + gisenv_location_name + " )" 
+    assert_mapset = "( MAPSET " + gisenv_mapset + " )" 
+    assert_grass_gui= "( GRASS_GUI " + gisenv_grass_gui + " )" 
+
+    # More variables to be included !
+    
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_gisdbase)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_location_name)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_mapset)
+    GLOBAL_CLIPS__ENVIRONMENT.Assert(assert_grass_gui)
+
+
+
+
+########################################################################
+#### GRASS7 TEMPORAL METADATA FACTS
+########################################################################
+
+# tbd: no python support yet
+
+########################################################################
+#### DATABASE CONNECTIVITY METADATA FACTS
+########################################################################
+
+#TBD: Integrate this metadata as CLIPS facts for use in the inference process.
+
+# grass.db_connection
+# grass.db_describe
+# grass.db_select
+
+
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## EXPORT from CLIPS constructs to GRASS layers
+##########################################################################
+##########################################################################
+
+
+# Export sanity checks needed ?
+
+
+def fact2rastercell(afact,raster_name,integer_case):
+   """! Returns for  a (raster-) fact the structured content of a GRASS - raster cell"""
+   the_x = float(afact.Slots['x'])
+   the_y = float(afact.Slots['y'])
+   if integer_case:
+      the_value = int(afact.Slots['value'])
+   else:
+      the_value = float(afact.Slots['value'])
+   ###^^ not everything is FLOAT !
+   
+   if 'attribute' in afact.Slots.keys():
+      #the_attribute=afact.Slots['attribute']
+      #alternative to deal with multiple string content - works for vector, untested here.
+      the_attribute=""
+      multifield_list = afact.Slots['attribute']
+      allitems=""
+      for item in multifield_list:
+       the_attribute=the_attribute + str(item).rstrip() + " "
+      the_attribute.rstrip(" ")
+   else: 
+      the_attribute=False
+
+   if 'z' in afact.Slots.keys():
+       the_elevation = float(afact.Slots['z'])
+   else: 
+      the_elevation=False
+   return the_x,the_y,the_value,the_attribute,the_elevation
+
+#######################################################################
+## RASTER EXPORT
+####################################################################### 
+
+def factslayer_fromraster2grassraster_internal(rastername,ignore_labels=False):
+  """! Internal Use: Exports a grassraster facts to GRASS vector (point) layer which are transformed into a GRASS raster layer"""
+  factslayer_fromraster2grassraster(rastername,ignore_labels,False)
+
+
+def factslayer_fromraster2grassraster(rastername,ignore_labels=False,raster_type=False):
+  """! Exports a grassraster facts to GRASS vector (point) layer which are transformed into a GRASS raster layer""" 
+  ### tbd: take care of Z-column for rast3d !
+
+  ### start a dictionary to track all attribute/value pairs 
+
+#  global layers_template
+  thetemplate = global_layers_template_get(rastername) 
+  raster_type = global_layers_raster_type_get(rastername) 
+
+# test: if exists: use ELSE: False
+  layers_raster_type[rastername] = raster_type
+  #??? is this the right ordering ?
+
+  attribute_dict = {}
+
+  #Check for number types:
+  if raster_type:
+     if raster_type == "CELL":
+        integer_case = TRUE
+        grass.debug("[factslayer_fromraster2grassraster] INTEGER LIKE INPUT MAP")
+     else:
+        integer_case = FALSE
+        grass.debug("[factslayer_fromraster2grassraster] FLOAT LIKE INPUT MAP")
+        # we don't care what kind of float it is
+  else:
+     # no raster type provided, we must check the facts to figure it out.
+     grass.message("[factslayer_fromraster2grassraster] No raster map type defined: PROBING FACTS TO DEFINE OUTPUT MAP TYPE")
+     integer_case = facts_all_integer(thetemplate,'value')
+
+  #define array to collect random access info from facts
+  if integer_case:
+     raster_output = garray.array(dtype=numpy.int32)
+     grass.debug("[factslayer_fromraster2grassraster] Integer Array")
+  else:
+     grass.debug("[factslayer_fromraster2grassraster] Float Array")
+     raster_output = garray.array()
+
+  #### GRASS LOW LEVEL COMMANDS start here
+  #setup GRASS helpers to transform coordinates into columns and rows.
+  mapset = G_find_cell2(rastername, '') 
+  hd=struct_Cell_head()
+  G_get_cellhd(rastername,mapset,byref(hd))
+
+  thisfact = fact_first(thetemplate)
+
+  if thisfact:   
+     now_x,now_y,now_value,now_attribute,now_elevation = fact2rastercell(thisfact,rastername,integer_case)
+     # now_elevation is currently not used further. 
+     # the z-component is ignored -> the z/level info is also part of the template name.
+     coo_col = int(G_easting_to_col(now_x, byref(hd)))
+     coo_row = int(G_northing_to_row(now_y, byref(hd)))
+     if now_attribute:
+         attribute_dict.update({str(now_attribute):now_value})
+            # push attribute into attribute dictionary if is does not exist yet. 
+     if integer_case:
+         raster_output[coo_row,coo_col] = numpy.int32(now_value)
+     else:
+         raster_output[coo_row,coo_col] = float(now_value)
+
+     count = 1
+     carry_on = 1
+
+  while carry_on:
+     count = count +1
+     thisfact = fact_next(thetemplate, thisfact)
+     if thisfact:
+         now_x,now_y,now_value,now_attribute,now_elevation = fact2rastercell(thisfact,rastername,integer_case)
+         coo_col = int(G_easting_to_col(now_x, byref(hd)))
+         coo_row = int(G_northing_to_row(now_y, byref(hd)))
+         if now_attribute:
+               attribute_dict.update({str(now_attribute):now_value})
+         if integer_case:
+               raster_output[coo_row,coo_col] = numpy.int32(now_value)
+         else:
+               raster_output[coo_row,coo_col] = float(now_value)
+     else:
+         carry_on = 0
+  #!!! coordinate skew is still there !: add +0.5 ?
+  
+  # Remove previous version of layer in GRASS domain:
+  grass.run_command('g.remove', rast=rastername, quiet='TRUE')
+  
+  #write changed raster out
+  raster_output.write(rastername)
+
+  #writeout attributes if any exist
+  if attribute_dict.keys():
+     grassfeed = grass.feed_command("r.category",rules='-',map=rastername, quiet='TRUE')
+     for key in attribute_dict.keys():
+         this_attribute  = str(int(attribute_dict[key])) + ":" + str(key)+"\n"
+         grassfeed.stdin.write(this_attribute)
+     grassfeed.stdin.close()
+
+  #get rid of NULL values (untested) #FACTNULL ist der UGLY interne Wert !
+  grass.run_command('r.null', map=rastername, setnull=FACT_NULL, quiet='TRUE')
+
+  #IF INTEGER: ^^^^
+  # IF FLOAT: Handle * => nan case for NULL value
+
+
+
+########################################################################
+####VECTOR EXPORT
+########################################################################
+
+
+
+def vector_facts2grassvector_string(afact,thecolumnslist):
+    """!Builds and returns a GRASS-formatted string from the facts associated to a GRASS vector """
+    #(grassraster (name foo) (x 596203) (y 4915149)(hanni 42)(nanni 43))
+
+    myresult = str(afact.Slots['x'])+"|"+ str(afact.Slots['y'])
+    multifield_list = list()
+    #^^dummy-define variable for later use
+     
+    for column in thecolumnslist:
+        if (column != 'x')and( column !='y'):
+            multifield_list = afact.Slots[column]
+            allitems=""    
+        if (len(multifield_list) > 0):
+            for item in multifield_list:
+                allitems=allitems + str(item).rstrip() + " "    
+            myresult = myresult+"|"+ allitems.rstrip(" ")
+
+    grass.debug(_("vector_facts2grassvector_string:" + myresult))
+    myresult = myresult + "\n"
+    return myresult
+
+
+def factslayer2grassvector_internal(vectorname):
+    """! Internal Use: Creates a GRASS vector from a factslayer"""
+    factslayer2grassvector(vectorname) 
+    # ^^^Untested ! 
+
+
+
+def factslayer2grassvector(vectorname):
+    """! Creates a GRASS vector from a factslayer"""
+    #!! To be considered: Shall the name  of a newly to be created  output vector is to be included ?
+    #
+
+    #!! In case that a OUTPUT layer has been created with COLUMNS, but remains empty:
+    #   v.in.ascii -e creates only an empty layer.
+    count = 0
+    thetemplate = global_layers_template_get(vectorname)  # --> Could cause a problem in a "new vector (Xanadu)" case. Otherwise: optional argument ?
+    the_columns = global_layers_vector_vinascii_get(vectorname)
+    the_columns_list = global_layers_vector_columns_get(vectorname)
+    #complete_columns= cat_filter('x double precision, y double precision,' + the_columns.strip("\'"))
+    #^^^ original version: assumes that x/y columns are NOT provided by the user.
+    complete_columns= cat_filter('' + the_columns.strip("\'"))
+    # works for now ^^^
+    #20120508: This must be discussed:
+    # is it a good thing if the user has to define X and Y columns when entering the columns-description ?
+    # con: x/X y/Y can be misleading -> internal import assumes that x/y are the needed coordinates.
+    #!!!
+    #print str(vectorname) +" Facts =>  "+str(facts_total(thetemplate))
+    if (facts_total(thetemplate) < 1):
+        # ^^^^FACTS_TOTAL needs a FAILSAFE for the NULL case !
+        #g.message(_("Export stopped: No facts found for export vector: " + the_template))
+        grass.message(_("[factslayer2grassvector]: No facts found for export vector: " + str(vectorname) + " --> EMPTY VECTOR CREATED"))
+        grass.run_command("v.in.ascii","e",input='-',output=vectorname, x=1, y=2, columns=complete_columns, overwrite='True', quiet='TRUE')
+     
+    else:
+        mystring = str(vectorname) + "-facts-count: "+ str(facts_total(thetemplate))
+        #g.message(_("Export continues: " + mystring))
+        grassfeed = grass.feed_command("v.in.ascii",input='-',output=vectorname, x=1, y=2, columns=complete_columns, overwrite='True',   quiet='TRUE')
+
+     
+        firstfact = fact_first(thetemplate)
+        thisfact = firstfact
+        if thisfact: 
+            carry_on = 1
+            grassfeed.stdin.write(vector_facts2grassvector_string(firstfact,the_columns_list))
+            count = 1
+            while carry_on:
+                count = count +1
+                thisfact = fact_next(thetemplate, thisfact)
+                if thisfact:
+                    grassfeed.stdin.write(vector_facts2grassvector_string(thisfact,the_columns_list))
+                else:
+                  carry_on = 0
+        grassfeed.stdin.close()
+    return count
+
+#######################################################################
+## VOLUME EXPORT
+#######################################################################
+
+### !!! The foofact.Slot.keys() mechanism allows to check whether a Z-value exists  
+### -> for now none is handed over.
+### Volume import/export could not be achieved via 2D rasters otherwise.
+
+def factslayer_fromraster3d2grassraster3d_internal(the_inference_map):
+   """! Internal USe: Update an existing GRASS volume layer from its CLIPS facts representation"""
+   factslayer_fromraster3d2grassraster3d(the_inference_map)
+# ^^ UNTESTED !
+
+
+def factslayer_fromraster3d2grassraster3d(the_inference_map):
+    """! Update an existing GRASS volume layer from its CLIPS facts representation"""
+    # for each item in the slices list: 
+    #   get the corresponding template from the vinasciss/templates list 
+    #   launch GRASSRASTER generation processess
+    # bundle rasters into a raster3d
+ 
+    #global_layers_raster_type_get(the_volume)
+    # shouldn't this one be handed over, too ?
+  
+    the_slices_list = global_layers_rast3d_slices_get(the_inference_map)
+    slices_list_string=""
+    for this_slice in the_slices_list:
+        layers_templates = global_layers_template_get(this_slice)   
+        slices_list_string=slices_list_string+","+str(this_slice)
+        #generate raster slice:
+        factslayer_fromraster2grassraster(this_slice,False) 
+
+    slices_list_string.lstrip(',')
+    #^^^remove leading comma 
+    p = grass.pipe_command('r.to.rast3',input=slices_list_string, output=the_inference_map, quiet='TRUE', overwrite='TRUE')
+
+
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## CLIPS Engine Settings
+##########################################################################
+##########################################################################
+
+#######################################################################
+## CLIPS Save options for knowledge items
+
+
+def clips_save(inference_map,save_option):
+    """! Write CLIPS information to file""" 
+     
+    if save_option.find("facts") > -1:
+        grass.debug(_("SAVE: Facts"))
+        forensics_facts=inference_map+"_facts.clips"
+        GLOBAL_CLIPS__ENVIRONMENT.SaveFacts(forensics_facts)
+ 
+    if save_option.find("constructs") > -1:
+        grass.debug(_("SAVE: Constructs"))
+        forensics_constructs=inference_map+"_constructs.clips"
+        GLOBAL_CLIPS__ENVIRONMENT.Save(forensics_constructs)
+
+    if save_option.find("instances") > -1:
+        grass.debug(_("SAVE: Instances"))
+        forensics_instances=inference_map+"_instances.clips"
+        GLOBAL_CLIPS__ENVIRONMENT.SaveInstances(forensics_instances)
+
+def clips_bsave(inference_map,save_option):
+    """! Write CLIPS information to file"""      
+    binary_export = 0
+
+    if save_option.find("facts") > -1:
+        grass.debug(_("BSAVE: Facts"))
+        forensics_facts=inference_map+"_facts.clips"
+        GLOBAL_CLIPS__ENVIRONMENT.SaveFacts(forensics_facts)
+ 
+    if save_option.find("constructs") > -1:
+        grass.debug(_("BSAVE: Constructs"))
+        forensics_constructs=inference_map+"_constructs.bin"
+        GLOBAL_CLIPS__ENVIRONMENT.BSave(forensics_constructs)
+ 
+    if save_option.find("instances") > -1:
+        grass.debug(_("BSAVE: Instances"))     
+        forensics_instances=inference_map+"_instances.bin"
+        GLOBAL_CLIPS__ENVIRONMENT.BSaveInstances(forensics_instances)
+     
+#######################################################################
+## CLIPS Set Config
+
+def clips_config(config_option):
+    """! Set CLIPS engine config-setting"""
+    config_string = "auto-float-dividend,dynamic-constraint-checking,fact-duplication,incremental-reset,reset- globals,sequence-operator-recognition,static-constraint-checking"
+    config_list = str(config_string).split(',')
+    for item in config_list:        
+        if watch_option.find(item) > -1:
+            grass.message(_("(set-"+str(item)+" TRUE )"))
+            now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-"+str(item)+" TRUE )")
+
+#######################################################################
+## CLIPS Set Watch
+
+def clips_watch(watch_option):
+    """! Set CLIPS engine watch-setting"""
+    watch_string = "activations,compilations,facts,functions,genericfunctions,globals,methods,messagehandlers,messages,rules,slots,statistics,all"
+    watch_list = str(watch_string).split(',')
+    for item in watch_list:        
+       if watch_option.find(item) > -1:
+         grass.message(_("(watch "+ str(item)+" )"))
+         now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(watch "+ str(item)+" )")
+
+#######################################################################
+## CLIPS Set list
+
+def clips_list(list_option):
+    """! Set CLIPS engine option-settings"""
+    if list_option.find("agenda") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintAgenda()
+    if list_option.find("breakpoints") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintBreakpoints()
+    if list_option.find("classes") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintClasses()
+    if list_option.find("deffacts") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintDeffacts()
+    if list_option.find("definstances") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintDefinstances()
+    if list_option.find("facts") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintFacts()
+    if list_option.find("focusstack") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintFocusStack()
+    if list_option.find("functions") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintFunctions()
+    if list_option.find("generics") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintGenerics()
+    if list_option.find("globals") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.ShowGlobals()
+      #"show" display the variables AND their values
+    if list_option.find("instances") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintInstances()
+    if list_option.find("messagehandlers") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintMessagehandlers()
+    if list_option.find("modules") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintModules()
+    if list_option.find("rules") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintRules()
+    if list_option.find("templates") > -1:
+      GLOBAL_CLIPS__ENVIRONMENT.PrintTemplates()
+      
+#######################################################################
+## CLIPS Set dribble
+
+def clips_dribble(inference_map,toggle_dribble):
+    """! Set CLIPS engine dribble-setting"""
+    if toggle_dribble:
+      grass.message(_("(dribble-on "+str(inference_map)+".dribble )"))
+      now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(dribble-on "+str(inference_map)+".dribble )")
+
+
+#######################################################################
+## CLIPS Set external traceback
+
+def clips_external_traceback(toggle_external_traceback):
+    """! Toggle CLIPS engine traceback-setting"""
+    if toggle_external_traceback:
+      clips.SetExternalTraceback(True)
+      #WORKS: confirmed 20120302
+
+#######################################################################
+## CLIPS Module stack seeding
+
+def clips_module_stack(inference_focus_module):
+    """! Set CLIPS engine focus-setting on a specific KB module"""
+    if inference_focus_module:
+        #iterate over comma seperated inference_focus_module AAA,BBB,CCCC and build up "focus AAA BBB CCC" string.
+        grass.message(_("clips_module_stack: Under development"))
+        clips.PrintFocusStack()
+        ### clips command: (focus AAA BB CC)
+        focus = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(focus AAA BBB CCC )")
+
+        
+        #FindModule($modulename) !! - finds an existing module 
+        # BuildModule
+        #popFocus
+        #printFocusStack
+        #
+        #clips.SetCurrent() / SetFocus / PopFocus
+        #CLIPS: (list-focus-stack) (clear-focus-stack) (focus fi fa fo)
+        #tbd: strip string "inference_focus_module" off commata ("A,B,C") -> "A B C" and assign GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(focus "+str(STTINGSANSCOMMATA)+".dribble )")
+    else:
+        grass.message(_("CLIPS_MODULE_STACK => ELSE:this should not happen"))
+
+#######################################################################
+## CLIPS Set class-default
+
+def clips_classdefault(classdefault_option):
+    """! Set CLIPS engine class-default-setting"""
+    #(set‑class-defaults-mode <mode>)
+    if classdefault_option.find("convenience") > -1:
+        now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("( set‑class-defaults-mode convenience)")
+    if classdefault_option.find("conservation") > -1:
+        now = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("( set‑class-defaults-mode conservation)")
+
+
+####################################################################### 
+###########SET DEBUG SETTING#########################
+    ###?? GLOBAL_CLIPS__ENVIRONMENT.Memory[Options] Object P42 pyclips manual
+    
+    #CLIPS Debug Settings which could be provided to the user for forensics.
+    
+    # Conserve: TRUE / False
+    # EnvironmentErrosEnabled
+    # Free()
+    # PPBuffersize
+    # Requests: readonly!
+    # Used: readonly !
+    # NumberOffEnvironmenst
+    
+
+
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## INFERENCE RUN
+##########################################################################
+##########################################################################
+
+
+##########################################################
+# Interactive mode.
+# code snippet adapted from http://pyclips.sourceforge.net/web/?q=node/19 author: franzg
+##########################################################
+
+# Description: TBD
+
+# needed: uo/down keys to navigate a history similar to the bash shell history.
+
+class interactive_shell(object):
+    """an interactive CLIPS prompt activated via the i-Flag"""
+ 
+    def __init__(self):
+        self.__ps1 = "g.infer CLIPS prompt[%(cmdno)s/%(lineno)s] (Exit: Ctrl-D)> "
+        self.__ps2 = "g.infer CLIPS prompt[%(cmdno)s/%(lineno)s] (Exit: Ctrl-D): "
+        self.__cmdno = 1
+        self.__lineno = 1
+ 
+    def __cmdcomplete(self, cms):
+        """check if CLIPS command is complete (stolen from 'commline.c')"""
+        def eat_ws(s, i):
+            """eat up whitespace"""
+            while i < len(s) and s[i] in _string.whitespace: i += 1
+            return i
+        def eat_string(s, i):
+            """eat up strings"""
+            if s[i] != '"' or i >= len(s): return i
+            i += 1
+            while i < len(s):
+                if s[i] == '"': return i + 1
+                else:
+                    if s[i] == '\\': i += 1
+                    i += 1
+            if i > len(s): raise ValueError, "non-terminated string"
+            return i
+        def eat_comment(s, i):
+            """eat up comments"""
+            if s[i] != ';' or i >= len(s): return i
+            while i < len(s) and s[i] not in '\n\r': i += 1
+            return i + 1
+        s = cms.strip()
+        if len(s) == 0: return False
+        depth = 0
+        i = 0
+        while i < len(s):
+            c = s[i]
+            if c in '\n\r' and depth == 0: return True
+            elif c == '"': i = eat_string(s, i)
+            elif c == ';': i = eat_comment(s, i)
+            elif c == '(': depth += 1; i += 1
+            elif c == ')': depth -= 1; i += 1
+            elif c in _string.whitespace: i = eat_ws(s, i)
+            else: i += 1
+            if depth < 0: raise ValueError, "invalid command"
+        if depth == 0: return True
+        else: return False
+ 
+    def Run(self):
+        """start or resume an interactive CLIPS shell"""
+        exitflag = False
+        while not exitflag:
+            self.__lineno = 1
+            s = ""
+            dic = { 'cmdno': self.__cmdno, 'lineno': self.__lineno }
+            prompt = self.__ps1 % dic
+            try:
+                while not self.__cmdcomplete(s):
+                    if s: s += " "
+                    s += raw_input(prompt).strip()
+                    self.__lineno += 1
+                    dic = { 'cmdno': self.__cmdno, 'lineno': self.__lineno }
+                    prompt = self.__ps2 % dic
+            except ValueError, e:
+                sys.stderr.write("[SHELL] %s\n" % str(e))
+            except EOFError:
+                clips.ErrorStream.Read()
+                exitflag = True
+                # tbd: allow also an "graceful" exit using a (exit) command!
+            try:
+                if not exitflag:
+                    GLOBAL_CLIPS__ENVIRONMENT.SendCommand(s, True)
+            except clips.ClipsError, e:
+                sys.stderr.write("[PYCLIPS] %s\n" % str(e))
+            self.__cmdno += 1
+            r0 = clips.StdoutStream.Read()
+            r1 = clips.DisplayStream.Read()
+            tx = clips.TraceStream.Read()
+            r = ""
+            if r0: r += r0
+            if r1: r += r1
+            t = clips.ErrorStream.Read()
+            if r: r = "%s\n" % r.rstrip()
+            if t: t = "%s\n" % t.rstrip()
+            if tx: t = "%s\n" % tx.rstrip() + t
+            #^^^2013_Feb19: This throws an error if WATCH is not set:
+            # TypeError: cannot concatenate 'str' and 'NoneType' objects
+
+
+            if t: sys.stderr.write(t)
+            if r: sys.stdout.write(r)
+ 
+##########################################################################
+# CLI Interface code
+# taken from http://commentsarelies.blogspot.de/2008/07/using-printout-and-readline-in-pyclips.html
+# Author: Johan Lindberg, 2008-07-14
+
+# Description: code to provide an interactive CLIPS shell for g.infer sessions.
+
+def pyprintout(*args):
+    """! TBD"""
+    for arg in args[1]:
+        if arg.cltypename().upper() == "SYMBOL":
+            if arg.upper() == "CRLF":
+               print
+            elif arg.upper() == "TAB":
+               print "\t",
+            else:
+              print arg,
+
+        else:
+            print arg,
+
+
+def pyreadline(*args):
+    """! TBD"""
+    return raw_input()
+
+def pyread(*args):
+    """! TBD"""
+    return raw_input()
+
+#######################################################################
+## CLIPS LAYER BATCHSTAR SEEDING
+
+
+def prelude_upload(the_string):
+    """! CReate a tempfile on the GRASS_level,and announce this file at the CLIPS level for BatchSTar usage?"""
+    #generate prelude for batchstar and write it out to a tempfile
+    tempfile = grass.read_command('g.tempfile',pid=random.randint(1,1000000))
+    file = open(tempfile, 'w')
+    file.write(the_string)
+    file.close()
+    # Make the template definitions available on the BatchStar level.
+    GLOBAL_CLIPS__ENVIRONMENT.BatchStar(tempfile)
+    # Remove the template
+    os.remove(tempfile)
+
+
+#######################################################################	
+## Set CLIPS engine options
+
+def set_inference_strategy(inference_strategy):
+    """! Set CLIPS engine inference strategy accoring to user input"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    strategy_was = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.Strategy
+    istrat = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-strategy "+str(inference_strategy)+")")
+    strategy_is = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.Strategy
+    mymessage = "Inference strategy="+str(inference_strategy)
+    grass.debug(_(mymessage))
+
+def set_salience_evaluation_behaviour(salience_evaluation_behaviour):
+    """! Set CLIPS salience evaluation accoring to user input"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    behaviour_was = GLOBAL_CLIPS__ENVIRONMENT.EngineConfig.SalienceEvaluation
+    is_behave = GLOBAL_CLIPS__ENVIRONMENT.SendCommand("(set-salience-evaluation "+str(salience_evaluation_behaviour)+")")
+    mymessage = "Salience evaluation strategy="+str(salience_evaluation_behaviour)
+    grass.debug(_(mymessage))
+
+
+#######################################################################
+## Ingest knowledge data: rulebases, facts, instances
+
+
+def ingest_rulebase_file(rulebase_file):
+    """! Ingestion of a user-provided rulebase file (KB)"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    if os.path.isfile(rulebase_file):
+        GLOBAL_CLIPS__ENVIRONMENT.BatchStar(rulebase_file)
+    else:
+        grass.fatal(_("File does not exist: " + rulebase_file))
+
+def ingest_facts_file(facts_file):
+    """! Ingestion of all user-provided facts file"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    if os.path.isfile(facts_file):
+        GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
+        grass.debug(_("[ingest_facts_file] Facts ingested from: " + facts_file))
+    else:
+        grass.fatal(_("File does not exist: " + facts_file))
+
+def ingest_instances_ascii_file(instances_ascii_file):
+    """! Ingestion of all user-provided ASCII instances (COOL, etc) file"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
+    if os.path.isfile(instances_ascii_file):
+        GLOBAL_CLIPS__ENVIRONMENT.LoadInstances(instances_ascii_file)
+        grass.message(_("Instances (ascii) ingested from: " + instances_ascii_file))
+    else:
+        grass.fatal(_("File does not exist: " + instances_ascii_file))
+
+def ingest_instances_binary_file(instances_binary_file):
+    """! Ingestion of all user-provided binary instances (COOL, etc) file"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    GLOBAL_CLIPS__ENVIRONMENT.LoadFacts(facts_file)
+    if os.path.isfile(instances_binary_file):
+     GLOBAL_CLIPS__ENVIRONMENT.BLoadInstances(instances_binary_file)
+     grass.message(_("Instances (binary) ingested from: " + instances_binary_file))
+    else:
+     grass.fatal(_("File does not exist: " + instances_binary_file))
+
+#######################################################################
+## Invoke inference process
+
+def launch_inference(max_rule_firing=False):
+    """! Invoke inference process, with the option to limit the maximum number of firing rules"""
+    global GLOBAL_CLIPS__ENVIRONMENT
+    grass.debug(_("[launch_inference]-----Inference starts-------"))
+    if max_rule_firing:
+       GLOBAL_CLIPS__ENVIRONMENT.Run(int(max_rule_firing))
+    else:
+       GLOBAL_CLIPS__ENVIRONMENT.Run()
+    grass.debug(_("[launch_inference]-----Inference stops-------"))
+
+
+
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## KNOWLEDGEBASES
+##########################################################################
+##########################################################################
+
+
+#2013-01-16: Exported into seperate files
+# tbd: Provide mechanisms to manage external KB as simple text-files (not *.PY)
+	
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## G.INFER SESSION SETUP
+##########################################################################
+##########################################################################
+	
+####################
+# Clips to Python/GRASS downlink tools:
+
+def register_grass_functions_in_clips():
+    """! Register several GRASS-related functions for use on the Rule level."""
+    #Usage: GLOBAL_CLIPS__ENVIRONMENT.Eval("python-call g.message _(/"hello world/") "))
+
+    # pyCLIPS CLI i/o code: 
+    clips.RegisterPythonFunction(pyprintout)
+    clips.RegisterPythonFunction(pyreadline)
+    clips.RegisterPythonFunction(pyread)
+
+    # !!! Keep an eye on this stuff and how it works (documenatation!) 
+    # The functions (below) rely on the already registered Python functions (right above).
+    ############################################
+    #Build CLIPS function: GINFER_PRINTOUT (on the CLIPS and pyCLIPS levels)
+    py_printout1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_printout","?logical-name $?args","""(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg)))""")
+    bashstar_printout1="(deffunction ginfer_printout (?logical-name $?args)(if (member$ python-call (get-function-list)) then (funcall python-call pyprintout ?logical-name $?args) else (progn$ (?arg $?args)(printout ?logical-name ?arg))))"
+    prelude_upload(bashstar_printout1)
+
+    ############################################
+    #Build CLIPS function: GINFER_READLINE (on the CLIPS and pyCLIPS levels)
+    py_readline1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_readline","$?logical-name","""(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (funcall python-call pyreadline ?logical-name) else (readline ?logical-name)))  """)
+    bashstar_readline1 = "(deffunction ginfer_readline ($?logical-name)"
+    bashstar_readline1 = bashstar_readline1 + "(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t))" 
+    bashstar_readline1=bashstar_readline1 + "(if (member$ python-call (get-function-list)) then (funcall python-call pyreadline ?logical-name) else (readline ?logical-name)))"
+    prelude_upload(bashstar_readline1)
+
+    ############################################
+    #Build CLIPS function: GINFER_READ (on the CLIPS and pyCLIPS levels)
+    py_read1 = GLOBAL_CLIPS__ENVIRONMENT.BuildFunction("ginfer_read","$?logical-name","""(if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (eval (funcall python-call pyread ?logical-name)) else (read ?logical-name))) """)
+    bashstar_read1="(deffunction ginfer_read ($?logical-name) (if (> (length$ $?logical-name) 0) then (bind ?logical-name (first$ $?logical-name)) else (bind ?logical-name t)) (if (member$ python-call (get-function-list)) then (eval (funcall python-call pyread ?logical-name)) else (read ?logical-name)))"
+    prelude_upload(bashstar_read1)
+
+    #############################################
+    # Pyclips stuff (to be accessible in rules and on the CLIPS prompt
+    # issue a grass(?) command:
+    clips.RegisterPythonFunction(pyclips_send_command)
+    #upload and execute facts/rules/whatnot from a file
+    clips.RegisterPythonFunction(pyclips_batchstar)
+
+    # GRASS stuff:
+    clips.RegisterPythonFunction(grass_message)
+    clips.RegisterPythonFunction(grass_fatal)
+    #clips.RegisterPythonFunction(grass.message)
+    clips.RegisterPythonFunction(assert_vector_metadata)
+    clips.RegisterPythonFunction(grassvector2factlayer)
+    clips.RegisterPythonFunction(grassvector2factlayer_internal)
+    clips.RegisterPythonFunction(grassraster2factlayer)
+    #clips.RegisterPythonFunction(grassraster2factlayer_internal) #removed 2013-05-16
+    clips.RegisterPythonFunction(grassvolume2factlayer)
+    clips.RegisterPythonFunction(grassvolume2factlayer_internal)
+    #clips.RegisterPythonFunction(factslayer_fromraster2grassraster_internal)
+    #clips.RegisterPythonFunction(factslayer_fromraster3d2grassraster3d_internal)
+    #clips.RegisterPythonFunction(factslayer2grassvector_internal)
+    #^^^ These functions require a central storgae place for INPUT INFORMATION
+    clips.RegisterPythonFunction(assert_region)
+    clips.RegisterPythonFunction(assert_gisenv)
+
+    clips.RegisterPythonFunction(grass.mapcalc)
+    clips.RegisterPythonFunction(grass_raster_info)
+    clips.RegisterPythonFunction(grass_run_command)
+    clips.RegisterPythonFunction(grass_read_command)
+
+    clips.RegisterPythonFunction(grass_start_command)
+    #clips.RegisterPythonFunction(LOADFACTS)
+    #clips.RegisterPythonFunction(ASSERT_RASTER_METADATA)
+    #clips.RegisterPythonFunction(DATENBANKZEUGS)
+    #clips.RegisterPythonFunction(MAPCALC)
+    #clips.RegisterPythonFunction("GRASS_LAMBDA")
+    #tbd:
+    # r.mapcalc
+    # raster/vector layer import
+    # database queries
+
+#####################################################
+## EXPERIMENTAL:
+
+#def KB_layers_spearfish():
+    #these KB layers will be imported BEFORE the rulebase is loaded.
+    #this assures that the rules can become valid as the templates they are referring to
+    #have already been instantiated.
+    #
+    #2013-02-19: Currently the check for the Spearfish location is done as rule #1.
+    # the check needs to be executed BEFORE the Spearfish layers are attempted to be uploaded.
+    #
+    # Maybe a simple failsafe in grassraster_KB_load_raster: Test for existance of layer.
+    #
+
+
+    ################SPEARFISH Raster Layers#########################################
+    #grass.message(_("SPEARFISH RASTER LAYER RUSHMORE: Loading"))            
+    #grassraster_KB_load_raster("geology")
+    #grassraster_KB_load_raster("rushmore")
+    #grassraster_KB_load_raster("landuse")
+    #grassraster_KB_load_raster("soils")
+    #grassraster_KB_load_raster("vegcover")
+
+    ################SPEARFISH Vector Layers#########################################
+    #grass.message(_(""SPEARFISH VECTOR LAYER bugsites: starting...")) 
+    #grassvector_KB_load_vector("archsites")
+    #grassvector_KB_load_vector("bugsites") #Mountain Pine Beetle Damage
+##
+#####################################################
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+##########################################################################
+## MAIN
+##########################################################################
+
+def main():
+ 
+                               
+    #################################################
+    ##### Sanity Check 1: Ensure that g.infer is run within a GRASS environment
+    if "GISBASE" not in os.environ:
+      print "You must be in GRASS GIS to run this program."
+      sys.exit(1)
+
+    #################################################
+    #### Import parameters provided from the GRASS GUI
+    
+     
+    #################################################
+    #### GRASS GUI Flags
+    
+    toggle_dribble = flags['d']
+    toggle_external_traceback = flags['e']
+    interactive_mode = flags['i']
+    ignore_raster_labels = flags['l']
+    toggle_suddendeath_mode = flags['x']
+
+    #################################################
+    #### GRASS GUI Options
+        
+    ## GRASS input layers
+    facts_rasters = options['rast']
+    facts_vectors = options['vector']
+    facts_raster3ds = options['rast3d']
+
+    # CLIPS knowledge items
+    facts_file = options['facts']
+    instances_binary_file = options['bload_instances']
+    instances_ascii_file = options['load_instances']
+
+    instances_binary_output = options['bsave_instances']
+    instances_ascii_output = options['save_instances']
+
+    ## GRASS output layers
+    inference_map = options['output']
+    output_maps = options['export'] 
+    result_columns = options['columns']
+
+    ## CLIPS parameters
+    max_rule_firing = options['limit']
+    inference_strategy = options['strategy']
+    salience_evaluation_behaviour = options['salience']
+    inference_focus_module = options['module']
+    #^^^--- tbd: remains to be switched on & tested  
+    # CLIPS: (set-current-module FOO)
+    # (focus module2 module1 )
+    
+    save_option = options['save_rulebase']
+    bsave_option = options['bsave_rulebase']
+    config_option = options['config']
+    watch_option = options['watch']
+    print_option = options['print']
+    classdefault_option = options['classdefault']
+    #^-tbd
+    #structure can be either default (builtin template) or custom (user-provided template - this requries a proper SQL description in the payload file)
+    # even better: remove the XOR option: Its either a deafault with a defined value, OR a STRUCTstring has to be provided
+
+    ## Knowledge bases 
+    rulebase_file = options['rulebase']
+    builtin_rulesbase_files = options['library']
+
+
+    #################################################
+    #Set Variables and Data Structures 
+    #################################################
+    
+    #Initialize dictionary to keep the attribute structures for all vectors:
+    global layers_vector_vinascii
+
+    global layers_template
+    global layers_vector_columns
+    global layers_raster_type
+    global layers_raster3d_slices
+
+    facts_vectors_set={}
+    facts_rasters_set={}
+    facts_raster3ds_set={}
+
+    ###^^^^ REFACTOR !
+
+
+
+    #################################################
+    ##### Invoke GRASS Ctype low level  interface
+    #################################################
+    G_gisinit('g.infer')
+    
+  
+
+    #################################################
+    ## Initialize the CLIPS session 
+    #################################################    
+    global GLOBAL_CLIPS__ENVIRONMENT
+    xps = clips.Environment()
+    GLOBAL_CLIPS__ENVIRONMENT=xps
+
+    #################################################
+    ## Register additional Python modules with CLIPS session 
+    register_grass_functions_in_clips()
+    
+    #################################################
+    ## change inference strategy
+    if inference_strategy:
+       set_inference_strategy(inference_strategy)
+
+    #################################################
+    ## set salience evaluation behaviour 
+    if salience_evaluation_behaviour:
+       set_salience_evaluation_behaviour(salience_evaluation_behaviour)
+
+
+    #################################################
+    ## load knowledge base module stack
+    if inference_focus_module:
+       focus_string = "(focus"
+       for this_module in str(inference_focus_module).split(','): 
+           grass.message(_("> Module: "+this_module))
+           focus_string += " "+this_module
+       focus_string += ")"
+       #GLOBAL_CLIPS__ENVIRONMENT.SendCommand(focus_string)
+    ### ^^^Refactor / Encapsulate
+
+    #################################################
+    ##### CLIPS options
+    clips_dribble(inference_map,toggle_dribble)
+  
+    clips_external_traceback(toggle_external_traceback)
+
+    if save_option: 
+        clips_save(inference_map,save_option)
+
+    if bsave_option: 
+        clips_bsave(inference_map,save_option)
+
+    if config_option: 
+        clips_config(config_option)
+
+    if watch_option: 
+        clips_watch(watch_option)
+
+    if print_option: 
+        clips_list(print_option)
+
+    if classdefault_option: 
+        clips_classdefault(classdefault_option)
+
+
+    #################################################
+    ## Sanity Checks of Input Layers
+    #################################################
+    sanity_checks_input_layers(facts_rasters,facts_raster3ds,facts_vectors,facts_file,rulebase_file)
+    
+
+
+    #################################################
+    ## DETECT VECTORS
+    #################################################
+    #Iterate over all input vector layers (if existing): create a set and count total 
+    if facts_vectors > "":
+        count_vectors,facts_vectors_set=detect_input_layer(facts_vectors,facts_rasters_set,facts_raster3ds_set)
+
+    #################################################
+    ## DETECT RASTER
+    #################################################
+    #Iterate over all input raster layers (if existing): create a set and count total 
+    if facts_rasters > "":
+        count_maps,facts_rasters_set=detect_input_layer(facts_rasters,facts_vectors_set,facts_raster3ds_set)
+
+    #################################################
+    ## DETECT RASTER3D (Volume)
+    #################################################
+    #Iterate over all input raster layers (if existing): create a set and count total 
+ 
+    if facts_raster3ds > "":
+        count_maps,facts_raster3ds_set=detect_input_layer(facts_raster3ds,facts_vectors_set,facts_rasters_set)
+
+
+    #################################################
+    # DETECT AND ACCESS OUTPUT MAP  
+    #################################################
+
+    if inference_map:
+        if not result_columns:
+            grass.fatal(_("Unable to create output vector map: Parameter <columns> missing."))
+        else:
+            create_vector=TRUE  
             #grass_message(str("[MAIN: INFERENCE MAP DETECTED] Export Vector: " + inference_map +  " columns = " + result_columns))
 
             grassvector_new(inference_map,result_columns)
-            grassvector2factlayer(inference_map,result_columns)
+            grassvector2factlayer(inference_map,result_columns)
             #grass_message(str("*** [MAIN: INFERENCE MAP CREATED !] *** "))
-
-    #################################################
-    ## INGEST VECTORS
-    #################################################
-    # Iterate over all vector layers and create grassvector-facts for each one from the provided attribute
-
-    if facts_vectors:
-        ingest_facts_vectors(facts_vectors,inference_map)
-
-    #################################################
-    ## INGEST RASTER
-    #################################################
-    # Iterate over all raster layers and create grassraster-facts for each one and return total count as list 
-    if facts_rasters: 
-        facts_rasters_set = ingest_facts_rasters(facts_rasters,ignore_raster_labels)
-
-    #################################################
-    ## INGEST RASTER3D
-    #################################################
-    # Iterate over all raster3d layers and create grassraster-facts for each one and return total count as list 
-    if facts_raster3ds: 
-        facts_raster3ds_set = ingest_factsraster3ds(facts_raster3ds)
-
-    #################################################
-    ## Ingest GRASS Session Metadata facts 
-    #################################################
-    region3() #ensure the 3d settings are available
-    assert_region()
-    assert_gisenv()
-
-       
-    #################################################
-    ## load built-in knowledge bases
-    #################################################
-
-    if builtin_rulesbase_files:
-        #grass.debug(_(""PREBUILT KB BEING LOADED !"))
-        this_count = 0
-        for this_kb in str(builtin_rulesbase_files).split(','): 
-            this_count = this_count + 1
-            __import__(this_kb)
-            kb_mods=sys.modules[this_kb]
-            grass.message(_("[g.infer Main] Using library KB: " + str(this_kb)))
-            prelude_upload(kb_mods.knowledgebase())
-        if interactive_mode:
-            grass.message(_("[-i Flag:]: Built-in knowledgebase has been loaded:")) 
-            grass.message(_("[-i Flag:]: Enter (run) on the CLIPS prompt to start."))
-            grass.message(_("[-i Flag:]: [Ctrl-D to leave CLIPS-prompt]"))
-         
-    #################################################
-    ## INGEST RULEBASE
-    #################################################
-    #### Upload rulebase payload into CLIPS space
-    if rulebase_file:
-        ingest_rulebase_file(rulebase_file)
-
-
-    #################################################
-    ## INGEST FACTS
-    #################################################
-    # This has to be done AFTER the payload has been ingested -> payload (may) have to include fact templates first !
-    if facts_file:
-        ingest_facts_file(facts_file)
-
-    #################################################
-    ## INGEST INSTANCES
-    #################################################
-    # This has to be done AFTER the  has been ingested -> payload (may) have to include object definitions for instances !
-
-    if instances_ascii_file:
-        ingest_instances_ascii_file(instances_ascii_file)
- 
-    if instances_binary_file:
-        ingest_instances_binary_file(instances_binary_file)
-
-
-   #################################################
-   ##### Interactive mode
-    if interactive_mode:
-        grass.debug(_("[i-Flag]: Entering interactive mode "))
-        clips_shell = interactive_shell()
-        clips_shell.Run()
- 
-
-    #################################################
-    ##### "No rules, no facts, no inference" abort option:
-    norules_nofacts_noservice()
-
-   #################################################
-   ##### Pre-Inference Early Abort
-    if toggle_suddendeath_mode:
-        grass.message(_("Pre-inference abort by user request (s-flag)"))
-        sys.exit()
-
-    #################################################
-    ##### Start Main Inference Loop 
-    launch_inference(max_rule_firing)
-
-   #################################################
-   ## SAVE INSTANCES
-   #################################################
-    if instances_ascii_output:
-        GLOBAL_CLIPS__ENVIRONMENT.SaveInstances(instances_ascii_output)
-        grass.message(_("Instances saved to ASCII-file: " + instances_ascii_output))
-
-    if instances_binary_output:
-        GLOBAL_CLIPS__ENVIRONMENT.BLoadInstances(instances_binary_output)
-        grass.message(_("Instances saved to binary file: " + instances_binary_output))
-
-    #################################################
-    ##### Create new output or updates of an input layer ?
-    #################################################
-    if output_maps: 
-        for export_map in str(output_maps).split(','):
-            if export_map in facts_raster3ds_set:
-                factslayer_fromraster3d2grassraster3d(export_map)
-            elif export_map in facts_rasters_set:
-                factslayer_fromraster2grassraster(export_map,ignore_raster_labels)
-            elif export_map in facts_vectors_set:
-                factslayer2grassvector(export_map)
-            else:
-                grass.fatal(_("g.infer [MAIN]: Strange Export Map Error: this should never happen."))
-    ### ^^^ REFACTOR / ENCAPSLUATE 
-
-
-    if inference_map:
-       #grass.message(_(""MAIN: commencing EXPORT-Layer writeout " + inference_map))
-       factslayer2grassvector(inference_map)
-
-if __name__ == "__main__":
-    options, flags = grass.parser()
-    atexit.register(cleanup)
-    sys.exit(main())
-    main()
-
-
-
-	
-	
-
-
-
+
+    #################################################
+    ## INGEST VECTORS
+    #################################################
+    # Iterate over all vector layers and create grassvector-facts for each one from the provided attribute
+
+    if facts_vectors:
+        ingest_facts_vectors(facts_vectors,inference_map)
+
+    #################################################
+    ## INGEST RASTER
+    #################################################
+    # Iterate over all raster layers and create grassraster-facts for each one and return total count as list 
+    if facts_rasters: 
+        facts_rasters_set = ingest_facts_rasters(facts_rasters,ignore_raster_labels)
+
+    #################################################
+    ## INGEST RASTER3D
+    #################################################
+    # Iterate over all raster3d layers and create grassraster-facts for each one and return total count as list 
+    if facts_raster3ds: 
+        facts_raster3ds_set = ingest_factsraster3ds(facts_raster3ds)
+
+    #################################################
+    ## Ingest GRASS Session Metadata facts 
+    #################################################
+    region3() #ensure the 3d settings are available
+    assert_region()
+    assert_gisenv()
+
+       
+    #################################################
+    ## load built-in knowledge bases
+    #################################################
+
+    if builtin_rulesbase_files:
+        #grass.debug(_(""PREBUILT KB BEING LOADED !"))
+        this_count = 0
+        for this_kb in str(builtin_rulesbase_files).split(','): 
+            this_count = this_count + 1
+            __import__(this_kb)
+            kb_mods=sys.modules[this_kb]
+            grass.message(_("[g.infer Main] Using library KB: " + str(this_kb)))
+            prelude_upload(kb_mods.knowledgebase())
+        if interactive_mode:
+            grass.message(_("[-i Flag:]: Built-in knowledgebase has been loaded:")) 
+            grass.message(_("[-i Flag:]: Enter (run) on the CLIPS prompt to start."))
+            grass.message(_("[-i Flag:]: [Ctrl-D to leave CLIPS-prompt]"))
+         
+    #################################################
+    ## INGEST RULEBASE
+    #################################################
+    #### Upload rulebase payload into CLIPS space
+    if rulebase_file:
+        ingest_rulebase_file(rulebase_file)
+
+
+    #################################################
+    ## INGEST FACTS
+    #################################################
+    # This has to be done AFTER the payload has been ingested -> payload (may) have to include fact templates first !
+    if facts_file:
+        ingest_facts_file(facts_file)
+
+    #################################################
+    ## INGEST INSTANCES
+    #################################################
+    # This has to be done AFTER the  has been ingested -> payload (may) have to include object definitions for instances !
+
+    if instances_ascii_file:
+        ingest_instances_ascii_file(instances_ascii_file)
+ 
+    if instances_binary_file:
+        ingest_instances_binary_file(instances_binary_file)
+
+
+   #################################################
+   ##### Interactive mode
+    if interactive_mode:
+        grass.debug(_("[i-Flag]: Entering interactive mode "))
+        clips_shell = interactive_shell()
+        clips_shell.Run()
+ 
+
+    #################################################
+    ##### "No rules, no facts, no inference" abort option:
+    norules_nofacts_noservice()
+
+   #################################################
+   ##### Pre-Inference Early Abort
+    if toggle_suddendeath_mode:
+        grass.message(_("Pre-inference abort by user request (s-flag)"))
+        sys.exit()
+
+    #################################################
+    ##### Start Main Inference Loop 
+    launch_inference(max_rule_firing)
+
+   #################################################
+   ## SAVE INSTANCES
+   #################################################
+    if instances_ascii_output:
+        GLOBAL_CLIPS__ENVIRONMENT.SaveInstances(instances_ascii_output)
+        grass.message(_("Instances saved to ASCII-file: " + instances_ascii_output))
+
+    if instances_binary_output:
+        GLOBAL_CLIPS__ENVIRONMENT.BLoadInstances(instances_binary_output)
+        grass.message(_("Instances saved to binary file: " + instances_binary_output))
+
+    #################################################
+    ##### Create new output or updates of an input layer ?
+    #################################################
+    if output_maps: 
+        for export_map in str(output_maps).split(','):
+            if export_map in facts_raster3ds_set:
+                factslayer_fromraster3d2grassraster3d(export_map)
+            elif export_map in facts_rasters_set:
+                factslayer_fromraster2grassraster(export_map,ignore_raster_labels)
+            elif export_map in facts_vectors_set:
+                factslayer2grassvector(export_map)
+            else:
+                grass.fatal(_("g.infer [MAIN]: Strange Export Map Error: this should never happen."))
+    ### ^^^ REFACTOR / ENCAPSLUATE 
+
+
+    if inference_map:
+       #grass.message(_(""MAIN: commencing EXPORT-Layer writeout " + inference_map))
+       factslayer2grassvector(inference_map)
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    atexit.register(cleanup)
+    sys.exit(main())
+    main()
+
+
+
+	
+	
+
+
+


Property changes on: grass-addons/grass6/general/g.infer/g.infer
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native



More information about the grass-commit mailing list