From 4a7f97f2272942f6ccd53fb5ba7b8e37ae621e80 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 3 Jan 2025 17:02:31 -0700 Subject: [PATCH] [sourcegen] Add vector> handling Also fix issues caused by differences of doxygen and Cantera whitespace conventions in argument lists and add recipes for functions used in googletests. --- .../sourcegen/sourcegen/_data/ctkin_auto.yaml | 3 +- .../sourcegen/sourcegen/_data/ctsol_auto.yaml | 5 +- .../sourcegen/_data/ctthermo_auto.yaml | 13 +++++ .../sourcegen/_data/cttrans_auto.yaml | 1 + .../sourcegen/sourcegen/_dataclasses.py | 2 +- .../sourcegen/clib/_CLibSourceGenerator.py | 52 ++++++++++++++----- .../sourcegen/sourcegen/clib/_Config.py | 5 +- .../sourcegen/sourcegen/clib/config.yaml | 4 +- 8 files changed, 66 insertions(+), 19 deletions(-) diff --git a/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml index 5c17cf2f24..2a1c6e2ad9 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctkin_auto.yaml @@ -10,7 +10,8 @@ parents: [] # List of parent classes derived: [] # List of specializations recipes: - name: nReactions -# - name: getFwdRatesOfProgress +- name: kineticsType +- name: getFwdRatesOfProgress - name: del what: noop brief: Destructor; required by some APIs although object is managed by Solution. diff --git a/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml index 5edd1056b7..3e7fed73a3 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctsol_auto.yaml @@ -12,7 +12,7 @@ recipes: - name: newSolution implements: newSolution(const string&, const string&, const string&) uses: [thermo, kinetics, transport] -- name: newInterface # currently disabled in CLib's config.yaml +- name: newInterface implements: newInterface(const string&, const string&, const vector>&) uses: [thermo, kinetics] @@ -23,10 +23,11 @@ recipes: - name: thermo - name: kinetics - name: transport -- name: setTransport +- name: setTransport # currently disabled in CLib's config.yaml - name: nAdjacent - name: adjacent implements: Solution::adjacent(size_t) uses: [thermo, kinetics, transport] what: constructor # registers object in CLib storage +# - name: adjacentName - name: cabinetSize diff --git a/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml b/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml index ddb6903d64..a5cb8fafd9 100644 --- a/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/ctthermo_auto.yaml @@ -36,6 +36,19 @@ recipes: implements: Phase::setMoleFractionsByName(const string&) - name: setMassFractionsByName implements: Phase::setMassFractionsByName(const string&) +- name: enthalpy_mole +- name: enthalpy_mass +- name: entropy_mole +- name: entropy_mass +- name: intEnergy_mole +- name: intEnergy_mass +- name: cp_mole +- name: cp_mass +- name: getPartialMolarEnthalpies +- name: getPartialMolarEntropies +- name: getPartialMolarIntEnergies +- name: getPartialMolarCp +- name: getPartialMolarVolumes - name: equilibrate implements: ThermoPhase::equilibrate(const string&, const string&, double, int, int, int) diff --git a/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml b/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml index c881ad2b88..671e68ca12 100644 --- a/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml +++ b/interfaces/sourcegen/sourcegen/_data/cttrans_auto.yaml @@ -12,6 +12,7 @@ recipes: - name: transportModel - name: viscosity - name: thermalConductivity +- name: getMixDiffCoeffs - name: del what: noop brief: Destructor; required by some APIs although object is managed by Solution. diff --git a/interfaces/sourcegen/sourcegen/_dataclasses.py b/interfaces/sourcegen/sourcegen/_dataclasses.py index 474e3d36ce..132e164d8e 100644 --- a/interfaces/sourcegen/sourcegen/_dataclasses.py +++ b/interfaces/sourcegen/sourcegen/_dataclasses.py @@ -50,7 +50,7 @@ def from_xml(cls, param: str) -> 'Param': Note: Converts from doxygen style to simplified C++ whitespace notation. """ - for rep in [(" &", "& "), ("< ", "<"), (" >", ">")]: + for rep in [(" &", "& "), ("< ", "<"), (" >", ">"), (" *", "* ")]: param = param.replace(*rep) return cls.from_str(param.strip()) diff --git a/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py b/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py index 86268a2f43..0f62de860c 100644 --- a/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py +++ b/interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py @@ -21,6 +21,8 @@ class CLibSourceGenerator(SourceGenerator): """The SourceGenerator for generating CLib.""" + _clib_bases: list[str] = None #: list of bases provided via YAML configurations + def __init__(self, out_dir: str, config: dict, templates: dict): self._out_dir = out_dir or None if self._out_dir is not None: @@ -126,11 +128,11 @@ def _prop_crosswalk(self, par_list: list[Param]) -> list[Param]: for par in par_list: what = par.p_type if what in self._config.prop_type_crosswalk: - if "vector" in what: + if "vector<" in what: params.append( Param("int", f"{par.name}Len", f"Length of vector reserved for {par.name}.", "in")) - elif what.endswith("*const"): + elif what.endswith("* const") or what.endswith("double*"): direction = "in" if what.startswith("const") else "out" params.append( Param("int", f"{par.name}Len", @@ -140,8 +142,18 @@ def _prop_crosswalk(self, par_list: list[Param]) -> list[Param]: elif "shared_ptr" in what: handle = self._handle_crosswalk( what, self._config.prop_type_crosswalk, []) - description = f"Integer handle to {handle} object. {par.description}" - params.append(Param("int", par.name, description, par.direction)) + if "vector<" in what: + params.append( + Param("int", f"{par.name}Len", + f"Length of array reserved for {par.name}.", "in")) + description = f"Memory holding {handle} objects. " + description += par.description + params.append(Param("const int*", par.name, description.strip())) + else: + description = f"Integer handle to {handle} object. " + description += par.description + params.append( + Param("int", par.name, description.strip(), par.direction)) else: _LOGGER.critical(f"Failed crosswalk for argument type {what!r}.") sys.exit(1) @@ -211,7 +223,17 @@ def shared_object(cxx_type): if check_array: # Need to handle cross-walked parameter with length information c_prev = c_args[c_ix-1].name - if "vector" in cxx_type: + if "vector> + cxx_type = cxx_type.lstrip("const ").rstrip("&") + lines.extend([ + f"{cxx_type} {c_name}_;", + f"for (int i = 0; i < {c_prev}; i++) {{", + f" {c_name}_.push_back({base}Cabinet::at({c_name}[i]));", + "}", + ]) + args.append(f"{c_name}_") + elif "vector" in cxx_type: # Example: vector par_(par, par + parLen); cxx_type = cxx_type.rstrip("&") lines.append( @@ -303,7 +325,7 @@ def _scaffold_body(self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]: template = loader.from_string(self._templates["clib-method"]) elif recipe.what == "reserved": - args["cabinets"] = [kk for kk in self._config.includes.keys() if kk] + args["cabinets"] = [kk for kk in self._clib_bases if kk] template = loader.from_string( self._templates[f"clib-reserved-{recipe.name}-cpp"]) @@ -393,7 +415,9 @@ def merge_params(implements, cxx_func: CFunc) -> tuple[list[Param], int]: recipe.what = "getter" elif "void" in cxx_func.ret_type and cxx_arglen == 1: p_type = cxx_func.arglist[0].p_type - if "*" in p_type and not p_type.startswith("const"): + if cxx_func.name.startswith("get"): + recipe.what = "getter" + elif "*" in p_type and not p_type.startswith("const"): recipe.what = "getter" # getter assigns to existing array else: recipe.what = "setter" @@ -483,7 +507,7 @@ def _write_implementation(self, headers: HeaderFile) -> None: if not headers.base: # main CLib file receives references to all cabinets - other = [kk for kk in self._config.includes.keys() if kk] + other = [kk for kk in self._clib_bases if kk] includes = [] for obj in [headers.base] + list(other): includes += self._config.includes[obj] @@ -504,13 +528,17 @@ def _write_implementation(self, headers: HeaderFile) -> None: def resolve_tags(self, headers_files: list[HeaderFile], quiet: bool=True): """Resolve doxygen tags.""" - def get_bases() -> list[str]: + def get_bases() -> tuple[list[str], list[str]]: bases = set() + classes = set() for headers in headers_files: + bases |= {headers.base} for recipe in headers.recipes: - bases |= set([recipe.base] + recipe.parents) - return list(bases) - self._doxygen_tags = TagFileParser(get_bases()) + classes |= set([recipe.base] + recipe.parents + recipe.derived) + return sorted(bases), sorted(classes) + + self._clib_bases, classes = get_bases() + self._doxygen_tags = TagFileParser(classes) for headers in headers_files: if not quiet: diff --git a/interfaces/sourcegen/sourcegen/clib/_Config.py b/interfaces/sourcegen/sourcegen/clib/_Config.py index 8838e4b1c0..10173dfcdf 100644 --- a/interfaces/sourcegen/sourcegen/clib/_Config.py +++ b/interfaces/sourcegen/sourcegen/clib/_Config.py @@ -28,8 +28,9 @@ class Config: "size_t": "int", "double": "double", "const double": "double", - "double *const": "double*", - "const double *const": "const double*", + "double*": "double*", + "double* const": "double*", + "const double* const": "const double*", "const string&": "const char*", "shared_ptr": "int", "const shared_ptr": "int", diff --git a/interfaces/sourcegen/sourcegen/clib/config.yaml b/interfaces/sourcegen/sourcegen/clib/config.yaml index 10cdb51288..6dbe2782a9 100644 --- a/interfaces/sourcegen/sourcegen/clib/config.yaml +++ b/interfaces/sourcegen/sourcegen/clib/config.yaml @@ -8,7 +8,7 @@ ignore_files: [] # Ignore these specific functions: ignore_funcs: - ctsol_auto.yaml: [newInterface, setTransport] + ctsol_auto.yaml: [setTransport] # Cabinets with associated includes includes: @@ -16,6 +16,8 @@ includes: - cantera/base/global.h Solution: - cantera/base/Solution.h + Interface: + - cantera/base/Interface.h ThermoPhase: - cantera/thermo/ThermoFactory.h Kinetics: