def instantiate(mac, operands, toplevel=True): """ Return a copy of macro cobject ``mac`` where arguments are instantiated by the list `operands', used in the order of depth-first tree traversal of ``mac``. Check that the number of operands is OK vs mac """ if isinstance(mac, cdummy): if len(operands) > 0: rep = operands.pop(0) else: raise Climaf_Macro_Error('no operand left') elif isinstance(mac, ctree): opers = [] for o in mac.operands: opers.append(instantiate(o, operands, toplevel=False)) rep = ctree(mac.operator, mac.script, *opers, **mac.parameters) elif isinstance(mac, scriptChild): father = instantiate(mac.father, operands, toplevel=False) rep = scriptChild(father, mac.variable) elif isinstance(mac, cdataset): rep = cdataset if toplevel and len(operands) != 0: raise Climaf_Macro_Error('too many operands; left operands are : ' + ` operands `) return (rep)
def instantiate(mac, operands, toplevel=True): """ Return a copy of macro cobject ``mac`` where arguments are instantiated by the list `operands', used in the order of depth-first tree traversal of ``mac``. Check that the number of operands is OK vs mac """ if isinstance(mac, cdummy): if len(operands) > 0: rep = operands.pop(0) else: raise Climaf_Macro_Error("no operand left") elif isinstance(mac, ctree): opers = [] for o in mac.operands: opers.append(instantiate(o, operands, toplevel=False)) rep = ctree(mac.operator, mac.script, *opers, **mac.parameters) elif isinstance(mac, scriptChild): father = instantiate(mac.father, operands, toplevel=False) rep = scriptChild(father, mac.variable) elif isinstance(mac, cdataset): rep = cdataset if toplevel and len(operands) != 0: raise Climaf_Macro_Error("too many operands; left operands are : " + ` operands `) return rep
def maketree(script_name, script, *operands, **parameters): rep=classes.ctree(script_name, script, *operands, **parameters) # TBD Analyze script inputs cardinality vs actual arguments # Create one child for each output defaultVariable=varOf(operands[0]) #defaultPeriod=operands[0].period for outname in script.outputs : if outname is None : rep.variable=script.outputs[None]%defaultVariable else : son=classes.scriptChild(rep,outname) son.variable=script.outputs[outname]%defaultVariable rep.outputs[outname]=son setattr(rep,outname,son) return rep
def macro(name, cobj, lobjects=[]): """ Define a CliMAF macro from a CliMAF compound object. Transform a Climaf object in a macro, replacing all datasets, and the objects of lobjects, by a dummy argument. Register it in dict cmacros, if name is not None Args: name (string) : the name you want to give to the macro; a Python function with the same name will be defined cobj (CliMAF object, or string) : any CliMAF object, usually the result of a series of operators, that you would like to repeat using other input datasets; alternatively, you can provide the macro formula as a string (when accustomed to the syntax) lobjects (list, optional): for expert use- a list of objects, which are sub-objects of cobject, and which should become arguments of the macro Returns: a macro; the returned value is usualy not used 'as is' : a python function is also defined in module cmacros and in main namespace, and you may use it in the same way as a CliMAF operator. All the datasets involved in ``cobj`` become arguments of the macro, which allows you to re-do the same computations and easily define objects similar to ``cobjs`` Example:: >>> # First use and combine CliMAF operators to get some interesting result using some dataset(s) >>> january_ta=ds(project='example',simulation='AMIPV6ALB2G',variable='ta',frequency='monthly',period='198001') >>> ta_europe=llbox(january_ta,latmin=40,latmax=60,lonmin=-15,lonmax=25) >>> ta_ezm=ccdo(ta_europe,operator='zonmean') >>> fig_ezm=plot(ta_ezm) >>> # >>> # Using this result as an example, define a macro named 'eu_cross_section', >>> # which arguments will be the datasets involved in this result >>> cmacro('eu_cross_section',fig_ezm) >>> # >>> # You can of course apply a macro to another dataset(s) (even here to a 2D variable) >>> pr=ds(project='example',simulation='AMIPV6ALB2G', variable='pr', frequency='monthly', period='198001') >>> pr_ezm=eu_cross_section(pr) >>> # >>> # All macros are registered in dictionary climaf.cmacro.cmacros, >>> # which is imported by climaf.api; you can list it by : >>> cmacros Note : macros are automatically saved in file ~/.climaf.macros, and can be edited See also much more explanations in the example at :download:`macro.py <../examples/macro.py>` """ if isinstance(cobj, str): s = cobj # Next line used for interpreting macros's CRS exec("from climaf.cmacro import cdummy; ARG=cdummy()", sys.modules['__main__'].__dict__) try: cobj = eval(cobj, sys.modules['__main__'].__dict__) except: # usually case of a CRS which project is not currently defined clogger.error( "Cannot interpret %s with the projects currently define" % s) return None #print "string %s was interpreted as %s"%(s,cobj) domatch = False for o in lobjects: domatch = domatch or cobj==o or \ ( isinstance(cobj,cobject) and cobj.buildcrs() == o.buildcrs()) if isinstance(cobj, cdataset) or isinstance(cobj, cdummy) or domatch: return cdummy() elif isinstance(cobj, ctree): rep = ctree(cobj.operator, cobj.script, *cobj.operands, **cobj.parameters) rep.operands = map(macro, [None for o in rep.operands], rep.operands) elif isinstance(cobj, scriptChild): rep = scriptChild(macro(None, cobj.father), cobj.varname) elif isinstance(cobj, cpage): rep = cpage([ map(macro, [None for fig in line], line) for line in cobj.fig_lines ], cobj.widths, cobj.heights) elif isinstance(cobj, cens): d = dict() for k, v in zip( cobj.keys(), map(macro, [None for o in cobj.values()], cobj.values())): d[k] = v rep = cens(d) elif cobj is None: return None else: clogger.error("Cannot yet handle object :%s", ` cobj `) rep = None if name and rep: cmacros[name] = rep doc = "A CliMAF macro, which text is " + ` rep ` defs='def %s(*args) :\n """%s"""\n return instantiate(cmacros["%s"],[ x for x in args])\n'\ % (name,doc,name) exec defs in globals() exec "from climaf.cmacro import %s" % name in sys.modules[ '__main__'].__dict__ clogger.debug("Macro %s has been declared" % name) return rep
def macro(name, cobj, lobjects=[]): """ Define a CliMAF macro from a CliMAF compound object. Transform a Climaf object in a macro, replacing all datasets, and the objects of lobjects, by a dummy argument. Register it in dict cmacros, if name is not None Args: name (string) : the name you want to give to the macro; a Python function with the same name will be defined cobj (CliMAF object, or string) : any CliMAF object, usually the result of a series of operators, that you would like to repeat using other input datasets; alternatively, you can provide the macro formula as a string (when accustomed to the syntax) lobjects (list, optional): for expert use- a list of objects, which are sub-objects of cobject, and which should become arguments of the macro Returns: a macro; the returned value is usualy not used 'as is' : a python function is also defined in module cmacros and in main namespace, and you may use it in the same way as a CliMAF operator. All the datasets involved in ``cobj`` become arguments of the macro, which allows you to re-do the same computations and easily define objects similar to ``cobjs`` Example:: >>> # First use and combine CliMAF operators to get some interesting result using some dataset(s) >>> january_ta=ds(project='example',simulation='AMIPV6ALB2G',variable='ta',frequency='monthly',period='198001') >>> ta_europe=llbox(january_ta,latmin=40,latmax=60,lonmin=-15,lonmax=25) >>> ta_ezm=ccdo(ta_europe,operator='zonmean') >>> fig_ezm=plot(ta_ezm) >>> # >>> # Using this result as an example, define a macro named 'eu_cross_section', >>> # which arguments will be the datasets involved in this result >>> cmacro('eu_cross_section',fig_ezm) >>> # >>> # You can of course apply a macro to another dataset(s) (even here to a 2D variable) >>> pr=ds(project='example',simulation='AMIPV6ALB2G', variable='pr', frequency='monthly', period='198001') >>> pr_ezm=eu_cross_section(pr) >>> # >>> # All macros are registered in dictionary climaf.cmacro.cmacros, >>> # which is imported by climaf.api; you can list it by : >>> cmacros Note : macros are automatically saved in file ~/.climaf.macros, and can be edited See also much more explanations in the example at :download:`macro.py <../examples/macro.py>` """ if isinstance(cobj, str): s = cobj # Next line used for interpreting macros's CRS exec ("from climaf.cmacro import cdummy; ARG=cdummy()", sys.modules["__main__"].__dict__) cobj = eval(cobj, sys.modules["__main__"].__dict__) # print "string %s was interpreted as %s"%(s,cobj) domatch = False for o in lobjects: domatch = domatch or cobj == o or (isinstance(cobj, cobject) and cobj.buildcrs() == o.buildcrs()) if isinstance(cobj, cdataset) or isinstance(cobj, cdummy) or domatch: return cdummy() elif isinstance(cobj, ctree): rep = ctree(cobj.operator, cobj.script, *cobj.operands, **cobj.parameters) rep.operands = map(macro, [None for o in rep.operands], rep.operands) elif isinstance(cobj, scriptChild): rep = scriptChild(cmacro(None, cobj.father), cobj.varname) elif isinstance(cobj, cpage): rep = cpage( cobj.widths, cobj.heights, [map(cmacro, [None for fig in line], line) for line in cobj.fig_lines], cobj.orientation, ) elif cobj is None: return None else: clogger.error("Cannot yet handle object :%s", ` cobj `) rep = None if name and rep: cmacros[name] = rep doc = "A CliMAF macro, which text is " + ` rep ` defs = 'def %s(*args) :\n """%s"""\n return instantiate(cmacros["%s"],[ x for x in args])\n' % ( name, doc, name, ) exec defs in globals() exec "from climaf.cmacro import %s" % name in sys.modules["__main__"].__dict__ clogger.debug("Macro %s has been declared" % name) return rep