Skip to content

Instantly share code, notes, and snippets.

@kenwebb
Last active December 3, 2024 18:20
Show Gist options
  • Save kenwebb/a060c49abd0b29a1b075a7fad691e0ef to your computer and use it in GitHub Desktop.
Save kenwebb/a060c49abd0b29a1b075a7fad691e0ef to your computer and use it in GitHub Desktop.
Industrial Dynamics - Chapter 15 - Xholonish - Factory
<?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:20:25 GMT-0500 (Eastern Standard Time)-->
<XholonWorkbook>
<Notes><![CDATA[
Xholon
------
Title: Industrial Dynamics - Chapter 15 - Xholonish - Factory
Description:
Url: http://www.primordion.com/Xholon/gwt/
InternalName: a060c49abd0b29a1b075a7fad691e0ef based on c8c90e6e6d761e1268747bb1b5e0d430
Keywords:
My Notes
--------
28 Nov 2024
The third of three workbooks: Retail, Distributor, Factory
- connect the three at runtime using broadcastChannel
- use arrow functions within beh to implement DYNAMO auxiliaries
Industrial Dynamics - Chapter 15 - Xholonish - DataCollector
α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω
### broadcastChannel
- connect the Factory and Distributor workbooks; see Figure 15-14 and Figure 15-15 in the Forrester book
- I have done this using broadcastChannel
Xholon Signals for use between the three models
Signal From To
------ ----------- --------------------
101 Retail Distributor
102 Distributor Retail
201 Distributor Factory
202 Factory Distributor
301 R|D|F data collector, etc.
Structure of a BroadcastChannel message (a JS Object; JSO and not JSON)
ex: Retail -> Distributor
{
signal: 101,
data: [
{
dtype: "SSF",
dval: 3.1234
}
]
}
ex: Factory -> Distributor
{
signal: 202,
data: [
{
dtype: "SSF",
dval: 3.1234
},
{
dtype: "UOF",
dval: 3.1235
},
{
dtype: "DFF",
dval: 3.1236
}
]
}
### 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 - Factory System, chapters 2, 15 -->
<ProdDistSystem/>
</DynamicalSystem>
<Retail/>
</_-.XholonClass>
<xholonClassDetails>
<Avatar><Color>red</Color></Avatar>
</xholonClassDetails>
<ProdDistSystem>
<Factory roleName="one"/>
</ProdDistSystem>
<Factorybehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
// what is special about these? why are they here? TODO
//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 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
AIF = 8,
ALF = 7,
DCF = 3,
DHF = 1,
DIF = 4,
DPF = 5,
DRF = 8,
DUF = 0.4;
const DT = 1; // Delta Time (weeks), the time interval between solutions of the equations
// FACTORY ------------------------
// levels
const CPF={K:1.1};
const IAF={K:1.2};
const OPF={K:1.3};
const RSF={K:1.5};
const UOF={K:1.6}; // Unfilled Orders (measured in units of goods on order)
// rates
const MDF={KL:1.11};
const MOF={KL:1.12};
const RRF={KL:1.13}; // from Distributor
const SRF={KL:1.14};
const SSF={KL:1.15}; // Shipments Sent from Retail (units/week)
// auxiliary
// these are recalculated from scratch each time step
const DFF={K:1.21};
const IDF={K:1.22};
const LAF={K:1.23};
const LDF={K:1.24};
const MWF={K:1.25};
const NIF={K:1.26};
const STF={K:1.27};
const UNF={K:1.28};
// 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 uoff = (uof, dt, rrf, ssf) => uof + dt * (rrf - ssf); // p.162 15-37, L
const iaff = (iaf, dt, srf, ssf) => iaf + dt * (srf - ssf); // p.162 15-38, L
const stff = (uof, dff) => uof / dff; // p.162 15-39, A
const niff = (iaf, dt) => iaf / dt; // p.162 15-40, A
const ssff = (stf, nif) => nif >= stf ? stf : nif; // p.162 15-41, R
const dfff = (dhf, duf, idf, iaf) => dhf + duf * (idf/ iaf); // p.162 15-42, A
const idff = (aif, rsf) => aif * rsf; // p.162 15-43, A
const rsff = (rsf, dt, drf, rrf) => rsf + dt * (1 / drf) * (rrf - rsf); // p.162 15-44, L
const mwff = (rrf, dif, idf, iaf, ldf, laf, uof, unf) => rrf + (1 / dif) * ((idf - iaf) + (ldf - laf) + (uof - unf)); // p. 164 15-45, A
const mdff = (mwf, alf) => alf >= mwf ? mwf : alf; // p. 164 15-46, R
const ldff = (rsf, dcf, dpf) => rsf * (dcf + dpf); // p.165 15-47, A
const laff = (cpf, opf) => cpf + opf; // p.166 15-48, A
const unff = (rsf, dhf, duf) => rsf * (dhf + duf); // p.167 15-49, A
const cpff = (cpf, dt, mdf, mof) => cpf + dt * (mdf - mof); // p.165 15-50, L
const moff = (mdf, dcf) => DELAY3(mdf, dcf); // p.165 15-51, R
const opff = (opf, dt, mof, srf) => opf + dt * (mof - srf); // p.165 15-52, L
const srff = (mof, dpf) => DELAY3(mof, dpf); // p.165 15-53, 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 = "Factory\nUOF.K,IAF.K,STF.K,NIF.K,SSF.KL,DFF.K,IDF.K,RSF.K,MWF.K,MDF.KL,LDF.K,LAF.K,UNF.K,CPF.K,MOF.KL,OPF.K,SRF.KL\n"; // DONE
counter = 0;
//console.log(this, this.cnode, me);
me.println(`\nUOF,IAF,RSF,CPF,OPF`);
bchan = new BroadcastChannel("proddist");
bchan.onmessage = (event) => {
console.log(event); // this works
switch (event.data.signal) {
case 201:
me.msg(event.data.signal, JSON.stringify(event.data.data));
break;
default: break;
}
}
},
processReceivedMessage: function(msg) {
//me.println(msg.data); // this works
me.println("msg received: " + msg.signal + " " + msg.data);
},
act: function() {
const arrA = [UOF.K,IAF.K,STF.K,NIF.K,SSF.KL,DFF.K,IDF.K,RSF.K,MWF.K,MDF.KL,LDF.K,LAF.K,UNF.K,CPF.K,MOF.KL,OPF.K,SRF.KL];
const arrB = arrA.map((item) => item.toFixed(4), []);
const csvC = arrB.join(",") + "\n";
csvK += csvC;
UOF.K = uoff(UOF.J, DT, RRF.JK, SSF.JK); // 15-37, L
IAF.K = iaff(IAF.J, DT, SRF.JK, SSF.JK); // 15-38, L
STF.K = stff(UOF.K, DFF.K); // 15-39, A
NIF.K = niff(IAF.K, DT); // 15-40, A
SSF.KL = ssff(STF.K, NIF.K); // 15-41, R
DFF.K = dfff(DHF, DUF, IDF.K, IAF.K); // 15-42, A
IDF.K = idff(AIF, RSF.K); // 15-43, A
RSF.K = rsff(RSF.J, DT, DRF, RRF.JK, RSF.J); // 15-44, L
// manufacturing
MWF.K = mwff(RRF.JK, DIF, IDF.K, IAF.K, LDF.K, LAF.K, UOF.K, UNF.K); // 15-45, A
MDF.KL = mdff(MWF.K, ALF); // 15-46, R
LDF.K = ldff(RSF.K, DCF, DPF); // 15-47, A
LAF.K = laff(CPF.K, OPF.K); // 15-48, A
UNF.K = unff(RSF.K, DHF, DUF); // 15-49, A
CPF.K = cpff(CPF.J, DT, MDF.JK, MOF.JK); // 15-50, L
MOF.KL = moff(MDF.JK, DCF); // 15-51, R
OPF.K = opff(OPF.J, DT, MOF.JK, SRF.JK); // 15-52, L
SRF.KL = srff(MOF.JK, DPF); // 15-53, R
if (counter++ == 5) {
console.log(csvK);
}
const sender = me.name();
me.println("sender:" + sender);
bchan.postMessage(
{
signal: 202,
data: [
{
dtype: "SSF",
dval: 3.1234
},
{
dtype: "UOF",
dval: 3.1235
},
{
dtype: "DFF",
dval: 3.1236
}
],
sender: sender
}
)
},
preAct: function() {
// handle the transition as the present (K) becomes the past (J)
// TODO some of these may be unnecessary/unused and/or may cause problems
// FACTORY - levels, rates
CPF.J = CPF.K;
DFF.J = DFF.K; // ???
IAF.J = IAF.K;
IDF.J = IDF.K; // ???
LAF.J = LAF.K;
LDF.J = LDF.K;
MDF.JK = MDF.KL; // ???
MWF.J = MWF.K;
NIF.J = NIF.K; // ???
OPF.J = OPF.K;
RSF.J = RSF.K;
MDF.JK = MDF.KL;
MOF.JK = MOF.KL;
OPF.J = OPF.K;
RRF.JK = RRF.KL;
RSF.J = RSF.K;
SRF.JK = SRF.KL;
SSF.JK = SSF.KL;
STF.J = STF.K; // ???
UNF.J = UNF.K; // ???
UOF.J = UOF.K;
},
postAct: function() {
let dpl = 3; // number of decimal places
me.print(`${UOF.J.toFixed(dpl)},${IAF.J.toFixed(dpl)},${RSF.J.toFixed(dpl)},`);
me.print(`${CPF.J.toFixed(dpl)},${OPF.J.toFixed(dpl)}`);
me.print("\n");
/*
UOF,IAF,RSF,CPF,OPF
1.600,1.200,1.500,1.100,1.300
1.580,1.190,1.454,1.090,1.280
1.520,1.000,1.413,4.000,1.280
1.650,1.000,1.378,8.966,1.280
2.496,1.716,1.347,13.825,1.280
3.184,2.274,1.320,17.859,1.280
3.438,2.398,1.296,20.571,1.280
...
*/
}
}
//# sourceURL=Factorybehavior.js
]]></Factorybehavior>
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml,
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Factory</title>
<rect id="ProdDistSystem/Factory" fill="#98FB98" height="50" width="50" x="25" y="0"/>
<g>
<title>Factory</title>
<rect id="ProdDistSystem/Factory" 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