مدل انتشار راه حل در جامعه Rust – DEV

تصمیم گرفتم به یک ماجراجویی بروم. من یک شبیه ساز سلولی ساده بیولوژیکی در Rust خواهم نوشت. این اولین بار است که شبیه ساز می نویسم و همچنین اولین بار است که از Rust استفاده می کنم.
در مراحل اولیه فقط برای درک بهتر مفاهیم زیست شناختی از قبل شناخته شده مفید خواهد بود. با این حال، امیدواریم بعداً به آزمایش سؤالات تکاملی و دارویی کمک کند. هدف بلند مدت من شبیه سازی چندین باکتری اشریشیا کلی در یک محیط پیچیده است. این باکتری ها به دلیل اهمیت آنها در سلامت انسان و حیوانات به خوبی مورد مطالعه قرار گرفته اند. آنها می توانند هم به عنوان پروبیوتیک مفید باشند و هم به عنوان پاتوژن مضر.
من Rust را انتخاب کردم، زیرا زبانی سریع و سطح پایین است. عملکردی قابل مقایسه با C و C++ دارد، اما بر خلاف آنها دارای یک راه حل داخلی و ساده برای مدیریت بسته و تولید اسناد است. من توانستم در 5 دقیقه به عنوان اولین تایمر از آنها استفاده کنم.
با این حال گویاترین شاخص این است که من توانستم ساده ترین اثبات مفهوم را در حدود یک ساعت بنویسم. انتزاعات زبان به نوعی شبیه به این است که من دوست دارم مشکلات را در ذهنم مدل کنم، که عمیقا ذهنی است، اما با این حال تصمیم من را تقویت کرد.
من قصد دارم در مراحل کودکی کار کنم، بنابراین ابتدا یک مدل انتشار بسیار ساده را برنامه ریزی کردم.
اگر در مورد انتشار چیزی نشنیده اید، توضیح اولیه آن آسان است. با توجه به اینکه شما یک مخزن آب دارید و آن را با اکسیژن یا مواد محلول دیگر تزریق می کنید، ذرات آن ماده می توانند آزادانه در هر جهتی حرکت کنند.
بنابراین با توجه به زمان، آنها کم و بیش به طور یکنواخت در مخزن آب پراکنده خواهند شد. با این حال، اگر مخزن آب را با یک غشاء تقسیم کنید، همان نتیجه را خواهید داشت، اما پس از مدت زمان طولانی تر. تأخیر زمانی به نفوذپذیری غشا برای آن ماده داده شده بستگی دارد. هرچه نفوذپذیری کمتر باشد، زمان بیشتری باید منتظر بمانید.
من اسکریپت پایتون شبه کد نوشتم تا ساده ترین مدل را برای این مشکل ارائه کنم.
def membrane_permeate(a_solvent_o2_count, b_solvent_o2_count, o2_permeability):
o2_forward = int(round(a_solvent_o2_count * o2_permeability))
o2_reverse = int(round(b_solvent_o2_count * o2_permeability))
a_solvent_o2_count = a_solvent_o2_count - o2_forward
b_solvent_o2_count = b_solvent_o2_count - o2_reverse
a_solvent_o2_count = a_solvent_o2_count + o2_reverse
b_solvent_o2_count = b_solvent_o2_count + o2_forward
return a_solvent_o2_count, b_solvent_o2_count
a_solvent_o2_count = 10000
b_solvent_o2_count = 10
o2_permeability = 0.3
for cycle in range(10):
a_solvent_o2_count, b_solvent_o2_count = membrane_permeate(
a_solvent_o2_count,
b_solvent_o2_count,
o2_permeability,
)
print(f"{cycle},{a_solvent_o2_count},{b_solvent_o2_count}")
اجرای Rust از نظر منطقی تقریباً یکسان است، اما برای 3 فضای حلال با حجم مساوی در 2 غشا بین آنها.
خب تقریباً یک باکتری گرم منفی است، فقط چند قسمت از آن وجود ندارد. XD
(منبع تصویر ویکی پدیا)
همچنین باید توجه داشته باشید که من اصطلاح “exosol” را پیدا کردم. بنابراین در آزمون خود باید آنچه را که معلمتان گفته است بنویسید، که به احتمال زیاد “محیط خارج سلولی” است که طولانی و خسته کننده است اما پاسخ درستی خواهد بود.
بازگشت به موضوع: من عاشق زنگ زدم، زیرا با ویژگی زبان صفت میتوانستم انتشار را به روشی بسیار نزدیک به نحوه استدلالم در مورد آن برنامهریزی کنم:
“انتشار بر اساس ویژگی غشاها است که می توانند مولکول های بین حلال ها را که از هم جدا می کنند نفوذ کنند.”
و یکی از مهمترین ویژگیهای هر کد این است که چگونه میتوان درباره آن استدلال کرد.
پس بیایید کد را ببینیم:
اول من تعریف کردم Solvent
ساختار، که تنها یک میدان دارد، تعداد مولکول های اکسیژن. به نظر می رسد که ساختارهای زنگ بسیار شبیه سازه های C هستند، اما در برخی موارد مهم با هم تفاوت دارند. مهمترین تفاوت در مورد این کد، توانایی در Rust برای پیاده سازی توابع متصل به یک ساختار است.
struct Solvent {
o2_count: i128,
}
سپس من تعریف کردم Membrane
همچنین به عنوان یک ساختار، دارای یک میدان تنها، نفوذپذیری آن برای اکسیژن مولکولی، به عنوان یک عامل ساده بیان می شود.
struct Membrane {
o2_permeability: f32,
}
سپس من تعریف کردم Permeate
صفت که روشی با 2 حلال به عنوان پارامتر دارد.
trait Permeate {
fn permeate(&self, solvent1: &mut Solvent, solvent2: &mut Solvent);
}
سپس من آن را اجرا کردم Permeate
صفت برای Membrane
ساخت. من فقط مقدار شار اکسیژن را در هر دو جهت با ضرب کردن تعداد اکسیژن در چرخه شبیه سازی داده شده با ضریب نفوذپذیری غشاء محاسبه کردم.
impl Permeate for Membrane {
fn permeate(&self, solvent1: &mut Solvent, solvent2: &mut Solvent) {
let o2_forward = (solvent1.o2_count as f32) * self.o2_permeability;
let o2_reverse = (solvent2.o2_count as f32) * self.o2_permeability;
solvent1.o2_count = solvent1.o2_count - (o2_forward.round() as i128);
solvent2.o2_count = solvent2.o2_count - (o2_reverse.round() as i128);
solvent1.o2_count = solvent1.o2_count + (o2_reverse.round() as i128);
solvent2.o2_count = solvent2.o2_count + (o2_forward.round() as i128);
}
}
در نهایت در main
عملکرد من بازیکنان را اعلام می کنم: extrasol
، periplasm
، cytosol
، outer_membrane
و inner_membrane
. بنابراین در یک حلقه شبیه سازی می توانم انتشار در دو غشا را محاسبه کنم.
مهمترین دو خط عبارتند از:
outer_membrane.permeate(&mut extrasol, &mut periplasm);
inner_membrane.permeate(&mut periplasm, &mut cytosol);
این تمام چیزی است که برای محاسبه انتشار در هر چرخه شبیه سازی لازم است. خیلی مرتبه
با این حال در اینجا تابع اصلی کامل است:
fn main() {
let mut extrasol = Solvent { o2_count: 10000 };
let mut periplasm = Solvent { o2_count: 10 };
let mut cytosol = Solvent { o2_count: 5 };
let outer_membrane = Membrane {
o2_permeability: 0.3,
};
let inner_membrane = Membrane {
o2_permeability: 0.3,
};
println!("cycle,extrasol_o2,periplasm_o2,cytosol_o2");
for cycle in 1..=10 {
println!(
"{},{},{},{}",
cycle, extrasol.o2_count, periplasm.o2_count, cytosol.o2_count
);
outer_membrane.permeate(&mut extrasol, &mut periplasm);
inner_membrane.permeate(&mut periplasm, &mut cytosol);
}
}
پس تجربه خوبی بود. در نسخه بعدی بازی خود را با توسعه یک مدل انتشار پیچیده تر افزایش خواهم داد، زیرا اکنون با یک مدل قوی بسیار فاصله دارم. یکی از بارزترین محدودیت ها این است که در واقعیت حجم آن حلال ها بسیار متفاوت است. همچنین نواحی سطح غشاء باید در نظر گرفته شود. بنابراین من مدل را با استفاده از قانون فیک بیشتر توسعه خواهم داد. که در پست بعدی توضیح خواهم داد.
اما با این وجود من یک مدل بسیار ساده به عنوان نقطه شروع در راهم به سمت یک مدل باکتریایی زیباتر دارم و همچنین کمی Rust را یاد گرفتم که خوشحال کننده بود.
این پروژه رایگان و منبع باز تحت مجوز GPL 3.0 است و در GitHub قابل مشاهده است.