379 lines
10 KiB
Markdown
379 lines
10 KiB
Markdown
# جریان واقعی `location_data`
|
||
|
||
این توضیح دقیقاً بر اساس منطق جدید نوشته شده:
|
||
|
||
- اول مختصات گوشههای کل زمین گرفته میشود
|
||
- بعد مختصات بلوکهایی که کشاورز خودش تعریف کرده گرفته میشود
|
||
- هر بلوک جداگانه به grid های `30×30` تبدیل میشود
|
||
- برای هر grid دادهی یک بازه زمانی از openEO گرفته میشود
|
||
- میانگین همان بازه، وضعیت نهایی همان grid حساب میشود
|
||
- بعد برای همان grid ها `KMeans` اجرا میشود
|
||
- برای هر `K` مقدار `SSE / Inertia` ذخیره میشود
|
||
- نمودار `K - SSE` رسم میشود
|
||
- نقطهای که افت شیب ناگهانی دارد به عنوان تعداد مناسب زیربلوکها انتخاب میشود
|
||
- در نهایت هر بلوک کشاورز به چند زیربلوک دادهمحور تقسیم میشود
|
||
|
||
---
|
||
|
||
## 1) ورودی مرحله اول
|
||
|
||
در مرحله اول این دادهها ثبت میشوند:
|
||
|
||
- مختصات گوشههای کل زمین
|
||
- مختصات بلوکهایی که کشاورز تعریف کرده
|
||
- کد هر بلوک
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/views.py`
|
||
- `location_data/serializers.py`
|
||
- `location_data/models.py`
|
||
|
||
خروجی این مرحله:
|
||
|
||
- یک `SoilLocation` برای زمین
|
||
- یک `block_layout` که داخلش boundary هر بلوک هست
|
||
- یک `BlockSubdivision` برای هر بلوک، فقط به عنوان تعریف مرز بلوک کشاورز
|
||
|
||
نکته مهم:
|
||
|
||
- در این مرحله هیچ subdivision سنکرونی اجرا نمیشود
|
||
- هیچ داده خاکی از adapter قدیمی گرفته نمیشود
|
||
|
||
---
|
||
|
||
## 2) هر بلوک کشاورز جداگانه grid میشود
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/grid_analysis.py`
|
||
|
||
اینجا چه اتفاقی میافتد:
|
||
|
||
- boundary هر بلوک خوانده میشود
|
||
- آن بلوک به cell های `30×30` متر تبدیل میشود
|
||
- برای هر cell یک رکورد ساخته میشود
|
||
|
||
مدل ذخیره:
|
||
|
||
- `AnalysisGridCell`
|
||
|
||
هر `AnalysisGridCell` این چیزها را نگه میدارد:
|
||
|
||
- `cell_code`
|
||
- `block_code`
|
||
- `geometry`
|
||
- `centroid_lat`
|
||
- `centroid_lon`
|
||
- `chunk_size_sqm`
|
||
|
||
یعنی از اینجا به بعد، کوچکترین واحد تحلیل ما دیگر خود بلوک نیست؛
|
||
بلکه grid های `30×30` داخل هر بلوک هستند.
|
||
|
||
---
|
||
|
||
## 3) داده ماهوارهای هر grid از openEO گرفته میشود
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/openeo_service.py`
|
||
|
||
منطق این بخش شبیه همان چیزی است که گفتی:
|
||
|
||
- برای هر بازه زمانی، cube هر سنجنده load میشود
|
||
- روی زمان `mean_time()` زده میشود
|
||
- بعد برای geometry هر grid از `aggregate_spatial(..., reducer=\"mean\")` استفاده میشود
|
||
|
||
یعنی:
|
||
|
||
- داده خام چند روز یا یک ماهه میآید
|
||
- میانگین همان بازه زمانی برای هر grid محاسبه میشود
|
||
- همان مقدار میانگین، وضعیت نهایی آن grid در آن بازه است
|
||
|
||
metric هایی که الان گرفته میشوند:
|
||
|
||
- `ndvi`
|
||
- `ndwi`
|
||
- `lst_c`
|
||
- `soil_vv`
|
||
- `soil_vv_db`
|
||
- `dem_m`
|
||
- `slope_deg`
|
||
|
||
نکته مهم:
|
||
|
||
- این دادهها برای **تمام grid های یک بلوک** گرفته میشوند
|
||
- نه فقط برای مرکز مزرعه
|
||
- نه فقط برای geometry خام
|
||
|
||
---
|
||
|
||
## 4) داده هر grid داخل جدول ذخیره میشود
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/tasks.py`
|
||
|
||
مدل ذخیره:
|
||
|
||
- `AnalysisGridObservation`
|
||
|
||
برای هر grid و هر بازه زمانی، این دادهها ذخیره میشوند:
|
||
|
||
- `ndvi`
|
||
- `ndwi`
|
||
- `lst_c`
|
||
- `soil_vv`
|
||
- `soil_vv_db`
|
||
- `dem_m`
|
||
- `slope_deg`
|
||
|
||
پس هر grid یک بردار ویژگی واقعی دارد.
|
||
|
||
یعنی به زبان ساده:
|
||
|
||
- هر خانه 30×30 فقط یک polygon نیست
|
||
- یک وضعیت دادهای واقعی هم دارد
|
||
|
||
---
|
||
|
||
## 5) اینجا یادگیری بدون نظارت استفاده میشود
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/data_driven_subdivision.py`
|
||
|
||
اینجا از:
|
||
|
||
- `KMeans`
|
||
|
||
استفاده میشود.
|
||
|
||
این بخش unsupervised است چون:
|
||
|
||
- هیچ label آمادهای نداریم
|
||
- فقط میخواهیم grid هایی که از نظر رفتار ماهوارهای شبیه هم هستند در یک گروه قرار بگیرند
|
||
|
||
---
|
||
|
||
## 6) feature matrix دقیقاً از چه چیزی ساخته میشود؟
|
||
|
||
هر سطر:
|
||
|
||
- یک `AnalysisGridCell`
|
||
|
||
هر ستون:
|
||
|
||
- یکی از feature های ماهوارهای
|
||
|
||
feature های پیشفرض:
|
||
|
||
- `ndvi`
|
||
- `ndwi`
|
||
- `lst_c`
|
||
- `soil_vv_db`
|
||
- `dem_m`
|
||
- `slope_deg`
|
||
|
||
یعنی ورودی `KMeans` از observation های واقعی میآید، نه از مختصات هندسی.
|
||
|
||
---
|
||
|
||
## 7) داده ناقص چطور مدیریت میشود؟
|
||
|
||
قبل از اجرای KMeans:
|
||
|
||
- اگر یک grid برای همه feature ها خالی باشد، حذف میشود
|
||
- اگر فقط بعضی feature ها خالی باشند، مقداردهی میشود
|
||
|
||
روش فعلی:
|
||
|
||
- `median imputation`
|
||
|
||
بعد از آن:
|
||
|
||
- دادهها استاندارد میشوند
|
||
|
||
روش فعلی:
|
||
|
||
- `StandardScaler`
|
||
|
||
این کار لازم است چون:
|
||
|
||
- مقیاس `ndvi` با `dem_m` فرق دارد
|
||
- مقیاس `dem_m` با `lst_c` فرق دارد
|
||
|
||
---
|
||
|
||
## 8) برای هر K مقدار SSE ذخیره میشود
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/data_driven_subdivision.py`
|
||
- `location_data/block_subdivision.py`
|
||
|
||
در زمان انتخاب تعداد خوشه:
|
||
|
||
- برای `K = 1, 2, 3, ...`
|
||
- مدل اجرا میشود
|
||
- مقدار `SSE / Inertia` ذخیره میشود
|
||
|
||
این داده داخل metadata نتیجه clustering ذخیره میشود.
|
||
|
||
پس ما برای هر بلوک این را داریم:
|
||
|
||
- لیست `K`
|
||
- مقدار `SSE` هر `K`
|
||
|
||
---
|
||
|
||
## 9) نمودار `K - SSE` رسم میشود
|
||
|
||
منطق رسم نمودار در سیستم وجود دارد و از همان منطق elbow استفاده میشود.
|
||
|
||
هدف نمودار:
|
||
|
||
- ببینیم از چه جایی به بعد کم شدن SSE دیگر خیلی شدید نیست
|
||
- یعنی شیب نمودار ناگهان کمتر میشود
|
||
|
||
همان نقطه:
|
||
|
||
- تعداد مناسب زیربلوکهای آن بلوک است
|
||
|
||
به زبان ساده:
|
||
|
||
- اگر شیب تا `K=3` خیلی زیاد کم شود
|
||
- ولی بعد از آن خیلی آرام شود
|
||
- `K=3` انتخاب مناسب است
|
||
|
||
---
|
||
|
||
## 10) هر بلوک کشاورز جداگانه خوشهبندی میشود
|
||
|
||
این خیلی مهم است:
|
||
|
||
- کل مزرعه یکجا خوشهبندی نمیشود
|
||
- هر بلوکی که کشاورز تعریف کرده جداگانه پردازش میشود
|
||
|
||
پس برای هر بلوک:
|
||
|
||
1. grid های 30×30 ساخته میشوند
|
||
2. داده ماهوارهای همان grid ها گرفته میشود
|
||
3. observation ذخیره میشود
|
||
4. `KMeans` فقط روی grid های همان بلوک اجرا میشود
|
||
5. تعداد زیربلوکهای مناسب همان بلوک تعیین میشود
|
||
|
||
---
|
||
|
||
## 11) نتیجه subdivision جدید کجا ذخیره میشود؟
|
||
|
||
مدل اصلی نتیجه:
|
||
|
||
- `RemoteSensingSubdivisionResult`
|
||
|
||
این مدل چیزهای اصلی را نگه میدارد:
|
||
|
||
- `block_code`
|
||
- `cluster_count`
|
||
- `selected_features`
|
||
- `skipped_cell_codes`
|
||
- `kmeans_params`
|
||
- `inertia_curve`
|
||
- `cluster_summaries`
|
||
|
||
و برای هر grid هم assignment جدا ذخیره میشود در:
|
||
|
||
- `RemoteSensingClusterAssignment`
|
||
|
||
یعنی برای هر grid مشخص است:
|
||
|
||
- در کدام cluster قرار گرفته
|
||
- raw feature هایش چه بوده
|
||
- scaled feature هایش چه بوده
|
||
|
||
---
|
||
|
||
## 12) `BlockSubdivision` الان چه نقشی دارد؟
|
||
|
||
الان `BlockSubdivision` دیگر مدل اصلی خوشهبندی نیست.
|
||
|
||
نقشش این است که:
|
||
|
||
- boundary بلوک کشاورز را نگه دارد
|
||
- metadata بلوک را نگه دارد
|
||
- به grid سازی و pipeline کمک کند
|
||
|
||
اما نتیجه اصلی data-driven subdivision در این دو مدل ذخیره میشود:
|
||
|
||
- `RemoteSensingSubdivisionResult`
|
||
- `RemoteSensingClusterAssignment`
|
||
|
||
---
|
||
|
||
## 13) اجرای async کجا انجام میشود؟
|
||
|
||
فایل اصلی:
|
||
|
||
- `location_data/tasks.py`
|
||
|
||
این pipeline داخل Celery اجرا میشود.
|
||
|
||
مراحل run:
|
||
|
||
1. run ساخته میشود
|
||
2. grid های بلوک ساخته میشوند
|
||
3. داده openEO گرفته میشود
|
||
4. observation ها ذخیره میشوند
|
||
5. feature matrix ساخته میشود
|
||
6. `KMeans` اجرا میشود
|
||
7. نتیجه نهایی ذخیره میشود
|
||
|
||
مدل status:
|
||
|
||
- `RemoteSensingRun`
|
||
|
||
وضعیتهایی که track میشوند:
|
||
|
||
- `pending`
|
||
- `running`
|
||
- `failed`
|
||
- `completed`
|
||
|
||
---
|
||
|
||
## 14) چیزی که حذف شده
|
||
|
||
این بخشها دیگر منبع اصلی داده نیستند و باید حذفشده در نظر گرفته شوند:
|
||
|
||
- منطق قدیمی دریافت soil depth
|
||
- adapter های خاک
|
||
- وابستگی اصلی به `SoilDepthData`
|
||
|
||
منبع اصلی داده از این به بعد:
|
||
|
||
- داده ماهوارهای هر grid
|
||
|
||
یعنی:
|
||
|
||
- به جای جدول depth-based
|
||
- جدول observation های ماهوارهای grid-based مرجع اصلی است
|
||
|
||
---
|
||
|
||
## 15) خلاصه خیلی کوتاه
|
||
|
||
جریان نهایی این است:
|
||
|
||
1. گوشههای زمین و بلوکهای کشاورز ثبت میشوند
|
||
2. هر بلوک به grid های `30×30` تبدیل میشود
|
||
3. برای هر grid دادهی ماهوارهای یک بازه زمانی از openEO گرفته میشود
|
||
4. میانگین آن بازه، وضعیت همان grid میشود
|
||
5. همه grid ها در جدول observation ذخیره میشوند
|
||
6. برای هر بلوک، روی feature های grid ها `KMeans` اجرا میشود
|
||
7. برای هر `K` مقدار `SSE` ذخیره میشود
|
||
8. نمودار `K - SSE` ساخته میشود
|
||
9. elbow point تعداد مناسب زیربلوکها را مشخص میکند
|
||
10. هر بلوک کشاورز به چند زیربلوک دادهمحور تقسیم میشود
|
||
|
||
این دقیقاً همان منطق اصلی جدید سیستم است.
|