Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Begin coding data model, object classes. #7

Open
8 of 13 tasks
rburghol opened this issue Jul 18, 2022 · 3 comments
Open
8 of 13 tasks

Begin coding data model, object classes. #7

rburghol opened this issue Jul 18, 2022 · 3 comments
Assignees

Comments

@rburghol
Copy link

rburghol commented Jul 18, 2022

Overview

Note that the previous implementation was fully object oriented, though since hsp2 uses the numba compiler to create faster execution we will make a hybrid to leverage the speed benefits. will be instantiated to process model inputs from JSON (or from UCI if we support that).

  • Object Orientation - the current implementation uses the term classes in 2 ways.
    1. Handlers: the handlers that load dynamic model operations elements (parsed from JSON or created manually), and convert into sets of ordered and linked executable model opcodes.
    2. Conceptually: as the numba compiler make it difficult (impossible?) to pass in dynamic lists of classes of a multiple types. Thus, classes are simulated via the functions that are called to execute them, but do not have any actual type of class in the numba code.
  • Key primitive objects
    • ModelObject: the base class type, can have inputs, and component/child objects, but does not possess any calculations of its own.
      • Inputs: Objects can have links to any state variable via inputs.
        • if a variable is named as an input without a full state path, the model class functions search in this order:
          • children; grand-children are not searched, however, if a direct child has an established input of a matching named variable from a grandchild, this link will be returned.
          • siblings
          • parent
          • grandparent
    • Equation: equation operations amongst data inputs.
    • DataMatrix: provide 1-D and 2-D list lookups with exact key matching or multiple modes of interpolation
    • ModelLinkage: a specific link from one state variable to another
    • ModelBroadcast: A general data sharing/linkage framework that establishes data "channels" with 1 or more values in it broadCastObject #36
      • broadcast objects: allows objects to make data available to any other objects, and register objects that allow many objects to funnel data into a variety of variable slots, additively i.e. if 3 objects push data to a single register, the state value of the rgister at the end of a timestep is val1 + val2 + val3
    • SimTimer
  • Execution of model elements
    • Time Step: A model time-step is split into 3 possible phases pre-step, step, and post-step
      • These are defined in utilities_specl.py as pre_step_model(), step_model(), and post_step_model()
      • To be enabled for a given class, a step_[class name] function must be defined in the class code file, and added to the (pre_,post_)step_model() function
        • These functions are all optional for object classes. But if defined for an object class, they need to be added in the appropriate function.
        • While most activity takes place in the step() function, certain things benefit from happening in the preStep() and postStep() phases.
          • preStep() Example: ModelRegister classes can act as accumulators of data from multiple senders in a single time-step. For a register, it is desirable to reset to zero at the beginning of each timestep, thus, the reset to zero happens in pre_step_register().
    • Op Codes/Tokens
  • Functions for each class type may defined for operations code lines (opcode) for
    • Object attributes will be stored in opcodes, i.e., opcodes["/SPECL/Equations/RCHRES_001/Qlocal"] = "sin(step)"
    • Object result at time step will be stored in ts[/path_to_object/property_name][step]
  • Functional code
  • Data Model Each object has:
    • state - in hsp2 these are often simply held as variable values that exist only within the context of the function that is being executed. The ts dictionary also has state, but presumably that state is only for things that are being logged, and in the interest of data storage, we may not want every single item to be logged, especially as sub-components grow larger. Thus it is theoretically possible that something is important enouh to be stored in state, but not important enough to be logged every time step?
    • log - in hsp2 these are stored in a variable called ts. ts can contain data paths copied from the hdf5 /TIMESERIES/ and /RESULTS/
    • attributes (static) - in base hsp2, these are stored in a variable called ui (named thusly because they are an excerpt from uci)
    • The hdf5 library can produce graphs of the relationships inside the hdf5 data structure itself, which can be huge benefits. See here
    • hdf5 info: https://cgns.github.io/CGNS_docs_current/hdf5/summary.html
  • since ts essentially provides state for all objects referenceable via unique paths, the state function of what an object framework provides is satisfied.
  • The tricky elements will be to see how these work
  • numba does in fact have some object support, using @jitclass
  • So, @jitclass might be useable.
    • However, it seems that @jitclass object cannot be passed as arguments, so we would need to instantiate the objects inside of the specl routine (or whatever operational entities base we use).
    • This could be somewhat time-consuming as it would need to happen at the beginning of each module that uses specl/entities so would need to test.

Tasks

Priority objects/method/functions to develop:

  • Base Class modelObject: base class for object that has logging capabilities #37
  • SimTimer
  • DataMatrix runtime iteration controllers #45
  • Equation ModelLinkage: multi purpose method of linking local and remote data #44
  • modelSubObject: base class for non-standalone object, has less plumbing, no logging facilities of it's own -- this may not be needed, as all objects are slim in this implementation?
  • dataMatrix #26
    • inherits ModelObject
  • Equation #25
    • inherits ModelObject
  • Statistic/Stack #63
    • inherits ModelObject
  • Constant
    • not an object, just a numeric value on the class
  • AlphanumericConstant
    • not an object, just a numeric value on the class
  • FlowBy / FlowByLookup (find real name here)
    • inherits modelSubObject
    • could be defined by primitives Equation, dataMatrix and alphaconstant
      • equation is flowby equation
      • conditional flowby variable option, alphaConstant, i.e., flowby_eq or Alt if Alt <,>,=,<=,>=, ex: "10% of Qin or 5cfs whichever is lower"
      • dataMatrix = alternate to equation based, lookup list based, still has the conditional flowby option
    • If defined as primitives we can simply configure it to export as a tree of primitives from VAHydro
  • broadCastObject #36
    • These can be represented as simple "registers" in the hdf5/ts array, with specific hub addresses (resolved to the parent, or the selfs own path in the hdf5)
    • on preStep(), set these registers to zero: ts["/BROADCASTS/RCHRES_0001/hydroObject/ps_mgd"][step]
    • anything that sends on the broadcast simply performs an add to the register, i.e.: ts["/BROADCASTS/RCHRES_0001/hydroObject/ps_mgd"][step] += ts["/OBJECTS/OBJECT0001/ps_local_mgd"][step]
  • modelContainer
    • inherits modelObject
    • has plumbing to contain other full model objects and pass runtime information to them.
@jdkleiner
Copy link
Member

jdkleiner commented Aug 3, 2022

Spent some time locating the current php versions of these object classes

class modelObject {}
class modelSubObject extends modelObject {}
class broadCastObject extends modelSubObject {}
class dataMatrix extends modelSubObject {}
class modelContainer extends modelObject {}

@jdkleiner
Copy link
Member

See example for setting up objects in python: https://github.com/HARPgroup/pydro-tools/tree/main/OOP

@rburghol
Copy link
Author

rburghol commented Nov 17, 2022

Example:

  • Equations:
    • available_mgd = (Qintake - flowby) / 1.547
    • Qintake = Qreach * 1.0
    • flowby = 0.9 * Qintake`
  • hdf5 paths for object op code:
    • available_mgd = /OBJECTS/INTAKE_001/Equation/available_mgd
    • Qintake = /OBJECTS/INTAKE_001/Equation/Qintake
    • flowby = /OBJECTS/INTAKE_001/Equation/flowby
  • hdf5 paths for current values:
    • available_mgd = /RESULTS/INTAKE_001/SPECL/available_mgd
    • Qintake = /RESULTS/INTAKE_001/SPECL/Qintake
    • flowby = /RESULTS/INTAKE_001/SPECL/flowby
  • Executable code with expanded paths, in dependency order, assuming that all state variales are located in the Dict ts that is passed to the function:
    • Qintake:
      ts["/RESULTS/INTAKE_001/SPECL/Qintake"][step] = ts["/RESULTS/RCHRES_001/SPECL/Qin"][step] * 1.0
    • flowby:
      ts["/RESULTS/INTAKE_001/SPECL/flowby"][step] = 0.9 * ts["/RESULTS/INTAKE_001/SPECL/Qintake"][step]
    • available_mgd:
      ts["/RESULTS/INTAKE_001/SPECL/available_mgd"][step] = ( ts["/RESULTS/INTAKE_001/SPECL/Qintake"][step] - ts["/RESULTS/INTAKE_001/SPECL/flowby"][step] ) / 1.547

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants