溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

發(fā)布時(shí)間:2020-02-14 11:10:54 來(lái)源:網(wǎng)絡(luò) 閱讀:2662 作者:androidguy 欄目:編程語(yǔ)言

摘要:本文首先會(huì)解釋一下到底什么是"冠狀病毒",以及殺死"冠狀病毒"的方法。然后會(huì)利用Python實(shí)現(xiàn)一個(gè)"冠狀病毒"傳播仿真器,來(lái)演示一下為何“不出門(mén)“ +“瘋狂建醫(yī)院”會(huì)間接殺死病毒(動(dòng)態(tài)模擬了從發(fā)生疫情,到疫情結(jié)束的整個(gè)過(guò)程)。以及如果控制不好,會(huì)有什么后果(一定是很嚴(yán)重的)。


????相信大家現(xiàn)在一定和我一樣,無(wú)比郁悶。好不容易盼到過(guò)年了,買(mǎi)了一大堆好吃的,結(jié)果哪也去不了,只能在家消耗這些美食了。而且很多人宅在家里的每一天都會(huì)做同一個(gè)偉大的計(jì)劃??!

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????那么我們?yōu)槭裁床荒艹鲩T(mén)呢?答案大家都已經(jīng)知道了,這就是一種被稱為“冠狀病毒”的東西在搗亂。據(jù)鐘南山院士和其他一些專家推測(cè),這種“冠狀病毒”的潛伏期是14天左右,所以需要盡可能避免在14天內(nèi)接觸更多的人。而宅在家里是最好的選擇。不過(guò)這是頭一次放這么長(zhǎng)的假,而且還必須呆在家里,也是相當(dāng)郁悶,恍惚間竟想起了猴哥,500年你是怎么熬過(guò)來(lái)的呢!

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

下面就先來(lái)了解下到底什么是冠狀病毒!

1. 什么是冠狀病毒

????如果詳細(xì)解釋什么是冠狀病毒,先要從病毒講起,估計(jì)要寫(xiě)一本書(shū)了,不過(guò)完全沒(méi)有必要。大家只要知道一點(diǎn)就好。病毒不是生物(類生物,有生物的部分特征),不能獨(dú)立生存,需要依賴于宿主,也就是人體的細(xì)胞。換句話說(shuō),病毒需要***人體的細(xì)胞才能生存。病毒可以利用細(xì)胞中的成分復(fù)制自身,從而達(dá)到繁殖的目的。如果受到感染的細(xì)胞過(guò)多,人體就會(huì)生病。

????那么"冠狀病毒"呢?當(dāng)然也屬于病毒的一種,不過(guò)它不是普通的病毒。首先看看"冠狀病毒"的樣子,病毒表面有很多凸起的冠(看起來(lái)還挺漂亮的),所以稱為"冠狀病毒"。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????"冠狀病毒"除了外形上與普通病毒有差異,在本質(zhì)上與普通病毒也是不同的。普通病毒通常都是DNA病毒,也就是雙螺旋結(jié)構(gòu)。而"冠狀病毒"屬于RNA病毒,也就是單螺旋結(jié)構(gòu)。雙螺旋結(jié)構(gòu)的DNA病毒更穩(wěn)定,不容易變異。但RNA病毒只有一個(gè)鏈,非常不穩(wěn)定,容易變異。這才是"冠狀病毒"的殺手锏,通過(guò)變異抵抗人類的反擊。目前"冠狀病毒"是否變異,還很難說(shuō)。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

2. 如何殺死"冠狀病毒"

????現(xiàn)在的問(wèn)題是,如何殺死"冠狀病毒"。當(dāng)然,最直接的方法是將"冠狀病毒"趕出細(xì)胞,或直接從細(xì)胞中清除,不過(guò)目前人類的技術(shù)還做不到這一點(diǎn)。這應(yīng)該屬于比細(xì)胞醫(yī)學(xué)更高端的醫(yī)學(xué):分子醫(yī)學(xué)或原子醫(yī)學(xué)。目前人類的科技水平甚至還沒(méi)完全達(dá)到細(xì)胞醫(yī)學(xué)的高度(最多0.7個(gè)細(xì)胞醫(yī)學(xué)),因?yàn)榘┌Y等細(xì)胞疾病還無(wú)法完全治愈。

????既然病毒目前還無(wú)法直接殺死,那么這么多痊愈的病人是如何做到的呢?其實(shí)可以采用如下兩種方法間接殺死"冠狀病毒",也包括其他大多數(shù)病毒。

1.? 利用人體內(nèi)的抗體細(xì)胞(如T細(xì)胞),將被感染的細(xì)胞連同"冠狀病毒"一起消滅

2. 干擾"冠狀病毒"在細(xì)胞內(nèi)的復(fù)制過(guò)程(例如,RNA干擾),讓"冠狀病毒"無(wú)法正常復(fù)制自身,也就是讓"冠狀病毒"沒(méi)有后代,這樣"冠狀病毒"就會(huì)由于自身的生命終結(jié)而死亡。

????目前絕大多數(shù)痊愈的病人屬于第一種情況,也就是通過(guò)自身的抗體細(xì)胞(如T細(xì)胞)檢測(cè)人體內(nèi)被感染的細(xì)胞,然后通知這些被感染的細(xì)胞啟動(dòng)自毀程序,當(dāng)這些細(xì)胞被銷毀后,那么病毒也就被消滅了。

????不過(guò)可能有的同學(xué)會(huì)問(wèn),既然病毒可以被抗體細(xì)胞消滅,那么這么多醫(yī)護(hù)人員和醫(yī)療設(shè)備豈不是多余了。其實(shí)并不是多于的,而是非常必要。這是因?yàn)椴《驹?**正常細(xì)胞的同時(shí),也讓人體的抵抗力開(kāi)始下降,人體內(nèi)的抗體細(xì)胞是有限的,這些抗體細(xì)胞會(huì)到處救火,顧不上對(duì)付"冠狀病毒"了。正是由于這些醫(yī)療器械(如呼吸機(jī)),盡可能讓人體機(jī)能恢復(fù)到接近正常人的水平,這樣各種抗體細(xì)胞就可以集中力量對(duì)付"冠狀病毒"了。所以說(shuō),這些痊愈的病人其實(shí)是通過(guò)自身的抗體細(xì)胞消滅了"冠狀病毒",而醫(yī)療器械、各種藥物,醫(yī)務(wù)人員的護(hù)理,其實(shí)是抗體細(xì)胞的援軍。另外,由于不同人的體質(zhì)不同。極個(gè)別的個(gè)體,抗體細(xì)胞非常強(qiáng)大,造成了"冠狀病毒"無(wú)法快速?gòu)?fù)制(但仍然在復(fù)制,只是增速變慢),這也是為什么有的個(gè)體的潛伏期會(huì)超過(guò)14天的原因,但這畢竟是極少數(shù)。潛伏期是被病毒感染的細(xì)胞數(shù)量達(dá)到足以致病的時(shí)間(人體內(nèi)如果只有少量的被病毒感染的細(xì)胞,是不會(huì)表現(xiàn)出任何癥狀的)。

????還有就是,為什么"冠狀病毒"感染者在發(fā)病時(shí)大多會(huì)有肺炎的癥狀,而且伴隨著發(fā)燒呢?其實(shí)這就是抗體細(xì)胞在和"冠狀病毒"進(jìn)行較量呢!進(jìn)醫(yī)院隔離,是為了增強(qiáng)抗體細(xì)胞對(duì)抗"冠狀病毒"的籌碼。不過(guò)由于一些人的抗體細(xì)胞的戰(zhàn)斗力實(shí)在太差(可能有部分人是因?yàn)槟挲g太大的原因),所以就算抗體細(xì)胞等來(lái)了援軍,也于事無(wú)補(bǔ),這些就是已經(jīng)死亡的被感染者(大多是60歲以上的老年人)。所以等疫情結(jié)束后,好好鍛煉身體吧,擁有強(qiáng)壯的身體,不能保證你不得病,但至少可以增加得病后活下來(lái)的幾率。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

對(duì)于目前正在研發(fā)的抗"冠狀病毒"的藥物主要是通過(guò)第2種方式消滅病毒的。也就是干擾病毒的復(fù)制過(guò)程,不過(guò)很遺憾,到現(xiàn)在為止,還沒(méi)有被證明非常有效的藥物可以做到這一點(diǎn)。

3. 對(duì)付"冠狀病毒"的手段

????從生物學(xué)角度,我們已經(jīng)了解了"冠狀病毒"的發(fā)病原理,但在現(xiàn)實(shí)中,如何操作呢?

????其實(shí)對(duì)付"冠狀病毒"以及其他大多數(shù)病毒,基本上就是基于12個(gè)字: 有癥狀趕快治,沒(méi)癥狀要隔離。這也是國(guó)際上通用的原則。

????前6個(gè)字容易理解,有癥狀了,就直接進(jìn)醫(yī)院了。如果沒(méi)癥狀呢?沒(méi)癥狀有兩種情況:疑似和正常人。疑似主要是指與被感染者近距離接觸,或從外地來(lái)本地的人員(輸入者),由于"冠狀病毒"的潛伏期是14天左右,所以這些疑似者至少需要被隔離14天才會(huì)確定是否真的被感染。而正常人只要沒(méi)和被感染者近距離接觸,就不會(huì)被感染。這些人之所以也需要隔離,是因?yàn)榕卤粍e人感染。不過(guò)這里的隔離通常是在自己的家中,不出門(mén)。通過(guò)隔離,可以大幅度減少病毒感染新的人群,也就是讓存量不再增加或少增加。而還有很多被感染者,這些人就需要在醫(yī)院里接受治療了。不過(guò)由于被感染者太多,所以武漢等地區(qū)快速建起了很多臨時(shí)醫(yī)院。 這是用來(lái)減少存量的。 當(dāng)存量不但不會(huì)增加、而且在不斷減少,直到被感染者為0,疑似者為0時(shí),疫情才會(huì)徹底結(jié)束,這也是本文要介紹的病毒擴(kuò)散仿真器的基本原理。

4. 用病毒擴(kuò)散仿真器來(lái)演示病毒擴(kuò)散和疫情結(jié)束的全過(guò)程

????在實(shí)現(xiàn)這個(gè)仿真器之前,先來(lái)演示下這個(gè)仿真器。

????仿真器可以對(duì)多個(gè)數(shù)據(jù)進(jìn)行模擬,包括健康者人數(shù)、潛伏期人數(shù)、發(fā)病者人數(shù)、已經(jīng)隔離的人數(shù)、已經(jīng)死亡的人數(shù)、空余床位、繼續(xù)床位、病毒傳播率、病毒潛伏期、醫(yī)院收治響應(yīng)時(shí)間、醫(yī)院當(dāng)前床位、安全距離、平均流動(dòng)意向。

