SWaTSimulationManagerPhysical.java 139 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547
  1. package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;
  2. import java.beans.PropertyChangeListener;
  3. import java.beans.PropertyChangeSupport;
  4. import java.io.File;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileWriter;
  7. import java.io.IOException;
  8. import java.math.BigDecimal;
  9. import java.text.ParseException;
  10. import java.text.SimpleDateFormat;
  11. import java.util.ArrayList;
  12. import java.util.Calendar;
  13. import java.util.Date;
  14. import java.util.LinkedHashMap;
  15. import java.util.LinkedList;
  16. import java.util.List;
  17. import java.util.Scanner;
  18. import java.util.concurrent.ThreadLocalRandom;
  19. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
  20. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.NetworkController;
  21. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.devices.SWaTDevice;
  22. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.distributionHandler.SWaTDatasetDistributionHandler;
  23. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.SWaTSimplifiedModbusProtocol;
  24. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.SWaTDeviceTypes;
  25. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.SWaTUtilities;
  26. /**
  27. * The functions of the SWaT physical data simulation.</br>
  28. * The simulation methods may contain a lot of copied and slightly changed code.
  29. * This was done on purpose to make it easier to fine-adjust the parameters.
  30. *
  31. * @author Fabian Kaiser
  32. */
  33. public class SWaTSimulationManagerPhysical {
  34. /**
  35. * Network controller for the simulation.
  36. */
  37. private NetworkController networkController;
  38. /**
  39. * The duration of the simulation in seconds.
  40. */
  41. private int durationInSeconds;
  42. /**
  43. * The path of the directory where the output files are saved.
  44. */
  45. private String outputDirectoryPath;
  46. /**
  47. * The path of the last output file;
  48. */
  49. private static String lastOutputFilePath = "";
  50. /**
  51. * The start time of the simulation.
  52. */
  53. private Calendar startTime;
  54. /**
  55. * The start time of the simulation.
  56. */
  57. private Calendar currentTime;
  58. /**
  59. * Offset of the start of the backup interval. Is 600 for the tests in the main method and 0 for general use.
  60. */
  61. private static int backupIntervalTestOffset = 0;
  62. /**
  63. * Pass-by-reference value to stop the simulation.
  64. */
  65. private boolean[] passByReferenceValue_KeepSimulationRunning;
  66. /**
  67. * Variable needed as Observable.
  68. */
  69. private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
  70. /**
  71. * The list with the output line by line.
  72. */
  73. private LinkedList<String> outputList = new LinkedList<String>();
  74. /**
  75. * The first line of the output with the description of the columns.
  76. */
  77. private String outputColumnDescription = "";
  78. /**
  79. * A HashMap with the time in seconds as key and a String array of double representations as value.</br>
  80. * String[]: [0] = LIT-101, [1] = AIT-201, [2] = FIT-201, [3] = LIT-301, [4] = LIT-401, [5] = 0 for normal, 1 for attack
  81. */
  82. private LinkedHashMap<Integer, String[]> resultsMap = new LinkedHashMap<Integer, String[]>();
  83. ///////////////////////// Lists for the status values (start)
  84. /**
  85. * The list for the timestamps.
  86. */
  87. private LinkedList<String> listTimestamp;
  88. /**
  89. * The list for the attack status.
  90. */
  91. private LinkedList<String> listNormalAttack;
  92. /**
  93. * The list for FIT-101 values.
  94. */
  95. private LinkedList<Double> listFIT101;
  96. /**
  97. * The list for LIT-101 values.
  98. */
  99. private LinkedList<Double> listLIT101;
  100. /**
  101. * The list for LIT-101 values without jittering.
  102. */
  103. private LinkedList<Double> listLIT101WithoutJittering;
  104. /**
  105. * The list for MV-101 values.
  106. */
  107. private LinkedList<Integer> listMV101;
  108. /**
  109. * The list for P-101 values.
  110. */
  111. private LinkedList<Integer> listP101;
  112. /**
  113. * The list for P-102 values.
  114. */
  115. private LinkedList<Integer> listP102;
  116. /**
  117. * The list for MV-201 values.
  118. */
  119. private LinkedList<Integer> listMV201;
  120. /**
  121. * The list for AIT-201 values.
  122. */
  123. private LinkedList<Double> listAIT201;
  124. /**
  125. * The list for AIT-202 values.
  126. */
  127. private LinkedList<Double> listAIT202;
  128. /**
  129. * The list for AIT-203 values.
  130. */
  131. private LinkedList<Double> listAIT203;
  132. /**
  133. * The list for FIT-201 values.
  134. */
  135. private LinkedList<Double> listFIT201;
  136. /**
  137. * The list for P-201 values.
  138. */
  139. private LinkedList<Integer> listP201;
  140. /**
  141. * The list for P-202 values.
  142. */
  143. private LinkedList<Integer> listP202;
  144. /**
  145. * The list for P-203 values.
  146. */
  147. private LinkedList<Integer> listP203;
  148. /**
  149. * The list for P-204 values.
  150. */
  151. private LinkedList<Integer> listP204;
  152. /**
  153. * The list for P-205 values.
  154. */
  155. private LinkedList<Integer> listP205;
  156. /**
  157. * The list for P-206 values.
  158. */
  159. private LinkedList<Integer> listP206;
  160. /**
  161. * The list of backwash intervals from the training data for MV-301.
  162. */
  163. private LinkedList<Integer> backwashIntervalList;
  164. /**
  165. * The list for DPIT-301 values.
  166. */
  167. private LinkedList<Double> listDPIT301;
  168. /**
  169. * The list for FIT-301 values.
  170. */
  171. private LinkedList<Double> listFIT301;
  172. /**
  173. * The list for LIT-301 values.
  174. */
  175. private LinkedList<Double> listLIT301;
  176. /**
  177. * The list for LIT-301 values without jittering.
  178. */
  179. private LinkedList<Double> listLIT301WithoutJittering;
  180. /**
  181. * The list for MV-301 values.
  182. */
  183. private LinkedList<Integer> listMV301;
  184. /**
  185. * The list for MV-302 values.
  186. */
  187. private LinkedList<Integer> listMV302;
  188. /**
  189. * The list for MV-303 values.
  190. */
  191. private LinkedList<Integer> listMV303;
  192. /**
  193. * The list for MV-304 values.
  194. */
  195. private LinkedList<Integer> listMV304;
  196. /**
  197. * The list for P-301 values.
  198. */
  199. private LinkedList<Integer> listP301;
  200. /**
  201. * The list for P-302 values.
  202. */
  203. private LinkedList<Integer> listP302;
  204. /**
  205. * The list for AIT-401 values.
  206. */
  207. private LinkedList<Double> listAIT401;
  208. /**
  209. * The list for AIT-402 values.
  210. */
  211. private LinkedList<Double> listAIT402;
  212. /**
  213. * The list for FIT-401 values.
  214. */
  215. private LinkedList<Double> listFIT401;
  216. /**
  217. * The list for LIT-401 values.
  218. */
  219. private LinkedList<Double> listLIT401;
  220. /**
  221. * The list for P-401 values.
  222. */
  223. private LinkedList<Integer> listP401;
  224. /**
  225. * The list for P-402 values.
  226. */
  227. private LinkedList<Integer> listP402;
  228. /**
  229. * The list for P-403 values.
  230. */
  231. private LinkedList<Integer> listP403;
  232. /**
  233. * The list for P-404 values.
  234. */
  235. private LinkedList<Integer> listP404;
  236. /**
  237. * The list for UV-401 values.
  238. */
  239. private LinkedList<Integer> listUV401;
  240. /**
  241. * The list for AIT-501 values.
  242. */
  243. private LinkedList<Double> listAIT501;
  244. /**
  245. * The list for AIT-502 values.
  246. */
  247. private LinkedList<Double> listAIT502;
  248. /**
  249. * The list for AIT-503 values.
  250. */
  251. private LinkedList<Double> listAIT503;
  252. /**
  253. * The list for AIT-504 values.
  254. */
  255. private LinkedList<Double> listAIT504;
  256. /**
  257. * The list for FIT-501 values.
  258. */
  259. private LinkedList<Double> listFIT501;
  260. /**
  261. * The list for FIT-502 values.
  262. */
  263. private LinkedList<Double> listFIT502;
  264. /**
  265. * The list for FIT-503 values.
  266. */
  267. private LinkedList<Double> listFIT503;
  268. /**
  269. * The list for FIT-504 values.
  270. */
  271. private LinkedList<Double> listFIT504;
  272. /**
  273. * The list for P-501 values.
  274. */
  275. private LinkedList<Integer> listP501;
  276. /**
  277. * The list for P-502 values.
  278. */
  279. private LinkedList<Integer> listP502;
  280. /**
  281. * The list for PIT-501 values.
  282. */
  283. private LinkedList<Double> listPIT501;
  284. /**
  285. * The list for PIT-502 values.
  286. */
  287. private LinkedList<Double> listPIT502;
  288. /**
  289. * The list for PIT-503 values.
  290. */
  291. private LinkedList<Double> listPIT503;
  292. /**
  293. * The list for FIT-601 values.
  294. */
  295. private LinkedList<Double> listFIT601;
  296. /**
  297. * The list for P-601 values.
  298. */
  299. private LinkedList<Integer> listP601;
  300. /**
  301. * The list for P-602 values.
  302. */
  303. private LinkedList<Integer> listP602;
  304. /**
  305. * The list for P-603 values.
  306. */
  307. private LinkedList<Integer> listP603;
  308. ///////////////////////// Lists for the status values (end)
  309. /**
  310. * The distribution handlers for the physical data.
  311. */
  312. private LinkedHashMap<String, SWaTDatasetDistributionHandler> distributionHandlers = new LinkedHashMap<String, SWaTDatasetDistributionHandler>();
  313. /**
  314. * A Hashmap of transition information with key sensor name and value array of length 5 with [0] = {0, 1} for {false, true}, [1] = total transition time, [2] = remaining transition time, [3] = goal status {1, 2}, [4] = remaining time offset before transition starts.
  315. */
  316. private LinkedHashMap<String, int[]> transitionInformation = new LinkedHashMap<String, int[]>();
  317. /**
  318. * A Hashmap of extreme values with key sensor name and value extreme values list.
  319. */
  320. private LinkedHashMap<String, LinkedList<Double>> extremeValues = new LinkedHashMap<String, LinkedList<Double>>();
  321. /**
  322. * A Hashmap of extreme value informations with key sensor name and value {-1, 0, 1} for {none, minimum, maximum}.
  323. */
  324. private LinkedHashMap<String, Integer> extremeValueInformation = new LinkedHashMap<String, Integer>();
  325. /**
  326. * A Hashmap of plateaus values with key sensor name and value plateau values list.
  327. */
  328. private LinkedHashMap<String, LinkedList<Double>> plateauValues = new LinkedHashMap<String, LinkedList<Double>>();
  329. /**
  330. * Maps the device names of sensors to their lists.
  331. */
  332. private LinkedHashMap<String, LinkedList<Double>> deviceNamesToDeviceListsSensors = new LinkedHashMap<String, LinkedList<Double>>();
  333. /**
  334. * Maps the device names of sensors to their lists.
  335. */
  336. private LinkedHashMap<String, LinkedList<Integer>> deviceNamesToDeviceListsActuators = new LinkedHashMap<String, LinkedList<Integer>>();
  337. /**
  338. * The constructor.
  339. * @param controller The controller of the scenario.
  340. */
  341. public SWaTSimulationManagerPhysical(Controller controller) {
  342. this.networkController = controller.getNetworkController();
  343. }
  344. /**
  345. * Starts the physical simulation.
  346. * @param duration The duration of the simulation in seconds.
  347. * @param outputFileTime A calendar object for the timestamp in the file name of the output file
  348. * @param outputDirectoryPath The path of the directory for the output files.
  349. * @param startStatus The status at which the simulation is to be started. Has the format of a line of the network traffic data.
  350. * @param passByReferenceValue_KeepSimulationRunning The PropertyChangeListener to observe this class.
  351. * @param propertyChangeListener The PropertyChangeListener to observe this class.
  352. * @param attackData The attack data as a two-dimensional array. Each row is an attack with [0] = start time, [1] = end time, [2] = device name, [3] = value/status to change to
  353. */
  354. public void startSimulation(String duration, Calendar outputFileTime, String outputDirectoryPath, String startStatus,
  355. boolean[] passByReferenceValue_KeepSimulationRunning, PropertyChangeListener propertyChangeListener,
  356. Object[][] attackData) {
  357. // Reset lists
  358. outputList = new LinkedList<String>();
  359. listTimestamp = new LinkedList<String>();
  360. listNormalAttack = new LinkedList<String>();
  361. listFIT101 = new LinkedList<Double>();
  362. listLIT101 = new LinkedList<Double>();
  363. listLIT101WithoutJittering = new LinkedList<Double>();
  364. listMV101 = new LinkedList<Integer>();
  365. listP101 = new LinkedList<Integer>();
  366. listP102 = new LinkedList<Integer>();
  367. listMV201 = new LinkedList<Integer>();
  368. listAIT201 = new LinkedList<Double>();
  369. listAIT202 = new LinkedList<Double>();
  370. listAIT203 = new LinkedList<Double>();
  371. listFIT201 = new LinkedList<Double>();
  372. listP201 = new LinkedList<Integer>();
  373. listP202 = new LinkedList<Integer>();
  374. listP203 = new LinkedList<Integer>();
  375. listP204 = new LinkedList<Integer>();
  376. listP205 = new LinkedList<Integer>();
  377. listP206 = new LinkedList<Integer>();
  378. backwashIntervalList = new LinkedList<Integer>();
  379. setUpBackwashIntervalList();
  380. listDPIT301 = new LinkedList<Double>();
  381. listFIT301 = new LinkedList<Double>();
  382. listLIT301 = new LinkedList<Double>();
  383. listLIT301WithoutJittering = new LinkedList<Double>();
  384. listMV301 = new LinkedList<Integer>();
  385. listMV302 = new LinkedList<Integer>();
  386. listMV303 = new LinkedList<Integer>();
  387. listMV304 = new LinkedList<Integer>();
  388. listP301 = new LinkedList<Integer>();
  389. listP302 = new LinkedList<Integer>();
  390. listAIT401 = new LinkedList<Double>();
  391. listAIT402 = new LinkedList<Double>();
  392. listFIT401 = new LinkedList<Double>();
  393. listLIT401 = new LinkedList<Double>();
  394. listP401 = new LinkedList<Integer>();
  395. listP402 = new LinkedList<Integer>();
  396. listP403 = new LinkedList<Integer>();
  397. listP404 = new LinkedList<Integer>();
  398. listUV401 = new LinkedList<Integer>();
  399. listAIT501 = new LinkedList<Double>();
  400. listAIT502 = new LinkedList<Double>();
  401. listAIT503 = new LinkedList<Double>();
  402. listAIT504 = new LinkedList<Double>();
  403. listFIT501 = new LinkedList<Double>();
  404. listFIT502 = new LinkedList<Double>();
  405. listFIT503 = new LinkedList<Double>();
  406. listFIT504 = new LinkedList<Double>();
  407. listP501 = new LinkedList<Integer>();
  408. listP502 = new LinkedList<Integer>();
  409. listPIT501 = new LinkedList<Double>();
  410. listPIT502 = new LinkedList<Double>();
  411. listPIT503 = new LinkedList<Double>();
  412. listFIT601 = new LinkedList<Double>();
  413. listP601 = new LinkedList<Integer>();
  414. listP602 = new LinkedList<Integer>();
  415. listP603 = new LinkedList<Integer>();
  416. deviceNamesToDeviceListsSensors = new LinkedHashMap<String, LinkedList<Double>>();
  417. deviceNamesToDeviceListsSensors.put("FIT-101", listFIT101);
  418. deviceNamesToDeviceListsSensors.put("LIT-101", listLIT101);
  419. deviceNamesToDeviceListsSensors.put("AIT-201", listAIT201);
  420. deviceNamesToDeviceListsSensors.put("AIT-202", listAIT202);
  421. deviceNamesToDeviceListsSensors.put("AIT-203", listAIT203);
  422. deviceNamesToDeviceListsSensors.put("FIT-201", listFIT201);
  423. deviceNamesToDeviceListsSensors.put("DPIT-301", listDPIT301);
  424. deviceNamesToDeviceListsSensors.put("FIT-301", listFIT301);
  425. deviceNamesToDeviceListsSensors.put("LIT-301", listLIT301);
  426. deviceNamesToDeviceListsSensors.put("AIT-401", listAIT401);
  427. deviceNamesToDeviceListsSensors.put("AIT-402", listAIT402);
  428. deviceNamesToDeviceListsSensors.put("FIT-401", listFIT401);
  429. deviceNamesToDeviceListsSensors.put("LIT-401", listLIT401);
  430. deviceNamesToDeviceListsSensors.put("AIT-501", listAIT501);
  431. deviceNamesToDeviceListsSensors.put("AIT-502", listAIT502);
  432. deviceNamesToDeviceListsSensors.put("AIT-503", listAIT503);
  433. deviceNamesToDeviceListsSensors.put("AIT-504", listAIT504);
  434. deviceNamesToDeviceListsSensors.put("FIT-501", listFIT501);
  435. deviceNamesToDeviceListsSensors.put("FIT-502", listFIT502);
  436. deviceNamesToDeviceListsSensors.put("FIT-503", listFIT503);
  437. deviceNamesToDeviceListsSensors.put("FIT-504", listFIT504);
  438. deviceNamesToDeviceListsSensors.put("PIT-501", listPIT501);
  439. deviceNamesToDeviceListsSensors.put("PIT-502", listPIT502);
  440. deviceNamesToDeviceListsSensors.put("PIT-503", listPIT503);
  441. deviceNamesToDeviceListsSensors.put("FIT-601", listFIT601);
  442. deviceNamesToDeviceListsActuators = new LinkedHashMap<String, LinkedList<Integer>>();
  443. deviceNamesToDeviceListsActuators.put("MV-101", listMV101);
  444. deviceNamesToDeviceListsActuators.put("P-101", listP101);
  445. deviceNamesToDeviceListsActuators.put("P-102", listP102);
  446. deviceNamesToDeviceListsActuators.put("MV-201", listMV201);
  447. deviceNamesToDeviceListsActuators.put("P-201", listP201);
  448. deviceNamesToDeviceListsActuators.put("P-202", listP202);
  449. deviceNamesToDeviceListsActuators.put("P-203", listP203);
  450. deviceNamesToDeviceListsActuators.put("P-204", listP204);
  451. deviceNamesToDeviceListsActuators.put("P-205", listP205);
  452. deviceNamesToDeviceListsActuators.put("P-206", listP206);
  453. deviceNamesToDeviceListsActuators.put("MV-301", listMV301);
  454. deviceNamesToDeviceListsActuators.put("MV-302", listMV302);
  455. deviceNamesToDeviceListsActuators.put("MV-303", listMV303);
  456. deviceNamesToDeviceListsActuators.put("MV-304", listMV304);
  457. deviceNamesToDeviceListsActuators.put("P-301", listP301);
  458. deviceNamesToDeviceListsActuators.put("P-302", listP302);
  459. deviceNamesToDeviceListsActuators.put("P-401", listP401);
  460. deviceNamesToDeviceListsActuators.put("P-402", listP402);
  461. deviceNamesToDeviceListsActuators.put("P-403", listP403);
  462. deviceNamesToDeviceListsActuators.put("P-404", listP404);
  463. deviceNamesToDeviceListsActuators.put("UV-401", listUV401);
  464. deviceNamesToDeviceListsActuators.put("P-501", listP501);
  465. deviceNamesToDeviceListsActuators.put("P-502", listP502);
  466. deviceNamesToDeviceListsActuators.put("P-601", listP601);
  467. deviceNamesToDeviceListsActuators.put("P-602", listP602);
  468. deviceNamesToDeviceListsActuators.put("P-603", listP603);
  469. // Reset additional variables
  470. transitionInformation = new LinkedHashMap<String, int[]>();
  471. transitionInformation.put("MV-101", new int[]{0,0,0,0,0});
  472. transitionInformation.put("MV-201", new int[]{0,0,0,0,3});
  473. transitionInformation.put("P-203", new int[]{0,0,0,0,0});
  474. transitionInformation.put("P-205", new int[]{0,0,0,0,0});
  475. transitionInformation.put("AIT-201", new int[]{0,0,0,0,0});
  476. transitionInformation.put("AIT-202", new int[]{0,0,0,0,0});
  477. transitionInformation.put("AIT-203", new int[]{0,0,0,0,0});
  478. transitionInformation.put("FIT-201", new int[]{0,0,0,0,0});
  479. transitionInformation.put("MV-301", new int[]{0,0,0,0,0});
  480. transitionInformation.put("MV-302", new int[]{0,0,0,0,0});
  481. transitionInformation.put("MV-303", new int[]{0,0,0,0,0});
  482. transitionInformation.put("MV-304", new int[]{0,0,0,0,0});
  483. transitionInformation.put("P-302", new int[]{0,0,0,0,0});
  484. transitionInformation.put("LIT-301", new int[]{0,0,0,0,0});
  485. transitionInformation.put("LIT-401", new int[]{0,0,0,0,0});
  486. transitionInformation.put("FIT-401", new int[]{0,0,0,0,0});
  487. transitionInformation.put("P-402", new int[]{0,0,0,0,0});
  488. transitionInformation.put("UV-401", new int[]{0,0,0,0,0});
  489. transitionInformation.put("AIT-402", new int[]{0,0,0,0,0});
  490. transitionInformation.put("LIT-401", new int[]{0,0,0,0,0});
  491. transitionInformation.put("P-501", new int[]{0,0,0,0,0});
  492. transitionInformation.put("FIT-501", new int[]{0,0,0,0,0});
  493. transitionInformation.put("FIT-502", new int[]{0,0,0,0,0});
  494. transitionInformation.put("FIT-503", new int[]{0,0,0,0,0});
  495. transitionInformation.put("FIT-504", new int[]{0,0,0,0,0});
  496. transitionInformation.put("PIT-501", new int[]{0,0,0,0,0});
  497. transitionInformation.put("PIT-502", new int[]{0,0,0,0,0});
  498. transitionInformation.put("PIT-503", new int[]{0,0,0,0,0});
  499. transitionInformation.put("AIT-501", new int[]{0,0,0,0,0});
  500. transitionInformation.put("AIT-502", new int[]{0,0,0,0,0});
  501. transitionInformation.put("AIT-503", new int[]{0,0,0,0,0});
  502. transitionInformation.put("AIT-504", new int[]{0,0,0,0,0});
  503. transitionInformation.put("P-602", new int[]{0,0,-1,0,0});
  504. extremeValues = new LinkedHashMap<String, LinkedList<Double>>();
  505. LinkedList<Double> extremeValueListTemp = new LinkedList<Double>();
  506. extremeValueListTemp.add(0.0);
  507. extremeValues.put("FIT-101", extremeValueListTemp);
  508. extremeValues.put("LIT-101", new LinkedList<Double>());
  509. LinkedList<Double> extremeValueListTemp2 = new LinkedList<Double>();
  510. extremeValueListTemp2.add(0.0);
  511. extremeValues.put("FIT-201", new LinkedList<Double>());
  512. extremeValues.put("AIT-203", new LinkedList<Double>());
  513. extremeValues.put("AIT-202", new LinkedList<Double>());
  514. extremeValues.put("FIT-301", new LinkedList<Double>());
  515. extremeValueInformation = new LinkedHashMap<String, Integer>();
  516. extremeValueInformation.put("FIT-101", 0);
  517. extremeValueInformation.put("LIT-101", -1);
  518. extremeValueInformation.put("FIT-201", 0);
  519. extremeValueInformation.put("AIT-201", -1);
  520. extremeValueInformation.put("AIT-202", -1);
  521. extremeValueInformation.put("AIT-203", -1);
  522. extremeValueInformation.put("LIT-301", -1);
  523. extremeValueInformation.put("FIT-301", 1);
  524. extremeValueInformation.put("LIT-401", -1);
  525. extremeValueInformation.put("FIT-501", -1);
  526. extremeValueInformation.put("FIT-502", -1);
  527. extremeValueInformation.put("FIT-503", -1);
  528. extremeValueInformation.put("FIT-504", -1);
  529. extremeValueInformation.put("PIT-501", -1);
  530. extremeValueInformation.put("PIT-502", -1);
  531. extremeValueInformation.put("PIT-503", -1);
  532. extremeValueInformation.put("AIT-501", -1);
  533. extremeValueInformation.put("AIT-502", 1);
  534. extremeValueInformation.put("AIT-503", -1);
  535. extremeValueInformation.put("AIT-504", -1);
  536. extremeValueInformation.put("FIT-601", -1);
  537. plateauValues = new LinkedHashMap<String, LinkedList<Double>>();
  538. plateauValues.put("FIT-201", new LinkedList<Double>());
  539. plateauValues.put("DPIT-301", null);
  540. // Set parameters
  541. distributionHandlers = new LinkedHashMap<String, SWaTDatasetDistributionHandler>();
  542. setDatasetDistributionHandlers();
  543. durationInSeconds = Integer.parseInt(duration);
  544. this.outputDirectoryPath = outputDirectoryPath;
  545. startTime = (Calendar) outputFileTime.clone();
  546. currentTime = (Calendar) startTime.clone();
  547. setUpStatus(startStatus);
  548. this.passByReferenceValue_KeepSimulationRunning = passByReferenceValue_KeepSimulationRunning;
  549. if(listLIT301.getFirst() > 780) extremeValueInformation.put("LIT-301", 2);
  550. else transitionInformation.get("LIT-301")[4] = 4;
  551. this.propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
  552. resultsMap = new LinkedHashMap<Integer, String[]>();
  553. resultsMap.put(0, new String[] {listLIT101.getLast().toString(), listAIT201.getLast().toString(), listFIT201.getLast().toString(), listLIT301.getLast().toString(), listLIT401.getLast().toString(), "0"});
  554. // Simulate each second
  555. int durationInSecondsPercent = durationInSeconds/100;
  556. for(int s = 0; s < durationInSeconds; s++) {
  557. if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
  558. if(s % durationInSecondsPercent == 0) propertyChangeSupport.firePropertyChange("statusPercentagePhysicalSimulation", 0, (int)(s/durationInSecondsPercent));
  559. increaseTimeByOneSecond();
  560. listTimestamp.add(getCurrentTimeString());
  561. simulateStage1(s);
  562. simulateStage2(s);
  563. simulateStage3(s);
  564. simulateStage4(s);
  565. simulateStage5(s);
  566. simulateStage6(s);
  567. // Attacks here
  568. boolean attackHappened = false;
  569. for(Object[] attacks:attackData) {
  570. if(s >= Integer.parseInt((String) attacks[0]) && s <= Integer.parseInt((String) attacks[1])) { // the current second is between start time and end time of the attack
  571. String attackedDeviceName = (String) attacks[2];
  572. if(deviceNamesToDeviceListsSensors.containsKey(attackedDeviceName)) {
  573. LinkedList<Double> attackedSensorList = deviceNamesToDeviceListsSensors.get(attackedDeviceName);
  574. attackedSensorList.removeLast();
  575. String attackType = (String) attacks[3];
  576. Double attackValue = Double.parseDouble((String) attacks[4]);
  577. switch(attackType) {
  578. case "Increase by":
  579. attackedSensorList.add(attackedSensorList.getLast() + attackValue);
  580. break;
  581. case "Decrease by":
  582. attackedSensorList.add(attackedSensorList.getLast() - attackValue);
  583. break;
  584. default: // "Set to"
  585. attackedSensorList.add(attackValue);
  586. }
  587. attackHappened = true;
  588. }
  589. else if(deviceNamesToDeviceListsActuators.containsKey(attackedDeviceName)) {
  590. LinkedList<Integer> attackedActuatorList = deviceNamesToDeviceListsActuators.get(attackedDeviceName);
  591. int attackStatus = attackedActuatorList.removeLast();
  592. switch((String) attacks[4]) {
  593. case "On":
  594. attackStatus = 2;
  595. break;
  596. case "Off":
  597. attackStatus = 1;
  598. break;
  599. case "Transition":
  600. attackStatus = 0;
  601. break;
  602. }
  603. attackedActuatorList.add(attackStatus);
  604. attackHappened = true;
  605. }
  606. }
  607. }
  608. if(attackHappened)
  609. listNormalAttack.add("Attack");
  610. else
  611. listNormalAttack.add("Normal");
  612. resultsMap.put(s+1, new String[] {listLIT101.getLast().toString(), listAIT201.getLast().toString(), listFIT201.getLast().toString(), listLIT301.getLast().toString(), listLIT401.getLast().toString(), (attackHappened ? "1" : "0")});
  613. }
  614. // Create and save output
  615. if(passByReferenceValue_KeepSimulationRunning[0] == true) {
  616. createOutput();
  617. saveCSVOutput();
  618. }
  619. }
  620. /**
  621. * Simulates stage one for one second.
  622. *
  623. * @param seconds The current simulation time in seconds.
  624. */
  625. private void simulateStage1(int seconds) {
  626. // MV-101
  627. double lit101LastStatus = listLIT101.getLast();
  628. int mv101LastStatus = listMV101.getLast();
  629. simulateMV("MV-101", listMV101, listLIT101, 500, 800, 0, 0, true, true);
  630. int[] mv101TransitionInformation = transitionInformation.get("MV-101");
  631. // FIT-101
  632. double fit101LastValue = listFIT101.getLast();
  633. LinkedList<Double> extremeValueListFIT = extremeValues.get("FIT-101");
  634. if(mv101LastStatus == 0) { // Start or stop flow
  635. int totalTransitionTime = mv101TransitionInformation[1];
  636. if(mv101TransitionInformation[3] == 1) { // Transition to closed: decrease value immediately
  637. double fit101step = distributionHandlers.get("FIT-101 Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  638. double fit101New = BigDecimal.valueOf(fit101LastValue).subtract(BigDecimal.valueOf(fit101step)).doubleValue();
  639. if(fit101New < 0) fit101New = 0.0;
  640. listFIT101.add(fit101New);
  641. }
  642. else if(mv101TransitionInformation[3] == 2) { // Transition to open: increase value at half of transition time
  643. if(totalTransitionTime%2 == 1) totalTransitionTime++;
  644. if(totalTransitionTime/2 > mv101TransitionInformation[2]) {
  645. double fit101step = distributionHandlers.get("FIT-101 Flank Distribution Sharply Increasing").sampleNextValueExactly();
  646. listFIT101.add(BigDecimal.valueOf(fit101LastValue).add(BigDecimal.valueOf(fit101step)).doubleValue());
  647. }
  648. else
  649. listFIT101.add(0.0);
  650. }
  651. double minimum = distributionHandlers.get("FIT-101 Minima Distribution").sampleNextValueExactly();
  652. extremeValueInformation.put("FIT-101", 0);
  653. extremeValueListFIT.set(0, minimum);
  654. }
  655. else if(mv101LastStatus == 1) { // Valve is closed
  656. if(fit101LastValue > 0) { // Continue to decrease until 0
  657. double fit101step = distributionHandlers.get("FIT-101 Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  658. double fit101New = BigDecimal.valueOf(fit101LastValue).subtract(BigDecimal.valueOf(fit101step)).doubleValue();
  659. if(fit101New < 0) fit101New = 0.0;
  660. listFIT101.add(fit101New);
  661. }
  662. else
  663. listFIT101.add(0.0);
  664. }
  665. else if(mv101LastStatus == 2) { // Valve is open
  666. double extremeValue = extremeValueListFIT.get(0);
  667. if(extremeValueInformation.get("FIT-101") == 0) { // Decreasing
  668. double fit101step = distributionHandlers.get("FIT-101 Flank Distribution Decreasing").sampleNextValueExactly();
  669. double fit101New = BigDecimal.valueOf(fit101LastValue).subtract(BigDecimal.valueOf(fit101step)).doubleValue();
  670. if(fit101New < extremeValue) {
  671. fit101New = extremeValue;
  672. // Maximum after minimum
  673. double maximum = distributionHandlers.get("FIT-101 Maxima Distribution").sampleNextValueExactly();
  674. extremeValueInformation.put("FIT-101", 1);
  675. extremeValueListFIT.set(0, maximum);
  676. }
  677. listFIT101.add(fit101New);
  678. }
  679. else { // Increasing
  680. double fit101step = distributionHandlers.get("FIT-101 Flank Distribution Increasing").sampleNextValueExactly();
  681. double fit101New = BigDecimal.valueOf(fit101LastValue).add(BigDecimal.valueOf(fit101step)).doubleValue();
  682. if(fit101New > extremeValue) {
  683. fit101New = extremeValue;
  684. // Minimum after maximum
  685. double minimum = distributionHandlers.get("FIT-101 Minima Distribution").sampleNextValueExactly();
  686. extremeValueInformation.put("FIT-101", 0);
  687. extremeValueListFIT.set(0, minimum);
  688. }
  689. listFIT101.add(fit101New);
  690. }
  691. }
  692. // P-101 and P-102
  693. int p101102LastStatus = 1;
  694. int p101LastStatus = listP101.getLast();
  695. int p102LastStatus = listP102.getLast();
  696. if(p101LastStatus == 2 || p102LastStatus == 2)
  697. p101102LastStatus = 2;
  698. listP102.add(1); // Still off or again off
  699. // P-101
  700. int mv201LastStatus = listMV201.getLast();
  701. if(lit101LastStatus >= 250 && mv201LastStatus == 2) { // Turn on
  702. listP101.add(2);
  703. }
  704. else // Turn off
  705. listP101.add(1);
  706. // LIT-101
  707. double litstep = 0.0;
  708. double lit101New = 0.0;
  709. String litName = "LIT-101";
  710. int extremeValueInformationLIT101 = extremeValueInformation.get("LIT-101");
  711. if(mv101LastStatus != 2 && fit101LastValue == 0 && p101102LastStatus == 1) // Neither inflow nor outflow
  712. litstep = 0;
  713. // Inflow and outflow at the same time
  714. else if(mv101LastStatus == 2 && p101102LastStatus == 2) {
  715. litstep = 0.0115193476;//0.01014685;
  716. }
  717. // Only outflow
  718. else if((mv101LastStatus == 1 || mv101LastStatus == 0) && p101102LastStatus == 2) { // listFIT101.getLast() < listFIT201.getLast()
  719. litstep = -0.4870658842;
  720. }
  721. // Only inflow
  722. else {
  723. litstep = 0.4842940878;
  724. }
  725. listLIT101WithoutJittering.add(BigDecimal.valueOf(listLIT101WithoutJittering.getLast()).add(BigDecimal.valueOf(litstep)).doubleValue());
  726. LinkedList<Double> extremeValueList = extremeValues.get(litName);
  727. if(extremeValueList.size() > 0) {
  728. litstep = extremeValueList.pop();
  729. if(mv101LastStatus == 2 && p101102LastStatus == 2) litstep*=3;
  730. }
  731. else {
  732. int secondsToZero = (int) distributionHandlers.get("LIT-101 Seconds Between Zeros Distribution").sampleNextValueExactly();
  733. if(extremeValueInformationLIT101 == -1) {
  734. double firstJitterValue = distributionHandlers.get("LIT-101 Jitter").sampleNextValueExactlyAlsoNegative();
  735. extremeValueList.add(firstJitterValue);
  736. if(secondsToZero > 1) {
  737. if(firstJitterValue > 1) { // Positive Jitter
  738. extremeValueInformationLIT101 = 1;
  739. for(int i = 2; i <= secondsToZero; i++) {
  740. extremeValueList.add(distributionHandlers.get("LIT-101 Jitter Positive").sampleNextValueExactly());
  741. }
  742. }
  743. else { // Negative Jitter
  744. extremeValueInformationLIT101 = 0;
  745. for(int i = 2; i <= secondsToZero; i++) {
  746. extremeValueList.add(-distributionHandlers.get("LIT-101 Jitter Negative").sampleNextValueExactly());
  747. }
  748. }
  749. }
  750. }
  751. else if(extremeValueInformationLIT101 == 1) { // Negative Jitter
  752. extremeValueInformationLIT101 = 0;
  753. for(int i = 1; i <= secondsToZero; i++) {
  754. extremeValueList.add(-distributionHandlers.get("LIT-101 Jitter Negative").sampleNextValueExactly());
  755. }
  756. }
  757. else { // Positive Jitter
  758. extremeValueInformationLIT101 = 1;
  759. for(int i = 1; i <= secondsToZero; i++) {
  760. extremeValueList.add(distributionHandlers.get("LIT-101 Jitter Positive").sampleNextValueExactly());
  761. }
  762. }
  763. }
  764. extremeValueInformation.put("LIT-101", extremeValueInformationLIT101);
  765. extremeValues.put(litName, extremeValueList);
  766. lit101New = BigDecimal.valueOf(listLIT101WithoutJittering.getLast()).add(BigDecimal.valueOf(litstep)).doubleValue();
  767. if(lit101New < 0) lit101New = 0;// Tank cannot be less full than empty
  768. listLIT101.add(lit101New);
  769. }
  770. /**
  771. * Simulates stage two for one second.
  772. *
  773. * @param seconds The current simulation time in seconds.
  774. */
  775. private void simulateStage2(int seconds) {
  776. // MV-201
  777. int mv201LastStatus = listMV201.getLast();
  778. int[] mv201TransitionInformation = transitionInformation.get("MV-201");
  779. simulateMV("MV-201", listMV201, listLIT301, 800, 1000, 3, 3, true, true);
  780. // FIT-201
  781. String fitName = "FIT-201";
  782. int[] fitTransitionInformation = transitionInformation.get(fitName);
  783. double fit201LastValue = listFIT201.getLast();
  784. LinkedList<Double> extremeValueListFIT = extremeValues.get(fitName);
  785. double lit101LastValue = listLIT101.getLast();
  786. if(fitTransitionInformation[0] == 0 && mv201LastStatus == 0) { // New transition
  787. fitTransitionInformation[0] = 1;
  788. if(mv201TransitionInformation[3] == 1) { // Transition to closed
  789. fitTransitionInformation[3] = 1;
  790. fitTransitionInformation[4] = ThreadLocalRandom.current().nextInt(0, 2);
  791. }
  792. else { // Transition to open
  793. fitTransitionInformation[3] = 2;
  794. fitTransitionInformation[4] = mv201TransitionInformation[2] + ThreadLocalRandom.current().nextInt(3, 5);
  795. }
  796. listFIT201.add(fit201LastValue);
  797. }
  798. else if(lit101LastValue <= 250) {
  799. listFIT201.add(fit201LastValue);
  800. }
  801. else if(fitTransitionInformation[0] == 1) {
  802. if(fitTransitionInformation[4] <= 0) { // Flow changes
  803. plateauValues.put(fitName, new LinkedList<Double>());
  804. if(fitTransitionInformation[3] == 1) { // Transition to closed: sharply decreasing flow
  805. double fitStep = distributionHandlers.get(fitName+" Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  806. double fitNew = BigDecimal.valueOf(fit201LastValue).subtract(BigDecimal.valueOf(fitStep)).doubleValue();
  807. if(fitNew < 0) {
  808. fitNew = 0.0;
  809. fitTransitionInformation[0] = 0;
  810. }
  811. listFIT201.add(fitNew);
  812. }
  813. else if(fitTransitionInformation[3] == 2) { // Transition to open: sharply increasing flow
  814. double fit101step = distributionHandlers.get(fitName+" Flank Distribution Sharply Increasing").sampleNextValueExactly();
  815. double fitNew = BigDecimal.valueOf(fit201LastValue).add(BigDecimal.valueOf(fit101step)).doubleValue();
  816. if(fitNew > 2.488) {
  817. while(true) {
  818. fitNew -= 0.01;
  819. if(fitNew <= 2.488) break;
  820. }
  821. fitTransitionInformation[0] = 0;
  822. }
  823. listFIT201.add(fitNew);
  824. }
  825. }
  826. else { // Count down
  827. fitTransitionInformation[4]--;
  828. listFIT201.add(listFIT201.getLast());
  829. }
  830. }
  831. else if(mv201LastStatus == 1) { // Valve is closed
  832. if(fit201LastValue > 0) { // Continue to decrease until 0
  833. double fitStep = distributionHandlers.get(fitName+" Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  834. double fitNew = BigDecimal.valueOf(fit201LastValue).subtract(BigDecimal.valueOf(fitStep)).doubleValue();
  835. if(fitNew < 0) fitNew = 0.0;
  836. listFIT201.add(fitNew);
  837. }
  838. else
  839. listFIT201.add(0.0);
  840. }
  841. else if(mv201LastStatus == 2) { // Valve is open
  842. if(extremeValueListFIT.size() == 0) { // Initial value
  843. double minimum = distributionHandlers.get(fitName+" Minima Distribution").sampleNextValueExactly();
  844. if(fit201LastValue - minimum >= 0.005)
  845. while(true) {
  846. minimum += 0.001;
  847. if(fit201LastValue - minimum < 0.005) break;
  848. }
  849. extremeValueInformation.put(fitName, 0);
  850. extremeValueListFIT.add(minimum);
  851. }
  852. // Handle plateaus
  853. if(plateauValues.get(fitName).size() > 1) {
  854. listFIT201.add(plateauValues.get(fitName).pop());
  855. }
  856. else if(plateauValues.get(fitName).size() == 1) {
  857. listFIT201.add(plateauValues.get(fitName).pop());
  858. plateauValues.put(fitName, new LinkedList<Double>());
  859. }
  860. else {
  861. double extremeValue = extremeValueListFIT.get(0);
  862. double fitNew = fit201LastValue;
  863. if(extremeValueInformation.get(fitName) == 0) { // Decreasing
  864. double fitStep = distributionHandlers.get(fitName+" Flank Distribution Decreasing").sampleNextValueExactly();
  865. if(fitStep >= 0.005) fitStep = 0.005;
  866. fitNew = BigDecimal.valueOf(fit201LastValue).subtract(BigDecimal.valueOf(fitStep)).doubleValue();
  867. if(fitNew < extremeValue) {
  868. // Maximum after minimum
  869. double maximum = distributionHandlers.get(fitName+" Maxima Distribution").sampleNextValueExactly();
  870. if(maximum - fit201LastValue >= 0.005)
  871. while(true) {
  872. maximum -= 0.001;
  873. if(maximum - fit201LastValue < 0.005) break;
  874. }
  875. extremeValueInformation.put(fitName, 1);
  876. extremeValueListFIT.set(0, maximum);
  877. }
  878. }
  879. else { // Increasing
  880. double fitStep = distributionHandlers.get(fitName+" Flank Distribution Increasing").sampleNextValueExactly();
  881. if(fitStep >= 0.005) fitStep = 0.005;
  882. fitNew = BigDecimal.valueOf(fit201LastValue).add(BigDecimal.valueOf(fitStep)).doubleValue();
  883. if(fitNew > extremeValue) {
  884. double minimum = distributionHandlers.get(fitName+" Minima Distribution").sampleNextValueExactly();
  885. if(fit201LastValue - minimum >= 0.005)
  886. while(true) {
  887. minimum += 0.001;
  888. if(fit201LastValue - minimum < 0.005) break;
  889. }
  890. extremeValueInformation.put(fitName, 0);
  891. extremeValueListFIT.set(0, minimum);
  892. }
  893. }
  894. int plateauLength = (int) distributionHandlers.get(fitName+" Flank Plateaus Distribution").sampleNextValueExactly();
  895. LinkedList<Double> plateauList = new LinkedList<Double>();
  896. for(int i = 0; i < plateauLength; i++) {
  897. plateauList.add(fitNew);
  898. }
  899. plateauValues.put(fitName, plateauList);
  900. listFIT201.add(fitNew);
  901. }
  902. }
  903. // AIT-201
  904. String ait201Name = "AIT-201";
  905. double ait201LastValue = listAIT201.getLast();
  906. double ait201FirstValue = listAIT201.getFirst();
  907. double ait201Next = ait201LastValue;
  908. double ait201Maximum = 272.5263;
  909. double ait201Minimum = 244.3284;
  910. double ait201Middle = (ait201Maximum - ait201Minimum)/2;
  911. double ait201MiddlePosition = ait201Minimum + ait201Middle;
  912. int ait201ExtremeValueInformation = extremeValueInformation.get(ait201Name);
  913. if(ait201ExtremeValueInformation == -1) { // Wait for first water
  914. if(listFIT201.getLast() != 0)
  915. extremeValueInformation.put(ait201Name, 0);
  916. if(seconds % 25 == 0) {
  917. double randomStep = ThreadLocalRandom.current().nextDouble(-0.3, 0.031);
  918. if(ait201LastValue + randomStep < ait201FirstValue)
  919. ait201Next = ait201LastValue - randomStep;
  920. else
  921. ait201Next = ait201LastValue + randomStep;
  922. }
  923. else
  924. ait201Next = ait201LastValue;
  925. }
  926. else if(ait201ExtremeValueInformation == 0) { // Move to middle position
  927. if(ait201LastValue < ait201MiddlePosition) {
  928. double ait201Step = ThreadLocalRandom.current().nextDouble(-0.05, 0.15);
  929. ait201Next = ait201LastValue + ait201Step;
  930. if(ait201Next > ait201MiddlePosition) {
  931. ait201Next = ait201LastValue;
  932. extremeValueInformation.put(ait201Name, 1);
  933. }
  934. }
  935. else {
  936. extremeValueInformation.put(ait201Name, 1);
  937. }
  938. }
  939. else {
  940. if(seconds > 2 && mv201LastStatus == 2 && listMV201.get(listMV201.size()-3) == 0) { // Add spike
  941. ait201Next = ait201LastValue+ThreadLocalRandom.current().nextDouble(0.5, 1.5);
  942. }
  943. else {
  944. // Follow a sin curve
  945. double ait201SinPosition = Math.sin(2*Math.PI/200000*(seconds % 200000));
  946. ait201Next = ait201MiddlePosition+ait201Middle*ait201SinPosition;
  947. }
  948. }
  949. if(ait201ExtremeValueInformation != -1 && seconds % (200 + ThreadLocalRandom.current().nextInt(-20,21)) == 0) // Add jitter from time to time
  950. ait201Next = ait201Next + ThreadLocalRandom.current().nextDouble(-0.3, 0.31);
  951. if(ait201Next < ait201MiddlePosition-ait201Middle && ait201ExtremeValueInformation == 1)
  952. ait201Next = ait201MiddlePosition-ait201Middle;
  953. listAIT201.add(ait201Next);
  954. // AIT-202
  955. String ait202Name = "AIT-202";
  956. double ait202LastStatus = listAIT202.getLast();
  957. double ait202Next = ait202LastStatus;
  958. double ait202Maximum = 8.988273;
  959. double ait202Minimum = 8.19008;
  960. double ait202Middle = (ait202Maximum - ait202Minimum)/2;
  961. double ait202MiddlePosition = ait202Minimum + ait202Middle;
  962. int[] transitionInformationAIT202 = transitionInformation.get(ait202Name);
  963. int ait202ExtremeValueInformation = extremeValueInformation.get(ait202Name);
  964. if(ait202ExtremeValueInformation == -1) { // Wait for first water
  965. if(listFIT201.getLast() != 0)
  966. extremeValueInformation.put(ait202Name, 0);
  967. ait202Next = ait202LastStatus;
  968. }
  969. else if(ait202ExtremeValueInformation == 0) { // Move to middle position
  970. if(ait202LastStatus < ait202MiddlePosition) {
  971. double ait202Step = ThreadLocalRandom.current().nextDouble(-0.05, 0.15);
  972. ait202Next = ait202LastStatus + ait202Step;
  973. if(ait202Next > ait202MiddlePosition) {
  974. ait202Next = ait202MiddlePosition;
  975. extremeValueInformation.put(ait202Name, 1);
  976. }
  977. }
  978. else {
  979. extremeValueInformation.put(ait202Name, 1);
  980. }
  981. }
  982. else {
  983. if(seconds > 2) {
  984. if(mv201LastStatus == 1 && listMV201.get(listMV201.size()-3) == 0) { // Start spike
  985. transitionInformationAIT202[0] = ThreadLocalRandom.current().nextInt(68, 75);
  986. ait202Next = ait202LastStatus+transitionInformationAIT202[0]/1000.0;
  987. }
  988. else if(mv201LastStatus == 2 && listMV201.get(listMV201.size()-3) == 0) { // End spike
  989. ait202Next = ait202LastStatus-transitionInformationAIT202[0]/1000.0;
  990. }
  991. }
  992. }
  993. listAIT202.add(ait202Next + ThreadLocalRandom.current().nextGaussian()*0.00005);
  994. // AIT-203
  995. String ait203Name = "AIT-203";
  996. double ait203LastStatus = listAIT203.getLast();
  997. double ait203Next = ait203LastStatus;
  998. double ait203MiddlePosition = 335.0;
  999. int[] transitionInformationAIT203 = transitionInformation.get(ait203Name);
  1000. int ait203ExtremeValueInformation = extremeValueInformation.get(ait203Name);
  1001. if(ait203ExtremeValueInformation == -1) { // Wait for first water
  1002. if(listFIT201.getLast() != 0)
  1003. extremeValueInformation.put(ait203Name, 0);
  1004. ait203Next = ait203LastStatus;
  1005. }
  1006. else if(ait203ExtremeValueInformation == 0) { // Move to middle position
  1007. if(ait203LastStatus < ait203MiddlePosition) {
  1008. double ait203Step = ThreadLocalRandom.current().nextDouble(-0.05, 0.15);
  1009. ait203Next = ait203LastStatus + ait203Step;
  1010. if(ait203Next > ait203MiddlePosition) {
  1011. ait203Next = ait203MiddlePosition;
  1012. extremeValueInformation.put(ait203Name, 1);
  1013. }
  1014. }
  1015. else {
  1016. extremeValueInformation.put(ait203Name, 1);
  1017. }
  1018. }
  1019. else {
  1020. if(seconds > 2) {
  1021. if(mv201LastStatus == 1 && listMV201.get(listMV201.size()-3) == 0) { // Start spike
  1022. transitionInformationAIT203[0] = ThreadLocalRandom.current().nextInt(1400, 1600);
  1023. ait203Next = ait203LastStatus - transitionInformationAIT203[0]/100.0;
  1024. }
  1025. else if(mv201LastStatus == 2 && listMV201.get(listMV201.size()-3) == 0) { // End spike
  1026. ait203Next = ait203LastStatus + transitionInformationAIT203[0]/100.0;
  1027. }
  1028. else if(mv201LastStatus == 2) {
  1029. ait203Next = ait203LastStatus - 0.001;
  1030. }
  1031. else {
  1032. ait203Next = ait203LastStatus + 0.0035;
  1033. }
  1034. }
  1035. }
  1036. listAIT203.add(ait203Next + ThreadLocalRandom.current().nextGaussian()*0.05);
  1037. // P-201 and P-202
  1038. listP202.add(1); // Still off or again off
  1039. if(mv201LastStatus == 1 || (mv201LastStatus == 0 & transitionInformation.get("MV-201")[3] == 1)) {
  1040. listP201.add(1);
  1041. }
  1042. else {
  1043. listP201.add(1);
  1044. }
  1045. // P-203 and P-204
  1046. listP204.add(1); // Still off or again off
  1047. if(mv201LastStatus == 1 || (mv201LastStatus == 0 & transitionInformation.get("MV-201")[3] == 1)) {
  1048. listP203.add(1);
  1049. }
  1050. else{
  1051. if(transitionInformation.get("P-203")[0] == 0 && fit201LastValue > 0 && ait202LastStatus >= 6.94999980927) { // Start offset countdown
  1052. transitionInformation.get("P-203")[0] = 1;
  1053. transitionInformation.get("P-203")[4] = ThreadLocalRandom.current().nextInt(6, 10);
  1054. }
  1055. if(transitionInformation.get("P-203")[0] == 1) {
  1056. if(transitionInformation.get("P-203")[4] > 0 && (fit201LastValue <= 0 || ait202LastStatus < 6.94999980927)) { // Stop offset countdown
  1057. listP203.add(1);
  1058. transitionInformation.get("P-203")[0] = 0;
  1059. }
  1060. else {
  1061. transitionInformation.get("P-203")[4]--;
  1062. if(transitionInformation.get("P-203")[4] <= 0) { // Finish offset countdown
  1063. transitionInformation.get("P-203")[0] = 0;
  1064. listP203.add(2);
  1065. }
  1066. else {
  1067. listP203.add(listP203.getLast());
  1068. }
  1069. }
  1070. }
  1071. else {
  1072. listP203.add(listP203.getLast());
  1073. }
  1074. }
  1075. // P-205 and P-206
  1076. listP206.add(1); // Still off or again off
  1077. if(ait203LastStatus >= 500 || mv201LastStatus == 1 || (mv201LastStatus == 0 & transitionInformation.get("MV-201")[3] == 1)) {
  1078. listP205.add(1);
  1079. }
  1080. else{
  1081. if(transitionInformation.get("P-205")[0] == 0 && fit201LastValue > 0 && ait203LastStatus <= 436) { // Start offset countdown
  1082. transitionInformation.get("P-205")[0] = 1;
  1083. transitionInformation.get("P-205")[4] = ThreadLocalRandom.current().nextInt(2, 8);
  1084. }
  1085. if(transitionInformation.get("P-205")[0] == 1) {
  1086. if(transitionInformation.get("P-205")[4] > 0 && (fit201LastValue <= 0 || ait203LastStatus > 436 && ait203LastStatus < 500)) { // Stop offset countdown
  1087. listP205.add(1);
  1088. transitionInformation.get("P-205")[0] = 0;
  1089. }
  1090. else {
  1091. transitionInformation.get("P-205")[4]--;
  1092. if(transitionInformation.get("P-205")[4] <= 0) { // Finish offset countdown
  1093. transitionInformation.get("P-205")[0] = 0;
  1094. listP205.add(2);
  1095. }
  1096. else {
  1097. listP205.add(listP205.getLast());
  1098. }
  1099. }
  1100. }
  1101. else {
  1102. listP205.add(listP205.getLast());
  1103. }
  1104. }
  1105. }
  1106. /**
  1107. * Simulates stage three for one second.
  1108. * @param seconds The current simulation time in seconds.
  1109. */
  1110. private void simulateStage3(int seconds){
  1111. // P-301 and P-302
  1112. int p301302LastStatus = 1;
  1113. int p301LastStatus = listP301.getLast();
  1114. int p302LastStatus = listP302.getLast();
  1115. if(p301LastStatus == 2 || p302LastStatus == 2)
  1116. p301302LastStatus = 2;
  1117. listP301.add(1); // Still off or again off
  1118. double lit401LastStatus = listLIT401.getLast();
  1119. int[] mv301TransitionInformation = transitionInformation.get("MV-301");
  1120. int[] p302TransitionInformation = transitionInformation.get("P-302");
  1121. int[] mv304TransitionInformation = transitionInformation.get("MV-304");
  1122. int mv301LastStatus = listMV301.getLast();
  1123. double lit301LastStatus = listLIT301.getLast();
  1124. int p302New = 0;
  1125. if(p302TransitionInformation[0] == 1) {
  1126. if(p302TransitionInformation[4] > 0) { // Wait for offset to end
  1127. p302TransitionInformation[4]--;
  1128. p302New = p301302LastStatus;
  1129. }
  1130. else {
  1131. if(p302TransitionInformation[2] > 0) {
  1132. p302TransitionInformation[2]--;
  1133. p302New = 1;
  1134. }
  1135. else if(p302TransitionInformation[2] == 0) {
  1136. p302TransitionInformation[0] = 0;
  1137. if(p302TransitionInformation[3] == 2)
  1138. p302New = 2;
  1139. else
  1140. p302New = 1;
  1141. }
  1142. }
  1143. }
  1144. else if(seconds == backwashIntervalList.getFirst()-14) { // Backwash: Transition to off
  1145. int transitionTime = 10 + ThreadLocalRandom.current().nextInt(1, 4);
  1146. p302TransitionInformation[0] = 1;
  1147. p302TransitionInformation[1] = transitionTime;
  1148. p302TransitionInformation[2] = transitionTime;
  1149. p302TransitionInformation[3] = 1;
  1150. p302TransitionInformation[4] = 14 - transitionTime;
  1151. p302New = p301302LastStatus;
  1152. }
  1153. else if(mv301TransitionInformation[0] == 1 && mv301TransitionInformation[3] == 1 && p302TransitionInformation[0] == 0) { // Backwash: Transition to on
  1154. int transitionTime = ThreadLocalRandom.current().nextInt(60, 65);
  1155. p302TransitionInformation[0] = 1;
  1156. p302TransitionInformation[1] = transitionTime;
  1157. p302TransitionInformation[2] = transitionTime;
  1158. p302TransitionInformation[3] = 2;
  1159. p302TransitionInformation[4] = 0;
  1160. p302New = 1;
  1161. }
  1162. else if(p301302LastStatus != 2 && p302TransitionInformation[0] == 0 && mv301LastStatus == 1 && lit401LastStatus < 800 && lit301LastStatus > 250) { // Normal operation only: Turn on
  1163. p302TransitionInformation[0] = 1;
  1164. p302TransitionInformation[1] = 10;
  1165. p302TransitionInformation[2] = 10;
  1166. p302TransitionInformation[3] = 2;
  1167. p302TransitionInformation[4] = 0;
  1168. p302New = 1;
  1169. }
  1170. else if(mv301LastStatus == 1 && (lit401LastStatus >= 1000 || lit301LastStatus < 250)){ // Normal operation only: Turn off
  1171. p302New = 1;
  1172. p302TransitionInformation[0] = 0;
  1173. }
  1174. else {
  1175. p302New = p301302LastStatus;
  1176. }
  1177. listP302.add(p302New);
  1178. // LIT-301
  1179. double fit201LastValue = listFIT201.getLast();
  1180. double fit301LastValue = listFIT301.getLast();
  1181. double litstep = 0.0;
  1182. double lit301New = 0.0;
  1183. int lit301ExtremeValueInformation = extremeValueInformation.get("LIT-301");
  1184. int[] lit301TransitionInformation = transitionInformation.get("LIT-301");
  1185. int p101102LastStatus = 1;
  1186. int p101LastStatus = listP101.getLast();
  1187. int p102LastStatus = listP102.getLast();
  1188. if(p101LastStatus == 2 || p102LastStatus == 2)
  1189. p101102LastStatus = 2;
  1190. int mv201LastStatus = listMV201.getLast();
  1191. // Outflow until typical minimum
  1192. if(lit301ExtremeValueInformation == 2 && lit301LastStatus <= 800 && lit301LastStatus >= 787) {
  1193. litstep = -0.156944897959183;
  1194. }
  1195. // Only inflow
  1196. else if(p101102LastStatus == 2 && mv201LastStatus == 2 && p301302LastStatus == 1) {
  1197. litstep = 0.4930476987;
  1198. }
  1199. // Inflow and outflow at the same time
  1200. else if(p101102LastStatus == 2 && mv201LastStatus == 2 && p301302LastStatus == 2 && fit201LastValue > 2.43) {
  1201. litstep = 0.0531137471; // Intial climb to 1000
  1202. if(lit301TransitionInformation[4] <= 0) {
  1203. litstep = 0.04611385; // Second climb from 800 to 1000
  1204. }
  1205. else if(lit301ExtremeValueInformation == 0)
  1206. litstep = 0.0735018503; // First climb from 800 to 1000
  1207. }
  1208. // Only outflow
  1209. else if((p101102LastStatus == 1 || mv201LastStatus == 1) && p301302LastStatus == 2) {
  1210. litstep = -0.4181877264;
  1211. }
  1212. else {// Neither inflow nor outflow
  1213. litstep = 0;
  1214. }
  1215. listLIT301WithoutJittering.add(BigDecimal.valueOf(listLIT301WithoutJittering.getLast()).add(BigDecimal.valueOf(litstep)).doubleValue());
  1216. lit301New = BigDecimal.valueOf(listLIT301WithoutJittering.getLast()).add(BigDecimal.valueOf(litstep)).doubleValue();
  1217. if(lit301New < 0) lit301New = 0;// Tank cannot be less full than empty
  1218. listLIT301.add(lit301New);
  1219. if(lit301ExtremeValueInformation == -1 && lit301New >= 1000) extremeValueInformation.put("LIT-301", 1);
  1220. else if(lit301ExtremeValueInformation == 1 && lit301New <= 800) extremeValueInformation.put("LIT-301", 0);
  1221. else if(lit301ExtremeValueInformation == 0 && lit301New >= 1000) extremeValueInformation.put("LIT-301", 2);
  1222. else if(lit301ExtremeValueInformation == 2 && lit301New <= 788) extremeValueInformation.put("LIT-301", 3);
  1223. else if(lit301ExtremeValueInformation == 3 && lit301New >= 1000) extremeValueInformation.put("LIT-301", 2);
  1224. if(lit301LastStatus < 1000 && lit301New >= 1000) lit301TransitionInformation[4]--;
  1225. // FIT-301
  1226. String fitName = "FIT-301";
  1227. LinkedList<Double> extremeValueListFIT = extremeValues.get(fitName);
  1228. double fit301New = fit301LastValue;
  1229. int mv302LastStatus = listMV302.getLast();
  1230. int mv303LastStatus = listMV303.getLast();
  1231. int mv304LastStatus = listMV304.getLast();
  1232. if(p301302LastStatus == 1) { // Decrease
  1233. double fit301step = distributionHandlers.get(fitName+" Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  1234. fit301New = BigDecimal.valueOf(fit301LastValue).subtract(BigDecimal.valueOf(fit301step)).doubleValue();
  1235. if(fit301New < 0.0002562214) {
  1236. fit301New = 0.0002562214;
  1237. }
  1238. if(fit301New == 0.0002562214 && ThreadLocalRandom.current().nextInt(1, 100) < 5 &&
  1239. mv301LastStatus == 2 && mv302LastStatus == 1 && mv303LastStatus == 2 && mv304LastStatus == 1) {
  1240. fit301New = fit301New + ThreadLocalRandom.current().nextDouble(0.1, 0.31);
  1241. }
  1242. else if(mv301LastStatus == 1 && mv302LastStatus == 1 && (mv303LastStatus == 2 || mv303LastStatus == 0) && mv304LastStatus == 2) {
  1243. fit301New = 0.37 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1244. }
  1245. // Add new maximum
  1246. double maximum = ThreadLocalRandom.current().nextDouble(2.3, 2.358);
  1247. if(extremeValueListFIT.size() > 0)
  1248. extremeValueListFIT.set(0, maximum);
  1249. else
  1250. extremeValueListFIT.add(maximum);
  1251. extremeValueInformation.put(fitName, 1);
  1252. }
  1253. else if(p301302LastStatus == 2 && extremeValueInformation.get(fitName) == 1) { // Increase
  1254. if(extremeValueListFIT.size() == 0) { // New maximum
  1255. extremeValueListFIT.add(ThreadLocalRandom.current().nextDouble(2.3, 2.351));
  1256. }
  1257. double fit301step = distributionHandlers.get(fitName+" Flank Distribution Sharply Increasing").sampleNextValueExactly();
  1258. fit301New = BigDecimal.valueOf(fit301LastValue).add(BigDecimal.valueOf(fit301step)).doubleValue();
  1259. double extremeValue = extremeValueListFIT.getFirst();
  1260. if(fit301New >= extremeValue) {
  1261. fit301New = extremeValue;
  1262. // Small Minimum afterwards
  1263. extremeValueListFIT.set(0, 2.21 + ThreadLocalRandom.current().nextGaussian()*0.0015);
  1264. extremeValueInformation.put(fitName, 0);
  1265. }
  1266. }
  1267. else if(p301302LastStatus == 2 && extremeValueInformation.get(fitName) == 0) { // Small decrease after maximum
  1268. double fit301step = distributionHandlers.get(fitName+" Flank Distribution Sharply Decreasing").sampleNextValueExactly();
  1269. fit301New = BigDecimal.valueOf(fit301LastValue).subtract(BigDecimal.valueOf(fit301step)).doubleValue();
  1270. double extremeValue = extremeValueListFIT.getFirst();
  1271. if(fit301New < extremeValue) {
  1272. fit301New = extremeValue;
  1273. extremeValueInformation.put(fitName, -1);
  1274. }
  1275. }
  1276. else if(extremeValueInformation.get(fitName) == -1) { // Jitter slightly below maximum
  1277. fit301New = 2.21 + ThreadLocalRandom.current().nextGaussian()*0.0015;
  1278. }
  1279. listFIT301.add(fit301New);
  1280. // MV-303
  1281. // Must be before MV-301 in the code
  1282. String mv303Name = "MV-303";
  1283. LinkedList<Integer> mv303List = listMV303;
  1284. int[] mv303TransitionInformation = transitionInformation.get("MV-303");
  1285. if(mv303TransitionInformation[0] == 1) {
  1286. if(mv303TransitionInformation[4] > 0) {
  1287. mv303TransitionInformation[4]--;
  1288. mv303List.add(mv303LastStatus);
  1289. }
  1290. else {
  1291. int remainingTransistionTime = mv303TransitionInformation[2];
  1292. if(remainingTransistionTime == 0) { // Stop
  1293. mv303TransitionInformation[0] = 0;
  1294. if(mv303TransitionInformation[3] == 2)
  1295. mv303List.add(2);
  1296. else
  1297. mv303List.add(1);
  1298. }
  1299. else { // Continue
  1300. mv303TransitionInformation[2] = remainingTransistionTime-1;
  1301. mv303List.add(0);
  1302. }
  1303. }
  1304. }
  1305. else if(mv303LastStatus == 1) {
  1306. // Take interval times from the training set
  1307. if(seconds == backwashIntervalList.getFirst()) {
  1308. // Start new transition to opened
  1309. int transitionTime = (int) distributionHandlers.get(mv303Name+" Transition Distribution 1 to 2").sampleNextValueExactly();
  1310. mv303TransitionInformation[0] = 1;
  1311. mv303TransitionInformation[1] = transitionTime;
  1312. mv303TransitionInformation[2] = transitionTime-1;
  1313. mv303TransitionInformation[3] = 2;
  1314. mv303TransitionInformation[4] = 0;
  1315. mv303List.add(0);
  1316. }
  1317. else
  1318. mv303List.add(1);
  1319. }
  1320. else if(mv303LastStatus == 2 && mv301TransitionInformation[0] == 1 && mv301TransitionInformation[3] == 1) { // Backwash: Transition to on
  1321. int transitionTime = (int) distributionHandlers.get(mv303Name+" Transition Distribution 2 to 1").sampleNextValueExactly();
  1322. mv303TransitionInformation[0] = 1;
  1323. mv303TransitionInformation[1] = transitionTime;
  1324. mv303TransitionInformation[2] = transitionTime;
  1325. mv303TransitionInformation[3] = 1;
  1326. mv303TransitionInformation[4] = ThreadLocalRandom.current().nextInt(60, 65);
  1327. mv303List.add(2);
  1328. }
  1329. else {
  1330. mv303List.add(mv303LastStatus);
  1331. }
  1332. // MV-301
  1333. LinkedList<Integer> mv301List = listMV301;
  1334. String mv301Name = "MV-301";
  1335. if(mv301LastStatus == 1 && mv301TransitionInformation[0] == 0) {
  1336. // Take interval times from the training set
  1337. if(seconds == backwashIntervalList.getFirst()) {
  1338. backwashIntervalList.pop();
  1339. // Generate new time if all fixed times are used
  1340. // Use an interval of 70 + (1 to 3) minutes
  1341. if(backwashIntervalList.size() == 0) {
  1342. backwashIntervalList.add(seconds + (70 + ThreadLocalRandom.current().nextInt(1, 4)) * 60);
  1343. }
  1344. // Start new transition to opened
  1345. int transitionTime = (int) distributionHandlers.get(mv301Name+" Transition Distribution 1 to 2").sampleNextValueExactly();
  1346. mv301TransitionInformation[0] = 1;
  1347. mv301TransitionInformation[1] = transitionTime;
  1348. mv301TransitionInformation[2] = transitionTime-1;
  1349. mv301TransitionInformation[3] = 2;
  1350. mv301TransitionInformation[4] = ThreadLocalRandom.current().nextInt(30, 34);
  1351. mv301List.add(0);
  1352. }
  1353. else
  1354. mv301List.add(1);
  1355. }
  1356. else if(mv301LastStatus == 0) {
  1357. int remainingTransistionTime = mv301TransitionInformation[2];
  1358. if(remainingTransistionTime == 0) { // Stop
  1359. mv301TransitionInformation[0] = 0;
  1360. mv301List.add(mv301TransitionInformation[3]);
  1361. mv301TransitionInformation[4]--;
  1362. }
  1363. else { // Continue
  1364. mv301TransitionInformation[2] = remainingTransistionTime-1;
  1365. mv301List.add(0);
  1366. }
  1367. }
  1368. else if(mv301TransitionInformation[4] >= 0){
  1369. if(mv301TransitionInformation[4] == 0) {
  1370. // Start new transition to closed
  1371. int transitionTime = (int) distributionHandlers.get(mv301Name+" Transition Distribution 2 to 1").sampleNextValueExactly();
  1372. mv301TransitionInformation[0] = 1;
  1373. mv301TransitionInformation[1] = transitionTime;
  1374. mv301TransitionInformation[2] = transitionTime-1;
  1375. mv301TransitionInformation[3] = 1;
  1376. mv301List.add(0);
  1377. }
  1378. else {
  1379. mv301List.add(2);
  1380. }
  1381. mv301TransitionInformation[4]--;
  1382. }
  1383. else {
  1384. mv301List.add(1);
  1385. }
  1386. // MV-302
  1387. String mv302Name = "MV-302";
  1388. LinkedList<Integer> mv302List = listMV302;
  1389. int[] mv302TransitionInformation = transitionInformation.get(mv302Name);
  1390. if(mv302TransitionInformation[0] == 1 && mv302TransitionInformation[4] > 1) { // Wait for offset to end
  1391. mv302TransitionInformation[4]--;
  1392. mv302List.add(mv302List.getLast());
  1393. }
  1394. else if(mv302TransitionInformation[0] == 1 && mv302LastStatus != 0 && mv302TransitionInformation[4] == 1) {
  1395. mv302TransitionInformation[4]--;
  1396. mv302List.add(0); // Start transition in next second
  1397. }
  1398. else if(mv302LastStatus == 0) { // Transition
  1399. int remainingTransistionTime = mv302TransitionInformation[2];
  1400. if(remainingTransistionTime == 0) { // Stop
  1401. mv302TransitionInformation[0] = 0;
  1402. mv302List.add(mv302TransitionInformation[3]);
  1403. }
  1404. else { // Continue
  1405. mv302TransitionInformation[2] = remainingTransistionTime-1;
  1406. mv302List.add(0);
  1407. }
  1408. }
  1409. else if(mv302TransitionInformation[0] == 0 && mv302LastStatus == 1 && p301302LastStatus == 2) { // Start offset count down to opening transition
  1410. int transitionTime = (int) distributionHandlers.get(mv302Name+" Transition Distribution 1 to 2").sampleNextValueExactly();
  1411. mv302TransitionInformation[0] = 1;
  1412. mv302TransitionInformation[1] = transitionTime;
  1413. mv302TransitionInformation[2] = transitionTime;
  1414. mv302TransitionInformation[3] = 2;
  1415. mv302TransitionInformation[4] = ThreadLocalRandom.current().nextInt(30, 41)-1;
  1416. mv302List.add(1);
  1417. }
  1418. else if(mv302TransitionInformation[0] == 0 && mv302LastStatus == 2 && p301302LastStatus == 1) { // Start offset count down to closing transition
  1419. int transitionTime = (int) distributionHandlers.get(mv302Name+" Transition Distribution 2 to 1").sampleNextValueExactly();
  1420. mv302TransitionInformation[0] = 1;
  1421. mv302TransitionInformation[1] = transitionTime;
  1422. mv302TransitionInformation[2] = transitionTime;
  1423. mv302TransitionInformation[3] = 1;
  1424. mv302TransitionInformation[4] = 2-1;
  1425. mv302List.add(2);
  1426. }
  1427. else {
  1428. mv302List.add(mv302List.getLast());
  1429. }
  1430. // MV-304
  1431. String mv304Name = "MV-304";
  1432. int mv304New = mv304LastStatus;
  1433. if(mv304TransitionInformation[0] == 1 && mv304TransitionInformation[4] > 1) { // Wait for offset to end
  1434. mv304TransitionInformation[4]--;
  1435. mv304New = mv304LastStatus;
  1436. }
  1437. else if(mv304TransitionInformation[0] == 1 && mv304LastStatus != 0 && mv304TransitionInformation[4] == 1) {
  1438. if((mv301LastStatus != 1 || backwashIntervalList.getFirst()-seconds < 10)
  1439. && mv304TransitionInformation[3] == 2) {//System.out.println("aa "+seconds);
  1440. mv304TransitionInformation[0] = 0;
  1441. mv304New = mv304LastStatus;
  1442. }
  1443. else {
  1444. mv304TransitionInformation[4]--;
  1445. mv304New = 0; // Start transition in next second
  1446. }
  1447. }
  1448. else if(mv304LastStatus == 0) { // Transition
  1449. int remainingTransistionTime = mv304TransitionInformation[2];
  1450. if(remainingTransistionTime == 0) { // Stop
  1451. mv304TransitionInformation[0] = 0;
  1452. mv304New = mv304TransitionInformation[3];
  1453. }
  1454. else { // Continue
  1455. mv304TransitionInformation[2] = remainingTransistionTime-1;
  1456. mv304New = 0;
  1457. }
  1458. }
  1459. else if(mv304LastStatus != 2 && lit301LastStatus >= 250 && mv301LastStatus == 1 && mv302LastStatus == 1 && (mv303LastStatus == 2 || lit401LastStatus < 800)) { // Start offset count down to opening transition
  1460. int transitionTime = (int) distributionHandlers.get(mv304Name+" Transition Distribution 1 to 2").sampleNextValueExactly();
  1461. mv304TransitionInformation[0] = 1;
  1462. mv304TransitionInformation[1] = transitionTime;
  1463. mv304TransitionInformation[2] = transitionTime;
  1464. mv304TransitionInformation[3] = 2;
  1465. mv304TransitionInformation[4] = ThreadLocalRandom.current().nextInt(1, 4);
  1466. mv304New = 1;
  1467. }
  1468. else if(mv304LastStatus == 2 && listMV302.size() >= 3) {
  1469. int mv302SecondLastStatus = mv302List.get(mv302List.size()-3);
  1470. if(mv302SecondLastStatus == 0 && mv302LastStatus == 2) { // Start offset count down to closing transition
  1471. int transitionTime = (int) distributionHandlers.get(mv304Name+" Transition Distribution 2 to 1").sampleNextValueExactly();
  1472. mv304TransitionInformation[0] = 1;
  1473. mv304TransitionInformation[1] = transitionTime;
  1474. mv304TransitionInformation[2] = transitionTime;
  1475. mv304TransitionInformation[3] = 1;
  1476. mv304TransitionInformation[4] = ThreadLocalRandom.current().nextInt(1, 4);
  1477. mv304New = 2;
  1478. }
  1479. else
  1480. mv304New = mv304LastStatus;
  1481. }
  1482. else {
  1483. mv304New = mv304LastStatus;
  1484. }
  1485. if(mv301LastStatus != 1) {
  1486. if(mv304New == 0) { // Correct too early started transitions
  1487. for(int i = listMV304.size()-1; i >= 0; i--) {
  1488. if(listMV304.get(i) == 0)
  1489. listMV304.set(i, 1);
  1490. else
  1491. break;
  1492. }
  1493. }
  1494. mv304TransitionInformation[0] = 0;
  1495. mv304New = 1;
  1496. }
  1497. listMV304.add(mv304New);
  1498. // DPIT-301
  1499. double dpit301LastValue = listDPIT301.getLast();
  1500. double dpit301Step = 0.0;
  1501. double dpit301New = 0.0;
  1502. if(p301302LastStatus == 2) { // Increase
  1503. if(dpit301LastValue >= 8.5 && dpit301LastValue <= 11.5) {
  1504. dpit301Step = 0.3 + ThreadLocalRandom.current().nextDouble(-0.5, 0.51);}
  1505. else
  1506. if(dpit301LastValue >= 1.5 && dpit301LastValue <= 2.38) {
  1507. dpit301Step = ThreadLocalRandom.current().nextDouble(-0.2, 0.31);
  1508. }
  1509. else
  1510. dpit301Step = 1 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1511. double maximum = 19.5 + ThreadLocalRandom.current().nextDouble(-0.15, 0.151);
  1512. dpit301New = BigDecimal.valueOf(dpit301LastValue).add(BigDecimal.valueOf(dpit301Step)).doubleValue();
  1513. if(dpit301New > maximum)
  1514. dpit301New = maximum;
  1515. }
  1516. else {
  1517. if(mv301LastStatus == 1 && mv302LastStatus == 1 && mv303LastStatus == 1) { // Plateau if nothing happens
  1518. dpit301Step = 1.8 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1519. double minimum = 2.4 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1520. dpit301New = BigDecimal.valueOf(dpit301LastValue).subtract(BigDecimal.valueOf(dpit301Step)).doubleValue();
  1521. if(dpit301New < minimum)
  1522. dpit301New = minimum;
  1523. }
  1524. else if(mv301LastStatus == 0 && mv302LastStatus == 1 && mv303LastStatus == 0 && mv304LastStatus == 1) { // Backwash: small plateau during decrease
  1525. int dpit301ListSize = listDPIT301.size();
  1526. if(dpit301ListSize >= 2) {
  1527. double dpit301SecondLastValue = listDPIT301.get(dpit301ListSize-2);
  1528. if(dpit301LastValue >= dpit301SecondLastValue) { // If already on the plateau for one second, start small increase
  1529. dpit301New = dpit301LastValue + 0.02 + ThreadLocalRandom.current().nextDouble(-0.0051, 0.0051);
  1530. }
  1531. else
  1532. dpit301New = dpit301LastValue;
  1533. }
  1534. else {
  1535. dpit301New = dpit301LastValue;
  1536. }
  1537. }
  1538. else if(mv301LastStatus == 2 && mv302LastStatus == 1 && mv303LastStatus == 2 && mv304LastStatus == 1) { // Backwash: lowest plateau
  1539. dpit301Step = 1.8 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1540. double minimum = 0.03201229;
  1541. dpit301New = BigDecimal.valueOf(dpit301LastValue).subtract(BigDecimal.valueOf(dpit301Step)).doubleValue();
  1542. if(dpit301New < minimum)
  1543. dpit301New = minimum;
  1544. }
  1545. else {
  1546. // No backwash
  1547. dpit301Step = 0.9769087778 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1548. double minimum = 2.4 + ThreadLocalRandom.current().nextDouble(-0.05, 0.051);
  1549. dpit301New = BigDecimal.valueOf(dpit301LastValue).subtract(BigDecimal.valueOf(dpit301Step)).doubleValue();
  1550. if(dpit301New < minimum)
  1551. dpit301New = minimum;
  1552. }
  1553. }
  1554. listDPIT301.add(dpit301New);
  1555. }
  1556. /**
  1557. * Simulates stage four for one second.
  1558. * @param seconds The current simulation time in seconds.
  1559. */
  1560. private void simulateStage4(int seconds){
  1561. // LIT-401
  1562. double lit401LastStatus = listLIT401.getLast();
  1563. int lit401ExtremeValueInformation = extremeValueInformation.get("LIT-401");
  1564. int[] lit401TransitionInformation = transitionInformation.get("LIT-401");
  1565. int mv302LastStatus = listMV302.getLast();
  1566. double lit401Step = 0.0;
  1567. if(mv302LastStatus == 2) {
  1568. lit401TransitionInformation[4] = 1;
  1569. if(lit401TransitionInformation[3] == 0) { // Highest slope for initial climb to 250
  1570. lit401Step = 0.391;
  1571. }
  1572. else if(lit401TransitionInformation[0] == 0) { // Higher slope for initial climb to 800
  1573. lit401Step = 0.08335;
  1574. }
  1575. else if(lit401TransitionInformation[1] == 0) { // Higher slope for initial climb to 1000
  1576. lit401Step = 0.066;
  1577. }
  1578. else if(lit401TransitionInformation[2] == 0) { // Lower slope after climb from local minimum until 800
  1579. lit401Step = 0.048;
  1580. }
  1581. else { // Higher slope for the second half of the increase until 1000
  1582. lit401Step = 0.082;
  1583. }
  1584. extremeValueInformation.put("LIT-401", 0);
  1585. }
  1586. else {
  1587. if(lit401ExtremeValueInformation == 0) {
  1588. lit401TransitionInformation[4] = -1;
  1589. lit401Step = -0.32;
  1590. }
  1591. else
  1592. lit401Step = 0;
  1593. }
  1594. double lit401New = lit401LastStatus + lit401Step;
  1595. if(lit401New < 0)
  1596. lit401New = 0;
  1597. listLIT401.add(lit401New);
  1598. if(lit401New >= 250) lit401TransitionInformation[3] = 1;
  1599. if(lit401New >= 800) lit401TransitionInformation[0] = 1;
  1600. if(lit401New <= 800) lit401TransitionInformation[2] = 0;
  1601. else lit401TransitionInformation[2] = 1;
  1602. if(lit401New >= 1000) lit401TransitionInformation[1] = 1;
  1603. // P-401 and P-402
  1604. int p401402LastStatus = 1;
  1605. int p401LastStatus = listP401.getLast();
  1606. int p402LastStatus = listP402.getLast();
  1607. if(p401LastStatus == 2 || p402LastStatus == 2)
  1608. p401402LastStatus = 2;
  1609. listP401.add(1); // Still off or again off
  1610. int[] p402TransitionInformation = transitionInformation.get("P-402");
  1611. int p402New = p401402LastStatus;
  1612. if(p402TransitionInformation[0] == 1) {
  1613. if(p402TransitionInformation[4] > 0) { // Wait for offset to end
  1614. p402TransitionInformation[4]--;
  1615. p402New = p401402LastStatus;
  1616. }
  1617. else {
  1618. p402TransitionInformation[0] = 0;
  1619. if(p402TransitionInformation[3] == 2)
  1620. p402New = 2;
  1621. else
  1622. p402New = 1;
  1623. }
  1624. }
  1625. else if(p401402LastStatus == 1 && lit401LastStatus > 250) { // Turn on
  1626. p402TransitionInformation[0] = 1;
  1627. p402TransitionInformation[3] = 2;
  1628. p402TransitionInformation[4] = 3;
  1629. p402New = 1;
  1630. }
  1631. else if(p401402LastStatus == 2 && lit401LastStatus < 250){ // Turn off
  1632. p402New = 2;
  1633. p402TransitionInformation[0] = 0;
  1634. }
  1635. listP402.add(p402New);
  1636. // P-403 and P-404
  1637. listP403.add(1);
  1638. listP404.add(1);
  1639. // FIT-401
  1640. double fit401LastValue = listFIT401.getLast();
  1641. int[] fit401TransitionInformation = transitionInformation.get("FIT-401");
  1642. double fit401New = fit401LastValue;
  1643. double fit401NewMaximum = 1.7 + ThreadLocalRandom.current().nextDouble(-0.005, 0.0051);
  1644. if(fit401TransitionInformation[0] == 1) {
  1645. if(fit401TransitionInformation[4] > 0) { // Wait for offset to end
  1646. fit401TransitionInformation[4]--;
  1647. }
  1648. else {
  1649. fit401TransitionInformation[0] = -1; // Block decrease until increase
  1650. }
  1651. }
  1652. else if(lit401LastStatus >= 250) {
  1653. if(p401402LastStatus == 1) {// Decrease or initiate offset to decrease
  1654. if(fit401TransitionInformation[0] == 0) { // Decrease only possible after increase
  1655. fit401TransitionInformation[0] = 1;
  1656. fit401TransitionInformation[4] = 2;
  1657. }
  1658. else {
  1659. fit401New = fit401LastValue - (0.100139294117647 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011));
  1660. }
  1661. }
  1662. else { // Increase
  1663. fit401New = fit401LastValue + 0.013694855932203 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1664. if(fit401New > fit401NewMaximum)
  1665. fit401New = fit401NewMaximum;
  1666. fit401TransitionInformation[0] = 0;
  1667. }
  1668. }
  1669. if(fit401New < 0)
  1670. fit401New = 0;
  1671. listFIT401.add(fit401New);
  1672. // UV-401
  1673. int uv401LastStatus = listUV401.getLast();
  1674. int[] uv401TransitionInformation = transitionInformation.get("UV-401");
  1675. int uv401New = uv401LastStatus;
  1676. if(uv401TransitionInformation[0] == 1) {
  1677. if(uv401TransitionInformation[4] > 0) { // Wait for offset to end
  1678. uv401TransitionInformation[4]--;
  1679. uv401New = uv401LastStatus;
  1680. }
  1681. else {
  1682. uv401TransitionInformation[0] = 0;
  1683. if(uv401TransitionInformation[3] == 2)
  1684. uv401New = 2;
  1685. else
  1686. uv401New = 1;
  1687. }
  1688. }
  1689. else if(uv401LastStatus == 1 && p401402LastStatus == 2) { // Turn on
  1690. uv401TransitionInformation[0] = 1;
  1691. uv401TransitionInformation[3] = 2;
  1692. uv401TransitionInformation[4] = 3;
  1693. uv401New = 1;
  1694. }
  1695. else if(uv401LastStatus == 2 && p401402LastStatus == 1){ // Turn off
  1696. uv401New = 1;
  1697. uv401TransitionInformation[0] = 0;
  1698. }
  1699. listUV401.add(uv401New);
  1700. // AIT-401
  1701. // Stays constant as a simplification
  1702. listAIT401.add(listAIT401.getLast());
  1703. // AIT-402
  1704. double ait402LastValue = listAIT402.getLast();
  1705. double ait402New = 0.0;
  1706. int[] ait402TransitionInformation = transitionInformation.get("AIT-402");
  1707. if(fit401LastValue <= 1) {
  1708. ait402New = ait402LastValue + ThreadLocalRandom.current().nextDouble(-0.08, 0.091);
  1709. }
  1710. else if(ait402TransitionInformation[0] == 0){ // Increase until ~235
  1711. ait402New = ait402LastValue + 0.063792395833333 + ThreadLocalRandom.current().nextDouble(-0.04, 0.041);
  1712. if(ait402New >= 235)
  1713. ait402TransitionInformation[0] = 1;
  1714. }
  1715. else {
  1716. ait402New = ait402LastValue - ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1717. if(lit401TransitionInformation[4] == -1)
  1718. ait402New -= ThreadLocalRandom.current().nextDouble(0.001, 0.0011);
  1719. else if(lit401TransitionInformation[4] == 1)
  1720. ait402New += ThreadLocalRandom.current().nextDouble(0.00059, 0.000591);
  1721. }
  1722. if(ait402New < 0)
  1723. ait402New = 0;
  1724. listAIT402.add(ait402New);
  1725. }
  1726. /**
  1727. * Simulates stage five for one second.
  1728. * @param seconds The current simulation time in seconds.
  1729. */
  1730. private void simulateStage5(int seconds){
  1731. // P-501 and P-502
  1732. int p401402LastStatus = 1;
  1733. int p401LastStatus = listP401.getLast();
  1734. int p402LastStatus = listP402.getLast();
  1735. if(p401LastStatus == 2 || p402LastStatus == 2)
  1736. p401402LastStatus = 2;
  1737. int uv401LastStatus = listUV401.getLast();
  1738. int p501502LastStatus = 1;
  1739. int p501LastStatus = listP501.getLast();
  1740. int p502LastStatus = listP502.getLast();
  1741. if(p501LastStatus == 2 || p502LastStatus == 2)
  1742. p501502LastStatus = 2;
  1743. listP502.add(1); // Still off or again off
  1744. int[] p501TransitionInformation = transitionInformation.get("P-501");
  1745. int p501New = p501502LastStatus;
  1746. if(p501TransitionInformation[0] == 1) {
  1747. if(p501TransitionInformation[4] > 0) { // Wait for offset to end
  1748. p501TransitionInformation[4]--;
  1749. p501New = p501502LastStatus;
  1750. }
  1751. else {
  1752. p501TransitionInformation[0] = 0;
  1753. if(p501TransitionInformation[3] == 2)
  1754. p501New = 2;
  1755. else
  1756. p501New = 1;
  1757. }
  1758. }
  1759. else if(p501502LastStatus == 1 && p401402LastStatus == 2) { // Turn on
  1760. p501TransitionInformation[0] = 1;
  1761. p501TransitionInformation[3] = 2;
  1762. p501TransitionInformation[4] = 78;
  1763. p501New = 1;
  1764. }
  1765. else if(p501502LastStatus == 2 && (p401402LastStatus == 1 || uv401LastStatus == 1)){ // Turn off
  1766. p501New = 2;
  1767. p501TransitionInformation[0] = 0;
  1768. }
  1769. listP501.add(p501New);
  1770. // AIT-501
  1771. String ait501Name = "AIT-501";
  1772. double ait501LastValue = listAIT501.getLast();
  1773. int ait501ExtremeValueInformation = extremeValueInformation.get(ait501Name);
  1774. int[] ait501TransitionInformation = transitionInformation.get(ait501Name);
  1775. double ait501New = ait501LastValue;
  1776. if(ait501LastValue >= 8)
  1777. ait501ExtremeValueInformation = 0; // No need to further increase
  1778. if(ait501TransitionInformation[0] == 1) {
  1779. if(ait501TransitionInformation[4] > 0) { // Wait for offset to end
  1780. ait501TransitionInformation[4]--;
  1781. }
  1782. else {
  1783. ait501TransitionInformation[0] = -1;
  1784. }
  1785. ait501TransitionInformation[1] = 0;
  1786. ait501New = ait501LastValue - 0.0000224865497076031;
  1787. }
  1788. else if(p401402LastStatus == 2) {
  1789. if(ait501ExtremeValueInformation != 0) { // Increase
  1790. extremeValueInformation.put(ait501Name, 1);
  1791. if(ait501TransitionInformation[0] == 0) {
  1792. ait501TransitionInformation[0] = 1;
  1793. ait501TransitionInformation[4] = 19;
  1794. }
  1795. else {
  1796. if(ait501New <= 7.5) {
  1797. ait501New = ait501LastValue + 0.000256540785498;
  1798. }
  1799. else if(ait501New >= 7.5 && ait501New < 7.6) {
  1800. ait501New = ait501LastValue + 0.000112060335196;
  1801. }
  1802. else if(ait501New >= 7.6 && ait501New < 7.7) {
  1803. ait501New = ait501LastValue + 0.0000510995429151855;
  1804. }
  1805. else if(ait501New >= 7.7 && ait501New < 7.8) {
  1806. ait501New = ait501LastValue + 0.0000259445320715034;
  1807. }
  1808. else if(ait501New >= 7.8 && ait501New < 7.85) {
  1809. ait501New = ait501LastValue + 0.0000236707706338351;
  1810. }
  1811. else if(ait501New >= 7.85) {
  1812. extremeValueInformation.put(ait501Name, 0);
  1813. }
  1814. }
  1815. ait501TransitionInformation[1] = 0;
  1816. }
  1817. else {
  1818. // Follow a sin curve
  1819. if(ait501TransitionInformation[1] == 0) {
  1820. ait501TransitionInformation[2] = seconds; // Sine start
  1821. ait501TransitionInformation[1] = -1;
  1822. }
  1823. double ait501SinPosition = Math.sin(2*Math.PI/200000*((seconds-ait501TransitionInformation[2]) % 200000));
  1824. ait501New = 7.85+ait501SinPosition/10;
  1825. }
  1826. }
  1827. else { // Decrease
  1828. ait501New = ait501LastValue - 0.0000224865497076031;
  1829. if(ait501New < 0)
  1830. ait501New = 0;
  1831. ait501TransitionInformation[0] = 0;
  1832. }
  1833. if(seconds % ThreadLocalRandom.current().nextInt(10, 20) == 0) // Jitter from time to time
  1834. ait501New = ait501New + ThreadLocalRandom.current().nextDouble(-0.003, 0.0031);
  1835. if(ait501New < 0)
  1836. ait501New = 0;
  1837. listAIT501.add(ait501New);
  1838. // AIT-502
  1839. double ait502LastValue = listAIT502.getLast();
  1840. double ait502New = ait502LastValue;
  1841. int[] ait502TransitionInformation = transitionInformation.get("AIT-502");
  1842. int ait502ExtremeValueInformation = extremeValueInformation.get("AIT-502");
  1843. double fit401LastValue = listFIT401.getLast();
  1844. int[] lit401TransitionInformation = transitionInformation.get("LIT-401");
  1845. if(fit401LastValue <= 0.2) {
  1846. ait502New = ait502LastValue + 0.002892280285036 + ThreadLocalRandom.current().nextDouble(-0.01, 0.01);
  1847. }
  1848. else if(ait502TransitionInformation[0] == 0) { // Generate spikes
  1849. if(ait502ExtremeValueInformation == 1) {// Small positive spike
  1850. ait502New = ait502LastValue + 0.095903846153846 + ThreadLocalRandom.current().nextDouble(-0.08, 0.081);
  1851. if(ait502New >= 181.77)
  1852. extremeValueInformation.put("AIT-502", 0);
  1853. }
  1854. else if(ait502ExtremeValueInformation == 0) { // Larger negative spike
  1855. ait502New = ait502LastValue - 0.051939215686275 + ThreadLocalRandom.current().nextDouble(-0.08, 0.081);
  1856. if(ait502New <= 173.8273) {
  1857. extremeValueInformation.put("AIT-502", -1);
  1858. ait502TransitionInformation[0] = -1;
  1859. }
  1860. }
  1861. else
  1862. ait502TransitionInformation[0] = -1;
  1863. }
  1864. else if(ait502TransitionInformation[0] == -1){ // Increase until ~218
  1865. ait502New = ait502LastValue + 0.063792395833333 + ThreadLocalRandom.current().nextDouble(-0.08, 0.081);
  1866. if(ait502New >= 218)
  1867. ait502TransitionInformation[0] = 1;
  1868. ait502ExtremeValueInformation = 0;
  1869. }
  1870. else {
  1871. ait502New = ait502LastValue - ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1872. if(lit401TransitionInformation[4] == -1)
  1873. ait502New -= ThreadLocalRandom.current().nextDouble(0.001, 0.0011);
  1874. else if(lit401TransitionInformation[4] == 1)
  1875. ait502New += ThreadLocalRandom.current().nextDouble(0.00059, 0.000591);
  1876. ait502ExtremeValueInformation = 0;
  1877. }
  1878. if(ait502New < 0)
  1879. ait502New = 0;
  1880. listAIT502.add(ait502New);
  1881. // AIT-503
  1882. String ait503Name = "AIT-503";
  1883. double ait503LastValue = listAIT503.getLast();
  1884. int ait503ExtremeValueInformation = extremeValueInformation.get(ait503Name);
  1885. int[] ait503TransitionInformation = transitionInformation.get(ait503Name);
  1886. double ait503New = ait503LastValue;
  1887. int mv301LastValue = listMV301.getLast();
  1888. int mv301SecondLastValue = -1;
  1889. if(seconds >= 3)
  1890. mv301SecondLastValue = listMV301.get(listMV301.size()-3);
  1891. if(mv301SecondLastValue == 0 && mv301LastValue == 2)
  1892. ait503ExtremeValueInformation = 0;
  1893. if(ait503TransitionInformation[0] == 1) {
  1894. if(ait503TransitionInformation[4] > 0) { // Wait for offset to end
  1895. ait503TransitionInformation[4]--;
  1896. }
  1897. else {
  1898. ait503TransitionInformation[0] = -1;
  1899. extremeValueInformation.put(ait503Name, 1);
  1900. ait503TransitionInformation[1] = 0;
  1901. }
  1902. }
  1903. else if(ait503ExtremeValueInformation == 1) { // Fast increase of spike for 52 seconds
  1904. if(ait503TransitionInformation[1] == 0)
  1905. ait503TransitionInformation[2] = 52 + ThreadLocalRandom.current().nextInt(-5, 6);
  1906. ait503New = ait503LastValue + 0.184248076923077;
  1907. ait503TransitionInformation[1]++;
  1908. if(ait503TransitionInformation[1] == ait503TransitionInformation[2]) {
  1909. extremeValueInformation.put(ait503Name, 2);
  1910. ait503TransitionInformation[1] = 0;
  1911. }
  1912. }
  1913. else if(ait503ExtremeValueInformation == 2) { // Short fast decrease of spike for 105 seconds
  1914. if(ait503TransitionInformation[1] == 0)
  1915. ait503TransitionInformation[2] = 105 + ThreadLocalRandom.current().nextInt(-10, 11);
  1916. ait503New = ait503LastValue - 0.048827619047619;
  1917. ait503TransitionInformation[1]++;
  1918. if(ait503TransitionInformation[1] == ait503TransitionInformation[2]) {
  1919. extremeValueInformation.put(ait503Name, 3);
  1920. ait503TransitionInformation[1] = 0;
  1921. }
  1922. }
  1923. else if(ait503ExtremeValueInformation == 3) { // First long slow decrease of spike for 1323 seconds
  1924. if(ait503TransitionInformation[1] == 0)
  1925. ait503TransitionInformation[2] = 1323 + ThreadLocalRandom.current().nextInt(-130, 131);
  1926. ait503New = ait503LastValue - 0.003126701966717;
  1927. ait503TransitionInformation[1]++;
  1928. if(ait503TransitionInformation[1] == ait503TransitionInformation[2]) {
  1929. extremeValueInformation.put(ait503Name, 4);
  1930. ait503TransitionInformation[1] = 0;
  1931. }
  1932. }
  1933. else if(ait503ExtremeValueInformation == 4) { // Plateau during decrease of spike for 842 seconds
  1934. if(ait503TransitionInformation[1] == 0)
  1935. ait503TransitionInformation[2] = 842 + ThreadLocalRandom.current().nextInt(-84, 85);
  1936. ait503New = ait503LastValue;
  1937. ait503TransitionInformation[1]++;
  1938. if(ait503TransitionInformation[1] == 842) {
  1939. extremeValueInformation.put(ait503Name, 5);
  1940. ait503TransitionInformation[1] = 0;
  1941. }
  1942. }
  1943. else if(ait503ExtremeValueInformation == 5) { // Second long slow decrease of spike
  1944. ait503New = ait503LastValue - 0.001363149171271;
  1945. }
  1946. else if(mv301SecondLastValue == 0 && mv301LastValue == 2) {
  1947. ait503TransitionInformation[0] = 1;
  1948. ait503TransitionInformation[4] = 220 + ThreadLocalRandom.current().nextInt(-3, 3);
  1949. }
  1950. else
  1951. ait503New = ait503LastValue + 0.0025;
  1952. ait503New = ait503New + ThreadLocalRandom.current().nextDouble(-0.0119999999999999, 0.012);
  1953. if(ait503New < 0)
  1954. ait503New = 0;
  1955. listAIT503.add(ait503New);
  1956. // AIT-504
  1957. String ait504Name = "AIT-504";
  1958. double ait504LastValue = listAIT504.getLast();
  1959. int ait504ExtremeValueInformation = extremeValueInformation.get(ait504Name);
  1960. int[] ait504TransitionInformation = transitionInformation.get(ait504Name);
  1961. double ait504New = ait504LastValue;
  1962. double p401402SecondLastStatus = -1;
  1963. if(seconds >= 3) {
  1964. p401402SecondLastStatus = 1;
  1965. int p401SecondLastStatus = listP401.get(seconds-3);
  1966. int p402SecondLastStatus = listP402.get(seconds-3);
  1967. if(p401SecondLastStatus == 2 || p402SecondLastStatus == 2)
  1968. p401402SecondLastStatus = 2;
  1969. }
  1970. if(ait504TransitionInformation[0] == 1 && ait504TransitionInformation[4] > 0) { // Wait for offset to end
  1971. ait504TransitionInformation[4]--;
  1972. extremeValueInformation.put(ait504Name, 0); // Start with negative spike
  1973. }
  1974. else if(p401402LastStatus == 2) {
  1975. if(p401402SecondLastStatus == 1 && ait504ExtremeValueInformation == -1) { // Start new offset count down
  1976. ait504TransitionInformation[0] = 1;
  1977. ait504TransitionInformation[4] = 4;
  1978. }
  1979. else if(ait504ExtremeValueInformation == 0) { // Negative spike
  1980. ait504New = ait504LastValue - 2.1648 + ThreadLocalRandom.current().nextDouble(-0.1, 0.11);
  1981. if(ait504New < 102)
  1982. extremeValueInformation.put(ait504Name, 1); // Continue with positive spike
  1983. }
  1984. else if(ait504ExtremeValueInformation == 1) { // Positive spike
  1985. ait504New = ait504LastValue + 5.00793846153846 + ThreadLocalRandom.current().nextDouble(-0.1, 0.11);
  1986. if(ait504New >= 227) {
  1987. extremeValueInformation.put(ait504Name, 2); // Second negative spike
  1988. }
  1989. }
  1990. else if(ait504ExtremeValueInformation == 2) { // Second negative spike
  1991. ait504New = ait504LastValue - 2.10118023469388 + ThreadLocalRandom.current().nextDouble(-0.1, 0.11);
  1992. if(ait504New < 12){
  1993. ait504New = ait504LastValue - 0.1 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  1994. }
  1995. if(ait504New < 7.421174){
  1996. extremeValueInformation.put(ait504Name, 3); // Increase until normal level
  1997. }
  1998. }
  1999. else if(ait504ExtremeValueInformation == 3) { // Increase until normal level
  2000. ait504New = ait504LastValue + 0.006898988372093 + ThreadLocalRandom.current().nextDouble(-0.001, 0.0011);
  2001. if(ait504New >= 10){
  2002. extremeValueInformation.put(ait504Name, 4); // Stay constant
  2003. }
  2004. }
  2005. else if(ait504ExtremeValueInformation == 4) { // Increase until normal level
  2006. ait504New = ait504LastValue + 0.001298988372093 + ThreadLocalRandom.current().nextDouble(-0.001, 0.0011);
  2007. if(ait504New >= 12){
  2008. extremeValueInformation.put(ait504Name, 5); // Stay constant
  2009. }
  2010. }
  2011. }
  2012. else if(p401402LastStatus == 2) {
  2013. extremeValueInformation.put(ait504Name, -1);
  2014. }
  2015. if(seconds % ThreadLocalRandom.current().nextInt(30, 50) == 0 && ait504ExtremeValueInformation == 5) { // Jitter from time to time
  2016. ait504New = 12 + ThreadLocalRandom.current().nextDouble(-0.3, 0.31);
  2017. }
  2018. if(ait504New < 0)
  2019. ait504New = 0;
  2020. listAIT504.add(ait504New);
  2021. // FIT-501
  2022. String fit501Name = "FIT-501";
  2023. double fit501LastValue = listFIT501.getLast();
  2024. int fit501ExtremeValueInformation = extremeValueInformation.get(fit501Name);
  2025. int[] fit501TransitionInformation = transitionInformation.get(fit501Name);
  2026. double fit501New = fit501LastValue;
  2027. if(fit501TransitionInformation[0] == 1) {
  2028. if(fit501TransitionInformation[4] > 0) { // Wait for offset to end
  2029. fit501TransitionInformation[4]--;
  2030. }
  2031. else {
  2032. fit501TransitionInformation[0] = -1;
  2033. }
  2034. }
  2035. else if(p401402LastStatus == 2 && fit501ExtremeValueInformation != 0) { // Increase
  2036. extremeValueInformation.put(fit501Name, 1);
  2037. if(fit501TransitionInformation[0] == 0) {
  2038. fit501TransitionInformation[0] = 1;
  2039. fit501TransitionInformation[4] = 3;
  2040. }
  2041. else {
  2042. fit501New = fit501LastValue + 0.028255744740741;
  2043. if(fit501New >= 1.64) {
  2044. fit501New = fit501LastValue + 0.00007;
  2045. }
  2046. if(fit501New >= 1.71) {
  2047. extremeValueInformation.put(fit501Name, 0);
  2048. }
  2049. }
  2050. }
  2051. else if(p401402LastStatus == 1 && fit501ExtremeValueInformation != -1) { // Decrease
  2052. if(fit501TransitionInformation[0] == 0) {
  2053. fit501TransitionInformation[0] = 1;
  2054. fit501TransitionInformation[4] = 2;
  2055. }
  2056. else {
  2057. fit501New = fit501LastValue - 0.106816575833333;
  2058. if(fit501New < 0)
  2059. fit501New = 0;
  2060. fit501TransitionInformation[0] = 0;
  2061. if(fit501LastValue <= 1.7096)
  2062. extremeValueInformation.put(fit501Name, 1);
  2063. }
  2064. }
  2065. else if(fit501ExtremeValueInformation == 0){ // Stay in range
  2066. if(fit501New <= 1.7096 || fit501New >= 1.714)
  2067. fit501New = 1.71;
  2068. }
  2069. if(fit501New != 0.001538067 && seconds % ThreadLocalRandom.current().nextInt(5, 10) == 0) // Jitter from time to time
  2070. fit501New = fit501New + ThreadLocalRandom.current().nextDouble(-0.002, 0.0021);
  2071. if(fit501New < 0.001538067)
  2072. fit501New = 0.001538067;
  2073. listFIT501.add(fit501New);
  2074. // FIT-502
  2075. String fit502Name = "FIT-502";
  2076. double fit502LastValue = listFIT502.getLast();
  2077. int fit502ExtremeValueInformation = extremeValueInformation.get(fit502Name);
  2078. int[] fit502TransitionInformation = transitionInformation.get(fit502Name);
  2079. double fit502New = fit502LastValue;
  2080. if(fit502TransitionInformation[0] == 1) {
  2081. if(fit502TransitionInformation[4] > 0) { // Wait for offset to end
  2082. fit502TransitionInformation[4]--;
  2083. }
  2084. else {
  2085. fit502TransitionInformation[0] = -1;
  2086. }
  2087. }
  2088. else if(p401402LastStatus == 2 && fit502ExtremeValueInformation != 0) { // Increase
  2089. extremeValueInformation.put(fit502Name, 1);
  2090. if(fit502TransitionInformation[0] == 0) {
  2091. fit502TransitionInformation[0] = 1;
  2092. fit502TransitionInformation[4] = 1;
  2093. }
  2094. else {
  2095. fit502New = fit502LastValue + 0.028255744740741;
  2096. if(fit502LastValue >= 1.27) {
  2097. extremeValueInformation.put(fit502Name, 0);
  2098. fit502New = 1.27;
  2099. }
  2100. }
  2101. }
  2102. else if(p401402LastStatus == 1 && fit502ExtremeValueInformation != -1) { // Decrease
  2103. if(fit502TransitionInformation[0] == 0) {
  2104. fit502TransitionInformation[0] = 1;
  2105. fit502TransitionInformation[4] = 1;
  2106. }
  2107. else {
  2108. fit502New = fit502LastValue - 0.106816575833333;
  2109. if(fit502New < 0)
  2110. fit502New = 0;
  2111. fit502TransitionInformation[0] = 0;
  2112. if(fit502LastValue <= 1.235)
  2113. extremeValueInformation.put(fit502Name, 1);
  2114. }
  2115. }
  2116. else if(fit502ExtremeValueInformation == 0){ // Stay in range
  2117. if(fit502New <= 1.235 || fit502New >= 1.3)
  2118. fit502New = 1.27;
  2119. }
  2120. if(fit502New != 0.001408992 ) // Jitter
  2121. fit502New = fit502New + ThreadLocalRandom.current().nextDouble(-0.018, 0.0181);
  2122. if(fit502New < 0.001408992)
  2123. fit502New = 0.001408992;
  2124. listFIT502.add(fit502New);
  2125. // FIT-503
  2126. String fit503Name = "FIT-503";
  2127. double fit503LastValue = listFIT503.getLast();
  2128. int fit503ExtremeValueInformation = extremeValueInformation.get(fit503Name);
  2129. int[] fit503TransitionInformation = transitionInformation.get(fit503Name);
  2130. double fit503New = fit503LastValue;
  2131. if(fit503TransitionInformation[0] == 1) {
  2132. if(fit503TransitionInformation[4] > 0) { // Wait for offset to end
  2133. fit503TransitionInformation[4]--;
  2134. }
  2135. else {
  2136. fit503TransitionInformation[0] = -1;
  2137. }
  2138. }
  2139. else if(p401402LastStatus == 2 && fit503ExtremeValueInformation != 0) { // Increase
  2140. extremeValueInformation.put(fit503Name, 1);
  2141. if(fit503TransitionInformation[0] == 0) {
  2142. fit503TransitionInformation[0] = 1;
  2143. fit503TransitionInformation[4] = 4;
  2144. }
  2145. else {
  2146. fit503New = fit503LastValue + 0.006381567474138;
  2147. if(fit503LastValue >= 0.75)
  2148. extremeValueInformation.put(fit503Name, 0);
  2149. }
  2150. }
  2151. else if(p401402LastStatus == 1 && fit503ExtremeValueInformation != -1) { // Decrease
  2152. if(fit503TransitionInformation[0] == 0) {
  2153. fit503TransitionInformation[0] = 1;
  2154. fit503TransitionInformation[4] = 2;
  2155. }
  2156. else {
  2157. fit503New = fit503LastValue - 0.056470497769231;
  2158. if(fit503New < 0)
  2159. fit503New = 0;
  2160. fit503TransitionInformation[0] = 0;
  2161. if(fit503LastValue <= 0.743)
  2162. extremeValueInformation.put(fit503Name, 1);
  2163. }
  2164. }
  2165. else if(fit503ExtremeValueInformation == 0){ // Stay in range
  2166. if(fit503LastValue >= 1.45) {
  2167. fit503New = fit503LastValue - 0.001;
  2168. }
  2169. else if(fit503New <= 0.743 || fit503New >= 0.747)
  2170. fit503New = 0.745;
  2171. }
  2172. if(fit503New != 0.001664373 && seconds % ThreadLocalRandom.current().nextInt(5, 11) == 0) // Jitter from time to time
  2173. fit503New = fit503New + ThreadLocalRandom.current().nextDouble(-0.0015, 0.00151);
  2174. if(fit503New < 0.001664373)
  2175. fit503New = 0.001664373;
  2176. listFIT503.add(fit503New);
  2177. // FIT-504
  2178. String fit504Name = "FIT-504";
  2179. double fit504LastValue = listFIT504.getLast();
  2180. int fit504ExtremeValueInformation = extremeValueInformation.get(fit504Name);
  2181. int[] fit504TransitionInformation = transitionInformation.get(fit504Name);
  2182. double fit504New = fit504LastValue;
  2183. if(fit504TransitionInformation[0] == 1) {
  2184. if(fit504TransitionInformation[4] > 0) { // Wait for offset to end
  2185. fit504TransitionInformation[4]--;
  2186. }
  2187. else {
  2188. fit504TransitionInformation[0] = -1;
  2189. }
  2190. }
  2191. else if(p501502LastStatus == 2 && fit504ExtremeValueInformation != 0) { // Increase
  2192. extremeValueInformation.put(fit504Name, 1);
  2193. if(fit504TransitionInformation[0] == 0) {
  2194. fit504TransitionInformation[0] = 1;
  2195. fit504TransitionInformation[4] = 20;
  2196. }
  2197. else {
  2198. fit504New = fit504LastValue + 0.005026830540541;
  2199. if(fit504LastValue >= 0.15)
  2200. extremeValueInformation.put(fit504Name, 0);
  2201. }
  2202. }
  2203. else if(p501502LastStatus == 1 && fit504ExtremeValueInformation != -1) { // Decrease
  2204. if(fit504TransitionInformation[0] == 0) {
  2205. fit504TransitionInformation[0] = 1;
  2206. fit504TransitionInformation[4] = 2;
  2207. }
  2208. else {
  2209. fit504New = fit504LastValue - 0.028201818181818;
  2210. if(fit504New < 0)
  2211. fit504New = 0;
  2212. fit504TransitionInformation[0] = 0;
  2213. if(fit504LastValue <= 0.308)
  2214. extremeValueInformation.put(fit504Name, 1);
  2215. }
  2216. }
  2217. else if(fit504ExtremeValueInformation == 0){ // Stay in range
  2218. if(fit504LastValue >= 1.45) {
  2219. fit504New = fit504LastValue - 0.001;
  2220. }
  2221. else if(fit504New <= 0.308 || fit504New >= 0.31)
  2222. fit504New = 0.309;
  2223. }
  2224. if(fit504New != 0 && seconds % ThreadLocalRandom.current().nextInt(5, 11) == 0) // Jitter from time to time
  2225. fit504New = fit504New + ThreadLocalRandom.current().nextDouble(-0.0015, 0.00151);
  2226. if(fit504New < 0)
  2227. fit504New = 0;
  2228. listFIT504.add(fit504New);
  2229. // PIT-501
  2230. String pit501Name = "PIT-501";
  2231. double pit501LastValue = listPIT501.getLast();
  2232. int pit501ExtremeValueInformation = extremeValueInformation.get(pit501Name);
  2233. int[] pit501TransitionInformation = transitionInformation.get(pit501Name);
  2234. double pit501New = pit501LastValue;
  2235. if(pit501TransitionInformation[0] == 1) {
  2236. if(pit501TransitionInformation[4] > 0) { // Wait for offset to end
  2237. pit501TransitionInformation[4]--;
  2238. }
  2239. else {
  2240. pit501TransitionInformation[0] = -1;
  2241. }
  2242. }
  2243. else if(p401402LastStatus == 2 && pit501ExtremeValueInformation != 0) { // Increase
  2244. extremeValueInformation.put(pit501Name, 1);
  2245. if(pit501TransitionInformation[0] == 0) {
  2246. pit501TransitionInformation[0] = 1;
  2247. pit501TransitionInformation[3] = 2;
  2248. pit501TransitionInformation[4] = 0;
  2249. }
  2250. else {
  2251. pit501New = pit501LastValue + 2.00231330708661;
  2252. if(pit501LastValue >= 254)
  2253. extremeValueInformation.put(pit501Name, 0);
  2254. }
  2255. }
  2256. else if(p401402LastStatus == 1 && pit501ExtremeValueInformation != -1) { // Decrease
  2257. pit501New = pit501LastValue - 10.2795569565217;
  2258. if(pit501New < 10)
  2259. pit501New = 10 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  2260. pit501TransitionInformation[0] = 0;
  2261. if(pit501LastValue <= 252)
  2262. extremeValueInformation.put(pit501Name, 1);
  2263. }
  2264. else if(pit501ExtremeValueInformation == 0){ // Stay in range
  2265. if(pit501New <= 252.5 || pit501New >= 253.5)
  2266. pit501New = 253;
  2267. }
  2268. if(seconds % ThreadLocalRandom.current().nextInt(10, 20) == 0) // Jitter from time to time
  2269. pit501New = pit501New + ThreadLocalRandom.current().nextDouble(-0.3, 0.31);
  2270. if(pit501New < 0)
  2271. pit501New = 0;
  2272. listPIT501.add(pit501New);
  2273. // PIT-502
  2274. String pit502Name = "PIT-502";
  2275. double pit502LastValue = listPIT502.getLast();
  2276. int pit502ExtremeValueInformation = extremeValueInformation.get(pit502Name);
  2277. int[] pit502TransitionInformation = transitionInformation.get(pit502Name);
  2278. double pit502New = pit502LastValue;
  2279. if(pit502TransitionInformation[0] == 1) {
  2280. if(pit502TransitionInformation[4] > 0) { // Wait for offset to end
  2281. pit502TransitionInformation[4]--;
  2282. }
  2283. else {
  2284. pit502TransitionInformation[0] = -1;
  2285. }
  2286. }
  2287. else if(p401402LastStatus == 2 && pit502ExtremeValueInformation != 0) { // Increase
  2288. extremeValueInformation.put(pit502Name, 1);
  2289. if(pit502TransitionInformation[0] == 0) {
  2290. pit502TransitionInformation[0] = 1;
  2291. pit502TransitionInformation[3] = 2;
  2292. pit502TransitionInformation[4] = 4;
  2293. }
  2294. else {
  2295. pit502New = pit502LastValue + 0.2979528;
  2296. if(pit502LastValue >= 3)
  2297. extremeValueInformation.put(pit502Name, 0);
  2298. }
  2299. }
  2300. else if(p401402LastStatus == 1 && pit502ExtremeValueInformation != -1) { // Decrease
  2301. pit502New = pit502LastValue - 0.5 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  2302. if(pit502New < 0)
  2303. pit502New = 0;
  2304. pit502TransitionInformation[0] = 0;
  2305. if(pit502LastValue <= 0.95)
  2306. extremeValueInformation.put(pit502Name, 1);
  2307. }
  2308. else if(pit502ExtremeValueInformation == 0){ // Stay in range
  2309. if(pit502LastValue >= 1.45) {
  2310. pit502New = pit502LastValue - 0.0123529 + ThreadLocalRandom.current().nextDouble(-0.001, 0.0011);
  2311. }
  2312. else if(pit502New <= 0.95 || pit502New >= 1.2)
  2313. pit502New = 1.1;
  2314. }
  2315. if(pit502New != 0 && seconds % ThreadLocalRandom.current().nextInt(5, 11) == 0) // Jitter from time to time
  2316. pit502New = pit502New + ThreadLocalRandom.current().nextDouble(-0.09, 0.091);
  2317. if(pit502New < 0)
  2318. pit502New = 0;
  2319. listPIT502.add(pit502New);
  2320. // PIT-503
  2321. String pit503Name = "PIT-503";
  2322. double pit503LastValue = listPIT503.getLast();
  2323. int pit503ExtremeValueInformation = extremeValueInformation.get(pit503Name);
  2324. int[] pit503TransitionInformation = transitionInformation.get(pit503Name);
  2325. double pit503New = pit503LastValue;
  2326. if(pit503TransitionInformation[0] == 1) {
  2327. if(pit503TransitionInformation[4] > 0) { // Wait for offset to end
  2328. pit503TransitionInformation[4]--;
  2329. }
  2330. else {
  2331. pit503TransitionInformation[0] = -1;
  2332. }
  2333. }
  2334. else if(p401402LastStatus == 2 && pit503ExtremeValueInformation != 0) { // Increase
  2335. extremeValueInformation.put(pit503Name, 1);
  2336. if(pit503TransitionInformation[0] == 0) {
  2337. pit503TransitionInformation[0] = 1;
  2338. pit503TransitionInformation[3] = 2;
  2339. pit503TransitionInformation[4] = 0;
  2340. }
  2341. else {
  2342. pit503New = pit503LastValue + 2.00231330708661;
  2343. if(pit503LastValue >= 193)
  2344. extremeValueInformation.put(pit503Name, 0);
  2345. }
  2346. }
  2347. else if(p401402LastStatus == 1 && pit503ExtremeValueInformation != -1) { // Decrease
  2348. pit503New = pit503LastValue - 10.2795569565217;
  2349. if(pit503New < 4.6)
  2350. pit503New = 4.6 + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  2351. pit503TransitionInformation[0] = 0;
  2352. if(pit503LastValue <= 192)
  2353. extremeValueInformation.put(pit503Name, 1);
  2354. }
  2355. else if(pit503ExtremeValueInformation == 0){ // Stay in range
  2356. if(pit503New <= 192 || pit503New >= 193)
  2357. pit503New = 192.5;
  2358. }
  2359. if(seconds % ThreadLocalRandom.current().nextInt(5, 11) == 0) // Jitter from time to time
  2360. pit503New = pit503New + ThreadLocalRandom.current().nextDouble(-0.3, 0.31);
  2361. if(pit503New < 0)
  2362. pit503New = 0;
  2363. listPIT503.add(pit503New);
  2364. }
  2365. /**
  2366. * Simulates stage six for one second.
  2367. * @param seconds The current simulation time in seconds.
  2368. */
  2369. private void simulateStage6(int seconds){
  2370. // P-601
  2371. listP601.add(1);
  2372. //P-602
  2373. String p602Name = "P-602";
  2374. int p602LastStatus = listP602.getLast();
  2375. int p602NewStatus = p602LastStatus;
  2376. int[] p602TransitionInformation = transitionInformation.get(p602Name);
  2377. int mv301LastStatus = listMV301.getLast();
  2378. if(p602TransitionInformation[0] == 1) {
  2379. if(p602TransitionInformation[4] > 0) { // Wait for offset to end
  2380. p602TransitionInformation[4]--;
  2381. }
  2382. else {
  2383. p602TransitionInformation[0] = -1;
  2384. p602NewStatus = 2;
  2385. }
  2386. }
  2387. else {
  2388. int mv301SecondLastStatus = -1;
  2389. if(seconds > 3)
  2390. mv301SecondLastStatus = listMV301.get(listMV301.size()-3);
  2391. if(mv301SecondLastStatus == 0 && mv301LastStatus == 2 ) { // Increase
  2392. p602TransitionInformation[0] = 1;
  2393. p602TransitionInformation[4] = ThreadLocalRandom.current().nextInt(1, 3) - 1; // Offset to turning on
  2394. p602TransitionInformation[2] = ThreadLocalRandom.current().nextInt(29, 31); // Count down to turn off again
  2395. }
  2396. if(mv301SecondLastStatus == 0 && mv301LastStatus == 1 && p602LastStatus == 2) {
  2397. p602NewStatus = 1;
  2398. p602TransitionInformation[0] = -1;
  2399. p602TransitionInformation[2] = -1;
  2400. }
  2401. else {
  2402. if(p602TransitionInformation[2] == 0)
  2403. p602NewStatus = 1;
  2404. p602TransitionInformation[2]--;
  2405. }
  2406. }
  2407. listP602.add(p602NewStatus);
  2408. // P-603
  2409. listP603.add(1);
  2410. // FIT-601
  2411. String fit601Name = "FIT-601";
  2412. double fit601LastValue = listFIT601.getLast();
  2413. double fit601New = fit601LastValue;
  2414. int fit601ExtremeValueInformation = extremeValueInformation.get(fit601Name);
  2415. int[] mv301TransitionInformation = transitionInformation.get("MV-301");
  2416. if(fit601ExtremeValueInformation == -1) {
  2417. if(mv301TransitionInformation[0] == 1 && mv301TransitionInformation[2] == 1 && mv301TransitionInformation[3] == 2) {
  2418. extremeValueInformation.put(fit601Name, 1);
  2419. }
  2420. else {
  2421. fit601New = fit601LastValue - 0.086726684825;
  2422. }
  2423. }
  2424. else if(fit601ExtremeValueInformation == 1) {
  2425. if(p602LastStatus == 1) {
  2426. extremeValueInformation.put(fit601Name, 2);
  2427. }
  2428. if(fit601LastValue <= 1.675) {
  2429. fit601New = fit601LastValue + 0.0867203;
  2430. }
  2431. }
  2432. else if(fit601ExtremeValueInformation == 2) {
  2433. if(p602LastStatus == 2) {
  2434. extremeValueInformation.put(fit601Name, 3);
  2435. fit601New = fit601LastValue - 0.086726684825;
  2436. }
  2437. else if(fit601LastValue <= 1.675) {
  2438. fit601New = fit601LastValue + 0.0867203;
  2439. }
  2440. }
  2441. else if(fit601ExtremeValueInformation == 3) {
  2442. if(p602LastStatus == 1) {
  2443. extremeValueInformation.put(fit601Name, -1);
  2444. fit601New = fit601LastValue - 0.086726684825;
  2445. }
  2446. else if(fit601LastValue <= 1.675) {
  2447. fit601New = fit601LastValue + 0.0867203;
  2448. }
  2449. }
  2450. fit601New = fit601New + ThreadLocalRandom.current().nextDouble(-0.01, 0.011);
  2451. if(fit601New < 0.0002563035)
  2452. fit601New = 0.0002563035;
  2453. listFIT601.add(fit601New);
  2454. }
  2455. /**
  2456. * Simulates a motorized valve.
  2457. * @param mvName The name of the motorized valve.
  2458. * @param mvList The list of the motorized valve
  2459. * @param relatedLITList The list of the LIT related to the of the motorized valve.
  2460. * @param minimumValueRelatedLIT The minimum value for the motorized valve to start its transition to open.
  2461. * @param maximumValueRelatedLIT The maximum value for the motorized valve to start its transition to closed.
  2462. * @param mvOpeningOffset Offset in seconds before transition to open starts after conditions are met.
  2463. * @param mvClosingOffset Offset in seconds before transition to closed starts after conditions are met.
  2464. * @param additionalStartOpeningConditionMet Additional conditions that have to be met before the transition to open can start. True if none.
  2465. * @param additionalStartClosingConditionMet Additional conditions that have to be met before the transition to closed can start. True if none.
  2466. */
  2467. private void simulateMV(String mvName, LinkedList<Integer> mvList, LinkedList<Double> relatedLITList, int minimumValueRelatedLIT, int maximumValueRelatedLIT, int mvOpeningOffset, int mvClosingOffset, boolean additionalStartOpeningConditionMet, boolean additionalStartClosingConditionMet) {
  2468. int mvLastStatus = mvList.getLast();
  2469. int[] mvTransitionInformation = transitionInformation.get(mvName);
  2470. double litLastStatus = relatedLITList.getLast();
  2471. if(mvTransitionInformation[0] == 1 && mvTransitionInformation[4] > 1) { // Wait for offset to end
  2472. mvTransitionInformation[4]--;
  2473. mvList.add(mvList.getLast());
  2474. }
  2475. else if(mvTransitionInformation[0] == 1 && mvLastStatus != 0 && mvTransitionInformation[4] == 1) {
  2476. mvTransitionInformation[4]--;
  2477. mvList.add(0); // Start transition in next second
  2478. }
  2479. else if(mvLastStatus == 1) { // Closed
  2480. if(litLastStatus >= minimumValueRelatedLIT) // Do nothing
  2481. mvList.add(1);
  2482. else { // Start transition
  2483. if(additionalStartOpeningConditionMet) {
  2484. int transitionTime = (int) distributionHandlers.get(mvName+" Transition Distribution 1 to 2").sampleNextValueExactly();
  2485. mvTransitionInformation[0] = 1;
  2486. mvTransitionInformation[1] = transitionTime;
  2487. mvTransitionInformation[2] = transitionTime-1;
  2488. mvTransitionInformation[3] = 2;
  2489. mvTransitionInformation[4] = mvOpeningOffset-1;
  2490. if(mvTransitionInformation[4] <= 0)
  2491. mvList.add(0);
  2492. else
  2493. mvList.add(1);
  2494. }
  2495. else
  2496. mvList.add(1);
  2497. }
  2498. }
  2499. else if(mvLastStatus == 2) { // Open
  2500. if(litLastStatus <= maximumValueRelatedLIT) // Do nothing
  2501. mvList.add(2);
  2502. else { // Start transition
  2503. if(additionalStartClosingConditionMet) {
  2504. int transitionTime = (int) distributionHandlers.get(mvName+" Transition Distribution 2 to 1").sampleNextValueExactly();
  2505. mvTransitionInformation[0] = 1;
  2506. mvTransitionInformation[1] = transitionTime;
  2507. mvTransitionInformation[2] = transitionTime-1;
  2508. mvTransitionInformation[3] = 1;
  2509. mvTransitionInformation[4] = mvClosingOffset-1;
  2510. if(mvTransitionInformation[4] <= 0)
  2511. mvList.add(0);
  2512. else
  2513. mvList.add(2);
  2514. }
  2515. else
  2516. mvList.add(2);
  2517. }
  2518. }
  2519. else if(mvLastStatus == 0) {
  2520. int remainingTransistionTime = mvTransitionInformation[2];
  2521. if(remainingTransistionTime == 0) { // Stop
  2522. mvTransitionInformation[0] = 0;
  2523. mvList.add(mvTransitionInformation[3]);
  2524. }
  2525. else { // Continue
  2526. mvTransitionInformation[2] = remainingTransistionTime-1;
  2527. mvList.add(0);
  2528. }
  2529. }
  2530. }
  2531. /**
  2532. * Sets the status.
  2533. * @param startStatus The line of physical data to set the status from or "" for the standard status.
  2534. */
  2535. private void setUpStatus(String startStatus) {
  2536. if(startStatus.equals("")) setUpStandardStatus();
  2537. else setUpCustomStatus(startStatus);
  2538. }
  2539. /**
  2540. * Sets up the variables for the standard statuses.
  2541. */
  2542. private void setUpStandardStatus() {
  2543. listTimestamp.add(getCurrentTimeString());
  2544. listFIT101.add(0.0);
  2545. listLIT101.add(0.0);
  2546. listLIT101WithoutJittering.add(0.0);
  2547. listMV101.add(1);
  2548. listP101.add(1);
  2549. listP102.add(1);
  2550. listAIT201.add(244.3284);
  2551. listAIT202.add(8.19008);
  2552. listAIT203.add(300.8459);
  2553. listFIT201.add(0.0);
  2554. listMV201.add(1);
  2555. listP201.add(1);
  2556. listP202.add(1);
  2557. listP203.add(1);
  2558. listP204.add(1);
  2559. listP205.add(1);
  2560. listP206.add(1);
  2561. listLIT301.add(0.0);
  2562. listLIT301WithoutJittering.add(0.0);
  2563. listDPIT301.add(2.560983);
  2564. listFIT301.add(0.0);
  2565. listMV301.add(1);
  2566. listMV302.add(1);
  2567. listMV303.add(1);
  2568. listMV304.add(1);
  2569. listP301.add(1);
  2570. listP302.add(1);
  2571. listAIT401.add(0.0);
  2572. listAIT402.add(171.3407);
  2573. listFIT401.add(0.0);
  2574. listLIT401.add(0.0);
  2575. listP401.add(1);
  2576. listP402.add(1);
  2577. listP403.add(1);
  2578. listP404.add(1);
  2579. listUV401.add(1);
  2580. listAIT501.add(7.430659);
  2581. listAIT502.add(177.1597);
  2582. listAIT503.add(260.7665);
  2583. listAIT504.add(123.3914);
  2584. listFIT501.add(0.001538067);
  2585. listFIT502.add(0.001408992);
  2586. listFIT503.add(0.001664373);
  2587. listFIT504.add(0.0);
  2588. listP501.add(1);
  2589. listP502.add(1);
  2590. listPIT501.add(10.2698);
  2591. listPIT502.add(0.0);
  2592. listPIT503.add(4.6183);
  2593. listFIT601.add(0.0002563035);
  2594. listP601.add(1);
  2595. listP602.add(1);
  2596. listP603.add(1);
  2597. }
  2598. /**
  2599. * Sets up the variables for the custom statuses.
  2600. * @param startStatus The line of physical data to set the status from.
  2601. */
  2602. private void setUpCustomStatus(String startStatus) {
  2603. startStatus = startStatus.trim();
  2604. startStatus = startStatus.replace(",", ".");
  2605. String[] values = startStatus.split("\t");
  2606. String timestamp = values[0];
  2607. listTimestamp.add(timestamp);
  2608. setCurrentTimeString(timestamp);
  2609. listFIT101.add(Double.parseDouble(values[1]));
  2610. listLIT101.add(Double.parseDouble(values[2]));
  2611. listLIT101WithoutJittering.add(listLIT101.getFirst());
  2612. listMV101.add(Integer.parseInt(values[3]));
  2613. listP101.add(Integer.parseInt(values[4]));
  2614. listP102.add(Integer.parseInt(values[5]));
  2615. listAIT201.add(Double.parseDouble(values[6]));
  2616. listAIT202.add(Double.parseDouble(values[7]));
  2617. listAIT203.add(Double.parseDouble(values[8]));
  2618. listFIT201.add(Double.parseDouble(values[9]));
  2619. listMV201.add(Integer.parseInt(values[10]));
  2620. listP201.add(Integer.parseInt(values[11]));
  2621. listP202.add(Integer.parseInt(values[12]));
  2622. listP203.add(Integer.parseInt(values[13]));
  2623. listP204.add(Integer.parseInt(values[14]));
  2624. listP205.add(Integer.parseInt(values[15]));
  2625. listP206.add(Integer.parseInt(values[16]));
  2626. listDPIT301.add(Double.parseDouble(values[17]));
  2627. listFIT301.add(Double.parseDouble(values[18]));
  2628. listLIT301.add(Double.parseDouble(values[19]));
  2629. listLIT301WithoutJittering.add(listLIT301.getFirst());
  2630. listMV301.add(Integer.parseInt(values[20]));
  2631. listMV302.add(Integer.parseInt(values[21]));
  2632. listMV303.add(Integer.parseInt(values[22]));
  2633. listMV304.add(Integer.parseInt(values[23]));
  2634. listP301.add(Integer.parseInt(values[24]));
  2635. listP302.add(Integer.parseInt(values[25]));
  2636. listAIT401.add(Double.parseDouble(values[26]));
  2637. listAIT402.add(Double.parseDouble(values[27]));
  2638. listFIT401.add(Double.parseDouble(values[28]));
  2639. listLIT401.add(Double.parseDouble(values[29]));
  2640. listP401.add(Integer.parseInt(values[30]));
  2641. listP402.add(Integer.parseInt(values[31]));
  2642. listP403.add(Integer.parseInt(values[32]));
  2643. listP404.add(Integer.parseInt(values[33]));
  2644. listUV401.add(Integer.parseInt(values[34]));
  2645. listAIT501.add(Double.parseDouble(values[35]));
  2646. listAIT502.add(Double.parseDouble(values[36]));
  2647. listAIT503.add(Double.parseDouble(values[37]));
  2648. listAIT504.add(Double.parseDouble(values[38]));
  2649. listFIT501.add(Double.parseDouble(values[39]));
  2650. listFIT502.add(Double.parseDouble(values[40]));
  2651. listFIT503.add(Double.parseDouble(values[41]));
  2652. listFIT504.add(Double.parseDouble(values[42]));
  2653. listP501.add(Integer.parseInt(values[43]));
  2654. listP502.add(Integer.parseInt(values[44]));
  2655. listPIT501.add(Double.parseDouble(values[45]));
  2656. listPIT502.add(Double.parseDouble(values[46]));
  2657. listPIT503.add(Double.parseDouble(values[47]));
  2658. listFIT601.add(Double.parseDouble(values[48]));
  2659. listP601.add(Integer.parseInt(values[49]));
  2660. listP602.add(Integer.parseInt(values[50]));
  2661. listP603.add(Integer.parseInt(values[51]));
  2662. }
  2663. /**
  2664. * The current time as a string in the format of the physical data.
  2665. * @return The time string.
  2666. */
  2667. private String getCurrentTimeString() {
  2668. return new SimpleDateFormat("dd/MM/yyyy h:mm:ss a").format(currentTime.getTime());
  2669. }
  2670. /**
  2671. * Sets the current time from a string in the format of the physical data.
  2672. * @param timeString The time string.
  2673. */
  2674. private void setCurrentTimeString(String timeString) {
  2675. try {
  2676. Date date = new SimpleDateFormat("dd/MM/yyyy h:mm:ss a").parse(timeString);
  2677. currentTime.setTime(date);
  2678. } catch (ParseException e) {
  2679. System.out.println("Could not set current time.");
  2680. }
  2681. }
  2682. /**
  2683. * Increases the run time by one second.
  2684. */
  2685. private void increaseTimeByOneSecond() {
  2686. currentTime.set(Calendar.SECOND, currentTime.get(Calendar.SECOND)+1);
  2687. }
  2688. /**
  2689. * Sets the distribution handlers.
  2690. */
  2691. private void setDatasetDistributionHandlers() {
  2692. distributionHandlers.put("FIT-101 Flank Distribution Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Flank Distribution Decreasing.txt"));
  2693. distributionHandlers.put("FIT-101 Flank Distribution Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Flank Distribution Increasing.txt"));
  2694. distributionHandlers.put("FIT-101 Flank Distribution Sharply Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Flank Distribution Sharply Decreasing.txt"));
  2695. distributionHandlers.put("FIT-101 Flank Distribution Sharply Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Flank Distribution Sharply Increasing.txt"));
  2696. distributionHandlers.put("FIT-101 Maxima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Maxima Distribution.txt"));
  2697. distributionHandlers.put("FIT-101 Minima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-101 Minima Distribution.txt"));
  2698. distributionHandlers.put("MV-101 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-101 Transition Distribution 1 to 2.txt"));
  2699. distributionHandlers.put("MV-101 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-101 Transition Distribution 2 to 1.txt"));
  2700. distributionHandlers.put("LIT-101 Ventil Closed Pumps Off Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Ventil Closed Pumps Off Distribution.txt"));
  2701. // distributionHandlers.put("LIT-101 Ventil Closed Pumps On Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Ventil Closed Pumps On Distribution.txt"));
  2702. // distributionHandlers.put("LIT-101 Ventil Open Pumps Off Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Ventil Open Pumps Off Distribution.txt"));
  2703. // distributionHandlers.put("LIT-101 Ventil Open Pumps On Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Ventil Open Pumps On Distribution.txt"));
  2704. // distributionHandlers.put("LIT-101 Random Jitter", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Random Jitter.txt"));
  2705. distributionHandlers.put("LIT-101 Flank Distribution Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Flank Distribution Increasing.txt"));
  2706. distributionHandlers.put("LIT-101 Flank Distribution Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Flank Distribution Decreasing.txt"));
  2707. distributionHandlers.put("LIT-101 Maxima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Maxima Distribution.txt"));
  2708. distributionHandlers.put("LIT-101 Minima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Minima Distribution.txt"));
  2709. distributionHandlers.put("LIT-101 Jitter", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Jitter.txt"));
  2710. distributionHandlers.put("LIT-101 Seconds Between Zeros Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Seconds Between Zeros Distribution.txt"));
  2711. distributionHandlers.put("LIT-101 Jitter Negative", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Jitter Negative.txt"));
  2712. distributionHandlers.put("LIT-101 Jitter Positive", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_LIT-101 Jitter Positive.txt"));
  2713. distributionHandlers.put("MV-201 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-201 Transition Distribution 1 to 2.txt"));
  2714. distributionHandlers.put("MV-201 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-201 Transition Distribution 2 to 1.txt"));
  2715. distributionHandlers.put("AIT-201 Distribution of Durations of Unchanged Values", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-201 Distribution of Durations of Unchanged Values.txt"));
  2716. distributionHandlers.put("AIT-201 Value Change Slopes Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-201 Value Change Slopes Distribution.txt"));
  2717. distributionHandlers.put("AIT-202 Distribution of Durations of Unchanged Values", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-202 Distribution of Durations of Unchanged Values.txt"));
  2718. distributionHandlers.put("AIT-202 Value Change Slopes Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-202 Value Change Slopes Distribution.txt"));
  2719. distributionHandlers.put("AIT-203 Distribution of Durations of Unchanged Values", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-203 Distribution of Durations of Unchanged Values.txt"));
  2720. distributionHandlers.put("AIT-203 Value Change Slopes Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_AIT-203 Value Change Slopes Distribution.txt"));
  2721. distributionHandlers.put("FIT-201 Flank Distribution Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Flank Distribution Decreasing.txt"));
  2722. distributionHandlers.put("FIT-201 Flank Distribution Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Flank Distribution Increasing.txt"));
  2723. distributionHandlers.put("FIT-201 Flank Distribution Sharply Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Flank Distribution Sharply Decreasing.txt"));
  2724. distributionHandlers.put("FIT-201 Flank Distribution Sharply Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Flank Distribution Sharply Increasing.txt"));
  2725. distributionHandlers.put("FIT-201 Maxima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Maxima Distribution.txt"));
  2726. distributionHandlers.put("FIT-201 Minima Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Minima Distribution.txt"));
  2727. distributionHandlers.put("FIT-201 Flank Plateaus Distribution", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-201 Flank Plateaus Distribution.txt"));
  2728. distributionHandlers.put("MV-301 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-301 Transition Distribution 1 to 2.txt"));
  2729. distributionHandlers.put("MV-301 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-301 Transition Distribution 2 to 1.txt"));
  2730. distributionHandlers.put("MV-302 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-302 Transition Distribution 1 to 2.txt"));
  2731. distributionHandlers.put("MV-302 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-302 Transition Distribution 2 to 1.txt"));
  2732. distributionHandlers.put("MV-303 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-303 Transition Distribution 1 to 2.txt"));
  2733. distributionHandlers.put("MV-303 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-303 Transition Distribution 2 to 1.txt"));
  2734. distributionHandlers.put("MV-304 Transition Distribution 1 to 2", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-304 Transition Distribution 1 to 2.txt"));
  2735. distributionHandlers.put("MV-304 Transition Distribution 2 to 1", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_MV-304 Transition Distribution 2 to 1.txt"));
  2736. distributionHandlers.put("FIT-301 Flank Distribution Sharply Increasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-301 Flank Distribution Sharply Increasing.txt"));
  2737. distributionHandlers.put("FIT-301 Flank Distribution Sharply Decreasing", SWaTUtilities.readDatasetDistributionData("PhysicalDataA1_FIT-301 Flank Distribution Sharply Decreasing.txt"));
  2738. // distributionHandlers.put("", SWaTUtilities.readDatasetDistributionData(""));
  2739. }
  2740. /**
  2741. * Creates the output as list of lines from the variables.
  2742. */
  2743. private void createOutput() {
  2744. List<String> deviceNames = SWaTUtilities.getSortedDeviceNames(networkController);
  2745. outputList = new LinkedList<String>();
  2746. outputColumnDescription = "";
  2747. outputColumnDescription += " Timestamp";
  2748. if(deviceNames.contains("PLC 1"))
  2749. outputColumnDescription += ",FIT101,LIT101,MV101,P101,P102";
  2750. if(deviceNames.contains("PLC 2"))
  2751. outputColumnDescription += ",AIT201,AIT202,AIT203,FIT201,MV201,P201,P202,P203,P204,P205,P206";
  2752. if(deviceNames.contains("PLC 3"))
  2753. outputColumnDescription += ",DPIT301,FIT301,LIT301,MV301,MV302,MV303,MV304,P301,P302";
  2754. if(deviceNames.contains("PLC 4"))
  2755. outputColumnDescription += ",AIT401,AIT402,FIT401,LIT401,P401,P402,P403,P404,UV401";
  2756. if(deviceNames.contains("PLC 5"))
  2757. outputColumnDescription += ",AIT501,AIT502,AIT503,AIT504,FIT501,FIT502,FIT503,FIT504,P501,P502,PIT501,PIT502,PIT503";
  2758. if(deviceNames.contains("PLC 6"))
  2759. outputColumnDescription += ",FIT601,P601,P602,P603";
  2760. outputColumnDescription += ",Normal/Attack";
  2761. StringBuilder outputStringBuilder = new StringBuilder(300); // 388+290*durationInSeconds
  2762. for(int i = 0; i < durationInSeconds; i++) {
  2763. outputStringBuilder = new StringBuilder(300);
  2764. outputStringBuilder.append(" "+listTimestamp.pop());
  2765. if(deviceNames.contains("PLC 1")) {
  2766. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT101.pop(), 10));
  2767. outputStringBuilder.append(","+formatDoubleRoundMathematically(listLIT101.pop(), 4));
  2768. outputStringBuilder.append(","+listMV101.pop());
  2769. outputStringBuilder.append(","+listP101.pop());
  2770. outputStringBuilder.append(","+listP102.pop());
  2771. }
  2772. if(deviceNames.contains("PLC 2")) {
  2773. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT201.pop(), 4));
  2774. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT202.pop(), 6));
  2775. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT203.pop(), 4));
  2776. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT201.pop(), 6));
  2777. outputStringBuilder.append(","+listMV201.pop());
  2778. outputStringBuilder.append(","+listP201.pop());
  2779. outputStringBuilder.append(","+listP202.pop());
  2780. outputStringBuilder.append(","+listP203.pop());
  2781. outputStringBuilder.append(","+listP204.pop());
  2782. outputStringBuilder.append(","+listP205.pop());
  2783. outputStringBuilder.append(","+listP206.pop());
  2784. }
  2785. if(deviceNames.contains("PLC 3")) {
  2786. outputStringBuilder.append(","+formatDoubleRoundMathematically(listDPIT301.pop(), 6));
  2787. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT301.pop(), 10));
  2788. outputStringBuilder.append(","+formatDoubleRoundMathematically(listLIT301.pop(), 4));
  2789. outputStringBuilder.append(","+listMV301.pop());
  2790. outputStringBuilder.append(","+listMV302.pop());
  2791. outputStringBuilder.append(","+listMV303.pop());
  2792. outputStringBuilder.append(","+listMV304.pop());
  2793. outputStringBuilder.append(","+listP301.pop());
  2794. outputStringBuilder.append(","+listP302.pop());
  2795. }
  2796. if(deviceNames.contains("PLC 4")) {
  2797. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT401.pop(), 6));
  2798. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT402.pop(), 6));
  2799. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT401.pop(), 10));
  2800. outputStringBuilder.append(","+formatDoubleRoundMathematically(listLIT401.pop(), 4));
  2801. outputStringBuilder.append(","+listP401.pop());
  2802. outputStringBuilder.append(","+listP402.pop());
  2803. outputStringBuilder.append(","+listP403.pop());
  2804. outputStringBuilder.append(","+listP404.pop());
  2805. outputStringBuilder.append(","+listUV401.pop());
  2806. }
  2807. if(deviceNames.contains("PLC 5")) {
  2808. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT501.pop(), 6));
  2809. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT502.pop(), 6));
  2810. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT503.pop(), 6));
  2811. outputStringBuilder.append(","+formatDoubleRoundMathematically(listAIT504.pop(), 6));
  2812. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT501.pop(), 10));
  2813. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT502.pop(), 10));
  2814. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT503.pop(), 10));
  2815. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT504.pop(), 10));
  2816. outputStringBuilder.append(","+listP501.pop());
  2817. outputStringBuilder.append(","+listP502.pop());
  2818. outputStringBuilder.append(","+formatDoubleRoundMathematically(listPIT501.pop(), 4));
  2819. outputStringBuilder.append(","+formatDoubleRoundMathematically(listPIT502.pop(), 4));
  2820. outputStringBuilder.append(","+formatDoubleRoundMathematically(listPIT503.pop(), 4));
  2821. }
  2822. if(deviceNames.contains("PLC 6")) {
  2823. outputStringBuilder.append(","+formatDoubleRoundMathematically(listFIT601.pop(), 10));
  2824. outputStringBuilder.append(","+formatDoubleRoundMathematically(listP601.pop(), 4));
  2825. outputStringBuilder.append(","+formatDoubleRoundMathematically(listP602.pop(), 4));
  2826. outputStringBuilder.append(","+formatDoubleRoundMathematically(listP603.pop(), 4));
  2827. }
  2828. outputStringBuilder.append(","+listNormalAttack.pop());
  2829. outputList.add(outputStringBuilder.toString());
  2830. }
  2831. }
  2832. /**
  2833. * Saves the CSV output.
  2834. */
  2835. private void saveCSVOutput() {
  2836. String filePathName = outputDirectoryPath+"/IoTDGF_SWaT Simulation";
  2837. String fileNameAddition = "_"+new SimpleDateFormat("yyyy-MM-dd HH.mm.ss").format(startTime.getTime())+"_Physical";
  2838. // Write file
  2839. FileWriter outputWriter;
  2840. try {
  2841. double rowsPerFile = 500000;
  2842. double rowsPerFileCurrent = rowsPerFile;
  2843. double numberOfTimes = outputList.size();
  2844. int numberOfFiles = (int) Math.ceil(numberOfTimes/rowsPerFile);
  2845. int rowsInLastFile = (int) (numberOfTimes-rowsPerFile*(numberOfFiles-1));
  2846. int num = 0;
  2847. int numberOfTimesTenth = (int) numberOfTimes/100;
  2848. if(numberOfTimesTenth == 0) numberOfTimesTenth = 1;
  2849. for(int j = 0; j < numberOfFiles; j++) {
  2850. if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
  2851. if(j == numberOfFiles-1) // Last File
  2852. rowsPerFileCurrent = rowsInLastFile;
  2853. StringBuilder outputStringBuilder = new StringBuilder(300*((int) rowsPerFileCurrent));
  2854. outputStringBuilder.append(outputColumnDescription+"\n");
  2855. for(int i = 0; i < rowsPerFileCurrent; i++) {
  2856. if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
  2857. num++;
  2858. outputStringBuilder.append(outputList.pop()); //outputList.get((int)(j*rowsPerFile+i)));
  2859. if(i < rowsPerFileCurrent-1)
  2860. outputStringBuilder.append("\n");
  2861. if(num % numberOfTimesTenth == 0) {
  2862. propertyChangeSupport.firePropertyChange("statusPercentagePhysicalOutput", 0, (int)(num/numberOfTimesTenth));
  2863. }
  2864. }
  2865. if(passByReferenceValue_KeepSimulationRunning[0] == true) {
  2866. String outputFileName = filePathName+fileNameAddition;
  2867. if(numberOfFiles > 1)
  2868. outputFileName += "_"+String.valueOf(j+1)+" of "+numberOfFiles;
  2869. // Try file name combinations until one does not yet exist
  2870. File outputFile;
  2871. int fileNameAdditionExtra = 0;
  2872. while(true) {
  2873. String fileNameCandidate = outputFileName;
  2874. if(fileNameAdditionExtra > 0) fileNameCandidate += "_"+fileNameAdditionExtra;
  2875. outputFile = new File(fileNameCandidate+".csv");
  2876. if(outputFile.exists())
  2877. fileNameAdditionExtra++;
  2878. else
  2879. break;
  2880. }
  2881. if(fileNameAdditionExtra > 0) outputFileName += "_"+fileNameAdditionExtra;
  2882. outputFileName += ".csv";
  2883. lastOutputFilePath = outputFileName;
  2884. outputWriter = new FileWriter(outputFileName);
  2885. outputWriter.write(outputStringBuilder.toString());
  2886. outputWriter.close();
  2887. }
  2888. }
  2889. } catch (IOException e) {
  2890. e.printStackTrace();
  2891. System.out.println("Could not write physical simulation output to file");
  2892. }
  2893. }
  2894. /**
  2895. * Formats a double as a string by cutting off after the number of given floating point numbers.</br>
  2896. * Trailing zeros are removed.
  2897. * </br>
  2898. * Speed comparison:</br>
  2899. * 20-30 times faster than DecimalFormat.</br></br>
  2900. * double dbl = 123.123456789181112131415;
  2901. * long startTime = System.nanoTime();
  2902. * DecimalFormat decimalFormatMax10 = new DecimalFormat("0.##########", new DecimalFormatSymbols(Locale.ROOT));
  2903. * decimalFormatMax10.format(dbl);
  2904. * long durationDF = System.nanoTime()-startTime;
  2905. * System.out.println("DecimalFormat: "+durationDF);
  2906. * startTime = System.nanoTime();
  2907. * formatDoubleCutOff(dbl, 10);
  2908. * long durationFDCO = System.nanoTime()-startTime;
  2909. * System.out.println("formatDoubleCutOff: "+durationFDCO);
  2910. * System.out.println("formatDoubleCutOff is " + durationDF/durationFDCO + " faster than DecimalFormat");
  2911. *
  2912. * @param doubleToFormat The double to format.
  2913. * @param numberOfFloatingPointNumbers The number of positions after the floating point at which to cut off. Must be >= 0;
  2914. * @return The formatted double as a string.
  2915. */
  2916. @SuppressWarnings("unused")
  2917. private String formatDoubleCutOff(double doubleToFormat, int numberOfFloatingPointNumbers) {
  2918. if(numberOfFloatingPointNumbers < 0)
  2919. return "Error";
  2920. String doubleAsString = String.valueOf(doubleToFormat);
  2921. String[] strArray = doubleAsString.split("\\.");
  2922. int floatingPointNumbers = strArray[1].length();
  2923. if(numberOfFloatingPointNumbers > floatingPointNumbers)
  2924. numberOfFloatingPointNumbers = floatingPointNumbers;
  2925. doubleAsString = strArray[0]+"."+strArray[1].substring(0, numberOfFloatingPointNumbers);
  2926. return doubleAsString;
  2927. }
  2928. /**
  2929. * Formats a double as a string by rounding mathematically according to the number of given floating point numbers.</br>
  2930. * Trailing zeros are removed.
  2931. * </br>
  2932. * Speed comparison:</br>
  2933. * 150-400 times faster than DecimalFormat.</br></br>
  2934. * double dbl = 123.123456789181112131415;
  2935. * long startTime = System.nanoTime();
  2936. * DecimalFormat decimalFormatMax10 = new DecimalFormat("0.##########", new DecimalFormatSymbols(Locale.ROOT));
  2937. * decimalFormatMax10.format(dbl);
  2938. * long durationDF = System.nanoTime()-startTime;
  2939. * System.out.println("DecimalFormat: "+durationDF);
  2940. * startTime = System.nanoTime();
  2941. * formatDoubleRoundMathematically(dbl, 10);
  2942. * long durationFDRM = System.nanoTime()-startTime;
  2943. * System.out.println("formatDoubleRoundMathematically: "+durationFDRM);
  2944. * System.out.println("formatDoubleRoundMathematically is " + durationDF/durationFDRM + " faster than DecimalFormat");
  2945. * @param doubleToFormat The double to format.
  2946. * @param numberOfFloatingPointNumbers The number of positions after the floating point at which to cut off. Must be >= 0;
  2947. * @return The formatted double as a string.
  2948. */
  2949. private String formatDoubleRoundMathematically(double doubleToFormat, int numberOfFloatingPointNumbers) {
  2950. if(numberOfFloatingPointNumbers < 0)
  2951. return "Error";
  2952. // Round double mathematically
  2953. double multiplier = 1.0;
  2954. for(int i = 0; i < numberOfFloatingPointNumbers; i++) {
  2955. multiplier *= 10;
  2956. }
  2957. double roundedDouble = Math.round(doubleToFormat*multiplier)/multiplier;
  2958. long doubleRoundedToLong = Math.round(roundedDouble);
  2959. if(doubleRoundedToLong == roundedDouble) // Remove trailing zero after decimal point, e.g., 124.0 becomes 124
  2960. return String.valueOf(doubleRoundedToLong);
  2961. else
  2962. return String.valueOf(roundedDouble);
  2963. }
  2964. /**
  2965. * Sets the interval times for the backwash from the training set.
  2966. */
  2967. private void setUpBackwashIntervalList(){
  2968. int offset = backupIntervalTestOffset;
  2969. backwashIntervalList.add(2980 - offset);
  2970. backwashIntervalList.add(4901 - offset);
  2971. backwashIntervalList.add(6821 - offset);
  2972. backwashIntervalList.add(8742 - offset);
  2973. backwashIntervalList.add(10661 - offset);
  2974. backwashIntervalList.add(12582 - offset);
  2975. backwashIntervalList.add(14501 - offset);
  2976. backwashIntervalList.add(16421 - offset);
  2977. backwashIntervalList.add(19902 - offset);
  2978. backwashIntervalList.add(24103 - offset);
  2979. backwashIntervalList.add(28302 - offset);
  2980. backwashIntervalList.add(32503 - offset);
  2981. backwashIntervalList.add(34423 - offset);
  2982. backwashIntervalList.add(37843 - offset);
  2983. backwashIntervalList.add(42044 - offset);
  2984. backwashIntervalList.add(46244 - offset);
  2985. backwashIntervalList.add(50445 - offset);
  2986. backwashIntervalList.add(54645 - offset);
  2987. backwashIntervalList.add(58726 - offset);
  2988. backwashIntervalList.add(62865 - offset);
  2989. backwashIntervalList.add(67067 - offset);
  2990. backwashIntervalList.add(68986 - offset);
  2991. backwashIntervalList.add(73007 - offset);
  2992. backwashIntervalList.add(77147 - offset);
  2993. backwashIntervalList.add(81408 - offset);
  2994. backwashIntervalList.add(85728 - offset);
  2995. backwashIntervalList.add(89928 - offset);
  2996. backwashIntervalList.add(94129 - offset);
  2997. backwashIntervalList.add(98329 - offset);
  2998. backwashIntervalList.add(102529 - offset);
  2999. backwashIntervalList.add(106730 - offset);
  3000. backwashIntervalList.add(110930 - offset);
  3001. backwashIntervalList.add(115131 - offset);
  3002. backwashIntervalList.add(119271 - offset);
  3003. backwashIntervalList.add(123411 - offset);
  3004. backwashIntervalList.add(127551 - offset);
  3005. backwashIntervalList.add(131692 - offset);
  3006. backwashIntervalList.add(135832 - offset);
  3007. backwashIntervalList.add(139972 - offset);
  3008. backwashIntervalList.add(144112 - offset);
  3009. backwashIntervalList.add(148194 - offset);
  3010. backwashIntervalList.add(152333 - offset);
  3011. backwashIntervalList.add(156475 - offset);
  3012. backwashIntervalList.add(160615 - offset);
  3013. backwashIntervalList.add(164754 - offset);
  3014. backwashIntervalList.add(168835 - offset);
  3015. backwashIntervalList.add(172855 - offset);
  3016. backwashIntervalList.add(176875 - offset);
  3017. backwashIntervalList.add(181016 - offset);
  3018. backwashIntervalList.add(185156 - offset);
  3019. backwashIntervalList.add(189296 - offset);
  3020. backwashIntervalList.add(193437 - offset);
  3021. backwashIntervalList.add(197638 - offset);
  3022. backwashIntervalList.add(201778 - offset);
  3023. backwashIntervalList.add(205918 - offset);
  3024. backwashIntervalList.add(209999 - offset);
  3025. backwashIntervalList.add(214139 - offset);
  3026. backwashIntervalList.add(218339 - offset);
  3027. backwashIntervalList.add(222480 - offset);
  3028. backwashIntervalList.add(226620 - offset);
  3029. backwashIntervalList.add(230760 - offset);
  3030. backwashIntervalList.add(234840 - offset);
  3031. backwashIntervalList.add(238982 - offset);
  3032. backwashIntervalList.add(243121 - offset);
  3033. backwashIntervalList.add(247262 - offset);
  3034. backwashIntervalList.add(251462 - offset);
  3035. backwashIntervalList.add(255723 - offset);
  3036. backwashIntervalList.add(260043 - offset);
  3037. backwashIntervalList.add(264364 - offset);
  3038. backwashIntervalList.add(268684 - offset);
  3039. backwashIntervalList.add(272944 - offset);
  3040. backwashIntervalList.add(277205 - offset);
  3041. backwashIntervalList.add(281524 - offset);
  3042. backwashIntervalList.add(285726 - offset);
  3043. backwashIntervalList.add(289925 - offset);
  3044. backwashIntervalList.add(294125 - offset);
  3045. backwashIntervalList.add(298386 - offset);
  3046. backwashIntervalList.add(302586 - offset);
  3047. backwashIntervalList.add(306788 - offset);
  3048. backwashIntervalList.add(310987 - offset);
  3049. backwashIntervalList.add(315188 - offset);
  3050. backwashIntervalList.add(319388 - offset);
  3051. backwashIntervalList.add(323648 - offset);
  3052. backwashIntervalList.add(327849 - offset);
  3053. backwashIntervalList.add(332109 - offset);
  3054. backwashIntervalList.add(336430 - offset);
  3055. backwashIntervalList.add(338350 - offset);
  3056. backwashIntervalList.add(341650 - offset);
  3057. backwashIntervalList.add(346030 - offset);
  3058. backwashIntervalList.add(347950 - offset);
  3059. backwashIntervalList.add(351310 - offset);
  3060. backwashIntervalList.add(353231 - offset);
  3061. backwashIntervalList.add(356591 - offset);
  3062. backwashIntervalList.add(358512 - offset);
  3063. backwashIntervalList.add(361811 - offset);
  3064. backwashIntervalList.add(363732 - offset);
  3065. backwashIntervalList.add(367033 - offset);
  3066. backwashIntervalList.add(371292 - offset);
  3067. backwashIntervalList.add(375613 - offset);
  3068. backwashIntervalList.add(379933 - offset);
  3069. backwashIntervalList.add(384253 - offset);
  3070. backwashIntervalList.add(388574 - offset);
  3071. backwashIntervalList.add(392834 - offset);
  3072. backwashIntervalList.add(397095 - offset);
  3073. backwashIntervalList.add(401415 - offset);
  3074. backwashIntervalList.add(405675 - offset);
  3075. backwashIntervalList.add(409936 - offset);
  3076. backwashIntervalList.add(414196 - offset);
  3077. backwashIntervalList.add(418456 - offset);
  3078. backwashIntervalList.add(422777 - offset);
  3079. backwashIntervalList.add(427158 - offset);
  3080. backwashIntervalList.add(431538 - offset);
  3081. backwashIntervalList.add(433458 - offset);
  3082. backwashIntervalList.add(436758 - offset);
  3083. backwashIntervalList.add(438678 - offset);
  3084. backwashIntervalList.add(441978 - offset);
  3085. backwashIntervalList.add(446359 - offset);
  3086. backwashIntervalList.add(450680 - offset);
  3087. backwashIntervalList.add(455000 - offset);
  3088. backwashIntervalList.add(459320 - offset);
  3089. backwashIntervalList.add(463641 - offset);
  3090. backwashIntervalList.add(468021 - offset);
  3091. backwashIntervalList.add(472341 - offset);
  3092. backwashIntervalList.add(476722 - offset);
  3093. backwashIntervalList.add(480983 - offset);
  3094. backwashIntervalList.add(485303 - offset);
  3095. backwashIntervalList.add(489564 - offset);
  3096. backwashIntervalList.add(493824 - offset);
  3097. }
  3098. /**
  3099. * Returns the results of the simulation as a HashMap with the time in seconds as key and a String array of double representations as value.</br>
  3100. * Empty, if simulation has not been started before.</br>
  3101. * Does only return the elements necessary for the physical simulation.</br>
  3102. * String[]: [0] = LIT-101, [1] = AIT-201, [2] = FIT-201, [3] = LIT-301, [4] = LIT-401, [5] = 0 for normal, 1 for attack
  3103. * @return The results of the simulation as a HashMap with the time in seconds as key and a double array as value
  3104. */
  3105. public LinkedHashMap<Integer, String[]> getSimulationResults(){
  3106. return resultsMap;
  3107. }
  3108. /**
  3109. * The main methods creates plots to compare the generated data with the original data from the training set.</br>
  3110. * The path to the needed files has to be set correctly.
  3111. * @see #generatePythonPlotScript(int, String)
  3112. * @param args Not used.
  3113. */
  3114. public static void main(String[] args){
  3115. String pathToCSVDirectory = "C:/Users/user/master"; // Set the path correctly.
  3116. Model testmodel = new Model();
  3117. Controller testController = new Controller(testmodel);
  3118. NetworkController testNetworkController = testController.getNetworkController();
  3119. Link ethernetLink = new PrecisionLink("Ethernet");
  3120. Connection SWaTConnection = new ConnectionPrecision();
  3121. testNetworkController.addLink(ethernetLink);
  3122. SWaTConnection.setName("SWaT");
  3123. testNetworkController.addConnectionToLink(SWaTConnection, ethernetLink);
  3124. SWaTSimplifiedModbusProtocol SWaTProtocol = new SWaTSimplifiedModbusProtocol();
  3125. SWaTConnection.setProtocol(SWaTProtocol);
  3126. testNetworkController.addConnection(SWaTConnection);
  3127. SmartDevice PLC1 = new SWaTDevice("PLC 1", SWaTDeviceTypes.PLC, 0.6);
  3128. testNetworkController.addSmartDevice(PLC1);
  3129. testNetworkController.addLinkToDevice(ethernetLink, PLC1);
  3130. Port portPLC1 = new Port(PLC1, (short)1);
  3131. portPLC1.setStatus(Port.SENDING);
  3132. testNetworkController.addDeviceToConnectionAndProtocol(portPLC1, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3133. SmartDevice PLC2 = new SWaTDevice("PLC 2", SWaTDeviceTypes.PLC, 0.6);
  3134. testNetworkController.addSmartDevice(PLC2);
  3135. testNetworkController.addLinkToDevice(ethernetLink, PLC2);
  3136. Port portPLC2 = new Port(PLC2, (short)1);
  3137. portPLC2.setStatus(Port.SENDING);
  3138. testNetworkController.addDeviceToConnectionAndProtocol(portPLC2, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3139. SmartDevice PLC3 = new SWaTDevice("PLC 3", SWaTDeviceTypes.PLC, 0.6);
  3140. testNetworkController.addSmartDevice(PLC3);
  3141. testNetworkController.addLinkToDevice(ethernetLink, PLC3);
  3142. Port portPLC3 = new Port(PLC3, (short)1);
  3143. portPLC3.setStatus(Port.SENDING);
  3144. testNetworkController.addDeviceToConnectionAndProtocol(portPLC3, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3145. SmartDevice PLC4 = new SWaTDevice("PLC 4", SWaTDeviceTypes.PLC, 0.6);
  3146. testNetworkController.addSmartDevice(PLC4);
  3147. testNetworkController.addLinkToDevice(ethernetLink, PLC4);
  3148. Port portPLC4 = new Port(PLC4, (short)1);
  3149. portPLC3.setStatus(Port.SENDING);
  3150. testNetworkController.addDeviceToConnectionAndProtocol(portPLC4, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3151. SmartDevice PLC5 = new SWaTDevice("PLC 5", SWaTDeviceTypes.PLC, 0.6);
  3152. testNetworkController.addSmartDevice(PLC5);
  3153. testNetworkController.addLinkToDevice(ethernetLink, PLC5);
  3154. Port portPLC5 = new Port(PLC5, (short)1);
  3155. portPLC3.setStatus(Port.SENDING);
  3156. testNetworkController.addDeviceToConnectionAndProtocol(portPLC5, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3157. SmartDevice PLC6 = new SWaTDevice("PLC 6", SWaTDeviceTypes.PLC, 0.6);
  3158. testNetworkController.addSmartDevice(PLC6);
  3159. testNetworkController.addLinkToDevice(ethernetLink, PLC6);
  3160. Port portPLC6 = new Port(PLC6, (short)1);
  3161. portPLC3.setStatus(Port.SENDING);
  3162. testNetworkController.addDeviceToConnectionAndProtocol(portPLC6, SWaTConnection, SWaTProtocol.roleSenderAndReceiver);
  3163. backupIntervalTestOffset = 600;
  3164. boolean[] passByReferenceValue_KeepSimulationRunning = {true};
  3165. SWaTSimulationManagerPhysical testObject = new SWaTSimulationManagerPhysical(testController);
  3166. String startStatus = " 22/12/2015 4:40:00 PM 0 121,4088 1 1 1 251,7944 8,307358 315,7652 0 1 1 1 1 1 1 1 2,560983 0,0002562214 136,1029 1 1 1 1 1 1 0 171,0843 0 132,8121 1 1 1 1 1 7,430659 177,1597 260,7665 123,3914 0,001538067 0,001408992 0,001664373 0 1 1 8,891951 0 3,108177 0,0002563035 1 1 1 Normal";
  3167. startStatus = "25/12/2015 12:00:00 AM 2.649649 742.5052 2 1 1 267.0469 8.416304 324.2758 0 1 1 1 1 1 1 1 2.29208 0 1012.12 1 1 1 1 1 1 148.8032 171.0587 1.701855 841.3997 1 2 1 1 2 7.877019 162.3686 268.617 11.11254 1.710972 1.272064 0.7435906 0.3104122 2 1 255.6716 1.121328 194.3092 6.41E-05 1 1 1 Normal";
  3168. long startTimeInNanoSeconds = System.nanoTime();
  3169. testObject.startSimulation("30000", Calendar.getInstance(), pathToCSVDirectory, startStatus, passByReferenceValue_KeepSimulationRunning, null, new Object[0][0]);
  3170. System.out.println("Physical simulation run time in nano seconds: "+ (System.nanoTime()-startTimeInNanoSeconds));
  3171. System.out.print("Creating plots");
  3172. for(int i = 1; i <= 51; i++) {
  3173. System.out.print(".");
  3174. generatePythonPlotScript(i, pathToCSVDirectory);
  3175. }
  3176. System.out.println("\nFinished");
  3177. }
  3178. /**
  3179. * Creates Python plot scripts for one IoT device. </br>
  3180. * Make sure the needed files exist. </br> </br>
  3181. * SWaT_Dataset_Normal_v1_stripped 10 Min_30k.csv </br>
  3182. * The file consists of data from SWaT_Dataset_Normal_v1.xlsx for 22/12/2015 4:40:00 PM to 23/12/2015 12:59:59 AM </br>
  3183. * The file's first line are the column description. It has 30001 lines in total. </br>
  3184. * Creation of the file: </br>
  3185. * 1) Convert SWaT_Dataset_Normal_v1.xlsx to a CSV file </br>
  3186. * 2) Remove the first row with the stage descriptions </br>
  3187. * 3) Remove all rows after the row with the timestamp 23/12/2015 12:59:59 AM </br>
  3188. * @param column The column of the device data in the CSV files.
  3189. * @param pathToCSVDirectory The path to the directory of the CSV files (without trailing "/").
  3190. */
  3191. private static void generatePythonPlotScript(int column, String pathToCSVDirectory){
  3192. // Hashmap for the column names
  3193. LinkedHashMap<Integer, String> columnNames = new LinkedHashMap<Integer, String>();
  3194. columnNames.put(0,"Timestamp");
  3195. columnNames.put(1,"FIT-101");
  3196. columnNames.put(2,"LIT-101");
  3197. columnNames.put(3,"MV-101");
  3198. columnNames.put(4,"P-101");
  3199. columnNames.put(5,"P-102");
  3200. columnNames.put(6,"AIT-201");
  3201. columnNames.put(7,"AIT-202");
  3202. columnNames.put(8,"AIT-203");
  3203. columnNames.put(9,"FIT-201");
  3204. columnNames.put(10,"MV-201");
  3205. columnNames.put(11,"P-201");
  3206. columnNames.put(12,"P-202");
  3207. columnNames.put(13,"P-203");
  3208. columnNames.put(14,"P-204");
  3209. columnNames.put(15,"P-205");
  3210. columnNames.put(16,"P-206");
  3211. columnNames.put(17,"DPIT-301");
  3212. columnNames.put(18,"FIT-301");
  3213. columnNames.put(19,"LIT-301");
  3214. columnNames.put(20,"MV-301");
  3215. columnNames.put(21,"MV-302");
  3216. columnNames.put(22,"MV-303");
  3217. columnNames.put(23,"MV-304");
  3218. columnNames.put(24,"P-301");
  3219. columnNames.put(25,"P-302");
  3220. columnNames.put(26,"AIT-401");
  3221. columnNames.put(27,"AIT-402");
  3222. columnNames.put(28,"FIT-401");
  3223. columnNames.put(29,"LIT-401");
  3224. columnNames.put(30,"P-401");
  3225. columnNames.put(31,"P-402");
  3226. columnNames.put(32,"P-403");
  3227. columnNames.put(33,"P-404");
  3228. columnNames.put(34,"UV-401");
  3229. columnNames.put(35,"AIT-501");
  3230. columnNames.put(36,"AIT-502");
  3231. columnNames.put(37,"AIT-503");
  3232. columnNames.put(38,"AIT-504");
  3233. columnNames.put(39,"FIT-501");
  3234. columnNames.put(40,"FIT-502");
  3235. columnNames.put(41,"FIT-503");
  3236. columnNames.put(42,"FIT-504");
  3237. columnNames.put(43,"P-501");
  3238. columnNames.put(44,"P-502");
  3239. columnNames.put(45,"PIT-501");
  3240. columnNames.put(46,"PIT-502");
  3241. columnNames.put(47,"PIT-503");
  3242. columnNames.put(48,"FIT-601");
  3243. columnNames.put(49,"P-601");
  3244. columnNames.put(50,"P-602");
  3245. columnNames.put(51,"P-603");
  3246. List<String> generatedDataList = new ArrayList<String>();
  3247. List<String> trainingSetDataList = new ArrayList<String>();
  3248. // Process files
  3249. try {
  3250. File csvFile = new File(lastOutputFilePath);
  3251. Scanner csvFileReader = new Scanner(csvFile);
  3252. while (csvFileReader.hasNextLine() == true) {
  3253. String csvLine = csvFileReader.nextLine();
  3254. String[] entries = csvLine.split(",");
  3255. generatedDataList.add(entries[column]);
  3256. }
  3257. csvFileReader.close();
  3258. File csvFile2 = new File(pathToCSVDirectory+"/"+"SWaT_Dataset_Normal_v1_stripped 10 Min_30k.csv");
  3259. Scanner csvFileReader2 = new Scanner(csvFile2);
  3260. boolean firstLine = true;
  3261. while (csvFileReader2.hasNextLine() == true) {
  3262. String csvLine = csvFileReader2.nextLine();
  3263. String[] entries = csvLine.split(",");
  3264. if(firstLine == false)
  3265. trainingSetDataList.add(entries[column]);
  3266. else
  3267. firstLine = false;
  3268. }
  3269. csvFileReader2.close();
  3270. FileWriter rFWriter = new FileWriter(pathToCSVDirectory+"/"+"Combo plot_"+column+"_"+columnNames.get(column)+".py");
  3271. generatedDataList.remove(0);
  3272. rFWriter.write("import matplotlib.pyplot as plt\n");
  3273. rFWriter.write("plt.plot("+trainingSetDataList.toString()+", label='original')");
  3274. rFWriter.write("\nplt.plot("+generatedDataList.toString()+", label='generated')");
  3275. rFWriter.write("\nplt.grid()");
  3276. rFWriter.write("\nplt.legend()");
  3277. rFWriter.write("\nplt.title(label=\""+columnNames.get(column)+"\")");
  3278. rFWriter.write("\nplt.show()");
  3279. rFWriter.close();
  3280. } catch (FileNotFoundException e) {
  3281. System.out.println("Input files for the SWaT Physical Simulation test plots not found. Check if the path is set correctly and the files exist.");
  3282. } catch (IOException e) {
  3283. System.out.println("Cannot write SWaT Physical Simulation test plots to files.");
  3284. }
  3285. }
  3286. }