def value(self): """ Return the value of the variable in a given workspace. By default this function will check the value in the workspace associated with the variable of in the workspace object provided as argument to the function call. If the variable has an associated workspace the workspace provided as argument will be ignored. Returns: The value of the workspace variable represented by an object of the corresponding python types. Raises: Exception: If the type of the workspace variable is not supported by the interface. """ if (self.ws): ws = self.ws if not ws: raise ValueError("WorkspaceVariable object need Workspace to determine value.") v = arts_api.get_variable_value(ws.ptr, self.ws_id, self.group_id) if not v.initialized: raise Exception("WorkspaceVariable " + self.name + " is uninitialized.") # TODO: Use group attribute here istead of lookup in group_names. # TODO: Move this to VariableValueStruct class if group_names[self.group_id] == "Index": return c.cast(v.ptr, c.POINTER(c.c_long))[0] if group_names[self.group_id] == "Numeric": return c.cast(v.ptr, c.POINTER(c.c_double))[0] if group_names[self.group_id] == "String": return (c.cast(v.ptr, c.c_char_p)).value.decode("utf8") if group_names[self.group_id] == "ArrayOfIndex": return [c.cast(v.ptr, c.POINTER(c.c_long))[i] for i in range(v.dimensions[0])] if group_names[self.group_id] == "Sparse": m = v.dimensions[0] n = v.dimensions[1] nnz = v.dimensions[2] data = np.ctypeslib.as_array(c.cast(v.ptr, c.POINTER(c.c_double)), (nnz,)) row_indices = np.ctypeslib.as_array(v.inner_ptr, (nnz,)) col_starts = np.ctypeslib.as_array(v.outer_ptr, (m + 1,)) return sp.sparse.csr_matrix((data, row_indices, col_starts), shape=(m,n)) if group_names[self.group_id] == "Agenda": return Agenda(v.ptr) try: self.update() a = np.asarray(self) return a except: raise Exception("Type of workspace variable is not supported by the interface.")
def arts_agenda(func): """ Parse python method as ARTS agenda This decorator can be used to define ARTS agendas using python function syntax. The function should have one arguments which is assumed to be a Workspace instance. All expressions inside the function must be calls to ARTS WSMs. The result is an Agenda object that can be used to copied into a named ARTS agenda Example: >>> @arts_agenda >>> def inversion_iterate_agenda(ws): >>> ws.x2artsStandard() >>> ws.atmfields_checkedCalc() >>> ws.atmgeom_checkedCalc() >>> ws.yCalc() >>> ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline) >>> ws.jacobianAdjustAfterIteration() >>> >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda) """ source = getsource(func) source = unindent(source) ast = parse(source) func_ast = ast.body[0] if not type(func_ast) == FunctionDef: raise Exception("ARTS agenda definition can only decorate function definiitons.") args = func_ast.args.args try: arg_name = func_ast.args.args[0].arg except: raise Exception("Agenda definition needs workspace arguments.") ws = Workspace(0) context = copy(func.__globals__) context.update({arg_name : ws}) # Add resolved non-local variables from closure. nls, _, _, _ = getclosurevars(func) context.update(nls) # # Helper functions # callback_body = [] def callback_make_fun(body): """ Helper function that creates a wrapper function around python code to be executed withing an ARTS agenda. """ m = Module(body) def callback(ptr): try: context[arg_name].ptr = ptr eval(compile(m , "<unknown>", 'exec'), context) except Exception as e: logger.error(r"Exception in Python callback:\n", e) context[arg_name].ptr = None callback_body = [] return callback def eval_argument(expr): """ Evaluate argument of workspace method call. """ if not hasattr(expr, "lineno"): setattr(expr, "lineno", 0) return eval(compile(Expression(expr), "<unknown>", 'eval'), context) # Create agenda a_ptr = arts_api.create_agenda(func.__name__.encode()) agenda = Agenda(a_ptr) illegal_statement_exception = Exception( "Agenda definitions may only contain calls to WSMs of the" "workspace argument " + arg_name + " or INCLUDE statements.") # # Here the body of the function definition is traversed. Cases # that are treated specieal are INCLUDE statements and calls # of workspace methods. Remaining statements are accumulated # in callback_body and then added to the agenda as a single callback. # for e in func_ast.body: if not isinstance(e, Expr): callback_body += [e] continue else: call = e.value if not isinstance(call, Call): callback_body += [e] continue # Include statement if type(call.func) == Name: if not call.func.id == "INCLUDE": callback_body += [e] else: args = [] for a in call.args: args.append(eval_argument(a)) include = Include(*args) if len(callback_body) > 0: agenda.add_callback(callback_make_fun(callback_body)) callback_body = [] arts_api.agenda_append(agenda.ptr, include.agenda.ptr) else: att = call.func.value if not att.id == arg_name: callback_body += [e] continue # Extract method name. name = call.func.attr # m is not a workspace method if not name in workspace_methods: callback_body += [e] continue # m is a workspace method. m = workspace_methods[name] args = [ws, m] for a in call.args: # Handle starred expression if type(a) == Starred: bs = eval_argument(a.value) for b in bs: args.append(b) continue args.append(eval_argument(a)) # Extract keyword arguments kwargs = dict() for k in call.keywords: kwargs[k.arg] = eval( compile(Expression(k.value), "<unknown>", 'eval'), context) # Add function to agenda if len(callback_body) > 0: agenda.add_callback(callback_make_fun(callback_body)) callback_body = [] agenda.add_method(*args, **kwargs) # Check if there's callback code left to add to the agenda. if len(callback_body) > 0: agenda.add_callback(callback_make_fun(callback_body)) callback_body = [] return agenda
def arts_agenda(func): """ Parse python method as ARTS agenda This decorator can be used to define ARTS agendas using python function syntax. The function should have one arguments which is assumed to be a Workspace instance. All expressions inside the function must be calls to ARTS WSMs. The result is an Agenda object that can be used to copied into a named ARTS agenda Example: >>> @arts_agenda >>> def inversion_iterate_agenda(ws): >>> ws.x2artsStandard() >>> ws.atmfields_checkedCalc() >>> ws.atmgeom_checkedCalc() >>> ws.yCalc() >>> ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline) >>> ws.jacobianAdjustAfterIteration() >>> >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda) """ source = getsource(func) ast = parse(source) func_ast = ast.body[0] if not type(func_ast) == FunctionDef: raise Exception( "ARTS agenda definition can only decorate function definiitons.") args = func_ast.args.args try: arg_name = func_ast.args.args[0].arg except: raise Exception("Agenda definition needs workspace arguments.") ws = Workspace() context = func.__globals__ context[arg_name] == ws # Create agenda a_ptr = arts_api.create_agenda(func.__name__.encode()) agenda = Agenda(a_ptr) for e in func_ast.body: if not type(e.value) == Call: raise Exception("Agendas may only contain call expressions.") # Extract workspace object. try: call = e.value att = call.func.value if not att.id == arg_name: raise (Exception( "Agenda definition may only contain call to WSMs of the " + "workspace argument " + arg_name + ".")) except: raise (Exception( "Agenda definition may only contain call to WSMs of the " + "workspace argument " + arg_name + ".")) # Extract method name. try: name = call.func.attr m = workspace_methods[name] if not type(m) == WorkspaceMethod: raise Exception(name + " is not a known WSM.") except: raise Exception(name + " is not a known WSM.") # Extract positional arguments args = [ws, m] for a in call.args: args.append( eval(compile(Expression(a), "<unknown>", 'eval'), context)) # Extract keyword arguments kwargs = dict() for k in call.keywords: kwargs[k.arg] = eval( compile(Expression(k.value), "<unknown>", 'eval'), context) # Add function to agenda agenda.add_method(*args, **kwargs) return agenda
def value(self): """ Return the value of the variable in a given workspace. By default this function will check the value in the workspace associated with the variable of in the workspace object provided as argument to the function call. If the variable has an associated workspace the workspace provided as argument will be ignored. Returns: The value of the workspace variable represented by an object of the corresponding python types. Raises: Exception: If the type of the workspace variable is not supported by the interface. """ if (self.ws): ws = self.ws if not ws: raise ValueError("WorkspaceVariable object need Workspace to determine value.") v = arts_api.get_variable_value(ws.ptr, self.ws_id, self.group_id) if not v.initialized: raise Exception("WorkspaceVariable " + self.name + " is uninitialized.") if self.group == "Index": return c.cast(v.ptr, c.POINTER(c.c_long))[0] elif self.group == "Numeric": return c.cast(v.ptr, c.POINTER(c.c_double))[0] elif self.group == "String": return (c.cast(v.ptr, c.c_char_p)).value.decode("utf8") elif self.group == "ArrayOfIndex": return [c.cast(v.ptr, c.POINTER(c.c_long))[i] for i in range(v.dimensions[0])] elif self.group == "Sparse": m = v.dimensions[0] n = v.dimensions[1] nnz = v.dimensions[2] if nnz == 0: return sp.sparse.csr_matrix(0) else: data = np.ctypeslib.as_array(c.cast(v.ptr, c.POINTER(c.c_double)), (nnz,)) row_indices = np.ctypeslib.as_array(v.inner_ptr, (nnz,)) col_starts = np.ctypeslib.as_array(v.outer_ptr, (m + 1,)) return sp.sparse.csr_matrix((data, row_indices, col_starts), shape=(m,n)) elif self.group == "Agenda": return Agenda(v.ptr) elif self.ndim: shape = [] size = 1 for i in range(self.ndim): shape.append(v.dimensions[i]) size *= v.dimensions[i] if size > 0: self.__array_interface__ = {"shape" : tuple(shape), "typestr" : "|f8", "data" : (v.ptr, False), "version" : 3} return np.asarray(self) else: return np.zeros(shape) else: try: return self.to_typhon() except: raise Exception("Type of workspace variable is not supported " + " by the interface.")
def arts_agenda(func): """ Parse python method as ARTS agenda This decorator can be used to define ARTS agendas using python function syntax. The function should have one arguments which is assumed to be a Workspace instance. All expressions inside the function must be calls to ARTS WSMs. The result is an Agenda object that can be used to copied into a named ARTS agenda Example: >>> @arts_agenda >>> def inversion_iterate_agenda(ws): >>> ws.x2artsStandard() >>> ws.atmfields_checkedCalc() >>> ws.atmgeom_checkedCalc() >>> ws.yCalc() >>> ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline) >>> ws.jacobianAdjustAfterIteration() >>> >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda) """ source = getsource(func) source = unindent(source) ast = parse(source) func_ast = ast.body[0] if not type(func_ast) == FunctionDef: raise Exception( "ARTS agenda definition can only decorate function definiitons.") args = func_ast.args.args try: arg_name = func_ast.args.args[0].arg except: raise Exception("Agenda definition needs workspace arguments.") ws = Workspace() context = copy(func.__globals__) context.update({arg_name: ws}) # Add resolved non-local variables from closure. nls, _, _, _ = getclosurevars(func) context.update(nls) def eval_argument(expr): if not hasattr(expr, "lineno"): setattr(expr, "lineno", 0) return eval(compile(Expression(expr), "<unknown>", 'eval'), context) # Create agenda a_ptr = arts_api.create_agenda(func.__name__.encode()) agenda = Agenda(a_ptr) illegal_statement_exception = Exception( "Agenda definitions may only contain calls to WSMs of the" "workspace argument " + arg_name + " or INCLUDE statements.") for e in func_ast.body: try: call = e.value except: raise Exception("Agendas may only contain call expressions.") # Include statement if type(call.func) == Name: if not call.func.id == "INCLUDE": raise illegal_statement_exception else: args = [] for a in call.args: args.append(eval_argument(a)) include = Include(*args) arts_api.agenda_append(agenda.ptr, include.agenda.ptr) else: att = call.func.value if not att.id == arg_name: raise illegal_statement_exception # Extract method name. try: name = call.func.attr m = workspace_methods[name] if not type(m) == WorkspaceMethod: raise Exception(name + " is not a known WSM.") except: raise Exception(name + " is not a known WSM.") # Extract positional arguments args = [ws, m] for a in call.args: # Handle starred expression if type(a) == Starred: bs = eval_argument(a.value) for b in bs: args.append(b) continue args.append(eval_argument(a)) # Extract keyword arguments kwargs = dict() for k in call.keywords: kwargs[k.arg] = eval( compile(Expression(k.value), "<unknown>", 'eval'), context) # Add function to agenda agenda.add_method(*args, **kwargs) return agenda