Skip to content

Instantly share code, notes, and snippets.

@kenwebb
Last active December 3, 2024 18:20
Show Gist options
  • Save kenwebb/82a5616d810776f53ed5e0b79c2d3e74 to your computer and use it in GitHub Desktop.
Save kenwebb/82a5616d810776f53ed5e0b79c2d3e74 to your computer and use it in GitHub Desktop.
Industrial Dynamics - Chapter 15 - Xholonish - Retail
<?xml version="1.0" encoding="UTF-8"?>
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Tue Dec 03 2024 13:19:37 GMT-0500 (Eastern Standard Time)-->
<XholonWorkbook>
<Notes><![CDATA[
Xholon
------
Title: Industrial Dynamics - Chapter 15 - Xholonish - Retail
Description:
Url: http://www.primordion.com/Xholon/gwt/
InternalName: 82a5616d810776f53ed5e0b79c2d3e74 based on c8c90e6e6d761e1268747bb1b5e0d430
Keywords:
My Notes
--------
16 Nov 2024
The first of three workbooks: Retail, Distributor, Factory
- connect the three at runtime using broadcastChannel
- use arrow functions within beh to implement DYNAMO auxiliaries
α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω
### TODO
- connect the Retail and Distributor workbooks; see Figure 15-14 and Figure 15-15 in the Forrester book
- I have done this using broadcastChannel
30 Nov 2024
### How the runtime can access the Retailbehavior code as text
How could I convert the source code into a standard Xholon model with distinct nodes for each Level, Rate, Aux, Constant?
I could then do things like regeneratte a diagram similar to Figure 15-14 in the book.
console.log(temp0.implName); // org.primordion.xholon.base.Behavior_gwtjs
console.log(temp0.text()); // complete code as text I SHOULD BE ABLE TO PARSE THIS
console.log(temp0.toString());
// factorybehavior_47 scriptConfigured:true hasPreAct:true hasAct:true hasPostAct:true hasProcessReceivedMessage:true hasProcessReceivedSyncMessage:false hasTick:false hasVisit:false
Dev Tools script: (this works)
var bchan = new BroadcastChannel("proddist");
bchan.onmessage = (event) => {
console.log(event);
console.log(event.data);
switch (event.data.signal) {
case 402:
console.log(event.data);
break;
default: break;
}
}
bchan.postMessage({
signal: 401,
data: "code", //"stuff" "implName",
sender: "Firefox dev tools"
});
### References
() Jay Forrester, Industrial Dynamics, 1961
() https://developer.mozilla.org/en-US/blog/exploring-the-broadcast-channel-api-for-cross-tab-communication/
() https://www.digitalocean.com/community/tutorials/js-broadcastchannel-api
]]></Notes>
<_-.XholonClass>
<DynamicalSystem>
<!-- Production - Distribution System, chapters 2, 15 -->
<ProdDistSystem/>
</DynamicalSystem>
<Retail/>
</_-.XholonClass>
<xholonClassDetails>
<Avatar><Color>red</Color></Avatar>
</xholonClassDetails>
<ProdDistSystem>
<Retail/>
</ProdDistSystem>
<Retailbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
// what is special about these? why are they here?
//const RRR = {KL:1}; // Requisitions (orders) Received at Retail (units/week) from customers
//const RCR = {K:1}; // ???
//const STP = {K:1};
//const SNE = {K:1};
//const STR = {K:1}; // already done below
//const TIME = {K:1};
// what is special about these? why are they here?
const
//PER=1,
//RRI=1,
//SIH=1,
STH=1,
STT=1;
// constants
const
AIR = 8,
DCR = 3,
DHR = 1,
DIR = 4,
DMR = 0.5,
DRR = 8,
DTR = 1,
DUR = 0.4;
const DT = 1; // Delta Time (weeks), the time interval between solutions of the equations
// RETAIL ------------------------
// levels
const CPR={K:1.1};
const IAR={K:1.2};
const MTR={K:1.3};
const PMR={K:1.4};
const RSR={K:1.5};
const UOR={K:1.6}; // Unfilled Orders at Retail (measured in units of goods on order)
// rates
const PDR={KL:1};
const PSR={KL:1};
const RRD={KL:1};
const SRR={KL:1};
const SSR={KL:1}; // Shipments Sent from Retail (units/week)
// auxiliary
// these are recalculated from scratch each time step
const DFR={K:1};
const IDR={K:1};
const LAR={K:1};
const LDR={K:1};
const MNR={K:1};
const NIR={K:1};
const STR={K:1};
const UNR={K:1};
// from customers
const RRR={KL:1};
// from distributor
const DFD = {J: 4, K:4};
const UOD = {J: 1, K:1};
const SSD = {JK: 1,KL:1};
//functions, lambdas
// LDR.K=(RSR.K)*(DCR)+(RSR.K)*(DMR)+(RSR.K)*(DFD.K)+(RSR.K)*(DTR) // 15-10 16A
// λa.λb.λc.λd.λe.a*(b+c+d+e)
const uorf = (uor, dt, rrr, ssr) => uor + dt * (rrr - ssr); // p.142 15-1, L
const iarf = (iar, dt, srr, ssr) => iar + dt * (srr - ssr); // p.143 15-2, L
const strf = (uor, dfr) => uor / dfr; // p.145 15-3, A
const nirf = (iar, dt) => iar / dt; // p.145 15-4, A
const ssrf = (str, nir) => nir >= str ? str : nir; // p.146 15-5, R
const dfrf = (dhr, dur, idr, iar) => dhr + dur * (idr / iar); // p.148 15-6, A
const idrf = (air, rsr) => air * rsr; // p.149 15-7, A
const rsrf = (rsr, dt, drr, rrr) => rsr + dt * (1 / drr) * (rrr - rsr); // p.150 15-8, L
const pdrf = (rrr, dir, idr, iar, ldr, lar, uor, unr) => rrr + (1 / dir) * ((idr - iar) + (ldr - lar) + (uor - unr)); // p.152 15-9, R
const ldrf = (rsr, dcr, dmr, dfd, dtr) => rsr * (dcr + dmr + dfd + dtr); // p.155 15-10, A
const larf = (cpr, pmr, uod, mtr) => cpr + pmr + uod + mtr; // p.155 15-11, A
const unrf = (rsr, dhr, dur) => rsr * (dhr + dur); // p.155 15-12, A
const cprf = (cpr, dt, pdr, psr) => cpr + dt * (pdr - psr); // p.156 15-13, L
const psrf = (pdr, dcr) => DELAY3(pdr, dcr); // p.156 15-14, R
const pmrf = (pmr, dt, psr, rrd) => pmr + dt * (psr - rrd); // p.156 15-15, L
const rrdf = (psr, dmr) => DELAY3(psr, dmr); // p.156 15-16, R
const mtrf = (mtr, dt, ssd, srr) => mtr + dt * (ssd - srr); // p.158 15-17, L
const srrf = (ssd, dtr) => DELAY3(ssd, dtr); // p.158 15-18, R
// FUNCTIONS ----------------------
// TODO implement these functions correctly; see book
const STEP = (sth, stt) => 1;
const SIN = (x) => Math.sin(x);
const _2PI = () => Math.PI * 2;
const CLIP = (a,b,c,d) => 1;
const DELAY3 = (a,b) => 1;
var me, csvK, counter, bchan, beh = {
postConfigure: function() {
me = this.cnode.parent();
csvK = "Retail\nUOR.K,IAR.K,STR.K,NIR.K,SSR.KL,DFR.K,IDR.K,RSR.K,PDR.KL,LDR.K,LAR.K,UNR.K,CPR.K,PSR.KL,PMR.K,RRD.KL,MTR.K,SRR.KL\n";
counter = 0;
console.log(this, this.cnode, me);
me.println(`\nUOR,IAR,SSR,RSR,PDR,CPR,PSR,PMR,RRD,MTR,SRR`);
bchan = new BroadcastChannel("proddist");
bchan.onmessage = (event) => {
console.log(event); // this works
switch (event.data.signal) {
case 102:
case 401:
//me.msg(event.data.signal, JSON.stringify(event.data.data), event.data.sender);
me.msg(event.data.signal, event.data.data, event.data.sender);
break;
default: break;
}
}
bchan.postMessage({
signal: 101,
data: [
{
dtype: "RRD",
dval: 2.13
}
]
});
},
processReceivedMessage: function(msg) {
//me.println(msg.data); // this works
//me.println("msg received: " + msg.signal + " " + msg.data);
me.println("msg received: " + msg.signal + " " + msg.data + " " + msg.sender);
switch (msg.signal) {
case 102:
// TODO
break;
case 401:
// broadcast a 402 message that contains this.cnode.text()
if (msg.data === "implName") {
me.println(this.cnode.implName);
bchan.postMessage({signal: 402, data: this.cnode.implName, sender: me.name()});
}
else if (msg.data === "code") {
me.println(this.cnode.text().substring(0, 20));
bchan.postMessage({signal: 402, data: this.cnode.text(), sender: me.name()});
}
else {
bchan.postMessage({signal: 402, data: "testing 1 2 3 ...", sender: me.name()});
}
break;
default: break;
}
},
act: function() {
const arrA = [UOR.K,IAR.K,STR.K,NIR.K,SSR.KL,DFR.K,IDR.K,RSR.K,PDR.KL,LDR.K,LAR.K,UNR.K,CPR.K,PSR.KL,PMR.K,RRD.KL,MTR.K,SRR.KL];
const arrB = arrA.map((item) => item.toFixed(4), []);
const csvC = arrB.join(",") + "\n";
csvK += csvC;
UOR.K = uorf(UOR.J, DT, RRR.JK, SSR.JK); // 15-1, L
IAR.K = iarf(IAR.J, DT, SRR.JK, SSR.JK); // 15-2, L
STR.K = strf(UOR.K, DFR.K); // 15-3, A
NIR.K = nirf(IAR.K, DT); // 15-4, A
SSR.KL = ssrf(STR.K, NIR.K); // 15-5, R
DFR.K = dfrf(DHR, DUR, IDR.K, IAR.K); // 15-6, A
IDR.K = idrf(AIR, RSR.K); // 15-7, A
RSR.K = rsrf(RSR.J, DT, DRR, RRR.JK, RSR.J); // 15-8, L
PDR.KL = pdrf(RRR.JK, DIR, IDR.K, IAR.K, LDR.K, LAR.K, UOR.K, UNR.K); // 15-9, R
LDR.K = ldrf(RSR.K, DCR, DMR, DFD.K, DTR); // 15-10, A
LAR.K = larf(CPR.K, PMR.K, UOD.K, MTR.K); // 15-11, A
UNR.K = unrf(RSR.K, DHR, DUR); // 15-12, A
CPR.K = cprf(CPR.J, DT, PDR.JK, PSR.JK); // 15-13, L
PSR.KL = psrf(PDR.JK, DCR); // 15-14, R
PMR.K = pmrf(PMR.J, DT, PSR.JK, RRD.JK); // 15-15, L
RRD.KL = rrdf(PSR.JK, DMR); // 15-16, R
MTR.K = mtrf(MTR.J, DT, SSD.JK, SRR.JK); // 15-17, L
SRR.KL = srrf(SSD.JK, DTR); // 15-18, R
if (counter++ == 5) {
console.log(csvK);
}
},
preAct: function() {
// handle the transition as the present (K) becomes the past (J)
RRR.JK = RRR.KL; // from customers
// retail - levels, rates
CPR.J = CPR.K;
IAR.J = IAR.K;
MTR.J = MTR.K;
PMR.J = PMR.K;
RSR.J = RSR.K;
UOR.J = UOR.K;
PDR.JK = PDR.KL;
PSR.JK = PSR.KL;
RRD.JK = RRD.KL;
SRR.JK = SRR.KL;
SSR.JK = SSR.KL;
},
postAct: function() {
let dpl = 3; // number of decimal places
me.print(`${UOR.J.toFixed(dpl)},${IAR.J.toFixed(dpl)},${SSR.JK.toFixed(dpl)},${RSR.J.toFixed(dpl)},${PDR.JK.toFixed(dpl)},`);
me.print(`${CPR.J.toFixed(dpl)},${PSR.JK.toFixed(dpl)},${PMR.J.toFixed(dpl)},${RRD.JK.toFixed(dpl)},${MTR.J.toFixed(dpl)},${SRR.JK.toFixed(dpl)}`);
me.print("\n");
/*
UOR,IAR,SSR,RSR,PDR,CPR,PSR,PMR,RRD,MTR,SRR
...
...
*/
}
}
//# sourceURL=Retailbehavior.js
]]></Retailbehavior>
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml,
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Retail</title>
<rect id="ProdDistSystem/Retail" fill="#98FB98" height="50" width="50" x="25" y="0"/>
<g>
<title>Retail</title>
<rect id="ProdDistSystem/Retail" fill="#6AB06A" height="50" width="10" x="80" y="0"/>
</g>
</g>
</svg>
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient>
</XholonWorkbook>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment