# coding: utf8
from pycropml.transpiler.codeGenerator import CodeGenerator
from pycropml.transpiler.rules.csharpRules import CsharpRules
from pycropml.transpiler.generators.docGenerator import DocGenerator
from pycropml.transpiler.pseudo_tree import Node
from pycropml.nameconvention import signature2, signature2_from_name
import os
from path import Path
from pycropml.transpiler.Parser import parser
from pycropml.transpiler.ast_transform import AstTransformer, transform_to_syntax_tree
from pycropml import code2nbk
from pycropml.transpiler.generators.csharpGenerator import CsharpGenerator, CsharpTrans,CsharpCompo
category = {"state":"s", "rate":"r", "auxiliary":"a", "exogenous":"ex"}
param_datatype ={"STRING":"String",
"INT":"Integer",
"DOUBLE":"Double",
"BOOLEAN":"Boolean",
"DATE":"Date",
"DATELIST":"ListDate",
"STRINGLIST": "ListString",
"DOUBLELIST": "ListDouble",
"INTLIST": "ListInteger",
"BOOLEANLIST": "ListBoolean",
"DOUBLEARRAY":"ArrayDouble",
"INTARRAY":"ArrayInteger"}
[docs]
def getdefault(x, typ):
df = "-1D"
if typ in dir(x):
if x.datatype=="DOUBLE" or x.datatype == "INT":
p = getattr(x, typ)
if p and p is not None:
df = p
return df
[docs]
class ApsimGenerator(CsharpGenerator):
""" This class contains the specific properties of
APSIM components and use the NodeVisitor to generate a csharp
code source from a well formed syntax tree based on BioMa structure.
"""
def __init__(self, tree=None, model=None, name=None, customer=''):
CsharpGenerator.__init__(self, tree, model, name)
self.tree = tree
self.model=model
self.name = name
self.customer = customer
self.indent_with=' '*4
self.doc= DocGenerator(model, '///','')
print(self.doc.header)
self.usingApsim()
[docs]
def usingApsim(self):
self.write("""using System;
using System.Collections.Generic;
using System.Linq;
using Models.Core;
""")
[docs]
def visit_function_definition(self, node):
self.newline(node)
#self.add_features(node)
self.funcname = node.name
if (not node.name.startswith("model_") and not node.name.startswith("init_")) :
self.write("/// <summary>")
self.newline(1)
self.write(f"/// ")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
params = [pa.name for pa in node.params]
if isinstance(node.block, list) and node.block[-1].type=="implicit_return" and "elements" in dir(node.block[-1].value):
tg = [elt.name for elt in node.block[-1].value.elements]
not_in_node = []
for elt in node.block[-1].value.elements:
if elt.name not in params:
not_in_node.append(elt)
not_in = [elt.name for elt in not_in_node]
self.not_in_node = not_in_node
self.not_in = not_in
self.tg = tg
if len(not_in_node) != 1:
self.write("public static void ")
self.write(" Main(") if node.name=="main" else self.write(" %s("%node.name)
else:
self.write("public static ")
self.visit_decl(not_in_node[0].pseudo_type)
self.write(" %s("%node.name)
tb = []
for i, pa in enumerate(node.params):
if pa.name in tg:
self.write("ref ")
tb.append(pa.name)
self.visit_decl(pa.pseudo_type)
self.write(" %s"%pa.name)
if i!= (len(node.params)-1):
self.write(', ')
for elt in node.block[-1].value.elements:
if elt.name not in tb and elt.name not in not_in:
self.write(", out ")
self.visit_decl(elt.pseudo_type)
self.write(f' {elt.name}')
else:
self.write("public static ")
self.visit_decl(node.return_type) if node.return_type else self.write("void")
self.write(" Main(") if node.name=="main" else self.write(" %s("%node.name)
for i, pa in enumerate(node.params):
self.visit_decl(pa.pseudo_type)
self.write(" %s"%pa.name)
if i!= (len(node.params)-1):
self.write(', ')
self.write(')')
self.newline(node)
self.write('{')
self.newline(node)
else:
name = signature2_from_name(self.model.name)
cpnent = signature2_from_name(self.name)
if self.node_param and not node.name.startswith("init_") :
for arg in self.node_param:
self.newline(extra=1)
self.write ('private ')
self.visit_decl(arg.pseudo_type)
self.write(" _")
self.write(arg.name)
self.write(";")
#self.generator.private(self.node_param)
self.newline(node)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Gets and sets the {arg.description}")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f'[Description("{arg.description}")] ')
self.newline(1)
self.write(f'[Units("{arg.unit}")] ')
self.newline(1)
self.write(f'//[Crop2ML(datatype="{arg.datatype}", min={arg.mini}, max={arg.maxi}, default={arg.default}, parametercategory={arg.category}, inputtype="parameter")] ')
self.newline(1)
self.write("public ")
self.visit_decl(arg.pseudo_type)
self.write(' ' +arg.name)
self.write(self.public_properties%(arg.name,arg.name))
self.newline(extra=1)
self.write(self.constructor%(name,name)) if not node.name.startswith("init_") else ""
self.newline(node)
if node.name.startswith("init_"):
self.write("/// <summary>")
self.newline(1)
self.write(f"/// initialization of the {name} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
else:
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Algorithm of the {name} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write("public void ")
self.write(" CalculateModel(") if not node.name.startswith("init_") else self.write("Init(")
self.write('%sState s, %sState s1, %sRate r, %sAuxiliary a, %sExogenous ex)'%(cpnent, cpnent,cpnent, cpnent, cpnent))
self.newline(node)
self.write('{')
self.newline(node)
if not node.name.startswith("init_"):
pass
self.indentation += 1
for arg in self.add_features(node) :
if "feat" in dir(arg):
if arg.feat in ["IN","INOUT"] :
self.newline(node)
if self.model and arg.name not in self.newmodparam:
if not node.name.startswith("init_") :
if arg.name not in self.privates:
self.visit_decl(arg.pseudo_type)
self.write(" ")
self.write(arg.name)
if arg.name in self.states and not arg.name.endswith("_t1") :
self.write(" = s.%s"%arg.name)
elif arg.name.endswith("_t1") and arg.name in self.states:
self.write(" = s1.%s"%arg.name[:-3])
elif arg.name in self.rates:
self.write(" = r.%s"%arg.name)
elif arg.name in self.auxiliary:
self.write(" = a.%s"%arg.name)
elif arg.name in self.exogenous:
self.write(" = ex.%s"%arg.name)
self.write(";")
else:
if arg.name in self.privates:
self.visit_decl(arg.pseudo_type)
self.write(" ")
self.write(f"{arg.name}_loc = {arg.name}")
else:
self.visit_decl(arg.pseudo_type)
self.write(" ")
self.write(arg.name)
if arg.name in self.exogenous:
self.write(" = ex.%s"%arg.name)
elif arg.pseudo_type[0] =="list":
self.write(" = new List<%s>()"%(self.types[arg.pseudo_type[1]]))
elif arg.pseudo_type[0] =="array":
if not arg.elts:
self.write(" = null;")
else:
self.write(" = new %s[%s]"%(self.types[arg.pseudo_type[1]], arg.elts[0].value if "value" in dir(arg.elts[0]) else arg.elts[0].name))
self.write(";")
self.indentation -= 1
self.body(node.block)
self.newline(node)
self.visit_return(node)
self.newline(node)
self.indentation -= 1
self.write('}')
self.newline(node)
[docs]
def open(self, node):
self.newline(node)
self.write("{")
self.newline(node)
self.indentation += 1
[docs]
def close(self, node):
self.newline(node)
self.indentation -= 1
self.write("}")
[docs]
def visit_module(self, node):
self.write("namespace Models.Crop2ML;")
self.newline(extra=1)
self.write("/// <summary>")
self.newline(node)
self.write(self.doc.header)
self.newline(node)
self.write(self.doc.desc)
self.newline(node)
self.write(self.doc.inputs_doc)
self.newline(node)
self.write(self.doc.outputs_doc)
self.newline(node)
self.write("/// </summary>")
self.newline(node)
self.write("public class %s"%(signature2_from_name(self.model.name)))
self.open(node)
self.visit(node.body)
self.close(node) #class
[docs]
class ApsimTrans(CsharpTrans):
""" This class used to generates states, rates, auxiliary and exogenous classes
for Bioma.
"""
def __init__(self, models, customer=''):
self.models = models
self.customer=customer
CsharpTrans.__init__(self, self.models)
[docs]
def using(self):
self.write("""using System;
using System.Collections.Generic;
using Models.Core;
""")
[docs]
def open(self, node):
self.newline(node)
self.write("{")
self.newline(node)
self.indentation += 1
[docs]
def close(self, node):
self.newline(node)
self.indentation -= 1
self.write("}")
[docs]
def copyConstr(self, nodes, typ):
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Copy constructor")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f'/// <param name="toCopy"></param>')
self.newline(1)
self.write(f'/// <param name="copyAll"></param>')
self.newline(1)
self.write('public %s(%s toCopy, bool copyAll) // copy constructor '%(signature2_from_name(typ), signature2_from_name(typ)))
self.open(nodes)
self.write('if (copyAll)')
self.open(nodes)
self.indentation -= 2
self.copyconstructor(nodes)
self.close(nodes)
self.close(nodes)
self.newline(extra = 1)
[docs]
def constr(self, node, typ):
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Constructor {signature2_from_name(typ)} domain class")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write('public %s() { }'%signature2_from_name(typ))
self.newline(1)
[docs]
def generate(self, nodes, typ, name):
self.using()
self.write("namespace Models.Crop2ML;")
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// {nodes[0].category} variables class of the {name} component") if len(nodes)>0 else ""
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write("public class %s"%signature2_from_name(typ))
self.newline()
self.write("{")
self.indentation += 1
self.newline()
self.private(nodes)
self.newline()
self.constr(nodes, typ) ########### constructor
self.newline(extra = 1)
self.copyConstr(nodes, typ)###### copy constructor
self.getset(nodes)
self.newline(extra=1)
self.indentation -= 1
self.newline()
self.write("}")
[docs]
def getset(self,node, wrap=False):
for arg in node:
self.newline(node)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Gets and sets the {arg.description}")
self.newline(1)
self.write("/// </summary>")
self.newline(node)
self.write(f'[Description("{arg.description}")] ')
self.newline(1)
self.write(f'[Units("{arg.unit}")] ')
self.newline(1)
self.write("public ")
if isinstance(arg.pseudo_type, list):
if arg.pseudo_type[0] in ("list", "array"):
self.visit_decl(arg.pseudo_type)
self.write(' ' + arg.name)
else:
self.visit_decl(arg.pseudo_type)
self.write(' ' +arg.name)
self.write(self.public_properties%(arg.name,arg.name)) if wrap==False else self.write(self.public_properties_wrap%(arg.cat,arg.name))
self.newline(extra=1)
[docs]
def to_struct_apsim(models, rep, name):
generator = ApsimTrans(models)
generator.model2Node()
def createdc(states, catvar):
generator.result = []
generator.generate(states, "%s%s"%(name,catvar), name)
z= ''.join(generator.result)
filename = Path(os.path.join(rep, "%s%s.cs"%(name, catvar)))
with open(filename, "wb") as tg_file:
tg_file.write(z.encode('utf-8'))
states = generator.node_states
createdc(states,"State")
rates = generator.node_rates
createdc(rates,"Rate")
auxiliary = generator.node_auxiliary
createdc(auxiliary,"Auxiliary")
exogenous = generator.node_exogenous
createdc(exogenous,"Exogenous")
''' Csharp composite'''
[docs]
class ApsimCompo(CsharpCompo):
""" This class used to generates states, rates, auxiliary and exogenous classes
for C# languages.
"""
def __init__(self, tree=None, model=None, name=None, customer=""):
CsharpCompo.__init__(self, tree, model, name)
self.model=model
self.tree = tree
self.name = name
self.customer=customer
[docs]
def usingApsim(self):
self.write("""using Models.Core;
using Models.Utilities;
using System;
namespace Models.Crop2ML;
""")
[docs]
def constructor(self, node):
self.write("public %sComponent() {}"%signature2_from_name(self.model.name))
[docs]
def copy_Constructor(self, node):
self.write('public %sComponent(%sComponent toCopy): this() // copy constructor '%(signature2_from_name(self.model.name), signature2_from_name(self.model.name)))
self.open(node)
self.indentation -= 1
self.copyconstructor(self.node_param)
self.indentation -= 1
self.close(node)
[docs]
def visit_module(self, node):
self.usingApsim()
self.newline(node)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// {self.model.name} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f"public class {signature2_from_name(self.model.name)}Component ")
self.open(node)
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// constructor of {signature2_from_name(self.model.name)} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.constructor(node)
self.newline(extra=1)
self.createModelInstances()
self.newline(extra=1)
self.getsetParam(node,self.node_param)
self.newline(extra=1)
self.visit(node.body)
self.newline(extra=1)
self.newline(node)
if not self.model.initialization:
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Initialization of {signature2_from_name(self.model.name)} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.initcomposition(node)
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// constructor copy of {signature2_from_name(self.model.name)} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write('/// <param name="toCopy"></param>')
self.newline(1)
self.copy_Constructor(self.node_param)
self.newline(node)
self.close(node)
[docs]
def initcomposition(self, node):
name = signature2_from_name(self.model.name)
self.write(f"public void Init({name}State s, {name}State s1, {name}Rate r, {name}Auxiliary a, {name}Exogenous ex)")
self.open(node)
self.newline(1)
for m in self.model.ord:
for mod in self.model.model:
if m == mod.name and "initialization" in dir(mod) and mod.initialization:
self.write(f"_{signature2_from_name(m)}.Init(s, s1, r, a, ex);")
self.newline(1)
self.close(node)
[docs]
def getsetParam(self,node, pa) :
for arg in pa :
if arg.name in self.parameters:
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Gets and sets the {arg.description}")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f'[Description("{arg.description}")] ')
self.newline(1)
self.write(f'[Units("{arg.unit}")] ')
self.newline(1)
self.write("public ")
self.visit_decl(arg.pseudo_type)
self.write(' ' +arg.name)
self.open(node)
self.write("get")
self.open(node)
self.write(" return _%s.%s; "%(signature2_from_name(self.get_mo(arg.name)[0]["modu"]),self.get_mo(arg.name)[0]["var"]))
self.close(node)
self.newline(1)
self.write("set")
self.open(node)
self.setCompo(arg.name)
self.close(node)
self.close(node)
self.newline(extra=1)
[docs]
def visit_function_definition(self, node):
name = signature2_from_name(self.model.name)
cpnt = signature2_from_name(self.name)
if node.name.startswith("model"):
self.newline(1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Algorithm of {signature2_from_name(self.model.name)} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f"public void CalculateModel({cpnt}State s,{cpnt}State s1,{cpnt}Rate r,{cpnt}Auxiliary a,{cpnt}Exogenous ex)")
else:
self.write("/// <summary>")
self.newline(1)
self.write(f"/// initialization of the {name} component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f"public void Init({self.name}State s,{self.name}State s1,{self.name}Rate r,{self.name}Auxiliary a,{self.name}Exogenous ex)")
self.init=True
self.open(node)
self.visit(node.block)
self.close(node)
self.newline(extra=1)
[docs]
def visit_implicit_return(self, node):
self.newline(node)
[docs]
def wrapper(self):
name = signature2_from_name(self.model.name)
self.write("""using APSIM.Shared.Utilities;
using Models.Climate;
using Models.Core;
using Models.Interfaces;
using Models.PMF;
using Models.Soils;
using Models.Surface;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Models.Crop2ML;""")
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// This class encapsulates the {name}Component")
self.newline(1)
self.write("/// </summary>")
self.write("""
[Serializable]
[PresenterName("UserInterface.Presenters.PropertyPresenter")]
[ViewName("UserInterface.Views.PropertyView")]
[ValidParent(ParentType = typeof(Zone))]
""")
self.write("class %sWrapper : Model"%name)
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("[Link] Clock clock = null;")
self.newline(1)
self.write("//[Link] Weather weather = null; // other links")
self.newline(extra=1)
self.privateWrap()
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// The constructor of the Wrapper of the {name}Component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.constrWrap()
self.newline(extra=1)
self.outputWrap()
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// The Constructor copy of the wrapper of the {name}Component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f'/// <param name="toCopy"></param>')
self.newline(1)
self.write(f'/// <param name="copyAll"></param>')
self.newline(1)
self.copyconstrWrap()
self.newline(extra=1)
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// The Initialization method of the wrapper of the {signature2_from_name(self.model.name)}Component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.initWrap()
self.newline(extra=1)
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Load parameters of the wrapper of the {signature2_from_name(self.model.name)}Component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.loadParamWrap()
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// Set exogenous variables of the wrapper of the {signature2_from_name(self.model.name)}Component")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.setexogenousWrap()
self.newline(extra=1)
self.estimateWrap()
self.newline(extra=1)
self.indentation -= 1
self.write("}")
[docs]
def estimateWrap(self):
self.write('[EventSubscribe("Crop2MLProcess")]')
self.newline(1)
self.write("public void CalculateModel(object sender, EventArgs e)")
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("if (clock.Today == clock.StartDate)")
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("Init();")
self.newline(1)
self.indentation -= 1
self.newline(1)
self.write("}")
self.newline(1)
self.write("setExogenous();")
self.newline(1)
self.write("%sComponent.CalculateModel(s,s1, r, a, ex);"%(self.model.name.lower()))
self.newline(1)
self.indentation -= 1
self.write("}")
[docs]
def outputWrap(self):
out = [out.name for out in self.model.outputs]
tabout=[]
nodes =self.node_states+self.node_rates+self.node_auxiliary + self.node_exogenous
for node in nodes :
if node.name in out and node.name not in tabout:
self.newline(extra=1)
self.write("/// <summary>")
self.newline(1)
self.write(f"/// The get method of the {node.description} output variable")
self.newline(1)
self.write("/// </summary>")
self.newline(1)
self.write(f'[Description("{node.description}")]')
self.newline(1)
self.write(f'[Units("{node.unit}")]')
self.getset([node], True)
tabout.append(node.name)
[docs]
def constrWrap(self):
name = signature2_from_name(self.model.name)
self.write("public %sWrapper()"%(name))
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("s = new %sState();"%(name))
self.newline(1)
self.write("s1 = new %sState();"%(name))
self.newline(1)
self.write("r = new %sRate();"%(name))
self.newline(1)
self.write("a = new %sAuxiliary();"%(name))
self.newline(1)
self.write("ex = new %sExogenous();"%(name))
self.newline(1)
self.write("%sComponent = new %sComponent();"%(name.lower(), name))
self.newline(1)
self.indentation -= 1
self.write("}")
[docs]
def copyconstrWrap(self):
name = signature2_from_name(self.model.name)
self.write("public %sWrapper(%sWrapper toCopy, bool copyAll) "%(name,name))
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("s = (toCopy.s != null) ? new %sState(toCopy.s, copyAll) : null;"%(name))
self.newline(1)
self.newline(1)
self.write("r = (toCopy.r != null) ? new %sRate(toCopy.r, copyAll) : null;"%(name))
self.newline(1)
self.write("a = (toCopy.a != null) ? new %sAuxiliary(toCopy.a, copyAll) : null;"%(name))
self.newline(1)
self.write("ex = (toCopy.ex != null) ? new %sExogenous(toCopy.ex, copyAll) : null;"%(name))
self.newline(1)
self.write("if (copyAll)")
self.newline(1)
self.write("{")
self.newline(1)
self.indentation += 1
self.write("%sComponent = (toCopy.%sComponent != null) ? new %sComponent(toCopy.%sComponent) : null;"%(name.lower(),name.lower(),name,name.lower()))
self.newline(1)
self.indentation -= 1
self.write("}")
self.newline(1)
self.indentation -= 1
self.write("}")
[docs]
class ApsimInterface(CsharpCompo):
""" This class used to the component interface for APSIM platform.
"""
def __init__(self, tree=None, model=None, name=None, customer=""):
CsharpCompo.__init__(self, tree, model, name)
self.model=model
self.tree = tree
self.name = name
self.customer=customer
[docs]
def to_wrapper_apsim(models, rep, name, customer = ''):
generator = ApsimCompo(model = models, customer=customer)
generator.model2Node()
generator.wrapper()
z= ''.join(generator.result)
filename = Path(os.path.join(rep, "%sWrapper.cs"%name))
with open(filename, "wb") as tg2_file:
tg2_file.write(z.encode('utf-8'))
return 0