????啟動(dòng)程序,會(huì)利用初始值進(jìn)行模擬,初始發(fā)病人數(shù)為50人,市民總數(shù)為5000人。如下圖所示。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????中間區(qū)域的若干個(gè)點(diǎn)表示各種狀態(tài)的市民。白色的表示健康市民、黃色表示潛伏期市民、紅色表示發(fā)病市民、黑色表示死亡的市民。右側(cè)的豎條表示醫(yī)院的床位,初始值是100。如果用參數(shù)值進(jìn)行模擬,100張床位很快就會(huì)被填滿,然后病毒在人群中就會(huì)大爆發(fā),很快紅點(diǎn)就會(huì)遍布人群,如下圖所示:

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????當(dāng)前天數(shù)已經(jīng)顯示過(guò)了31天(耽誤了一個(gè)月),感染者已經(jīng)接近1000了,這時(shí)政府開(kāi)始采取緊急措施。主要有兩個(gè):封城和關(guān)閉娛樂(lè)場(chǎng)所、增加醫(yī)院的床位。前者是為了避免感染更多的人,后者是為了消耗被感染者的存量。所以通過(guò)下面的設(shè)置來(lái)調(diào)整參數(shù)。例如,將流動(dòng)意向調(diào)整為-1.71。并且增加床位323個(gè)。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????這時(shí)總床位數(shù)變成了423。這里的流動(dòng)意向在-3和3之間,如果是3,表示市民的活動(dòng)意愿非常強(qiáng)烈,例如,正好是春節(jié)時(shí)期,市民逛商場(chǎng),聚會(huì)非常頻繁。流動(dòng)意愿越小,流動(dòng)意愿就越低。這里調(diào)成-1.76,表示市民不能參加聚會(huì)、不能出城、出門(mén)需要戴口罩,但市民仍然可以在市內(nèi)流動(dòng)。 流動(dòng)意愿遠(yuǎn)低于春節(jié)正常的值。不過(guò)盡管政府采取了一定的措施,但由于是在疫情開(kāi)始后一個(gè)月才采取了緊急措施,所以病毒已經(jīng)擴(kuò)散了,因此,疫情并沒(méi)有得到非常明顯的緩解。如下圖所示。 主要表現(xiàn)為市民仍然可以自由活動(dòng)(盡管不能參加聚會(huì)),仍然存在一定的感染風(fēng)險(xiǎn)。 而且醫(yī)院床位明顯不足。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????為了更進(jìn)一步控制疫情,政府開(kāi)始封閉小區(qū),更進(jìn)一步限制人員的活動(dòng),以及軍方開(kāi)始干預(yù),派出了大量的醫(yī)護(hù)人員以及各種醫(yī)療設(shè)備,并且建立的多個(gè)方艙醫(yī)院。醫(yī)院床位得到了很大的緩解。這里將參數(shù)設(shè)置成最大值來(lái)模擬這一過(guò)程,增加床位1200個(gè),流動(dòng)意向設(shè)置為-3.0,也就是說(shuō)基本上市民不流動(dòng)了。如下圖所示。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????這時(shí)看到床位已經(jīng)增加到了1623,比急需的床位多了不少,而且人員趨于不流動(dòng),發(fā)病人數(shù)不斷減少(都被送進(jìn)了醫(yī)院),而且潛伏期人數(shù)逐漸轉(zhuǎn)換為發(fā)病人數(shù),也被送進(jìn)了醫(yī)院,最終,潛伏期人數(shù)和發(fā)病者人數(shù)都是0,疫情結(jié)束,如下圖所示。共耗費(fèi)了60天。當(dāng)然,實(shí)際情況沒(méi)這么順利。仿真器可以立刻增加醫(yī)院床位數(shù),可以立刻隔離人員,但在實(shí)際操作中,建立醫(yī)院需要時(shí)間,隔離也需要協(xié)調(diào),尤其是上千萬(wàn)人的大城市。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????不過(guò)只要能做到隔離和及時(shí)就醫(yī),冠狀病毒疫情結(jié)束也只是時(shí)間問(wèn)題。當(dāng)然,這要在這兩點(diǎn)做的比較好的情況下,如果處理失當(dāng),那么仿真器就會(huì)呈現(xiàn)下圖的狀態(tài),完全失控,人類將面臨一場(chǎng)浩劫。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

5. 病毒傳播仿真器的實(shí)現(xiàn)

????現(xiàn)在來(lái)談?wù)劮抡嫫鲗?shí)現(xiàn)的原理。仿真器使用Python和PyQt5實(shí)現(xiàn)。PyQt5是封裝了Qt library的跨平臺(tái)GUI開(kāi)發(fā)庫(kù),基于Python語(yǔ)言。

