From ebb379390c640b73c6c21df7264a8bd727fece8d Mon Sep 17 00:00:00 2001 From: Rolfes <alois.rolfes@hs-hannover.de> Date: Wed, 12 Jan 2022 14:07:00 +0100 Subject: [PATCH] load_sim_libs --- .env | 1 + .../requirements-checkpoint.txt | 2 + Balance_Binary.ipynb | 123 +- README.md | 3 +- __pycache__/nowo1_base.cpython-39.pyc | Bin 0 -> 43593 bytes __pycache__/nowo1_gui_base.cpython-39.pyc | Bin 0 -> 1791 bytes __pycache__/nowo1_log_base.cpython-39.pyc | Bin 0 -> 3377 bytes __pycache__/nowo1_sim_binary.cpython-39.pyc | Bin 0 -> 9603 bytes __pycache__/sim_base.cpython-39.pyc | Bin 0 -> 308 bytes nowo1_base.py | 1527 +++++++++++++++++ nowo1_gui_base.py | 47 + nowo1_log_base.py | 85 + nowo1_sim_binary.py | 406 +++++ requirements.txt | 1 + sim_base.py | 11 + 15 files changed, 2184 insertions(+), 22 deletions(-) create mode 100644 .env create mode 100644 .ipynb_checkpoints/requirements-checkpoint.txt create mode 100644 __pycache__/nowo1_base.cpython-39.pyc create mode 100644 __pycache__/nowo1_gui_base.cpython-39.pyc create mode 100644 __pycache__/nowo1_log_base.cpython-39.pyc create mode 100644 __pycache__/nowo1_sim_binary.cpython-39.pyc create mode 100644 __pycache__/sim_base.cpython-39.pyc create mode 100644 nowo1_base.py create mode 100644 nowo1_gui_base.py create mode 100644 nowo1_log_base.py create mode 100644 nowo1_sim_binary.py create mode 100644 sim_base.py diff --git a/.env b/.env new file mode 100644 index 0000000..3479d91 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +PYTHONPATH="/libs" \ No newline at end of file diff --git a/.ipynb_checkpoints/requirements-checkpoint.txt b/.ipynb_checkpoints/requirements-checkpoint.txt new file mode 100644 index 0000000..e76e091 --- /dev/null +++ b/.ipynb_checkpoints/requirements-checkpoint.txt @@ -0,0 +1,2 @@ +voila +voila-gridstack diff --git a/Balance_Binary.ipynb b/Balance_Binary.ipynb index 4c87cd9..9b71568 100644 --- a/Balance_Binary.ipynb +++ b/Balance_Binary.ipynb @@ -132,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "ab70ee95-ce3c-4c4c-a7bc-2658a1a5d41a", "metadata": { "extensions": { @@ -152,15 +152,15 @@ }, "outputs": [], "source": [ - "import nowo_base_1 as no_ba\n", - "import nowo_sim_binary as no_bi\n", - "import nowo_gui_base as no_gui\n", - "import nowo_log_base as no_log" + "import nowo1_base as no_ba\n", + "import nowo1_sim_binary as no_bi\n", + "import nowo1_gui_base as no_gui\n", + "import nowo1_log_base as no_log" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "eec838fd-a5a9-49c8-a873-07c0e3653622", "metadata": { "extensions": { @@ -180,15 +180,15 @@ }, "outputs": [], "source": [ - "test_obj = no_bi.binaer_node('test_obj') # Umgebungs\n", - "step_1 = no_ba.step_single('step_1')\n", + "bilanz_1 = no_bi.binary_node('bilanz_1') # Umgebungs\n", + "step = no_ba.step_single('step')\n", "gui_data = no_gui.gui_ipysheet('gui_data')\n", - "log_1 = no_log.log_sheet('log_1')" + "log = no_log.log_sheet('log')" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "5e7dc37c-8fe1-4569-a233-e3e45f450ae2", "metadata": { "extensions": { @@ -208,13 +208,13 @@ }, "outputs": [], "source": [ - "step_1.Init(work_objs=[test_obj.Calc_A_B])\n", - "log_1.Init(Values=[test_obj.log_all], Gui_For_Data = gui_data)" + "step.Init(work_objs=[bilanz_1.Calc_A_B])\n", + "log.Init(Values=[bilanz_1.log_all], Gui_For_Data = gui_data)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "9a853d13-b21f-475a-8262-b9616bad6a60", "metadata": { "extensions": { @@ -233,14 +233,29 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3b61942308af4a80ae7925cd8d0f83e0", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Sheet(cells=(Cell(column_end=0, column_start=0, row_end=7, row_start=0, squeeze_row=False, type…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "gui_data.Show_GUI()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "155a052c-b1b6-4098-8614-19388211296a", "metadata": { "extensions": { @@ -258,14 +273,29 @@ } } }, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6be30af1c3954d52ba1a8a26b2a93196", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(VBox(children=(Label(value='extensive Größe:'), HBox(children=(Dropdown(layout=Layout(width='10…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "test_obj.Show_GUI()" + "bilanz_1.Show_GUI()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "aa1fe3ad-55bb-491d-a677-ea20354ba5c1", "metadata": { "extensions": { @@ -283,10 +313,63 @@ } } }, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a7b9403b09c842cd849ebe6827a4801b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Button(description='Calc', style=ButtonStyle()),))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ed555c63520a4dd7a0a83be748fcfb44", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "step_1.Show_GUI()" + "step.Show_GUI()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e725524f-503a-4133-8445-2702b729abcf", + "metadata": { + "extensions": { + "jupyter_dashboards": { + "activeView": "grid_default", + "views": { + "grid_default": { + "col": null, + "height": 2, + "hidden": true, + "row": null, + "width": 2 + } + } + } + }, + "tags": [] + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/README.md b/README.md index 476b50c..22af31a 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,4 @@ -[](https://mybinder.org/v2/gh/was-ist-immer/Binary_Balance/HEAD?urlpath=voila/render/Balance_Binary.ipynb) - +[](https://mybinder.org/v2/gh/was-ist-immer/Binary_Balance/HEAD?urlpath=voila%2Frender%2FBalance_Binary.ipynb) diff --git a/__pycache__/nowo1_base.cpython-39.pyc b/__pycache__/nowo1_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a2d8537bfdba8749adffb5c8d4fb534ecbee302 GIT binary patch literal 43593 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 literal 0 HcmV?d00001 diff --git a/__pycache__/nowo1_gui_base.cpython-39.pyc b/__pycache__/nowo1_gui_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eedef653f6714a41958a39925eccf904fb940d62 GIT binary patch literal 1791 zcmYe~<>g{vU|?8$@m}H;HU@^rAPzESVPIfzU|?V<PGewTNMT4}%wdRP1k+4W%wU=& ziWN+=MX`fvjwntr%@xHBrg@@xQW#R0a(Hriqj(uXW-#aQ<?=`IGcvd{q_Cv0wlJiy zrZQ&<G&4sDrZ5IGXtKQoxxi18@fKfNQGRZGN@7W3T2W$dswU$t_LR)xf}F(4WRMbM z%nIccJ25aYq=Fq8#gxLG%ACrQ!Ze4eogs}eg*k<#g*S>dg*An(g&~S9g*}C%g&~R^ zEXSF`)xr_Q(ayla5XBkHpviNKC%rT?KC_^*I3qQ+#7&dw7E4}YZt5*&_fXGdW~gl- z3KT>j%nb@A3kC*;5{71mEXEqf8m2U+OokffC5(NHAdlBD#51Kc)G)*|gGrVY5StZD zvZXKtGpuCv(`3KJT3lL?T6BveK0Y%qvm`$L7Ax2RxA?$Rd~$vc$Qi{jeo=logwF+$ z2L)CXFNg#OS$uwJi6+Y}mg3Z$v?5R#6|pfeFx+CxE>A2<FJ8%bi!(kxIVZ8WI6i(Q z!!K1&s~E4+g36NABA>*hn2`MZoZ^_g{PKLmcu-&@B^IaZ6;u{+GB7akgM7;a@;{>( zBO4S}iGq~D!b}h5g=8j>Iw%IQLBZz?GC+rcfuV-6h9RDzgt3Mpi(vuNLWX7#pBci> zVp+fn6#)lP5jz6|gC=_sFUS)tIhn;Jw^%Y#6H|&nfq#oNGcP5z;uc#;K1ikr<T_2J zB0i8>PI!nE2{AA*KnP)wjG$*;W=VWfB_f$gfLsO&CI&_}MghhuITTM}C{JdD`V2&Y zd<RMlVBe{Le8-T*kj0qAw19abLoH(oOBQPlV+x}rLkd$0b1xGpSp+j^viKE&40#D6 zG#R6KlJj#)bMxYhOA?DpG}$1&Wh+a}DNQZD#TZf~4stgKESRIXl2dbX;)@dV(o<pH zWlJheOG_<+coXbluwQwLQWH}u<J0ns;#2cd<UsxeIhKKukFiP$#g`}wQG5uBJ5WLb z(ZyNd<etS?!c@bM#oP>`S(+JB7{wV<n9@OU$|BB?!raST!w}C{!jQ$9!U9qW%J;p@ zwTvZf3)pKIvKZ4D7c$m@%-~qSnZgDV$z)u}$jDH_)y%Mfdm#fOLk&|fgC@IQkrdeP zWr;<ZiAg!Bn#{LYit@{gZ?QvytT>7f!iWc@iqxWFaJXtR-r_9EFNcI@5vah^<SCK` zB?A!q7IRK&9yqZ;QV|=(gj?+8nJMY1CB?T`!kqFeZt=#uhkC|mmZau_64x!Z(t?!4 zlGGv&kbAh}lZ#RlOHx6(M3Whu;-Wyt6vrFh;w;H8Nz92)%C9IA09gr-jUp`u1_n?P zDFz8KF!3<*FmnClU=d>CV-#ZKVyu!ti4kNg7~M3vKqUky=f}t2;);*Y%}*)KNsW)c z#S<T2SeghfBjV$4F&CE<-C{|~&(8s8+9FAi3*<or$nsmf(991`K=DYa1?*B#k|_eE z4^R#&26>c&QH+y=je`v=sws4fqc}4+9#ksaVg<3%Z*f5i3$PFih<%F#6iOwTxv969 zQc7;I6(r`RBo^OdDoDA-npc`zP<e|fuizF}W<e!1w2Rb0t^-F7C@<aO_Y9~k$;i*s xgBJWnpmcYO0~9nMTfi<sayTd`i$D&)#bE;p6FX3*0tYb%BNQ@$XdXr$762eizjy!u literal 0 HcmV?d00001 diff --git a/__pycache__/nowo1_log_base.cpython-39.pyc b/__pycache__/nowo1_log_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a454f371b8823692aa4b1f24492237b7ff8d62d GIT binary patch literal 3377 zcmYe~<>g{vU|?8$@m?Y?4+Fzv5C<8vFfcGUFfcF_CowQEq%fo~<}gGtf@!8GW-!eX z#R{g`qS(PSM--<!Lkd$0a|=TXb1HKdS2J@Iw>v`$OA2cXLkcTYgvXsBg)N1>g&~C< zD#Dw>7|fu_@e*XaUowb9#;j0Iu^j^gLn_z}QA{bEsm!S?DNJ*i+8NRqQ<zg&T6m*a z!EDwPwib>kHZYq#g`<TdioKnIg&~R~m_d{47F$k!dU|S++e)TeEP08!skfNjLp_t3 zp>}{MkiS8g8{~Ht1_p)_hGvE=#u~;NrZlEZh8pH2jD3uZ3?)npm=`kCFvPQ@Fa$HK zWb|9fdW*HVv>>(U7Ds%1W?p7VeEcn@f|OgFE{P?HZbcxwICApS<5Ln#5?8X^Vku6| zNh<<bR0Q(jEw=3P#G>@#m5jGI<KvTa5{rxD<5x2LQuVZo@hUB-EJ-c$Nlc0f$<NOz zj>*d}&o_(*8J3h-oT^t)S;Wb}z`y}=Fvvg#Mlr@Jeuzi)U~Wlf1bGgML2M=l1_qG7 zizT3bT)?=H0o`9kYzzzxD_M&`X5ZpT&Ph!yiccy{OG_;(0;QfJP#_iYfYdM+@i8zk z6bXO`ArK)9B19P&7(mj+5O;AgRtZDhg=`jv+d#I0-KK}(wi1>U#uTO&h8l(})&*<} z8C)2e8JigwGS)D}vx8znli3f&IFK<Q<AOn<BgeqNkj_xU5GxkLRLfY)RKr-puz<0K zX(3}8(?q61mSBb=klQtxz`nc17Mxm?nOdyLe2YoX;1*-{EygmiJcIyw@D`U%PG)gQ za(-@s9Z2VAPyknHK>b*hnwU}<pO#+~pPHAVXOokkoS0K=r-#s@$pHyjUKEvJ%fUf= zizOv9x#Si%B*?)@=N4;bNosB}IM9p4Kw*p)<gyG53?Lyykc(h*jwYkqN={Hx1?7VH z_*-1@@wxdar8%kb@wa&5;|og@bD%QJ#U(|zSd#MdbHK^02o$G9AX{$nLQ`sTYEDjk zJS0>=p#Vt*pztXIr80I<(1YTDgHeoyhXpK#JDUd}XLBAx**u*gg*^>Y2ymouws3+n zdm3X3R|<CvM-&G*<8uZxX!73T1Z9`vjMUT;w<1uQz@6vKz-bPY8)_KhnM#<O8M0W= zb3Z5%#j}D*wiHk)08V@0+@i^Wh(Aayfie#`=x*_W9T1<K4-VU67{4gL92C~Yx40nk zpdzA(7falNvbiKEG(nk<fsu<*jFF9zjj>7y?m24Y_aYIH)!5P&DC!kK_QSKY7{X@c z9PNh^yr2ROghAn6JP91U&7gb-%6UwTpsWloOkEgaeQKF&m=}Pv_(G;ymKv56W=W7d zYZ+sa8zjp^#1=9#GSsl7Fo9*+%NUC!Y8bNE7qCIZK(d7rB^+6tAUz<N6qa758ishT z8ip+HqCOD0fTxBbiwmR@Tx_uV-D1>x2`U(iK!hgKE%xO6oYLI9;#;hlc`2zCn!J#_ z%Ho-qSyCj=z`$^eB|EjU_!et%K~82#ktRrlEwP{=H7}(|3lxH&NCIc$B5jZyk9%om zyjy-zJg7prB?vMmKB*F%snbB!gC;Au2))G?mY7qTT3loTG6NLQQCwgf;z4NylC{8@ z44l6V7#JATKrsS}GX_RJMm|O!Mm|OXMm|O%MiEfj;6ua^$V!yL5fmw)j0ujIG<d{- z>VX=DEG8F*ShHHj8ip)p7lv3ZP;r^UD9%vBB+gLFTm#A#%#sYCNCE|N7F!Kd4PzRU z4MU++p#Vr^0Xx(jj-sR*hAa+Hj$&j02R4&mkq!d`gC-|9NWp~(IQ$^t1`1n9kTE5e z+~O(8k5A6YEJ(^vEJ^_f3M`;FlJj%GfpUwZD8C%a%1*6>uvp7L!H6DSpmNI?6kebp zWMJfC=3?Yx<YDAu6k+57g_bxXv{1@qO-46Ot|BE+lqiD;P{W`|6~qFCei0{#1<D;o zpa_9@NF5{wvIbHxg39C~aGYr{Fff2B-C|I|z`-cS!NV%VTLcotT`E$g@xu%99H?*s zr#C|7Ajpfvw0*#(UJ<B}$601MgF+mXl)+6CaG3#j2JK5McZBU+j8#%7fuM(6Y7v_^ zAZ<Tz&R|)<3TlJI8pJTwGJy&&7lv4+T9y*F8kQ2KEaqmWB8?KJEcP148kTe>P|Ky4 zsg|)&qfn*>)MDWP<%=xN1zg~kBsVy3F#CmQGT!3JOwY?NN{xpUJv>PH1W~Gh^N9ke zXyM8%&de(=Nz6-5y~UQCpO>6i0;zgH?WbF8CHbI6N|7Zf%Rvhn=DgH$aO*RQ6P!=L z3T!|r7MxDO$rhYgK^eve6o4RcP?f{MD8$IY$ipbc#Ku@9jT)HfS*A!4WFpuwFaa_H zk_T)V7#N&D#)66;aJzuD2qdP-cZ;JqGdCX8u)W0!Vx`~Wg0y$RLM$NmEsm7LlGKvS z+|*l4DJ8eq3KH{D5{tpr?k(25(%gc|TTFQcw>S&(i%P&IftwuQ90s-ok|Dt^0uvyQ a-r}%<w14bC#eXrVG0VXSg-k+%LRtW`J-tZ) literal 0 HcmV?d00001 diff --git a/__pycache__/nowo1_sim_binary.cpython-39.pyc b/__pycache__/nowo1_sim_binary.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcc80afd87a78bb2f2485fba89fdead4adb99d0c GIT binary patch literal 9603 zcmYe~<>g{vU|?8$@m}I7TLy;5APzESVPIfzU|?V<4q{+nNMT4}%wdRP1k+4W%wU=& ziWN+=MX`fvjwntr%@xI+!jQt0!;{M!#mmUx&XB^K!qUQ!!jj6I#n8+g#h1bu%%I8o z5@eg7CgUykl+5CSoW#mxkN`4fhjNNl7#SE+!PZAHr81{5&S7k4NMlT4N?~r{iDCh> zSyEVAIHFin*izVA7^2ux*|Rus;WT!z4vrMg7S1Tn6s{ER7KSLURPHRE6rMSZDZD9s zEi6&IAbu)$7GDbg9Htb36u}mjD1H<%p%md3mM8%fF_9F}7M3VM6fv<B@fMaSp%jS} z$rgqv;S{M9=@y14krbH}*%pQ<(G<B9`4)yKu@r?A#TJGr@f4*L<rao0i4>I-)fR>* z$rQB|^%jOGDX^P0QZ!pQqNG9QgWal?qTRw0CDYEp!Vo1J%%G`ri#sVZFR`dHJ}*Bd zRg>`+OI~7bYBCcvAVCx}0|NsG0|Ns$C~kQe85nAq7BHkRmM~^9Wil>gWMn8|Zf3}0 zsbNfG%w(uxTEf@|5@TGzl)_ZQu#l;SA)d7a#AAl?*uXp%D385_aREmPYYjsQX9-st z(?aGNhInqU7#oTh4_J&HMT{3L#(^Tn2NvV3VJP8GV+5Nfkiu2N5HFa*UBeJBR3e<h zlg^OByNEH9v6-=kAzmbfFNGfzT`58-!YLvtqI1}57~(~17_!6`Fw`()iPtb>vDPqT zNz^c8vDGkSN!BoAv1c-a{GGxO%%CaecZ)qaBfg}vAoUiTdtymyyd#u$y2SzE$2;9( zcZ@GeEXmBj#qI=Ua5}~p<QJ7>=I7nwbb>QkJoD1>Ly8y~7#O11^Yc>U%Mx=mIl%mv zAi<ZQh<ORhX)i%h@=}0-f#IbBhydlhA`u1#h9Y4QAp{}>K?F!i5kH8<$H2g#$$pE` z@fM@gEoR4fry@>}Feq0Sfg-nv2c$si7F%gSN@7XsEtb6e^88yo=^#&~r{<*=CFa~> zEiNrcExN@KAD@|*SrQ*##0D|~l<$f_4!XrzoS6%9bZP1>*0h}b#FAUgnRzAHEV{*9 zTvAlT%fP^Jiz7KPCpj%AG5r=7L~nd{YUM4Kl+5IkD4zJ_jMU`p;*z4$<dR$52>Ie$ zobhR;dC4H>-C}c2%t;1?JeYR6#Q~-r<DE2_Z?P1o=A;#Y!t54Xc6nk^dhtreTb%Ln z$vKI|#qseg8GfmITE%#k7F3p`7WpJ5#f0SN=M=|)JZ~5e@(v_}=oM5J$uKZ5fC8!5 z0+cZr1sFvb`9P3Kgb@sxgqYYE*_fFax&E`UGBF~-pB!9lj2s~Nw@L(JAUMbA!2&WF z6ulr*K^PP&pfCkxz2ZL%3=HWEDU6F4YZ*%zvcRQSFJmnen9Y*Hn!?u0RLfk#kj0e3 zp2E?~Sj$qvki}dBDtb9vnIsufxN4YExO<svSxXqQSW<Yv`gl{Adl^&sdYNk3z&iQC zI@zH*1)w@Ou<GC}0c8o65{3nAHLNvk=}Ze5)0t9OQv`dNYPrC2>|i;L8cv8@4ReZ6 zFH<cySdOcP8?KrMl$jQAfJ~|3sNqZzp2GslSS6gz3=6mxGB7gK@B}kxiuh@=Ycf@_ z2bUD(=PEcBiGq?TobOa52I2Dtm*(cCDmW^X=A|e&6^VmIOF=;ymRgi?cu7u4US_d^ zBRDN;GGRzK6@fB>CQ}uMV_r#WW{!d*I8z`AIDs=r6^o&PfvP6sE!OhPl#+}pZo|}E z1p@^zy2V_Snxe^ci@hK*B_%U2{gyydVsdtRQGRJ&N_=vDPJU4-C}XBpl%(brXO^WZ zxECGXc6ffO709@<#GKO9m!K$z_>lP)dwv0^fG9392IUgAoW#of(voyg0s-MFW<yg| zO(w8pkr@L6Ln){rK$xAMl3JvYnTKW-B(xZdj6lJ|2-c^`a*L-dF(<w_H77N>B;N2A zJJ>1lhA6^DFkvH2?py5TnJMY1CB?Vce87&n#p;uol$vvk!=)&{ASJ&%?-r*UDEEh? zR+QXg33JM?xW(cDB6;K8Lp|d&OHy-lGK))!BtWHyG{|?{@ySK0;F6{^Q<Jwy6C_~@ zDh7EW-iEp^3dSu<%t^|xh~fr0JO^ZVykU_!NE0Y)A`2T8S%QSEKxT22CFU5$gY<z| zMj+NL&XW9+#2gT_NE@V37ewfR2xkTc22jXDb2|qo4<jEF4<jEV6BE;4HdZkv9!53@ zn?;OCgpuh#8<Pw(s04uK`#&6PT#QxXD7hWsNt6r^D%M#U7#KiS7K4iN8ip)}6h=vg zEJiSk3C?1Mvsgf^Or~0p3Z^uMOokdpNZkvrmstG}!GQ<?P39sekk>%oy2av|msz68 z1P<$4ECq>0iA7+~g9%Uw+~NhPi1#l`EdoVb0;mB1D&-kK<=sCPmMTePzoDp22CD-l zQ)ue}l&(RzxQT&*p@gBCVF4p3gQtM%V5S;|Eaohh1&lS|_5`TL1@o9dg#oDE1@pjl zF1Wy8tN|AjH4IrC3m9uyp{h6+FxId^*<1@4YuKS|?gfk~V3SgqYZ$V)<9Wd0!{P_7 zRjc^2Q#11vyz_H&Q}ap^i>lcDGZb<Y^YS!#i$LkJ$Q2Y^N+1GM)7@f+R)j^M;u&1! zfy)zc*#Ryuz-0uaT4RG$R+=2(5C&&zaP9*aO<1*|B|wnf8K6K1m2eDPT#Rgt;Od5v z2M((Q(4zn)U4beUP}%~gD^SRTQxl^DL$MI3{Z_*e4+;~86eb6TVil+e3s?=a14FSH zR0P!iVMt+dU?}#0ihx=|3@NM*48>7U5q7XHHV1~{9H<BfScKhyp|}nz!U+y}4nJbr zDO^#U@!9!BMc}3YQ(nO>=Dfr_BEoPbBP6uJi5N_PQ!;maacT)9K8ou>K?-UNF)#`t zLA0ETP!H;H6qlqH6r>hmG>qYywu_O0Aq8A3F92uAEan9)pya%evDgTdph3wvg-MdZ zi2>9gu3<`H7H0s};b7J5NU9Uys#$QT=0H;22UpFCLp3Md9lPLa*>I@kf~$Q7SIdq= zEjLW<1jb?!xM~g@s(Fx9JHb_RqN}c9O5w_8n7~*R0cx&i@y7F|@B}k}MOh{=7UiYz z)-b?D8M0VY_`s^$Quq<#DFVR^nu3t*4M{MdxF(SEKn>(lP}SjDtdM(nPjPW-o<eSB zUW%TAkwR%+NorAXaz<uqN={~SMyf)1YEen5LSkNeYEo*RLV0RYN@|{4sUrgegKM!u z%HcglX{mV%d6~%>B?`Hz8AS?-ImN^pQv_-sRGEWZQCeIKa)O=$sDOgBeKZ_(6r2>m z6+5VH3w8psBSJL!i@ZR!DQjjiD7%1)tRfGP0DF3B2`CE`fr~N~P<ckU1S|3cH4>O1 z8Ojf23~O?JX<i9NH34a(L$g;GD0_kGFa{<TMiE9KMh+Abl;t?U*$zdViHnhgk%bXV zGV_4gOsLfhiXECvMPT=^gL_z>dC8!v1zOuMfY_ksKDf{Wg=Y=J0)`sK8m5IzjG!(Z zV=%)?Mn6raTdeV*jt964vl7XdMZuup0hb+M0#tw$sWC7xYy$ZVWHJLI4`Y=Oa>)zn zZ;<MYq7YC3GZlq`ECk0#7>EV76-<DwR%c*f*iOJ|CyJ~FRn|q=tkz&)VAz9VHA?3N z;_G-!%Rx~94*oa>1_ns*FJvs{1C{^a8Xr_dG8RRpfJO%xYZw+Vf!YE!3=5c{Gz*kw zh0<(LnjK1WfapRIka?QSej#p}oJF8fry@mABIN}~YdoyW4duc*-uy6GSoa$$farv? zLsi^@GMsL4LPg@8u!a&S`VN9Z30zMz@-ec3A-KB->hdviFjfg7rxvhrD0K;_k_KUL zpn<yVpvtqDrv}tKVgPv)l2jPMK7_Z~Kz(M+%m}KvKnWWpdmiL0NRnk^M9Waf>QGt@ zpx6U-hQN+l2O9B#wnl3hvKSp0isV2s25nO@1T#!vtg-_+H-%XeoV^?vihNR7Qb6qp z<}4Ozh7=YF25FECYdlNd7qCiJxXL`RIyR6xP_+=xl6MKLf(@=>1(?r{!e`Io$O4(q z38LX<&j73BfUA51<|9l3@nJf-KsrIKNf3?Xz7Vh;xET`|iwwXbaQmSmF#TW`NPv9D z4R?nCB7DNZkq72;LffODv=46EJAs-4jNuG<UMvhHJQElzTNoK?85tR>c)}SX8B!Q( z8S5DH^dPhW0}De5?*zum6^snEOh{^&>X`DlQW$EP>X-}|48XQ&a`}N<mu`>-DY*6n zMJJ>(1f@}M3p7NNuLxWbfUAUfP{9Kp1p*cNVEvFrExZmvYVv~2xFr~sT9ogSS(aIx znV;ucRFq$Ii_^6tIThSzg_ftcSW_VqsW1t&<XRNYz`$@7lt^_z#W$k>BNrnJ6APmN zqZE?>qY#q<qZE?@qY9G>qXILi{maED1|D`1Ku^q|1RoF0^0*W85pZz?=~`h=%vDj~ z=td-EFVv(gj!4SbqZ!s6!Hi}%7KReG$~jmfSqCYS*(>)E5yfnN;K+4@L=-5BLo_+i zqmvU9r{L%WM=YrSR+I=5O9Bz#3I<GoYney}28M5-hyV?8F+d`MkqI0T(12&+1CMuA zNn;dc@$kXSkrDKuF+ev+_P`PJ;QR&-dXU;8{6QbZz`(%8$iPsH6!c8spogV-JV6hy zw{Qpj7GjEU7qoQm1}>Pv1vsQ&p1_y~D&`nc5QTREG;e^5Z<J#G8rU>M(Yp%FhZmwn zAU>=p1{b05!gCH-CA<JGdI#nsbb|OWov=a}%ttE3Bfxs#W=vo#G6Rdi-2)YY=?A+2 zT!@2NaJOL3;rI)3?g@;QU0CusazPF%?AH;I%enl(i3};1LxvYXBcO;5O^7Bh?wk)! zh~P8`ZeM~r1K<X45xC8VKV3#JFfb^9(j`*a%m^x*MVLV4Goox(VS*JApdoSWWizz> zg*%mkdeGolVuV-Vm<<gnunI)!3@NQy;5tBj<}4QQlnom=M%lAi;#u<!q3N3f<|9%v zh!4}pk;N(kO6d@t9blCR8_$9H@RU>p;$zq82UZDp+XTiU(0DgP3S2K#gcIssE);vQ zr#;x97G~`NYD9q2UIGzm57f{g)QI5l1Gg94z-@&hP>m0+aljQ0mJ|n0PT<r9F7?3b z!A%En)dNm@;OYo}ii-x#A%jvJsN(^xgqT<u6&NL;EdePe6-Fs|sR&JN!dNOK-094Z zU};$O0336OIFAAI;W1eR;=|&cEsG_K6)B~)fYl=OP6P81DGkJj=|xRxUSO37TP}e4 z@YGTS;)89gVaVd7IIVC^V60RjkXAtH$%BY;io>r66yeac0xq4vMGmO&3DM+1FP+fR z3OJd7QwUrWfeJH*fq@|&luSVFS6DJ(VpL$1VN_t00%0POh!aW@0gaS``aR%2PaDBz zA~<Rgkz4`hBccw(hea|t%EaLX3b-$Tqmc;e=z--S<JF+~Wi~%>26O{wMsO%&Y3PAN z5Rv)7VF?aoA1n>MSOx}$Dp25ohDKn42MRVWMj=KP#wt-PxhWnqut2?4P=FPKDhH7F zAp`m~3|UNY7BhrZ!U7-eX9#A1^kiAVwa_iL_@dO})Don=1$fjQ>~6Ht@Kgo{hIWv< zK|W((<N`y~Q5c9}7#(YnGr{qi0*zOsnFb~#HZu|%Wi|pyoDGT1j>HDdM1W^6Kye81 zA}7R)yx@u6_~O#!<kaF~B%gxILr@lh6s+LH51OuocJIL>T<G1UGzJESK2RWl#t1;e zP>87j9`r5|XhjFiT1`37oIPl5M|}J(uK4)e{FKt1)cE*YJn`{`rHMHZnIZ*HdXWJU zpztbk2eG_Bgg1x)%|{gZf>@HEaTZR{pm=;zVsR>D@I?wF0~#kQ0*zP|fr@a*$QHP7 z3F_z-fjSvQpyqB7sBKXMD(;IwnYjp*D2qTbTm<srEnevKd~#||PJBF4Ab`^ZxW595 zR8ZYg44V4nU=&j4(dFP|VMKyI`NTQ61vErh!H|!GjYE+`ghPx&fkU1{nuC{zy$EE6 zCjTuC@GO5~aq2Br5G(x_S6+U3z9GbGV6Sq37DSX}=BD0aN-4R;R*;yNl309;sUYPR zYhGz?K_z6=l`FHL5;`$jWDN=-e$Rl)l8pR3J?Mg^B2cCQ+lu5Rco*yzhYciJ>_Ezj MK|KrPAtWAV0FuztPyhe` literal 0 HcmV?d00001 diff --git a/__pycache__/sim_base.cpython-39.pyc b/__pycache__/sim_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0a283222cd5cdad6d62aca686191908ea88c219 GIT binary patch literal 308 zcmYe~<>g{vU|<NmcrTHek%8ech=Yuo7#J8F7#J9e%@`OMQW#Pga~Pr^G-DKFDq|K? z3X>#56mu#|GeZiqBtsM{NGz3Ak|ByMg(ZqTg)x{xll3LYM88`c@$tEdnR)T?AXZ*t zZfbmdm7r>*u4=BXYKnrYhn1?Ym1?ji$1V1P#FC7h%%oe)#g)ak*mLt!N^??+Z*lp8 zbo+vMx7gEj@{<yCif{1+r{<)^g9SlG-r_>=Z*iAo=B5@TmXxFx<*j5W;$dKb5WnO- ztzx`N3o1)ei+mE3VnXusbBbe%GjrpU5{pyy3My}L*g!0`V+8pf6hs`19L!vdT#Q^S E0RAph9{>OV literal 0 HcmV?d00001 diff --git a/nowo1_base.py b/nowo1_base.py new file mode 100644 index 0000000..3fdac91 --- /dev/null +++ b/nowo1_base.py @@ -0,0 +1,1527 @@ +import sys +import sim_base as sim_g +import pandas as pd +import datetime as dt +from dateutil.relativedelta import relativedelta +from typing import Any, Callable, List, Type +import math +import numpy as np +import ipywidgets as widgets +from IPython.display import display + + + +Main_Modul = sys.modules['__main__'] +Self_Modulname = globals()['__name__'] +Self_Modul = sys.modules[Self_Modulname] + + +def get_attr_rek(names, start_obj=Main_Modul): + """get attr / obj by list or str. + +Keyword arguments: +names -- as str or list (example: 'obj.attr1.attr2' or ['obj', 'attr1', 'attr2']) +start_obj -- obj where to search +""" + if isinstance(names, str): + name_list = names.split('.') + elif isinstance(names, list): + name_list = names + else: + return None + + obj = start_obj + for name in name_list: + if hasattr(obj, name): + obj = getattr(obj, name) + else: + return None + return obj + + +def analyse_func_old(func_to_analyse, sim_obj): + if isinstance(func_to_analyse, str): + func_name = func_to_analyse + func = get_attr_rek(func_to_analyse) + if not func: return None + sim_obj = func.__self__ + + elif callable(func_to_analyse): + func = func_to_analyse + func_name = func.__name__ + if hasattr(func, '__self__'): + sim_obj = func.__self__ + func_name = sim_obj.name + '.' + func_name + else: + setattr(sim_obj, func_name, func) + func_name = sim_obj.name + '.' + func_name + else: return None + + return [sim_obj, func, func_name] + + +def analyse_func(func): + if isinstance(func, str): + func_name = func + func = get_attr_rek(func) + if not func: return None + + if callable(func): + func_name = func.__name__ + sim_obj = None + if hasattr(func, '__self__'): + sim_obj = func.__self__ + func_name = sim_obj.name + '.' + func_name + + else: return None + + return [sim_obj, func, func_name] + + + +class sim_value(): + def __init__(self, name: str, parent, value_type ): + self.name = name + self._parent = parent + self._simparent = getattr(self._parent, 'sim_parent', self._parent) + if not self._simparent: self._simparent = self._parent + value_type_list = list(value_type) + value_type_list.append(type(None)) + self.value_type = tuple(value_type_list) + self._value = None + self._default_value = None + self.unit = '' + + self.set = self._set # Überschreibbar durch callback funktion + self.call_extern = None + self.call_intern = None + self._fullname = self._get_fullname() + self._loggerlist : set = set() + + + def _get_fullname(self): + namelist = [] + if not self._simparent == self._parent: + namelist.append(self._simparent.name) + namelist.append(self._parent.name) + namelist.append(self.name) + return '.'.join(namelist) + + #TODO typen überprüfen + def _set(self, value): + if not isinstance(value, self.value_type): raise Exception('ungültiger typ') + self._value = value + return self._value + + # Wird geändert über value erfolgt kein callback zugriff es wird nur + #_value geändert oder zurückgegeben + @property + def value(self): + return self._value + + + @value.setter + def value(self, value): + if not isinstance(value, self.value_type): raise Exception('ungültiger typ') + self._value = value + + + @property + def default_value(self): + return self._default_value + + + @default_value.setter + def default_value(self, value): + self._default_value = value + self._value = self._default_value + + + def get_set(self, stepper=None, value=None): + if self.call_extern: + self._value = self.call_extern(self, value, stepper) + elif self.call_intern: + self._value = self.call_intern(value, stepper) + return self._value + + + + #TODO Warum Any würde hier nicht auch ein None genügen? + def Init(self, value = Any, default = Any, unit = ''): + #self._loggerlist : set = set() + self.unit = unit + self._default_value = default + if isinstance(value, str): + value = get_attr_rek(value) + if isinstance(value, Callable): + if hasattr(value, '__self__') and (value.__self__ == self._simparent): + self.call_intern = value + else: self.call_extern = value + self._value = self._default_value + return + elif isinstance(value, type(None)): + self._value = value + self.set = self._set + elif isinstance(value, self.value_type): + self._value = self.value_type[0](value) + self.set = self._set + return + + + def _add_logger(self, logger): + self._simparent._add_logger(logger) + self._loggerlist.add(logger) + return self._fullname + + + def _del_logger(self, logger): + self._simparent._del_logger(logger) + + + def _node_success(self, stepper): + for logger in self._loggerlist: + logger._add_value(self._fullname, self._value) + + +#------------------------------------------------------------------- +class gate_base: + def __init__(self, name, sim_parent): + self.name = name + self.sim_parent = sim_parent + self._success_flag : bool = True + + def set(self, value: Any, value_name: str = ''):pass + + def get(self, value_name: str = ''):pass + + def Init(self, values):pass + + def _reset(self): + self._success_flag : bool = True + + def _node_success(self, stepper): pass + + def log_all(self, logger): + name_list = [] + for key, value in self.__dict__.items(): + if issubclass(type(value), sim_value): + name_list.append(value._add_logger(logger)) + return name_list + + +#------------------------------------------------------------------- +class gate_time(gate_base): + def __init__(self, name, sim_parent): + super().__init__(name, sim_parent) + self.time = sim_value('time', self, (dt.datetime,)) + + def _node_success(self, timer): + self.time._node_success(timer) + + def _reset(self): + super()._reset() + self.time.set(dt.datetime(1, 1, 1, 0, 0, 0)) + + def set(self, value): + if isinstance(value, dt.datetime): + self.time.value = value + + def get(self, value_name: str = ''): + if not value_name: + return self.time.value + elif value_name == 'time': + return self.time.value + + +#------------------------------------------------------------------- +class gate_general(gate_base): + def __init__(self, name, sim_parent): + super().__init__(name, sim_parent) + self.general = sim_value('general', self, (float, int,)) + + # self.time_factor = 0.0 + + + def _reset(self): + super()._reset() + #self.general.set(np.nan) + + + def set(self, value): + if isinstance(value, (float, int)): + self.general.set(float(value)) + elif isinstance(value, type(self)): + self.general.set(value.general.value) + + + def get(self, value_name: str = ''): + if not value_name: + return self.general.value + elif value_name == 'general': + return self.general.value + + + def _node_success(self, stepper): + if not self._success_flag: return + self.general._node_success(stepper) + self._success_flag = False + + +#------------------------------------------------------------------- +class gate_dynamic(gate_base): + def __init__(self, name, sim_parent): + super().__init__(name, sim_parent) + self.Dyn_Values : dict = dict() + + + def Init(self, values): + super().Init(values) + if not isinstance(values, dict): raise Exception('das ist kein Dictionary') + for key, value in values.items(): + base_val = sim_value(key, self, value['type']) + base_val.Init(value['value'], value['default'], value['unit']) + self.Dyn_Values.update({key : base_val}) + setattr(self,key,base_val) + + + def _reset(self): + super()._reset() + for val in self.Dyn_Values.values(): + val._value = val._default_value + + + def set(self, value, value_name): + if not isinstance(value_name, str): + raise Exception('Name nich korrekt') + if not value_name in self.Dyn_Values.keys(): + raise Exception('Name nich korrekt') + + val = self.Dyn_Values[value_name] + + if not isinstance(value, val.value_type): + raise Exception('Falscher typ') + val.set(value) + + + + def get(self, value_name: str = ''): + if not isinstance(value_name, str): + raise Exception('Name nich korrekt') + if not value_name in self.Dyn_Values.keys(): + raise Exception('Name nich korrekt') + + return self.Dyn_Values[value_name]._value + + + def _node_success(self, timer): + if not self._success_flag: return + for val in self.Dyn_Values.values(): + val._value = val._node_success(timer) + self._success_flag = False + + + def _actual_values(self, timer): + for val in self.Dyn_Values.values(): + val.get_set(timer) + + +class gate_dataframe(gate_base): + def __init__(self, name, sim_parent): + super().__init__(name, sim_parent) + self.dataframe = sim_value('dataframe', self, (pd.DataFrame,)) + + + def _reset(self): + super()._reset() + #self.dataframe.set(0.0) + + + def _add_logger(self, logger): + super()._add_logger(logger) + + + def set(self, value): + if isinstance(value, (float, int)): + self.dataframe.set(float(value)) + elif isinstance(value, type(self)): + self.dataframe.set(value.dataframe.value) + + + def get(self, value_name: str = ''): + if not value_name: + return self.dataframe.value + elif value_name == 'dataframe': + return self.dataframe.value + + + def _node_success(self, stepper): + if not self._success_flag: return + self.dataframe._node_success(stepper) + self._success_flag = False + + + +#***************************************************************** +class step_base(): + def __init__(self, name : str, GUI : bool = False): + self.name = name + self.step_nr: int = 0 + self.total_steps: int = 0 + self.work_objs = [ ] # Diese Objekte sind mit dem Timer verknüpft + self.sim_funcs : dict = {}# Ersetzt self.work_objs und self.work_funcs + self._loggerlist : set = set() + + self._GUI_visible = GUI + self._GUI_itemlist : dict = dict() + self.GUI_Item = self._create_gui() + self._GUI_is_visible = False + + self.info = widgets.Output() + + + + def on_start_clicked(self, args): + parent = args.parent + parent.reset() + #with self.info: + # print('Hier') + + # for obj in parent.work_objs: + # if obj._GUI_is_visible: + # obj.Init_Over_GUI() + parent.work() + + + def Show_GUI(self): + for obj in self.work_objs: + if obj._GUI_visible: + obj.Show_GUI() + if self.GUI_Item: + self._GUI_is_visible = True + display(self.GUI_Item, self.info) + #with self.info: + # print('Na dann wollen wir mal') + + + def _create_gui(self): + for widget in self._GUI_itemlist.values(): + setattr(widget, 'parent', self) + return None + + + def reset(self): + self.step_nr = 0 + + + + def Init(self, work_objs : list = []): + self.step_nr = 0 + if not work_objs: raise Exception(f'obj : {self.name} |wenigstens eine start Methode muss angeben werden!') + self.work_objs = [] # Diese Objekte sind mit dem Timer verknüpft + + for func_to_analyse in work_objs: + func_info = analyse_func(func_to_analyse) + if not func_info:raise Exception(f'obj : {self.name} Startfunktion nicht korrekt') + if not isinstance(func_info[0], work_base):raise Exception(f'obj : {self.name} |node ist kein Type von work_base') + self.work_objs.append(func_info[0]) + if not callable(func_info[1]): raise Exception(f'obj : {self.name} |node hat keine func_work methode') + gate = func_info[0].ch_type('Timer_Summe', self) + gate.set(0.0) + self.sim_funcs.update( + {func_info[1] : { + 'obj' : func_info[0], + 'gate' : gate}}) + + + def work(self): + for obj in self.work_objs: + if obj._GUI_is_visible: + obj.Init_Over_GUI() + + for obj in self.work_objs: + obj.ready_for_start(self) + for logger in self._loggerlist: + logger.ready_for_start(self) + + if self._GUI_visible: pass + while self.step() == 1: + self._node_success() + + for obj in self.work_objs: + obj.ready_for_end() + + for logger in self._loggerlist: + logger.ready_for_end() + + + def step(self): + for obj in self.work_objs: + obj._reset() #Todo ist das immer erforderlich? + + for func, values in self.sim_funcs.items(): + func(stepper = self, Gate_In = values['gate']) + values['obj']._node_success(stepper = self) + + self.step_nr = self.step_nr + 1 + + + def _add_logger(self, logger): + if isinstance(logger, set): + self._loggerlist.update(logger) + elif isinstance(logger, port_base): + self._loggerlist.add(logger) + + + def _del_logger(self, logger): + self._loggerlist.remove(logger) + + + def _node_success(self): pass + + +class step_range(step_base): + def __init__(self, name : str, GUI : bool = False): + super().__init__(name, GUI) + self.total_steps = sim_value('total_steps', self, (float, int,)) + self.Gate_Step: gate_general = gate_general( 'Gate_Step', self) + + + def Init(self, + work_objs : list = [], + total_steps = 1 + ): + + super().Init(work_objs=work_objs) + self.total_steps.Init(total_steps, 1) + self.step_nr = 0 + + + def _create_gui(self): + + start_button = widgets.Button(description='Calc') + start_button.on_click(self.on_start_clicked) + total_box = widgets.VBox([start_button]) + + self._GUI_itemlist.update({ + 'start_button' : start_button + }) + super()._create_gui()# Attention! --must-- because the widget get a parent attr. + return total_box + + + + + # ergebnis 1 ein step + # 0 kein step + def step(self): + if self.step_nr <= self.total_steps.get_set(self): + self.Gate_Step.set(self.step_nr) + super().step() + return 1 + else: return 0 + + + def _node_success(self): + super()._node_success() + self.Gate_Step._node_success(self) + + + +class step_single(step_base): + def __init__(self, name : str, GUI : bool = False): + super().__init__(name, GUI) + + + def Init(self, work_objs : list = []): + super().Init(work_objs=work_objs) + self.step_nr = 0 + + + # Später im Parent + def _create_gui(self): + start_button = widgets.Button(description='Calc') + start_button.on_click(self.on_start_clicked) + total_box = widgets.VBox([start_button]) + + self._GUI_itemlist.update({ + 'start_button' : start_button + }) + + super()._create_gui()# Attention! --must-- because the widget get a parent attr. + return total_box + + + def step(self): + if self.step_nr < 1: + super().step() + return 1 + else: return 0 + + +# ------------------------------------------------------------------ +class step_timer(step_base): + def __init__(self, name : str, GUI : bool = False): + super().__init__(name, GUI) + + self.abs_start = dt.datetime(1, 1, 1, 0, 0, 0) + self.start: dt.datetime = dt.datetime(1, 1, 1, 0, 0, 0) + self.ende: dt.datetime = dt.datetime(1, 1, 1, 1, 0, 0) + self.actual: dt.datetime = self.start + self.step_width: str = 's' + self.step_count: int = 0 + self.total_sec: int = 0 + self._max_sec: int = 0 + self._step_sec : int = 0 + self.step_props = dict(s=1, m=60, h=3600, d=86400, m15=900) + + self.Gate_Time: gate_time = gate_time( 'Gate_Time', self) + + self.factor : float = self.step_props[self.step_width] / 3600.0 + + + def Init(self, + work_objs : list = [], + start = '0001-01-01 00:00:00', + ende = '0001-01-01 01:00:00', + stepwidth = 's' + ): + + super().Init(work_objs=work_objs) + + self.start = dt.datetime.strptime(start, sim_g.timepattern) + self.ende = dt.datetime.strptime(ende, sim_g.timepattern) + if not self.start < self.ende: raise Exception('ende vor start') + + self.step_width = stepwidth + if not self.step_width in self.step_props.keys():raise Exception('step_width nicht bekannt (s,m,h,d, m15)') + + self.actual = self.start + self._step_sec = self.step_props[self.step_width] + self.Gate_Time.set(self.actual) + self.total_sec = 0 + self._max_sec = int((self.start - self.abs_start).total_seconds()) + + self.total_steps = int(self._max_sec /self.step_props[self.step_width]) + self.factor : float = self.step_props[self.step_width] / 3600.0 + + # ergebnis 1 ein step + # 0 kein step act_time < self.start + # -1 kein step act_time > self.ende + def step(self): + relation_time = self.actual + if relation_time < self.start: return 0 + + if (relation_time >= self.start) and (relation_time < self.ende): + # Mache einen step + self.total_sec = self.total_sec + self.step_props[self.step_width] + self.actual = self.actual + \ + dt.timedelta(seconds=self.step_props[self.step_width]) + self.Gate_Time.time.set(self.actual) + super().step() + return 1 + + if self.actual >= self.ende: return -1 + + + + def _node_success(self): + super()._node_success() + self.Gate_Time._node_success(self) + + + +#***************************************************************** +class work_base(): + def __init__(self, name: str, GUI : bool = False, **kwargs): + + self.name = name + self._ctrl_ok : bool = False + + self._GUI_visible = GUI + self._GUI_itemlist : dict = dict() + self.GUI_Item = None + self._GUI_is_visible = False + + self.info = widgets.Output() + + def Init(self): pass + + def ready_for_start(self, timer: step_timer): pass + + def ready_for_end(self):pass + + + def _create_gui(self): + for widget in self._GUI_itemlist.values(): + setattr(self, 'parent', widget) + return None + + + def Show_GUI(self): + #display(self.info) + if not self.GUI_Item: + self.GUI_Item = self._create_gui() + self._GUI_is_visible = True + display(self.GUI_Item) + + +class gui_base(work_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + + + def ready_for_start(self, stepper: step_base):pass + + def ready_for_end(self):pass + + def Init(self): super().Init() + + def Init_by_dataframe(self, dataframe): pass + + + +# ------------------------------------------------------------------ +class port_base(work_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + self.buffer_data: dict = dict() + self.col_name : list = list() + self.Gui_For_Data : gui_base = None + + + def clear_buffer(self): + for key in self.buffer_data.keys(): + self.buffer_data[key] = [] + + + def ready_for_start(self, stepper: step_base): + self.clear_buffer() + + + def ready_for_end(self):pass + + #with self.info: + # print('ready_for_end') + + + def reset_ports(self, port_parentname: str): + if port_parentname in self.ports.keys(): + self.ports[port_parentname] = dict() + + + def Init(self, + Values = [], + Gui_For_Data = None, + ): + super().Init() + self.Gui_For_Data = Gui_For_Data + self.buffer_data: dict = dict() + for value in Values: + if isinstance(value, sim_value): + name = value._add_logger(self) + self.buffer_data.update({name: []}) + elif isinstance(value, Callable): + for item in value(self): + self.buffer_data.update({item: []}) + self.col_name = list(self.buffer_data.keys()) + + + def _add_value(self, name, value): + if name in self.buffer_data.keys(): + self.buffer_data[name].append(value) + + +# ------------------------------------------------------------------- +class sim_base(work_base): + + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + self.time_factor: float = 0.0 + self.ch_type: gate_base = None + + if 'ch_type' in kwargs.keys(): + self.ch_type = kwargs['ch_type'] + if isinstance(self.ch_type, str): + self.ch_type = Main_Modul.sim_obj_factory.get_classtype_by_name( + self.ch_type) + + if not issubclass(self.ch_type, gate_base): raise Exception('ist nicht vom Type gate_base abgeleitet') + + self._loggerlist : set = set() + self._funcgate : dict = {} + + + + def _getgate_func(self, func : Callable): + if func in self._funcgate.keys(): + return self._funcgate[func] + return None + + def _node_success(self, timer: step_timer):pass + + + def _reset(self):pass + + + def _add_logger(self, logger): + self._loggerlist.add(logger) + + + def _del_logger(self, logger): + self._loggerlist.remove(logger) + + + def ready_for_start(self, stepper: step_base): + super().ready_for_start(stepper) + self._reset() + if isinstance(stepper, step_timer): + self.time_factor = stepper.factor + stepper._add_logger(self._loggerlist) + + + def log_all(self, logger): + name_list = [] + for key, value in self.__dict__.items(): + if issubclass(type(value), sim_value): + name_list.append(value._add_logger(logger)) + elif issubclass(type(value), gate_base): + name_list = name_list + value.log_all(logger) + return name_list + + + + def Init_Over_GUI(self): pass + + + + +class ctrl_base(): + def __init__(self, name : str, gate_type : gate_base): + super().__init__() + self._parent = None + self.name = name + self.Gate_Ctrl = gate_type('Gate_Ctrl', self) + + + def Do(self, timer: step_timer, Summe: gate_general): + pass + + def _init(self, parent): + self._parent = parent + return self.Do + + def ready_for_start(self, timer: step_timer): pass + + def ready_for_end(self):pass + + def _reset(self): + self.Gate_Ctrl.reset() + +#*****************************************************************#-------------------------------------------------------------------- +class ctrl_general_factor(ctrl_base): + def __init__(self, name : str = 'ctrl_general_factor', gate_type : gate_base = gate_general, Factor = 1.0): + super().__init__(name, gate_type) + self.Factor = sim_value('Factor', self, (float, int,)) + self.Factor.Init(Factor) + + + def Do(self, timer: step_timer, Gate_In: gate_general): + self.Gate_Ctrl.general._value = Gate_In.general._value * self.Factor.get_set(stepper=timer) + return self.Gate_Ctrl + + +class ctrl_general_rest(ctrl_base): + def __init__(self, name : str = 'ctrl_general_rest', gate_type : gate_base = gate_general): + super().__init__(name, gate_type) + + + def Do(self, timer: step_timer, Gate_In: gate_general): + sum = self._parent.Gate_In.general._value + for gate in self._parent._sequence_work[self._parent.Sequence_Key]['gates']: + sum = sum + gate.general._value + self.Gate_Ctrl.set(sum) + #self._parent.Gate_Node.set(sum) + return self.Gate_Ctrl + + +class ctrl_general_set(ctrl_base): + def __init__(self, name : str = 'ctrl_general_rest', gate_type : gate_base = gate_general, Value = 0.0): + super().__init__(name, gate_type) + self.Value = sim_value('Factor', self, (float, int,)) + self.Value.Init(Value) + + + def Do(self, timer: step_timer, Gate_In: gate_general): + self.Gate_Ctrl.general._value = self.Value.get_set(timer) + return self.Gate_Ctrl + + +class ctrl_general_zero(ctrl_general_rest): + def __init__(self, name : str = 'ctrl_general_zero', gate_type : gate_base = gate_general): + super().__init__(name, gate_type) + + + def Do(self, timer: step_timer, Gate_In: gate_general): + super().Do(timer = timer, Gate_In = Gate_In) + if (abs(self.Gate_Ctrl.general._value) < 0.0000001): + self._parent._ctrl_ok = True + return self.Gate_Ctrl + + +class ctrl_general_step(ctrl_base): + def __init__(self, name : str = 'ctrl_general_step', gate_type : gate_base = gate_general): + super().__init__(name, gate_type) + self.Gate_In = gate_general('Gate_In', self) + self._Gate_Step = gate_general('_Gate_Step', self) + self._sequence_work : dict = None + self.Sequence_Key : str = '' + + + def _init(self, parent): + super()._init(parent) + self._sequence_work = parent._sequence_work + self.Sequence_Key = parent.Sequence_Key + + def Do(self, timer: step_timer, Gate_In: gate_general): + self._ctrl_ok = False + self.Gate_In.general._value = Gate_In.general._value + self._Gate_Step.general._value = Gate_In.general._value + for gate_func in self._sequence_work[self.Sequence_Key]['funcs']: + gate = gate_func(timer, self.Summe) + self._Gate_Step.general._value = gate.general._value + if self._ctrl_ok: + self.Gate_Ctrl.set(0.0) + return self.Gate_Ctrl + + sum = 0 + for gate in self._sequence_work[self.Sequence_Key]['gates']: + sum = sum + gate.general._value + self.Gate_Ctrl.set(sum) + return self.Gate_Ctrl + + +#***************************************************************** +class sim_dynamic(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + self.Gate_Dynamic = gate_dynamic('Gate_Dynamic', self) + self.Feature : dict = None + self._funcgate.update({ + self.Do : self.Gate_Dynamic}) + + + def _reset(self): + self.Gate_Dynamic._reset() + super()._reset() + + + def _node_success(self, timer: step_timer): + self.Gate_Dynamic._node_success(timer) + + + def Init(self, Feature : None): + super().Init() + self.Feature = Feature + self.Gate_Dynamic.Init(self.Feature) + + + def Do(self, timer: step_timer, Gate_In: gate_general): + self.Gate_Dynamic._actual_values(timer) + return self.Gate_Dynamic + + +#-------------------------------------------------------------------- +class sim_general_node(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + self._iterat_counter : int = 0 + self.Max_Iterat = sim_value('Max_Iterat', self, (int,)) + self.Gate_Node = gate_general('Gate_Node', self) + self.Summe = gate_general('Summe', self) + self.Gate_In = gate_general('Gate_In', self) + + #Controll Strukturen + self._ctrl_nodeok : bool = False + + self.Sequence: dict = dict() # beinhaltet den vollen Namen und die Instance + self.Sequence_Key: str = '' + + self._sequence_work : dict = dict() # beinhaltet verschiedene Informationen für verschiedene Aufgaben wird gebildet + self._sequence_sims : set = set() # speichert alle verlinken sims + self._sims_gates : dict = dict() + self.Joker : sim_general_joker = None + + self._funcgate.update({ + self.Step : self.Gate_Node, + self.StepRec : self.Gate_Node, + self.SumEqual : self.Gate_Node}) + + + def Init(self, + Sequence = None, + Sequence_Key = '', + Joker = False, + Max_Iterat = -1 + ): + + super().Init() + self.Max_Iterat.Init(Max_Iterat) + + if Joker: self.Joker = sim_general_joker(self.name + '.joker') + + if not isinstance(Sequence, dict): + raise Exception(f'Sequence ist kein dict') + self.Sequence = Sequence + + + for sequence_name, sequence_list in self.Sequence.items(): + self._sequence_work.update({sequence_name : { + 'func_names' : [], + 'funcs' : [], + 'sims' : set(), + 'gates' : set() + }}) + + for seq_item in sequence_list: + if isinstance(seq_item, ctrl_base): + seq_item = seq_item._init(self) + + func_info = analyse_func(seq_item) + if not func_info: + raise Exception(f'obj : {self.name} Startfunktion nicht korrekt') + if not isinstance(func_info[0], (work_base, ctrl_base,)): + + raise Exception(f'obj : {self.name} | {func_info[0].name}|node ist kein Type von work_base') + if not callable(func_info[1]): + raise Exception(f'obj : {self.name} |node hat keine func_work methode') + + self._sequence_work[sequence_name]['func_names'].append(func_info[2]) + self._sequence_work[sequence_name]['funcs'].append(func_info[1]) + if isinstance(func_info[0], work_base): + self._sequence_work[sequence_name]['sims'].add(func_info[0]) + self._sequence_sims.add(func_info[0]) + + if not Sequence_Key : + self.Sequence_Key = next(iter(self._sequence_work)) # Der erste wird gewählt + elif Sequence_Key in self._sequence_str.keys(): + self.Sequence_Key = Sequence_Key + else: raise Exception(f'Sequence_Key {Sequence_Key} nicht vorhanden!') + + + def ready_for_start(self, timer: step_timer): + super().ready_for_start(timer) + for sim_obj in self._sequence_sims: + if sim_obj == self: + continue + sim_obj.ready_for_start(timer) + + for func in self._sequence_work[self.Sequence_Key]['funcs']: + for sim_obj in self._sequence_work[self.Sequence_Key]['sims']: + gate = sim_obj._getgate_func(func) + if isinstance(gate, gate_base): + self._sequence_work[self.Sequence_Key]['gates'].add(gate) + break + + #raise Exception('gate to Funktion not found') + + + #----------------------- Simulations Steps --------------------------------- + def _reset(self): + super()._reset() + self.Gate_Node._reset() + self.Gate_In._reset() + self.Summe._reset() + self._iterat_counter = 0 + for sim_obj in self._sequence_work[self.Sequence_Key]['sims']: + if sim_obj == self: + continue + sim_obj._reset() + if not self.Joker == None: + self.Joker._reset() + + + def _calc_node(self): + sum = 0.0 + for gate in self._sequence_work[self.Sequence_Key]['gates']: + sum = sum + gate.get() + + sum = sum - self.Gate_Node.get() + self.Summe.set(sum) + if (abs(sum) < 0.0000001): + return True + return False + + + def _node_success(self, timer: step_timer): + for sim_obj in self._sequence_work[self.Sequence_Key]['sims']: + if sim_obj == self: continue + sim_obj._node_success(timer) + + if not self.Joker == None: + self.Joker._node_success(timer) + + super()._node_success(timer) + self.Gate_Node._node_success(timer) + self.Gate_In._node_success(timer) + + + + def sum_master(self, timer: step_timer, Summe: gate_base = None): + master_gate : gate_general = gate_general('master_gate', self) + master_sum : gate_general = gate_general('master_sum', self) + + if isinstance(Summe, self.ch_type): + self.Summe.set(Summe) + self.Gate_Node.set(Summe) + else: + self.Summe.set(0.0) + + old_master = 0.0 + new_master = 0.0 + master_sum.set(old_master) + while True: + master_func = self._sequence_work[self.Sequence_Key]['funcs'][0] + value = master_func(timer, master_sum).general.value + master_gate.set(-value) + for gate_func in self._sequence_work[self.Sequence_Key]['funcs'][1:]: + gate_func(timer, master_gate) + + if self._calc_node(): + self._node_success(timer) + return self.Gate_Node + + new_master = master_gate.general.value + self.Summe.general.value + master_sum.general.value = new_master + if abs(new_master - old_master) < 0.0000001: + break + + old_master = new_master + + if self.Joker: + self.Joker.Var(timer, self.Summe) + #if self._calc_node(): + self._node_success(timer) + return self.Gate_Node + + + def SumEqual(self, timer: step_timer, Summe: gate_base = None): + self.Summe.general.value = Summe.general.value + # Hier eine Zählschleife um weitere Informationen über den Ablauf zu erhalten + + for gate_func in self._sequence_work[self.Sequence_Key]['funcs']: + gate_func(timer, self.Summe) + if self._ctrl_nodeok: + return self._ctrl_nodeok + + + if self.Joker: + self.Joker.Var(timer, self.Summe) + return self.Gate_Node + + + + def Step(self, timer: step_timer, Gate_In: gate_base = None): + self._ctrl_ok = False + self.Gate_In.general._value = Gate_In.general._value + self.Summe.general._value = Gate_In.general._value + for gate_func in self._sequence_work[self.Sequence_Key]['funcs']: + if gate_func == self.Step: # Verhindern von rekursiven Aufrufs + continue + gate = gate_func(timer, self.Summe) + self.Summe.general._value = gate.general._value + if self._ctrl_ok: + self.Gate_Node.set(0.0) + return self.Gate_Node + + #sum = self.In.general._value + sum = 0 + for gate in self._sequence_work[self.Sequence_Key]['gates']: + sum = sum + gate.general._value + self.Gate_Node.set(sum) + return self.Gate_Node + + + #Rekursiver aktiver Chanal von Step + # ruft sich selber auf wenn kein 0 erreicht ist am Ende + def StepRec(self, timer: step_timer, Gate_In: gate_base = None, counter : int = 0): + max_iterat = self.Max_Iterat.get_set(timer) + + self._ctrl_ok = False + self.Gate_In.general._value = Gate_In.general._value + self.Summe.general._value = Gate_In.general._value + for gate_func in self._sequence_work[self.Sequence_Key]['funcs']: + gate = gate_func(timer, self.Summe) + if gate_func == self.Step: # Verhindern von rekursiven Aufrufs + continue + + self.Summe.general._value = gate.general._value + if self._ctrl_ok: # rekursion beenden + self.Gate_Node.set(0.0) + return self.Gate_Node + + counter = counter + 1 + if (max_iterat >= 0) and (counter < max_iterat): + for sim_obj in self._sequence_work[self.Sequence_Key]['sims']: + if sim_obj == self: continue + sim_obj._reset() + self.StepRec(timer=timer, Gate_In=Gate_In, counter = counter) + + + sum = 0 + for gate in self._sequence_work[self.Sequence_Key]['gates']: + sum = sum + gate.general._value + self.Gate_Node.set(sum) + return self.Gate_Node + + + + def ready_for_end(self): + super().ready_for_end() + for sim_obj in self._sequence_sims: + if sim_obj == self:continue + sim_obj.ready_for_end() + + +class sim_general_chanal(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + self.Gate_Set = gate_general('Gate_Set', self) + self.Gate_Get = gate_general('Gate_Get', self) + self.Gate_Chanal = gate_general('Gate_Chanal', self) + + self._funcgate.update({ + self.Set : self.Gate_Set, + self.Get : self.Gate_Get}) + + + def Init(self, Gate_Set = None, Gate_Get = None): + super().Init() + self.Gate_Set.Init(Gate_Set) + self.Gate_Get.Init(Gate_Get) + self.Gate_Chanal.Init(None) + + + + def Set(self, timer: step_timer, Gate_In: gate_general): + self.Gate_Set.general._value = -Gate_In.general._value + self.Gate_Chanal.general._value = Gate_In.general._value + self.Gate_Get.general._value = 0 + return self.Gate_Set + + + def Get(self, timer: step_timer, Gate_In: gate_general): + self.Gate_Get.general._value = -self.Gate_Set.general._value + self.Gate_Set.general._value = 0 + return self.Gate_Get + + + def _reset(self): + self.Gate_Set._reset() + self.Gate_Get._reset() + self.Gate_Chanal._reset() + super()._reset() + + + def _node_success(self, timer: step_timer): + self.Gate_Set._node_success(timer) + self.Gate_Get._node_success(timer) + self.Gate_Chanal._node_success(timer) + + + +class sim_general_user(sim_base): + def __init__(self, name: str, **kwargs): + + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, **kwargs) + self.Gate_User = gate_general('Gate_User', self) + self.User_Func = sim_value('UserFunc', self, (float, int,)) + self._funcgate.update({ + self.User : self.Gate_User}) + + + def Init(self, + User_Func = None, + Gate_User = None + ): + + super().Init() + self.Gate_User.Init(Gate_User) + self.User_Func.Init(User_Func) + + + def User(self, timer: step_timer, Gate_In: gate_general): + gate = self.User_Func.get_set(stepper = timer, value = Gate_In) + self.Gate_User.general._value = gate.general._value + return self.Gate_User + + + def _reset(self): + self.Gate_User._reset() + super()._reset() + + + def _node_success(self, timer: step_timer): + self.Gate_User._node_success(timer) + + + +#TODO ergänzen um pulswidth von 0..1 +#TODO absolute zeit bezogen auf s einführen +#TODO verschiedene Formen auswählen +class sim_general_signal(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + self.Gate_Signal = gate_general('Gate_Signal', self) + + self.Frequency = sim_value('Frequency', self, (float, int,)) + self.Amplitude = sim_value('Amplitude', self, (float, int,)) + self.Offset = sim_value('Offset', self, (float, int,)) + + self._max_val: float = 0 + self._min_val: float = 0 + self._funcgate.update({ + self.Fix : self.Gate_Signal}) + + + def Init(self, + Amplitude = None, + Frequency = None, + Offset = None, + Gate_Signal = None + ): + + super().Init() + self.Gate_Signal.Init(Gate_Signal) + self.Amplitude.Init(Amplitude) + self.Frequency.Init(Frequency) + self.Offset.Init(Offset) + + self._max_val = self.Amplitude.value - self.Offset.value + self._min_val = self.Offset.value + + + def Fix(self, timer: step_timer, Gate_In: gate_general): + value = int(timer.step_nr / self.Frequency.value) + if value % 2: # ungrade + self.Gate_Signal.set(self._min_val) + else: # grade + self.Gate_Signal.set(self._max_val) + return self.Gate_Signal + + + def _reset(self): + self.Gate_Signal._reset() + super()._reset() + + + def _node_success(self, stepper: step_base): + self.Gate_Signal._node_success(stepper) + + +#-------------------------------------------------------------------- +class sim_general_joker(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + + def Init(self, + Gate = None): + super().Init() + self.Gate.Init(Gate) + + + def _reset(self): + self.Gate._reset() + super()._reset() + + + def _node_success(self, timer: step_timer): + self.Gate._node_success(timer) + + + def Var(self, timer: step_timer, Summe: gate_general): + self.Gate.general.set(-Summe.general.value) + return self.Gate + +#TODO ch_type raus +#-------------------------------------------------------------------- +class sim_general_store(sim_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + kwargs.update({'ch_type' : gate_general}) + super().__init__(name, GUI, **kwargs) + + self.Gate_Store = gate_general('Gate_Store', self) + self.Gate_Leak = gate_general('Gate_Leak', self) + self.Capacity_Actual = sim_value('Capacity_Actual', self, (float, int,)) + self.Leak_Capacity_Actual = sim_value('Leak_Capacity_Actual', self, (float, int,)) + + self.Capacity_Max = sim_value('Capacity_Max', self, (float, int,)) # Wenn None dann unendlich + + self.Capacity_Min = sim_value('Capacity_Min', self, (float, int,)) # Wenn None dann unendlich - + self.Load_Max = sim_value('Load_Max', self, (float, int,)) # Wenn None dann unendlich schnelles beladen + self.Unload_Max = sim_value('Unload_Max', self, (float, int,)) # Wenn None dann unendlich schnelles entladen + self.Leak_Rate = sim_value('Leak_Rate', self, (float, int,)) + self.Factor = sim_value('Factor', self, (float, int,)) + self.Invert = sim_value('invert', self, (bool,)) + + self.func_leak : dict = {'leak_rate' : 0.0} + + self._funcgate.update({self.Var : self.Gate_Store}) + + + + def Init(self, + Capacity_Max = None, + Capacity_Min = None, + Load_Max = None, + Unload_Max = None, + Leak_Rate = 0.0, + Gate_Store = 0.0, + Gate_Leak = 0.0, + Capacity_Actual = 0.0, + Factor = 1.0, + Invert = False + ): + """ Initialisiert den Speicher + + Keyword Arguments: + Capacity_Max {float oder funktion} -- maximale Kapazität des Speichers (default: {None}) + Kein Wert (None) Speichergröße im positiven Bereich unbegrenzt + Capacity_Min {[type]} -- [description] (default: {None}) + Load_Max {[type]} -- [description] (default: {None}) + Unload_Max {[type]} -- [description] (default: {None}) + Gate_Store {[type]} -- [description] (default: {None}) + Gate_Leak {[type]} -- [description] (default: {None}) + Capacity_Actual {[type]} -- [description] (default: {None}) + Factor{[float, int]} Bereich üblicherweise zwischen 0.0 und 1.0 + """ + + super().Init() + + self.Gate_Store.Init(Gate_Store) + self.Capacity_Actual.Init(Capacity_Actual, default = 0.0) + self.Gate_Leak.Init(Gate_Leak) + self.Capacity_Max.Init(Capacity_Max) + self.Capacity_Min.Init(Capacity_Min) + self.Load_Max.Init(Load_Max) + self.Unload_Max.Init(Unload_Max) + + self.Factor.Init(Factor, default = 1.0) + self.Invert.Init(Invert, default = False) + if isinstance(Leak_Rate, (float, int,)): + self.func_leak['leak_rate'] = Leak_Rate + Leak_Rate = self._leak + self.Leak_Rate.Init(Leak_Rate, default = 0.0) + + + + def _reset(self): + self.Gate_Store._reset() + super()._reset() + + # Es wird die Differenz berechnet + def _leak(self, value = None, timer : step_timer = None): + rate = self.func_leak['leak_rate'] + akt_cap = self.Capacity_Actual.value + if rate == 0.0: + return 0.0 + new_cap = akt_cap * math.exp(-rate * timer.total_sec) + return akt_cap - new_cap + + + + def calc_loadcapacity(self, value: float): + if not isinstance(self.Capacity_Max._value, (float, int,)): + return value + full_diff = (self.Capacity_Max._value - + self.Capacity_Actual._value) / self.time_factor + if full_diff > value: + return value + elif full_diff == 0.0: + return 0.0 + else: + return full_diff + + + + def calc_unloadcapacity(self, value: float): + if not isinstance(self.Capacity_Min._value, float): + return value + empty_diff = -(self.Capacity_Min._value - + self.Capacity_Actual._value) / self.time_factor + if empty_diff >= -value: + return value + elif empty_diff == 0: + return 0.0 + else: + return -empty_diff + + #TODO es sollte noch eine variante zu Var geben, um z.B. einfach Verluste Widerstände zu simulieren + def Var(self, timer: step_timer, Gate_In: gate_general): + aim_value = -Gate_In.general.value * self.Factor.get_set(timer) + if self.Invert.value : aim_value = -aim_value + if aim_value >= 0: # Beladen + max_value = self.Load_Max.get_set(stepper=timer) + if max_value == None: # Keine Begrenzung + real_value = aim_value + elif max_value >= 0 and max_value > aim_value: + real_value = aim_value + elif max_value >= 0 and max_value <= aim_value: + real_value = max_value + elif max_value < 0: + real_value = max_value + else: + max_value = self.Unload_Max.get_set(stepper=timer) + if max_value == None: # Keine Begrenzung + real_value = aim_value + elif max_value <= 0 and max_value < aim_value: + real_value = aim_value + elif max_value <= 0 and max_value >= aim_value: + real_value = max_value + elif max_value > 0: + real_value = max_value + + if real_value >= 0: # Beladen + real_value = self.calc_loadcapacity(real_value) + else: # Entladen + real_value = self.calc_unloadcapacity(real_value) + + self.Gate_Store.set(real_value) #Todo Set verbessern damit auch ein Callback erfolgt + return self.Gate_Store + + + # Immer den gleichen Wert speichern + def Fix_Load(self, timer: step_timer, Summe: gate_general): + self.Gate_Store.set(self.Load_Max) + return self.Gate_Store, True + + + # Immer den gleichen Wert entladen + def Fix_Unload(self, timer: step_timer, Summe: gate_general): + self.Gate_Store.set(self.Unload_Max) + return self.Gate_Store, True + + + def _node_success(self, timer: step_timer): + super()._node_success(timer) + + corr_value = self.Gate_Store.get() * self.time_factor + value = self.Capacity_Actual._value + corr_value + self.Capacity_Actual._value = value + + diff = self.Leak_Rate.get_set(stepper=timer) + self.Capacity_Actual._value = self.Capacity_Actual._value - diff + #self.Leak_Capacity_Actual._value = self.Leak_Capacity_Actual._value + diff + + self.Gate_Store._node_success(timer) + self.Capacity_Actual._node_success(timer) + self.Gate_Leak._node_success(timer) diff --git a/nowo1_gui_base.py b/nowo1_gui_base.py new file mode 100644 index 0000000..5cb8310 --- /dev/null +++ b/nowo1_gui_base.py @@ -0,0 +1,47 @@ +import sim_base as sim_g +import nowo1_base as nowo +import datetime as dt +import pandas as pd +import numpy as np + +import ipywidgets as widgets +import ipysheet +from ipysheet import from_dataframe +from IPython.display import display + + + +class gui_ipysheet(nowo.gui_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + self.sheet : ipysheet.sheet = None + self.sheet_colnames : list = [] + self.sheet_rownames : list = [] + self.sheet_data: pd.DataFrame = None + self.dataframe_out: pd.DataFrame = None + + + def Init_by_dataframe(self, dataframe): + self.sheet_data = dataframe + self.sheet_colnames = list(self.sheet_data.head()) + self.sheet_rownames = list(self.sheet_data.index.tolist()) + + + def ready_for_end(self): + buffer = self.sheet_data.values.T.tolist() + ipysheet.cell_range(buffer[0], column_start=1) + # self.dataframe_out = ipysheet.to_dataframe(self.sheet) + #self.sheet_data.to_clipboard() + + def _create_gui(self): + # sheet = ipysheet.sheet(rows = len(self.sheet_rownames) + 1, columns= len(self.sheet_colnames) + 1) + self.sheet = ipysheet.sheet(rows = len(self.sheet_rownames), + columns= len(self.sheet_colnames) + 1, + column_headers = ['variable'] + self.sheet_colnames) + + cols_1 = ipysheet.column(0, self.sheet_rownames, row_start = 0) + + total_box = widgets.VBox([self.sheet]) + self._GUI_itemlist.update({'sheet' : self.sheet}) + super()._create_gui()# Attention! --must-- because the widget get a parent attr. + return total_box \ No newline at end of file diff --git a/nowo1_log_base.py b/nowo1_log_base.py new file mode 100644 index 0000000..c65b4f7 --- /dev/null +++ b/nowo1_log_base.py @@ -0,0 +1,85 @@ +import sim_base as sim_g +import nowo1_base as nowo +import datetime as dt +import pandas as pd +import numpy as np + +class logger(nowo.port_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + self.log_data: pd.DataFrame = pd.DataFrame() + + def clear_buffer(self): + super().clear_buffer() + self.log_data = pd.DataFrame() + + def ready_for_end(self): + super().ready_for_end() + self.log_data = pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in self.buffer_data.items() ])) + + + +# Nimmt nur den ersten Wert und bildet eine Tabelle +# wird verwendet bei gleichen sim_obj die nur einmal berechnet wurden +class log_sheet(nowo.port_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + self.log_data: pd.DataFrame = pd.DataFrame() + super().__init__(name, GUI, **kwargs) + self.sheet_colnames : list = [] + self.sheet_rownames : list = [] + self.sheet_data: pd.DataFrame = None + + + def clear_buffer(self): + super().clear_buffer() + self.log_data = pd.DataFrame() + + + def Init(self, Values = [], Gui_For_Data = None, ): + super().Init(Values, Gui_For_Data) + for name in self.buffer_data.keys(): + split_name = name.split('.', 1) + if not split_name[0] in self.sheet_colnames: + self.sheet_colnames.append(split_name[0]) + if not split_name[1] in self.sheet_rownames: + self.sheet_rownames.append(split_name[1]) + self.sheet_data = pd.DataFrame(columns = self.sheet_colnames, index = self.sheet_rownames) + if self.Gui_For_Data: + self.Gui_For_Data.Init_by_dataframe(self.sheet_data) + + + def ready_for_end(self): + super().ready_for_end() + # self.log_data = pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in self.buffer_data.items() ])) + + for col_name in self.sheet_colnames: + for row_name in self.sheet_rownames: + key_name = col_name + '.' + row_name + value = self.buffer_data[key_name] + self.sheet_data.at[row_name, col_name] = value + self.sheet_data.to_clipboard() + if self.Gui_For_Data: + self.Gui_For_Data.ready_for_end() + + + +class log_dataframe(nowo.port_base): + def __init__(self, name: str, GUI : bool = False, **kwargs): + super().__init__(name, GUI, **kwargs) + self.log_data: pd.DataFrame = pd.DataFrame() + + def clear_buffer(self): + super().clear_buffer() + self.log_data = pd.DataFrame() + + + def ready_for_end(self): + super().ready_for_end() + new = pd.DataFrame() + for name, valuelist in self.buffer_data.items(): + for value in valuelist: + if isinstance(value, pd.DataFrame): + new = pd.concat([new,value], ignore_index=True) + + self.log_data = new + self.col_name = self.log_data.columns.tolist() \ No newline at end of file diff --git a/nowo1_sim_binary.py b/nowo1_sim_binary.py new file mode 100644 index 0000000..953e140 --- /dev/null +++ b/nowo1_sim_binary.py @@ -0,0 +1,406 @@ + +import sim_base as sim_g +import nowo1_base as nowo +import datetime as dt +import pandas as pd +import numpy as np +import ipywidgets as widgets +from IPython.display import display + + +class binary_node(nowo.sim_base): + def __init__(self, name: str, **kwargs): + kwargs.update({'ch_type' : nowo.gate_general}) + super().__init__(name, **kwargs) + self.Gate_A = nowo.gate_general('Gate_A', self) + self.Gate_B = nowo.gate_general('Gate_B', self) + self.Gate_A_B = nowo.gate_general('Gate_A_B', self) + + self.A_ratio = nowo.sim_value('A_ratio', self, (float, int,)) + self.B_ratio = nowo.sim_value('B_ratio', self, (float, int,)) + self.A_portion = nowo.sim_value('A_portion', self, (float, int,)) + self.B_portion = nowo.sim_value('B_portion', self, (float, int,)) + + self.Info = nowo.sim_value('Info', self, (str,)) + + self.calcflag : bool = True + self._value_key : np.byte = 0b00000000 + + + self._checkstruct : dict = dict( + {'one_val' : [0,1,2,4,8,16,32,64]} + ) + + self._value_keys : dict = { + 'A' : 0b01000000, + 'B' : 0b00100000, + 'A_B': 0b00010000, + 'A_ratio': 0b00001000, + 'B_ratio': 0b00000100, + 'A_portion':0b00000010, + 'B_portion':0b00000001 + } + + self._funcgate.update({ + self.Calc_A : self.Gate_A, + self.Calc_B : self.Gate_B, + self.Calc_A_B : self.Gate_A_B + }) + + + def _create_gui(self): + options =[('Strom A', 'A'), + ('Strom B', 'B'), + ('Summe A und B', 'A_B'), + ('Verhältnis A', 'A_ratio'), + ('Verhältnis B', 'B_ratio'), + ('Anteil A', 'A_portion'), + ('Anteil B', 'B_portion') + ] + + layout_select = widgets.Layout(width='100%') + layout_valbox = widgets.Layout(padding = '1em 0 0 0', background_color='red') + + val_label_1 = widgets.Label(value='extensive Größe:') + val_select_1 = widgets.Dropdown(options = options[:3], + value='A', + #description='Extensive Größe:', + layout = layout_select + ) + value_1 = widgets.FloatText(value = 0.0, layout=widgets.Layout(width='15%')) + + val_label_2 = widgets.Label(value='extensive oder intensive Größe') + val_select_2 = widgets.Dropdown(options = options, + value='B', + #description='extensive oder intensive Größe:', + layout = layout_select) + value_2 = widgets.FloatText(value = 0.0, layout=widgets.Layout(width='15%')) + + val1_box = widgets.VBox([val_label_1, widgets.HBox([val_select_1, value_1])], + background_color='red') + val2_box = widgets.VBox([val_label_2, widgets.HBox([val_select_2, value_2])], layout = layout_valbox) + + + total_box = widgets.VBox([val1_box, val2_box], background_color='red') + + self._GUI_itemlist.update({ + 'val_select_1' : val_select_1, + 'value_1' : value_1, + 'val_select_2' : val_select_2, + 'value_2' : value_2, + }) + super()._create_gui()# Attention! --must-- because the widget get a parent attr. + return total_box + + + def Init_Over_GUI(self): + para = { + self._GUI_itemlist['val_select_1'].value : self._GUI_itemlist['value_1'].value, + self._GUI_itemlist['val_select_2'].value : self._GUI_itemlist['value_2'].value + } + self.Init(**para) + + + def Init(self, + A = np.nan, + B = np.nan, + A_B = np.nan, + A_ratio = np.nan, + B_ratio = np.nan, + A_portion = np.nan, + B_portion = np.nan, + ): + + super().Init() + self._value_key = 0b00000000 + self.Gate_A.general.Init(A) + self.Gate_B.general.Init(B) + self.Gate_A_B.general.Init(A_B) + self.A_ratio.Init(A_ratio) + self.B_ratio.Init(B_ratio) + self.A_portion.Init(A_portion) + self.B_portion.Init(B_portion) + self.Info.Init('kein Kommentar') + self.Info._value = 'Oh mann' + + + def _set_values(self): + if not self._korr_key & 0b01000000: self.A = np.nan + if not self._korr_key & 0b00100000: self.B = np.nan + if not self._korr_key & 0b00010000: self.A_B = np.nan + if not self._korr_key & 0b00001000: self.A_ratio = np.nan + if not self._korr_key & 0b00000100: self.B_ratio = np.nan + if not self._korr_key & 0b00000010: self.A_portion = np.nan + if not self._korr_key & 0b00000001: self.B_portion = np.nan + + + # es muss mindestens ein A oder B oder A_B vorhanden sein aber nicht mehr wie zwei + def _check_values(self, stepper : nowo.step_base): + # Build zahl bei values + count : int = 0 + if not np.isnan(self.Gate_A.general.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['A'] + count = count + 1 + if not np.isnan(self.Gate_B.general.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['B'] + count = count + 1 + if not np.isnan(self.Gate_A_B.general.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['A_B'] + count = count + 1 + if not np.isnan(self.A_ratio.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['A_ratio'] + count = count + 1 + if not np.isnan(self.B_ratio.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['B_ratio'] + count = count + 1 + if not np.isnan(self.A_portion.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['A_portion'] + count = count + 1 + if not np.isnan(self.B_portion.get_set(stepper)): + self._value_key = self._value_key |self._value_keys['B_portion'] + count = count + 1 + + if count < 2: + self.Info._value = 'Es müssen mind. 2 unterschiedliche Werte angeben werden' + return False + elif count > 2: + self.Info._value = 'Es dürfen nicht mehr als 2 unterschiedliche Werte angeben werden' + return False + + # Abfrage ob wenigstens eine Masse vorhanden ist + if self._value_key < 16: + self.Info._value = 'Es muss min. ein Strom (A, B oder A_B) angegeben werden' + return False + + return True + + + def Calc_A(self, stepper : nowo.step_base, Gate_In: nowo.gate_general): + self._calc(stepper, Gate_In) + return self.Gate_A + + + def Calc_B(self, stepper : nowo.step_base, Gate_In: nowo.gate_general): + self._calc(stepper, Gate_In) + return self.Gate_B + + + def Calc_A_B(self, stepper : nowo.step_base, Gate_In: nowo.gate_general): + self._calc(stepper, Gate_In) + return self.Gate_A_B + + + def _calc(self, stepper : nowo.step_base, Gate_In: nowo.gate_general): + if not self._check_values(stepper): return + self.calcflag = True + while self.calcflag: + self.calcflag = False + self._calc_A_ratio() + self._calc_B_ratio() + self._calc_A_portion() + self._calc_B_portion() + self._calc_A() + self._calc_B() + self._calc_A_B() + + + def _set_calcflag(self, flag): + if not self.calcflag: + self.calcflag = flag + + + + def _calc_A_ratio(self): + if self._value_keys['A_ratio'] & self._value_key: + self._set_calcflag(False) + return + + try: + if self._value_keys['A_portion'] & self._value_key: + self.A_ratio._value = 1/(1/self.A_portion._value -1) + + elif self._value_keys['B_ratio'] & self._value_key: + self.A_ratio._value = 1/self.B_ratio._value + + elif self._value_keys['A'] & self._value_key and self._value_keys['B'] & self._value_key: + self.A_ratio._value = self.Gate_A.general._value / self.Gate_B.general._value + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['A'] & self._value_key: + self.A_ratio._value = self.Gate_A.general._value / (self.Gate_A_B.general._value - self.Gate_A.general._value) + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['B'] & self._value_key: + self.A_ratio._value = (self.Gate_A_B.general._value - self.Gate_B.general._value) / self.B + + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['A_ratio'] + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + def _calc_A_portion(self): + if self._value_keys['A_portion'] & self._value_key: + self._set_calcflag(False) + return + try: + if self._value_keys['A_ratio'] & self._value_key: + self.A_portion._value = 1/(1/self.A_ratio._value +1) + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['A_portion'] + + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + def _calc_B_portion(self): + if self._value_keys['B_portion'] & self._value_key: + self._set_calcflag(False) + return + + try: + if self._value_keys['B_ratio'] & self._value_key: + self.B_portion._value = 1/(1/self.B_ratio._value +1) + + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['B_portion'] + + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + def _calc_B_ratio(self): + if self._value_keys['B_ratio'] & self._value_key: + self._set_calcflag(False) + return + try: + if self._value_keys['A_ratio'] & self._value_key: + self.B_ratio._value = 1/self.A_ratio._value + + elif self._value_keys['B_portion'] & self._value_key: + self.B_ratio._value = 1/(1/self.B_portion._value -1) + + elif self._value_keys['A'] & self._value_key and self._value_keys['B'] & self._value_key: + self.B_ratio._value = self.Gate_B.general._value / self.Gate_A.general._value + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['B'] & self._value_key: + self.B_ratio._value = self.Gate_B.general._value / (self.Gate_A_B.general._value - self.Gate_B.general._value) + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['A'] & self._value_key: + self.B_ratio._value = (self.Gate_A_B.general._value - self.Gate_A.general._value) / self.Gate_A.general._value + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['B_ratio'] + + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + def _calc_A(self): + if self._value_keys['A'] & self._value_key: + self._set_calcflag(False) + return + + try: + if self._value_keys['A_B'] & self._value_key and self._value_keys['B'] & self._value_key: + self.Gate_A.general._value = (self.Gate_A_B.general._value - self.B) + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['A_portion'] & self._value_key: + self.Gate_A.general._value = (self.Gate_A_B.general._value * self.A_portion._value) + + elif self._value_keys['A_B'] & self._value_key and self._value_keys['A_ratio'] & self._value_key: + self.Gate_A.general._value = (self.Gate_A_B.general._value * self.A_portion._value) + + elif self._value_keys['B'] & self._value_key and self._value_keys['A_ratio'] & self._value_key: + self.Gate_A.general._value = (self.Gate_B.general._value * self.A_ratio._value) + + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['A'] + + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + def _calc_B(self): + if self._value_keys['B'] & self._value_key:# + self._set_calcflag(False) + return + + try: + if self._value_keys['A_B'] & self._value_key and self._value_keys['A'] & self._value_key: + self.Gate_B.general._value = (self.Gate_A_B.general._value - self.Gate_A.general._value) + elif self._value_keys['A_B'] & self._value_key and self._value_keys['B_portion'] & self._value_key: + self.Gate_B.general._value = (self.Gate_A_B.general._value * self.B_portion._value) + elif self._value_keys['A'] & self._value_key and self._value_keys['B_ratio'] & self._value_key: + self.Gate_B.general._value = (self.Gate_A.general._value * self.B_ratio._value) + + else: + self._set_calcflag(False) + return + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['B'] + + except ZeroDivisionError as error: + pass + except Exception as exception: + pass + + + + + def _calc_A_B(self): + if self._value_keys['A_B'] & self._value_key: + self._set_calcflag(False) + return + + if self._value_keys['A'] & self._value_key and self._value_keys['B'] & self._value_key: + self.Gate_A_B.general._value = (self.Gate_A.general._value + self.Gate_B.general._value) + self._set_calcflag(True) + self._value_key = self._value_key | self._value_keys['A_B'] + return + self._set_calcflag(False) + + + def _reset(self): + self.Gate_A._reset() + self.Gate_B._reset() + self.Gate_A_B._reset() + super()._reset() + + + def _node_success(self, stepper: nowo.step_base): + self.Gate_A._node_success(stepper) + self.Gate_B._node_success(stepper) + self.Gate_A_B._node_success(stepper) + self.A_ratio._node_success(stepper) + self.B_ratio._node_success(stepper) + self.A_portion._node_success(stepper) + self.B_portion._node_success(stepper) + self.Info._node_success(stepper) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e76e091..a02b580 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ voila voila-gridstack +ipysheet diff --git a/sim_base.py b/sim_base.py new file mode 100644 index 0000000..865172d --- /dev/null +++ b/sim_base.py @@ -0,0 +1,11 @@ +import pathlib +import sys + +# Globale Festlegungen +Main_Modul = sys.modules['__main__'] +Self_Modulname = globals()['__name__'] +Self_Modul = sys.modules[Self_Modulname] + +#sim_obj_factory = Main_Modul.sim_obj_factory + +timepattern = '%Y-%m-%d %H:%M:%S' \ No newline at end of file -- GitLab