Last active
December 3, 2024 18:20
-
-
Save kenwebb/82a5616d810776f53ed5e0b79c2d3e74 to your computer and use it in GitHub Desktop.
Industrial Dynamics - Chapter 15 - Xholonish - Retail
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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