????這里主要涉及到仿真器效果繪制,以及如何模擬多個(gè)參數(shù)。先來(lái)說(shuō)一下繪制市民的狀態(tài)。繪制的工作通過(guò)drawing.py文件的Drawing類來(lái)完成。該類是QWidget的子類,這也就意味著Drawing類本身是PyQt5的一個(gè)組件。與按鈕、標(biāo)簽類似。只是并不需要往Drawing上放置任何子組件。只要在Drawing上繪制各種圖形即可。

????在PyQt5中,任何一個(gè)QWidget的子類,都可以實(shí)現(xiàn)一個(gè)paintEvent方法,當(dāng)組件每次刷新時(shí),就會(huì)調(diào)用paintEvent方法重新繪制組件的內(nèi)容。Drawing類中paintEvent方法的代碼如下:

????def?paintEvent(self,?event):
????????qp?=?QPainter()
????????qp.begin(self)
????????#?繪制城市的各種狀態(tài)的市民
????????self.drawing(qp)
????????qp.end()

????在繪制圖像前,需要?jiǎng)?chuàng)建QPainter對(duì)象,然后調(diào)用QPainter對(duì)象的begin方法,結(jié)束繪制后,需要調(diào)用QPainter對(duì)象的end方法。上面代碼中的drawing方法用于完成具體的繪制工作。

仿真器可以模擬5000個(gè)市民的狀態(tài),所以需要用5000個(gè)小矩形來(lái)表示這5000個(gè)市民。也就是在drawing方法中需要繪制這5000個(gè)表示市民的小矩形。代碼如下:

def?drawing(self,?event):
???????...?...
????????#?繪制代表市民的小矩形
????????persons?=?Persons().persons
????????if?persons?==?None:
????????????return
????????normal_person_count?=?0
????????latency_person_count?=?0
????????confirmed_person_count?=?0
????????freeze_person_count?=?0
????????death_person_count?=?0
??????????????#?掃描內(nèi)一個(gè)人的狀態(tài)
????????for?person?in?persons:
????????????if?person.state?==?NORMAL:
????????????????#?健康人
????????????????qp.setPen(Qt.white)
????????????????normal_person_count?+=?1
????????????elif?person.state?==?LATENCY:
????????????????#?潛伏期感染者
????????????????qp.setPen(QColor(255,238,0))
????????????????latency_person_count?+=?1
????????????elif?person.state?==?CONFIRMED:
????????????????#?確診患者
????????????????qp.setPen(Qt.red)
????????????????confirmed_person_count?+=?1
????????????elif?person.state?==?FREEZE:
????????????????#?已隔離者
????????????????qp.setPen(QColor(72,?255,?252))
????????????????freeze_person_count?+=?1
????????????elif?person.state?==?DEATH:
????????????????#?死亡患者
????????????????qp.setPen(Qt.black)
????????????????death_person_count?+=?1
????????????person.update()???#?更新每一個(gè)人的狀態(tài)
????????????bed_half_size?=?Hospital().bed_size?//?2
????????????rect?=?QRect(person.x?-?bed_half_size,?person.y?-?bed_half_size,Hospital().bed_size//2,?Hospital().bed_size//2)
????????????brush?=?QBrush(Qt.SolidPattern)
????????????brush.setColor(qp.pen().color())

????????????qp.setBrush(brush)
????????????qp.drawRect(rect)
????????????...?...

????在上面的代碼中,通過(guò) Persons對(duì)象的persons屬性獲取表示市民的對(duì)象(Person對(duì)象)列表。并在循環(huán)中根據(jù)Person對(duì)象的狀態(tài)設(shè)置小矩形的顏色,以及分別統(tǒng)計(jì)不同人群的數(shù)量,這些數(shù)量會(huì)顯示在仿真器右側(cè)的組件中。最后,使用drawRect方法繪制表示每一個(gè)市民的小矩形。這樣就繪制了當(dāng)前狀態(tài)的5000個(gè)市民。

????當(dāng)然,這些狀態(tài)要不斷更新。這里使用線程每100毫秒刷新一次,這些功能在refresh.py文件的Refresh類中,代碼如下:

from?PyQt5.QtCore?import?*
from?params?import??*

class?Refresh(QThread):
????def?__init__(self,?drawing):
????????super(Refresh,?self).__init__()
????????self.drawing?=?drawing
????def?run(self):
????????while?not?Params.success:
????????????try:
????????????????QThread.msleep(100)
????????????????#?刷新Drawing
????????????????self.drawing.update()
????????????????Params.current_time?+=?1
????????????except:
????????????????pass

????每次刷新Drawing,需要調(diào)用update方法,調(diào)用該方法后,Drawing就會(huì)調(diào)用自身的paintEvent方法重新繪制整個(gè)組件的內(nèi)容。

????在paintEvent方法中,還調(diào)用了Person對(duì)象的update方法,該方法是我們自己編寫(xiě)的,用于不斷更新每一個(gè)人的狀態(tài),這些狀態(tài)會(huì)根據(jù)多個(gè)參數(shù)進(jìn)行協(xié)調(diào)。該方法屬于Person類,代碼如下:

????def?update(self):
????????#?如果已經(jīng)隔離或者死亡了,就不需要處理了
????????if?self.state?==?FREEZE?or?self.state?==?DEATH:
????????????return
????????#?處理已經(jīng)確診的感染者(即患者)
????????if?self.state?==?CONFIRMED?and?self.dead_time?==?0:
????????????destiny?=?random.randrange(1,10001)??#?幸運(yùn)數(shù)字,[1,10000]隨機(jī)數(shù)
????????????if?destiny?>=?1?and?destiny?<=?int(Params.fatality_rate?*?10000):
????????????????#?幸運(yùn)數(shù)字落在死亡區(qū)間
????????????????dt?=?int(sp.random.normal(Params.dead_time,Params.dead_variance))
????????????????self.dead_time?=?self.confirmed_time?+?self.dead_time
????????????else:
????????????????self.dead_time?=?-1???#?逃過(guò)了死神的魔爪

????????if?self.state?==?CONFIRMED?and?Params.current_time?-?self.confirmed_time?>=?Params.hospital_receive_time:
????????????#?如果患者已經(jīng)確診,且(世界時(shí)刻-確診時(shí)刻)大于醫(yī)院響應(yīng)時(shí)間,即醫(yī)院準(zhǔn)備好病床了,可以抬走了
????????????bed?=?Hospital().pick_bed()??#?查找空床位
????????????if?bed?==?None:
????????????????#?沒(méi)有空床位,報(bào)告需求床位數(shù)
????????????????if?not?self.need_bed:
????????????????????Hospital().need_bed_count?+=?1
????????????????????self.need_bed?=?True

????????????else:
????????????????#?安置病人
????????????????self.used_bed?=?bed
????????????????self.state?=?FREEZE
????????????????self.x?=?bed.x?+?Hospital().bed_size?//?2
????????????????self.y?=?bed.y?+??Hospital().bed_size?//?2
????????????????if?self.need_bed?and?Hospital().need_bed_count?>?0:
????????????????????Hospital().need_bed_count?-=?1
????????????????bed.is_empty?=?False
????????#?處理病死者
????????if?(self.state?==?CONFIRMED?or?self.state?==?FREEZE)?and?Params.current_time?>=?self.dead_time?and?self.dead_time?>?0:
????????????self.state?=?DEATH??????????????????????????#?患者死亡
????????????personpool.Persons().latency_persons.remove(self)??????#?已經(jīng)死亡,無(wú)法傳染別人,需要從確診者中刪除
????????????Hospital().empty_bed(self.used_bed)?????????#?騰出床位
????????????if?Hospital().need_bed_count?>?0:
????????????????Hospital().need_bed_count?-=?1

????????#?增加一個(gè)正態(tài)分布用于潛伏期內(nèi)隨機(jī)發(fā)病時(shí)間
????????latency_symptom_time?=?sp.random.normal(Params.virus_latency?/?2,25)

????????#?處理發(fā)病的潛伏期感染者

????????if?Params.current_time?-?self.infected_time?>?latency_symptom_time?and?self.state?==?LATENCY:
????????????self.state?=?CONFIRMED??????????????????????????????????#?潛伏者發(fā)病
????????????self.confirmed_time?=?Params.current_time??????????????#?刷新確診時(shí)間
????????#?處理未隔離者的移動(dòng)問(wèn)題
????????self.action()
????????#?處理健康人被感染的問(wèn)題
????????persons?=?personpool.Persons().persons

????????#?不是健康人,返回
????????if?self.state?>=?LATENCY:
????????????return
????????#?通過(guò)一個(gè)隨機(jī)幸運(yùn)值和安全距離決定感染其他人
????????latency_persons?=?personpool.Persons().latency_persons.copy()
????????for?person?in?latency_persons:
????????????random_value?=?random.random()
????????????if?random_value?<?Params.broad_rate?and?self.distance(person)?<?Params.safe_distance:
????????????????self.be_infected()
????????????????break

????update方法主要就是根據(jù)在params.py中的各種參數(shù)變量,以及隨機(jī)值,計(jì)算下一次狀態(tài)中潛伏期人數(shù)、感染人數(shù)、被隔離人數(shù)等數(shù)據(jù),并且在每次刷新頁(yè)面時(shí)更新這些數(shù)據(jù)。

????以上的描述就是如何繪制表示5000個(gè)市民的狀態(tài)。右側(cè)各種數(shù)據(jù)并不是繪制在頁(yè)面上的,而是通過(guò)QtDesigner設(shè)計(jì)的右側(cè)的界面,然后將Drawing對(duì)象作為標(biāo)準(zhǔn)的組件放在了主界面的左側(cè)。設(shè)計(jì)界面如下圖所示:

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????然后通過(guò)pyuic將.ui文件生成.py文件,在程序中調(diào)用即可。這些組件的更新同樣是在前面給出的drawing方法中。

????另外,這個(gè)仿真器還提供了動(dòng)態(tài)設(shè)置參數(shù)的功能。這是通過(guò)另外一個(gè)程序?qū)崿F(xiàn)的,兩個(gè)程序通過(guò)socket通訊。這個(gè)設(shè)置程序同樣是通過(guò)QtDesigner設(shè)計(jì)的,設(shè)計(jì)界面如下圖所示。

冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)

????在設(shè)置程序中,通過(guò)Transmission類的send_command方法向仿真器發(fā)布命令,例如,更新床位數(shù)的代碼如下:

from?PyQt5.QtWidgets?import?*
from?socket?import?*
class?Transmission:
????def?__init__(self,ui):
????????self.ui?=?ui
????????self.host?=?'localhost'
????????self.port?=?5678
????????self.addr?=?(self.host,?self.port)
??????#?向仿真器發(fā)布命令
????def?send_command(self,?command,?value?=?None):
????????tcp_client_socket?=?socket(AF_INET,?SOCK_STREAM)
????????tcp_client_socket.connect(self.addr)
????????if?value?==?None:
????????????value?=?0
????????data?=?command?+?':'?+?str(value)
????????tcp_client_socket.send(('%s\r\n'?%?data).encode(encoding='utf-8'))
????????data?=?tcp_client_socket.recv(1024)
????????result?=?data.decode('utf-8').strip()
????????tcp_client_socket.close()
????????return?result
?????#?更新床位數(shù)
????def?update_bed_count(self):
????????print(self.ui.horizontalSliderBedCount.value())
????????result?=?self.send_command('add_bed_count',self.ui.horizontalSliderBedCount.value())
????????if?result?==?'ok':
????????????QMessageBox.information(self.ui.centralwidget,?'消息',?f'成功添加了{(lán)self.ui.horizontalSliderBedCount.value()}張床位',?QMessageBox.Ok)

