Closed jpfairbanks closed 1 year ago
The judgements are where you declare variables, then the equations are where you declare equations in those variables. The judgements tell you the types of each variable including the dimension and space over which it is defined.
Just realized I named the model diffusion, but it is harmonic oscillator
Updated some field names
{
"header": {
"name": "harmonic_oscillator",
"schema": "modelreps.io/DecaExpr",
"description": "A Simple Harmonic Oscillator as a Diagrammatic Equation",
"schema_name": "DecaExpr",
"model_version": "v1.0"
},
"model": {
"context": [
{
"var": {
"name": "X"
},
"dim": "Form0",
"space": "Point"
},
{
"var": {
"name": "V"
},
"dim": "Form0",
"space": "Point"
},
{
"var": {
"name": "k"
},
"dim": "Constant",
"space": "Point"
}
],
"equations": [
{
"lhs": {
"var": {
"name": "X"
}
},
"rhs": {
"name": "V"
}
},
{
"lhs": {
"var": {
"name": "V"
}
},
"rhs": {
"args": [
{
"name": "-1"
},
{
"name": "k"
},
{
"name": "X"
}
]
}
}
]
}
}
Combinatorial Representation of the model is
{
"Var": [
{
"_id": 1,
"type": "Form0",
"name": "X"
},
{
"_id": 2,
"type": "Form0",
"name": "Ẋ"
},
{
"_id": 3,
"type": "Constant",
"name": "k"
},
{
"_id": 4,
"type": "infer",
"name": "mult_1"
},
{
"_id": 5,
"type": "infer",
"name": "Ẋ̇"
},
{
"_id": 6,
"type": "Literal",
"name": "-1"
}
],
"TVar": [
{
"_id": 1,
"incl": 2
},
{
"_id": 2,
"incl": 5
}
],
"Op1": [
{
"_id": 1,
"src": 1,
"tgt": 2,
"op1": "∂ₜ"
},
{
"_id": 2,
"src": 2,
"tgt": 5,
"op1": "∂ₜ"
}
],
"Op2": [
{
"_id": 1,
"proj1": 6,
"proj2": 3,
"res": 4,
"op2": "*"
},
{
"_id": 2,
"proj1": 4,
"proj2": 1,
"res": 5,
"op2": "*"
}
],
"Σ": [],
"Summand": [],
"Type": [],
"Operator": [],
"Name": []
}
I think we should probably support both the Syntactic and Combinatorial forms. Because some parts of the software will be easier to write with each representation.
The relevant parts of the Decapodes Source Code are:
DecaExpr definitions: https://github.com/AlgebraicJulia/Decapodes.jl/blob/a19e268808a657360b8e6b502cbad866d5c5222f/src/language.jl#L6
Schemas for the combinatorial representaions: https://github.com/AlgebraicJulia/Decapodes.jl/blob/a19e268808a657360b8e6b502cbad866d5c5222f/src/decapodeacset.jl#L6 and https://github.com/AlgebraicJulia/Decapodes.jl/blob/a19e268808a657360b8e6b502cbad866d5c5222f/src/decapodeacset.jl#L113
Could we not use short forms of names? for example:
var
instead of variable
dim
instead of dimensions
Can we remove the header
property and just put its content at the root level like other AMR?
Also this schema is missing id
for each of the context.var
I have added a UWD example.
Given a relation macro
@relation (x:X, z:Z) where y:Y begin
R(x,y)
S(y,z)
T(z,y,u)
end
The UWD is given by the following database:
Catlab.Programs.RelationalPrograms.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol} with elements Box = 1:3, Port = 1:7, OuterPort = 1:2, Junction = 1:4, Type = 1:0, Name = 1:0, VarName = 1:0
┌─────┬──────┐
│ Box │ name │
├─────┼──────┤
│ 1 │ R │
│ 2 │ S │
│ 3 │ T │
└─────┴──────┘
┌──────┬─────┬──────────┬───────────┐
│ Port │ box │ junction │ port_type │
├──────┼─────┼──────────┼───────────┤
│ 1 │ 1 │ 1 │ X │
│ 2 │ 1 │ 3 │ Y │
│ 3 │ 2 │ 3 │ Y │
│ 4 │ 2 │ 2 │ Z │
│ 5 │ 3 │ 2 │ Z │
│ 6 │ 3 │ 3 │ Y │
│ 7 │ 3 │ 4 │ untyped │
└──────┴─────┴──────────┴───────────┘
┌───────────┬────────────────┬─────────────────┐
│ OuterPort │ outer_junction │ outer_port_type │
├───────────┼────────────────┼─────────────────┤
│ 1 │ 1 │ x │
│ 2 │ 2 │ z │
└───────────┴────────────────┴─────────────────┘
┌──────────┬───────────────┬──────────┐
│ Junction │ junction_type │ variable │
├──────────┼───────────────┼──────────┤
│ 1 │ X │ x │
│ 2 │ Z │ z │
│ 3 │ Y │ y │
│ 4 │ untyped │ u │
└──────────┴───────────────┴──────────┘
The expression that creates it is serialized as:
{
"context": [
{
"var": "x",
"type": "X"
},
{
"var": "z",
"type": "Z"
}
],
"statements": [
{
"relation": "R",
"args": [
{
"var": "x",
"type": "X"
},
{
"var": "y",
"type": "Y"
}
]
},
{
"relation": "S",
"args": [
{
"var": "y",
"type": "Y"
},
{
"var": "z",
"type": "Z"
}
]
},
{
"relation": "T",
"args": [
{
"var": "z",
"type": "Z"
},
{
"var": "y",
"type": "Y"
},
{
"var": "u"
}
]
}
]
}
Take a look at src/julia/composite_models_examples.jl for an example of building a composite model in AMR.
If this were a real julia package, some of the horrific namespacing would go away.
The composite model is:
Decapodes.SummationDecapode{Any, Any, Symbol} with elements Var = 1:14, TVar = 1:3, Op1 = 1:4, Op2 = 1:4, Σ = 1:1, Summand = 1:2, Type = 1:0, Operator = 1:0, Name = 1:0
┌─────┬───────────┬───────────────────┐
│ Var │ type │ name │
├─────┼───────────┼───────────────────┤
│ 1 │ Form0 │ X │
│ 2 │ Form0 │ V │
│ 3 │ Constant │ oscillator_k │
│ 4 │ infer │ oscillator_mult_1 │
│ 5 │ infer │ oscillator_Ẋ̇ │
│ 6 │ Literal │ -1 │
│ 7 │ Form0 │ Q │
│ 8 │ Constant │ heating_κ │
│ 9 │ Constant │ heating_λ │
│ 10 │ Parameter │ heating_Q₀ │
│ 11 │ infer │ heating_Q̇ │
│ 12 │ infer │ heating_•2 │
│ 13 │ infer │ heating_•3 │
│ 14 │ infer │ heating_•4 │
└─────┴───────────┴───────────────────┘
┌──────┬──────┐
│ TVar │ incl │
├──────┼──────┤
│ 1 │ 2 │
│ 2 │ 5 │
│ 3 │ 11 │
└──────┴──────┘
┌─────┬─────┬─────┬─────┐
│ Op1 │ src │ tgt │ op1 │
├─────┼─────┼─────┼─────┤
│ 1 │ 1 │ 2 │ ∂ₜ │
│ 2 │ 2 │ 5 │ ∂ₜ │
│ 3 │ 7 │ 11 │ ∂ₜ │
│ 4 │ 14 │ 13 │ λ │
└─────┴─────┴─────┴─────┘
┌─────┬───────┬───────┬─────┬─────┐
│ Op2 │ proj1 │ proj2 │ res │ op2 │
├─────┼───────┼───────┼─────┼─────┤
│ 1 │ 6 │ 3 │ 4 │ * │
│ 2 │ 4 │ 1 │ 5 │ * │
│ 3 │ 8 │ 2 │ 12 │ * │
│ 4 │ 7 │ 10 │ 14 │ - │
└─────┴───────┴───────┴─────┴─────┘
┌───┬─────┐
│ Σ │ sum │
├───┼─────┤
│ 1 │ 11 │
└───┴─────┘
┌─────────┬─────────┬───────────┐
│ Summand │ summand │ summation │
├─────────┼─────────┼───────────┤
│ 1 │ 12 │ 1 │
│ 2 │ 13 │ 1 │
└─────────┴─────────┴───────────┘
Made some progress today:
{
"header": {
"description": "A Simple Harmonic Oscillator as a Diagrammatic Equation",
"name": "harmonic_oscillator",
"_type": "Header",
"model_version": "v1.0",
"schema": "modelreps.io/DecaExpr",
"schema_name": "DecaExpr"
},
"_type": "ASKEMDecaExpr",
"model": {
"context": [
{
"dim": "Form0",
"var": {
"name": "X",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "V",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Constant",
"var": {
"name": "k",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
}
],
"_type": "Decapodes.DecaExpr",
"equations": [
{
"rhs": {
"name": "V",
"_type": "Var"
},
"lhs": {
"var": {
"name": "X",
"_type": "Var"
},
"_type": "Tan"
},
"_type": "Eq"
},
{
"rhs": {
"args": [
{
"name": "-1",
"_type": "Decapodes.Lit"
},
{
"name": "k",
"_type": "Var"
},
{
"name": "X",
"_type": "Var"
}
],
"_type": "Decapodes.Mult"
},
"lhs": {
"var": {
"name": "V",
"_type": "Var"
},
"_type": "Tan"
},
"_type": "Eq"
}
]
}
}
Current status is that the UWDs, Decapodes, and Composite models are all serializable and deserializable. The current definition of correctness for serialization is that write, read, write == write
.
Here is the example of a nested hierarchical model:
{
"components": [
{
"interface": [
"X",
"Ẋ"
],
"_type": "OpenModel",
"model": {
"header": {
"description": "A Simple Harmonic Oscillator as a Diagrammatic Equation",
"name": "harmonic_oscillator",
"_type": "Header",
"model_version": "v1.0",
"schema": "modelreps.io/DecaExpr",
"schema_name": "DecaExpr"
},
"_type": "ASKEMDecaExpr",
"model": {
"context": [
{
"dim": "Form0",
"var": {
"name": "X",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "V",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Constant",
"var": {
"name": "k",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
}
],
"_type": "DecaExpr",
"equations": [
{
"rhs": {
"name": "V",
"_type": "Var"
},
"lhs": {
"var": {
"name": "X",
"_type": "Var"
},
"_type": "Tan"
},
"_type": "Eq"
},
{
"rhs": {
"args": [
{
"name": "-1",
"_type": "Lit"
},
{
"name": "k",
"_type": "Var"
},
{
"name": "X",
"_type": "Var"
}
],
"_type": "Mult"
},
"lhs": {
"var": {
"name": "V",
"_type": "Var"
},
"_type": "Tan"
},
"_type": "Eq"
}
]
}
}
},
{
"components": [
{
"interface": [
"V",
"Q₊"
],
"_type": "OpenModel",
"model": {
"header": {
"description": "velocity makes it get hot",
"name": "DragHeat",
"_type": "Header",
"model_version": "v1.0",
"schema": "modelreps.io/SummationDecapode",
"schema_name": "SummationDecapode"
},
"_type": "ASKEMDecaExpr",
"model": {
"context": [
{
"dim": "Form0",
"var": {
"name": "V",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "Q₊",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Constant",
"var": {
"name": "κ",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
}
],
"_type": "DecaExpr",
"equations": [
{
"rhs": {
"f": "*",
"arg1": {
"name": "κ",
"_type": "Var"
},
"_type": "App2",
"arg2": {
"name": "V",
"_type": "Var"
}
},
"lhs": {
"name": "Q₊",
"_type": "Var"
},
"_type": "Eq"
}
]
}
}
},
{
"interface": [
"Q₋",
"Q"
],
"_type": "OpenModel",
"model": {
"header": {
"description": "heat dissipates to the enviornment",
"name": "NetwonCooling",
"_type": "Header",
"model_version": "v1.0",
"schema": "modelreps.io/SummationDecapode",
"schema_name": "SummationDecapode"
},
"_type": "ASKEMDecaExpr",
"model": {
"context": [
{
"dim": "Form0",
"var": {
"name": "Q₋",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Parameter",
"var": {
"name": "Q₀",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "Q",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Constant",
"var": {
"name": "λ",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
}
],
"_type": "DecaExpr",
"equations": [
{
"rhs": {
"f": "λ",
"arg": {
"f": "-",
"arg1": {
"name": "Q",
"_type": "Var"
},
"_type": "App2",
"arg2": {
"name": "Q₀",
"_type": "Var"
}
},
"_type": "App1"
},
"lhs": {
"name": "Q₋",
"_type": "Var"
},
"_type": "Eq"
}
]
}
}
},
{
"interface": [
"X",
"Y",
"T"
],
"_type": "OpenModel",
"model": {
"header": {
"description": "variables be addin",
"name": "LinearSuperpositon",
"_type": "Header",
"model_version": "v1.0",
"schema": "modelreps.io/SummationDecapode",
"schema_name": "SummationDecapode"
},
"_type": "ASKEMDecaExpr",
"model": {
"context": [
{
"dim": "Form0",
"var": {
"name": "X",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "Y",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
},
{
"dim": "Form0",
"var": {
"name": "T",
"_type": "Var"
},
"space": "Point",
"_type": "Judgement"
}
],
"_type": "DecaExpr",
"equations": [
{
"rhs": {
"args": [
{
"name": "X",
"_type": "Var"
},
{
"name": "Y",
"_type": "Var"
}
],
"_type": "Plus"
},
"lhs": {
"name": "T",
"_type": "Var"
},
"_type": "Eq"
}
]
}
}
}
],
"composition_pattern": {
"statements": [
{
"variables": [
{
"var": "V",
"type": "Form0",
"_type": "Typed"
},
{
"var": "Q₊",
"_type": "Untyped"
}
],
"_type": "Statement",
"relation": "drag"
},
{
"variables": [
{
"var": "Q₋",
"_type": "Untyped"
},
{
"var": "Q",
"type": "Form0",
"_type": "Typed"
}
],
"_type": "Statement",
"relation": "cooling"
},
{
"variables": [
{
"var": "Q₊",
"_type": "Untyped"
},
{
"var": "Q₋",
"_type": "Untyped"
},
{
"var": "Q̇",
"_type": "Untyped"
}
],
"_type": "Statement",
"relation": "superposition"
}
],
"context": [
{
"var": "V",
"type": "Form0",
"_type": "Typed"
},
{
"var": "Q",
"type": "Form0",
"_type": "Typed"
}
],
"_type": "UWDExpr"
},
"header": {
"description": "A formula for heating - cooling",
"name": "heating_dynamics",
"_type": "Header",
"model_version": "v0.1",
"schema": "modelreps.io/Composite",
"schema_name": "CompositeModelExpr"
},
"_type": "CompositeModelExpr"
}
],
"composition_pattern": {
"statements": [
{
"variables": [
{
"var": "X",
"type": "Form0",
"_type": "Typed"
},
{
"var": "V",
"type": "Form0",
"_type": "Typed"
}
],
"_type": "Statement",
"relation": "oscillator"
},
{
"variables": [
{
"var": "V",
"type": "Form0",
"_type": "Typed"
},
{
"var": "Q",
"type": "Form0",
"_type": "Typed"
}
],
"_type": "Statement",
"relation": "heating"
}
],
"context": [
{
"var": "X",
"type": "Form0",
"_type": "Typed"
},
{
"var": "Q",
"type": "Form0",
"_type": "Typed"
}
],
"_type": "UWDExpr"
},
"header": {
"description": "A hierarchical composite model of frictional heating",
"name": "hierarchical_composite",
"_type": "Header",
"model_version": "v0.1",
"schema": "modelreps.io/Composite",
"schema_name": "CompositeModelExpr"
},
"_type": "CompositeModelExpr"
}
I pulled out all the data definitions from all the files using awk
The types used in the Decapodes part are
@data CompositeModel <: AbstractTerm begin
OpenModel(model::ASKEMDecapodes.ASKEMDecaExpr, interface::Vector{Symbol})
OpenDecapode(model::ASKEMDecapodes.ASKEMDecapode, interface::Vector{Symbol})
CompositeModelExpr(header::Header, composition_pattern::UWDExpr, components::Vector{CompositeModel})
end
@data ASKEMDeca <: AbstractTerm begin
ASKEMDecaExpr(header::AMR.Header, model::Decapodes.DecaExpr)
ASKEMDecapode(header::AMR.Header, model::Decapodes.SummationDecapode)
end
@data Var <: AbstractTerm begin
Untyped(var::Symbol)
Typed(var::Symbol, type::Symbol)
end
@data UWDTerm <: AbstractTerm begin
Statement(relation::Symbol, variables::Vector{Var})
UWDExpr(context::Vector{Var}, statements::Vector{Statement})
UWDModel(header::AMR.Header, uwd::UWDExpr)
end
@as_record struct Header <: AbstractTerm
name::String
schema::String
description::String
schema_name::String
model_version::String
end
And from Decapodes they are
@data Term begin
Var(name::Symbol)
Lit(name::Symbol)
Judgement(var::Var, dim::Symbol, space::Symbol)
AppCirc1(fs::Vector{Symbol}, arg::Term)
App1(f::Symbol, arg::Term)
App2(f::Symbol, arg1::Term, arg2::Term)
Plus(args::Vector{Term})
Mult(args::Vector{Term})
Tan(var::Term)
end
@data Equation begin
Eq(lhs::Term, rhs::Term)
end
@as_record struct DecaExpr
context::Vector{Judgement}
equations::Vector{Equation}
end
So these are all the types you would need to implement in order to properly process a model.
This PR has moved to its own package https://github.com/AlgebraicJulia/SyntacticModels.jl please provide feedback on issues on that repo.
Should the JSON examples that were part of this original PR still be added under multiphysics/examples
in a new PR? We could also work on creating (ideally generating automatically from the implementation) a JSON schema for validation purposes.
This uses PR #50 and requires a patch to decapodes https://github.com/AlgebraicJulia/Decapodes.jl/pull/132.