? 在仿真器端,通過(guò)Receiver以及TCPServer來(lái)接收設(shè)置程序發(fā)過(guò)來(lái)的命令,如果成功設(shè)置,返回ok。Receiver類以及相關(guān)的代碼如下:

以上就是這個(gè)病毒傳播仿真器的基本實(shí)現(xiàn)方法,其中涉及到了大量PyQt5的知識(shí),如果大家想詳細(xì)了解PyQt5技術(shù),可以參考我的《PyQt5(Python)開(kāi)發(fā)與實(shí)戰(zhàn)視頻課程》課程。另外,《冠狀病毒傳播仿真器的原理和實(shí)現(xiàn)(Python版)》視頻課程即將推出,歡迎關(guān)注。

from?socketserver?import?(TCPServer?as?TCP,StreamRequestHandler?as?SRH)
from?common?import?*
from?params?import?*
from?hospital?import?*
from?PyQt5.QtCore?import?*
import?sys
#?響應(yīng)客戶端請(qǐng)求事件的類
class?MyRequestHandler(SRH):
????def?handle(self):
???????#?讀取客戶端發(fā)送的數(shù)據(jù)
????????data?=?str(self.rfile.readline(),'utf-8')
????????index?=?data.find(':')
????????command?=?data[:index]
????????value?=?data[index?+?1:]
????????value?=?int(value)
?????????????#?執(zhí)行具體的命令
????????if?command?==?'add_bed_count':
????????????Params.hospital_bed_count?+=??value
????????????Hospital().free_bed_count?=?Hospital().free_bed_count?+?value
????????????Hospital().compute(value)
????????elif?command?==?'set_flow_intention':
????????????Params.average_flow_intention?=?value?/?100
????????elif?command?==?'set_broad_rate':
????????????Params.broad_rate?=?value?/?100
????????elif?command?==?'set_latency':
????????????Params.virus_latency?=?value?*?10
????????elif?command?==?'close':
????????????Params.app.quit()
????????self.wfile.write(b'ok\r\n')
#?在線程中監(jiān)聽(tīng)客戶端的請(qǐng)求
class?Receiver(QThread):
????tcp_server?=?None
????def?__init__(self):
????????super(Receiver,self).__init__()
????????self.host?=?''
????????self.port?=?5678
????????self.addr?=?(self.host,self.port)
????????Receiver.tcp_server?=?TCP(self.addr,?MyRequestHandler)

????def?run(self):
????????Receiver.tcp_server.serve_forever()


個(gè)人簡(jiǎn)介

李寧,沈陽(yáng)歐瑞科技創(chuàng)始人,寧哥教育創(chuàng)始人,暢銷書(shū)作家,51CTO金牌講師,企業(yè)內(nèi)訓(xùn)講師,擁有超過(guò)20年軟件開(kāi)發(fā)和培訓(xùn)經(jīng)驗(yàn)。曾經(jīng)出版超過(guò)40本IT暢銷書(shū),代表作有《Python爬蟲(chóng)技術(shù):深入理解原理、技術(shù)與開(kāi)發(fā)》、《Python從菜鳥(niǎo)到高手》,制作視頻課程超過(guò)1000小時(shí),擁有學(xué)員和讀者數(shù)百萬(wàn)。 主要使用的技術(shù)包括Python、Go、JavaScript、Java、Flutter等。目前正在帶領(lǐng)團(tuán)隊(duì)開(kāi)發(fā)超平臺(tái)開(kāi)發(fā)工具UnityMarvey,使用自研發(fā)的Ori語(yǔ)言,可以同時(shí)跨操作系統(tǒng)、數(shù)據(jù)庫(kù)、云平臺(tái)等多個(gè)平臺(tái),通過(guò)超布局技術(shù)實(shí)現(xiàn)可視化UI設(shè)計(jì),支持客戶端服務(wù)端一體化技術(shù)。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI