UPDATE
This commit is contained in:
@@ -0,0 +1,972 @@
|
||||
# مستند کامل اپ `location_data`
|
||||
|
||||
این سند، وضعیت فعلی اپ `location_data` را به صورت کامل توضیح میدهد:
|
||||
|
||||
- مدلهای داده
|
||||
- منطق business
|
||||
- جریان ساخت location و block
|
||||
- subdivision و خوشهبندی
|
||||
- تولید analysis grid
|
||||
- سنجشازدور با openEO
|
||||
- تسکهای Celery
|
||||
- APIهای فعلی
|
||||
- ساختار responseها
|
||||
- محدودیتها و فرضیات فعلی
|
||||
|
||||
این فایل بر اساس کد فعلی پروژه نوشته شده است و هدفش این است که یک مرجع فنی برای توسعهدهندههای بعدی باشد.
|
||||
|
||||
---
|
||||
|
||||
## 1) هدف اپ `location_data`
|
||||
|
||||
اپ `location_data` در وضعیت فعلی چند نقش اصلی دارد:
|
||||
|
||||
1. نگهداری موقعیت جغرافیایی زمین با `lat/lon`
|
||||
2. نگهداری مرز زمین یا مرز blockها
|
||||
3. ساخت ساختار blockهای مزرعه
|
||||
4. اجرای subdivision برای blockها
|
||||
5. تولید grid analysis با ابعاد 30x30 متر
|
||||
6. نگهداری نتایج سنجشازدور روی هر grid cell
|
||||
7. نگهداری دادههای خاک و NDVI سنتی
|
||||
8. فراهم کردن API برای:
|
||||
- location data
|
||||
- subdivision
|
||||
- remote sensing trigger/result
|
||||
- NDVI health
|
||||
|
||||
به صورت خلاصه، `location_data` الان فقط یک جدول مختصات نیست؛ بلکه هاب مکانی پروژه است.
|
||||
|
||||
---
|
||||
|
||||
## 2) مفاهیم اصلی دامنه
|
||||
|
||||
### 2.1) SoilLocation
|
||||
|
||||
`SoilLocation` نماینده یک location اصلی برای یک مزرعه یا مرکز زمین است.
|
||||
|
||||
این مدل:
|
||||
- مختصات `latitude` و `longitude` را نگه میدارد
|
||||
- `farm_boundary` را ذخیره میکند
|
||||
- تعداد blockهای اولیه را نگه میدارد
|
||||
- `block_layout` را نگه میدارد
|
||||
- مبنای ارتباط با:
|
||||
- `SoilDepthData`
|
||||
- `BlockSubdivision`
|
||||
- `AnalysisGridCell`
|
||||
- `RemoteSensingRun`
|
||||
- `NdviObservation`
|
||||
|
||||
---
|
||||
|
||||
### 2.2) BlockSubdivision
|
||||
|
||||
`BlockSubdivision` نتیجه خردسازی یک block است.
|
||||
|
||||
این مدل نگه میدارد:
|
||||
- block code
|
||||
- مرز همان block
|
||||
- chunk size برای subdivision
|
||||
- grid points اولیه
|
||||
- centroid points نهایی
|
||||
- elbow plot
|
||||
- metadata الگوریتم
|
||||
|
||||
این مدل برای مرحلهای است که یک block را به بخشهای کوچکتر تقسیم میکنیم.
|
||||
|
||||
---
|
||||
|
||||
### 2.3) AnalysisGridCell
|
||||
|
||||
`AnalysisGridCell` سلولهای 30x30 متری تحلیل سنجشازدور را نگه میدارد.
|
||||
|
||||
هر cell:
|
||||
- به یک `SoilLocation` وصل است
|
||||
- در صورت نیاز به یک `BlockSubdivision` وصل است
|
||||
- یک `cell_code` یکتا دارد
|
||||
- geometry خودش را به صورت Polygon نگه میدارد
|
||||
- centroid خودش را نگه میدارد
|
||||
|
||||
این مدل واحد اصلی تحلیل remote sensing است.
|
||||
|
||||
---
|
||||
|
||||
### 2.4) AnalysisGridObservation
|
||||
|
||||
`AnalysisGridObservation` داده زمانی هر سلول را نگه میدارد.
|
||||
|
||||
برای هر cell و بازه زمانی:
|
||||
- `ndvi`
|
||||
- `ndwi`
|
||||
- `lst_c`
|
||||
- `soil_vv`
|
||||
- `soil_vv_db`
|
||||
- `dem_m`
|
||||
- `slope_deg`
|
||||
|
||||
ذخیره میشود.
|
||||
|
||||
این مدل cache دیتابیسی اصلی برای نتایج openEO است.
|
||||
|
||||
---
|
||||
|
||||
### 2.5) RemoteSensingRun
|
||||
|
||||
`RemoteSensingRun` وضعیت یک اجرای async سنجشازدور را نگه میدارد.
|
||||
|
||||
این مدل:
|
||||
- به `SoilLocation` وصل است
|
||||
- optionally به `BlockSubdivision` وصل است
|
||||
- `block_code` و بازه زمانی را نگه میدارد
|
||||
- status execution را نگه میدارد
|
||||
- metadata مربوط به task/backend/result summary را نگه میدارد
|
||||
|
||||
این مدل برای tracking jobها در Celery استفاده میشود.
|
||||
|
||||
---
|
||||
|
||||
### 2.6) SoilDepthData
|
||||
|
||||
این مدل دادههای خاک را در عمقهای مختلف نگه میدارد:
|
||||
- `0-5cm`
|
||||
- `5-15cm`
|
||||
- `15-30cm`
|
||||
|
||||
---
|
||||
|
||||
### 2.7) NdviObservation
|
||||
|
||||
این مدل نگهدارنده NDVI سنتی است که جدا از workflow جدید openEO هم هنوز وجود دارد.
|
||||
|
||||
---
|
||||
|
||||
## 3) ساختار فایلهای مهم اپ
|
||||
|
||||
```text
|
||||
location_data/
|
||||
├── admin.py
|
||||
├── apps.py
|
||||
├── block_subdivision.py
|
||||
├── grid_analysis.py
|
||||
├── models.py
|
||||
├── ndvi.py
|
||||
├── openeo_service.py
|
||||
├── remote_sensing.py
|
||||
├── serializers.py
|
||||
├── soil_adapters.py
|
||||
├── tasks.py
|
||||
├── urls.py
|
||||
├── views.py
|
||||
├── migrations/
|
||||
└── tests...
|
||||
```
|
||||
|
||||
### نقش فایلها
|
||||
|
||||
- `models.py`: مدلهای اصلی
|
||||
- `serializers.py`: serializerهای API
|
||||
- `views.py`: endpointهای DRF
|
||||
- `urls.py`: routeها
|
||||
- `tasks.py`: تسکهای Celery
|
||||
- `block_subdivision.py`: subdivision و elbow/kmeans
|
||||
- `grid_analysis.py`: ساخت analysis grid cells
|
||||
- `openeo_service.py`: لایه سرویس openEO
|
||||
- `remote_sensing.py`: منطق قدیمیتر سنجشازدور/NDVI ساده
|
||||
- `soil_adapters.py`: adapterهای داده خاک
|
||||
|
||||
---
|
||||
|
||||
## 4) تنظیمات مهم
|
||||
|
||||
### `SUBDIVISION_CHUNK_SQM`
|
||||
|
||||
در `config/settings.py`:
|
||||
|
||||
```python
|
||||
SUBDIVISION_CHUNK_SQM = int(os.environ.get("SUBDIVISION_CHUNK_SQM", "900"))
|
||||
```
|
||||
|
||||
مقدار پیشفرض فعلی:
|
||||
- `900`
|
||||
|
||||
معنا:
|
||||
- grid analysis با سلولهای `30m x 30m`
|
||||
|
||||
چون:
|
||||
|
||||
```text
|
||||
step_m = sqrt(900) = 30m
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) مدلهای دیتابیس و منطق آنها
|
||||
|
||||
## 5.1) SoilLocation
|
||||
|
||||
فیلدهای مهم:
|
||||
|
||||
- `latitude`
|
||||
- `longitude`
|
||||
- `task_id`
|
||||
- `farm_boundary`
|
||||
- `input_block_count`
|
||||
- `block_layout`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
### قید مهم
|
||||
|
||||
- `latitude + longitude` یکتا هستند
|
||||
|
||||
### block_layout
|
||||
|
||||
`block_layout` JSON summary کلی blockها را نگه میدارد.
|
||||
|
||||
نمونه:
|
||||
|
||||
```json
|
||||
{
|
||||
"input_block_count": 1,
|
||||
"default_full_farm": true,
|
||||
"algorithm_status": "completed",
|
||||
"blocks": [
|
||||
{
|
||||
"block_code": "block-1",
|
||||
"order": 1,
|
||||
"source": "default",
|
||||
"needs_subdivision": true,
|
||||
"sub_blocks": [
|
||||
{
|
||||
"sub_block_code": "sub-block-1",
|
||||
"centroid_lat": 35.689123,
|
||||
"centroid_lon": 51.389456
|
||||
}
|
||||
],
|
||||
"subdivision_summary": {
|
||||
"chunk_size_sqm": 900,
|
||||
"grid_point_count": 12,
|
||||
"centroid_count": 3,
|
||||
"optimal_k": 3
|
||||
},
|
||||
"analysis_grid_summary": {
|
||||
"chunk_size_sqm": 900,
|
||||
"cell_count": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`block_layout` canonical source نیست؛ بیشتر یک summary سریع برای API است.
|
||||
|
||||
---
|
||||
|
||||
## 5.2) BlockSubdivision
|
||||
|
||||
فیلدهای مهم:
|
||||
|
||||
- `soil_location`
|
||||
- `block_code`
|
||||
- `source_boundary`
|
||||
- `chunk_size_sqm`
|
||||
- `grid_points`
|
||||
- `centroid_points`
|
||||
- `grid_point_count`
|
||||
- `centroid_count`
|
||||
- `elbow_plot`
|
||||
- `status`
|
||||
- `metadata`
|
||||
|
||||
### نقش
|
||||
|
||||
برای هر `block_code` در هر location، نتیجه subdivision در این مدل ذخیره میشود.
|
||||
|
||||
### metadata
|
||||
|
||||
شامل مواردی مثل:
|
||||
- `estimated_area_sqm`
|
||||
- `optimal_k`
|
||||
- `inertia_curve`
|
||||
- `analysis_grid`
|
||||
|
||||
---
|
||||
|
||||
## 5.3) RemoteSensingRun
|
||||
|
||||
فیلدهای مهم:
|
||||
|
||||
- `soil_location`
|
||||
- `block_subdivision`
|
||||
- `block_code`
|
||||
- `provider`
|
||||
- `chunk_size_sqm`
|
||||
- `temporal_start`
|
||||
- `temporal_end`
|
||||
- `status`
|
||||
- `metadata`
|
||||
- `error_message`
|
||||
- `started_at`
|
||||
- `finished_at`
|
||||
|
||||
### statusها
|
||||
|
||||
- `pending`
|
||||
- `running`
|
||||
- `success`
|
||||
- `failure`
|
||||
|
||||
### نقش
|
||||
|
||||
این جدول وضعیت اجرای async را نگه میدارد.
|
||||
|
||||
---
|
||||
|
||||
## 5.4) AnalysisGridCell
|
||||
|
||||
فیلدهای مهم:
|
||||
|
||||
- `soil_location`
|
||||
- `block_subdivision`
|
||||
- `block_code`
|
||||
- `cell_code`
|
||||
- `chunk_size_sqm`
|
||||
- `geometry`
|
||||
- `centroid_lat`
|
||||
- `centroid_lon`
|
||||
|
||||
### نقش
|
||||
|
||||
واحد spatial اصلی برای تحلیل remote sensing است.
|
||||
|
||||
### idempotency
|
||||
|
||||
سطح سرویس با این شرط enforce میشود:
|
||||
- اگر برای یک `SoilLocation + block_code + chunk_size_sqm` cellها قبلاً ساخته شده باشند، دوباره ساخته نمیشوند.
|
||||
|
||||
### geometry
|
||||
|
||||
به صورت GeoJSON-like polygon ذخیره میشود.
|
||||
|
||||
---
|
||||
|
||||
## 5.5) AnalysisGridObservation
|
||||
|
||||
فیلدهای مهم:
|
||||
|
||||
- `cell`
|
||||
- `run`
|
||||
- `temporal_start`
|
||||
- `temporal_end`
|
||||
- `ndvi`
|
||||
- `ndwi`
|
||||
- `lst_c`
|
||||
- `soil_vv`
|
||||
- `soil_vv_db`
|
||||
- `dem_m`
|
||||
- `slope_deg`
|
||||
- `metadata`
|
||||
|
||||
### uniqueness
|
||||
|
||||
برای جلوگیری از duplicate:
|
||||
- روی `cell + temporal_start + temporal_end` constraint داریم.
|
||||
|
||||
این باعث میشود cache دیتابیسی پایدار باشد.
|
||||
|
||||
---
|
||||
|
||||
## 5.6) SoilDepthData
|
||||
|
||||
این مدل دادههای خاک را در عمقهای مختلف نگه میدارد.
|
||||
|
||||
هنوز به صورت مستقیم برای هر analysis grid cell جداگانه استفاده نشده است.
|
||||
|
||||
---
|
||||
|
||||
## 5.7) NdviObservation
|
||||
|
||||
این مدل legacy / parallel NDVI store است.
|
||||
|
||||
workflow جدید openEO جایگزین آن نشده، بلکه کنار آن وجود دارد.
|
||||
|
||||
---
|
||||
|
||||
## 6) منطق subdivision در `block_subdivision.py`
|
||||
|
||||
این فایل مسئول خردسازی blockها است.
|
||||
|
||||
### کارهایی که انجام میدهد
|
||||
|
||||
- استخراج polygon از boundary
|
||||
- تبدیل مختصات جغرافیایی به مختصات محلی متری
|
||||
- تولید grid points اولیه
|
||||
- اجرای KMeans برای `K=1..10`
|
||||
- محاسبه SSE/Inertia
|
||||
- پیدا کردن elbow point
|
||||
- انتخاب centroidها
|
||||
- رسم elbow plot با matplotlib
|
||||
- ذخیره plot در `ImageField`
|
||||
- sync کردن نتیجه با `block_layout`
|
||||
|
||||
### input
|
||||
|
||||
ممکن است boundary به شکلهای زیر برسد:
|
||||
- GeoJSON Polygon
|
||||
- corners
|
||||
- list مستقیم از points
|
||||
|
||||
### خروجی
|
||||
|
||||
- centroidهای نهایی block
|
||||
- metadata الگوریتم
|
||||
- elbow plot
|
||||
|
||||
---
|
||||
|
||||
## 7) منطق ساخت analysis grid در `grid_analysis.py`
|
||||
|
||||
این فایل مسئول تولید سلولهای 30x30 متری برای تحلیل remote sensing است.
|
||||
|
||||
### تابع اصلی
|
||||
|
||||
- `create_or_get_analysis_grid_cells(...)`
|
||||
|
||||
### ورودیها
|
||||
|
||||
- `location`
|
||||
- optional `boundary`
|
||||
- optional `block_code`
|
||||
- optional `block_subdivision`
|
||||
- optional `chunk_size_sqm`
|
||||
|
||||
### رفتار
|
||||
|
||||
1. chunk size را تعیین میکند
|
||||
2. boundary را resolve میکند
|
||||
3. polygon را extract میکند
|
||||
4. اگر قبلاً برای همان `location + block_code + chunk_size` cell ساخته شده باشد، خروجی existing برمیگرداند
|
||||
5. اگر نه، grid cellها ساخته میشوند و `AnalysisGridCell` ذخیره میشود
|
||||
|
||||
### نحوه ساخت شبکه
|
||||
|
||||
- polygon به دستگاه محلی متری تبدیل میشود
|
||||
- `step_m = sqrt(chunk_size_sqm)` محاسبه میشود
|
||||
- یک grid مستطیلی روی bounding box ساخته میشود
|
||||
- هر cell که با polygon intersect داشته باشد نگه داشته میشود
|
||||
|
||||
### cell_code
|
||||
|
||||
فرمت فعلی deterministic است:
|
||||
|
||||
```text
|
||||
loc-{location_id}__block-{block_code}__chunk-{chunk_size_sqm}__rXXXXcYYYY
|
||||
```
|
||||
|
||||
### metadata summary
|
||||
|
||||
پس از ساخت grid:
|
||||
- روی `BlockSubdivision.metadata["analysis_grid"]`
|
||||
- و روی `SoilLocation.block_layout`
|
||||
|
||||
summary ذخیره میشود.
|
||||
|
||||
---
|
||||
|
||||
## 8) منطق openEO در `openeo_service.py`
|
||||
|
||||
این فایل لایه service اصلی برای تحلیل openEO است.
|
||||
|
||||
### backend
|
||||
|
||||
```text
|
||||
https://openeofed.dataspace.copernicus.eu
|
||||
```
|
||||
|
||||
### هدف
|
||||
|
||||
گرفتن batch metricها برای مجموعهای از `AnalysisGridCell`ها.
|
||||
|
||||
### جریان کلی
|
||||
|
||||
1. اتصال و auth به openEO
|
||||
2. ساخت `FeatureCollection` از cellها
|
||||
3. ساخت `spatial_extent`
|
||||
4. اجرای یک job per metric روی همه cellها
|
||||
5. parse کردن نتیجه aggregate_spatial
|
||||
6. merge کردن metricها روی map keyed by `cell_code`
|
||||
|
||||
### metricهای فعلی
|
||||
|
||||
- `ndvi` از `SENTINEL2_L2A`
|
||||
- `ndwi` از `SENTINEL2_L2A`
|
||||
- `lst_c` از `SENTINEL3_SLSTR_L2_LST`
|
||||
- `soil_vv` از `SENTINEL1_GRD`
|
||||
- `soil_vv_db` در Python از `soil_vv`
|
||||
- `dem_m` از `COPERNICUS_30`
|
||||
- `slope_deg` از DEM اگر backend پشتیبانی کند
|
||||
|
||||
### cloud mask Sentinel-2
|
||||
|
||||
کلاسهای معتبر SCL:
|
||||
- `4`
|
||||
- `5`
|
||||
- `6`
|
||||
|
||||
نکته مهم:
|
||||
- از `isin()` استفاده نمیشود
|
||||
- فقط logical comparison استفاده میشود
|
||||
|
||||
### aggregate_spatial
|
||||
|
||||
فقط از:
|
||||
|
||||
```python
|
||||
aggregate_spatial(geometries=feature_collection, reducer="mean")
|
||||
```
|
||||
|
||||
استفاده میشود.
|
||||
|
||||
### slope support
|
||||
|
||||
اگر backend `slope()` را پشتیبانی نکند:
|
||||
- `slope_deg = null`
|
||||
- و metadata میگوید `slope_supported=False`
|
||||
|
||||
### normalized output
|
||||
|
||||
خروجی نهایی به این شکل است:
|
||||
|
||||
```python
|
||||
{
|
||||
"results": {
|
||||
"cell-1": {
|
||||
"ndvi": ...,
|
||||
"ndwi": ...,
|
||||
"lst_c": ...,
|
||||
"soil_vv": ...,
|
||||
"soil_vv_db": ...,
|
||||
"dem_m": ...,
|
||||
"slope_deg": ...,
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"backend": "openeo",
|
||||
"collections_used": [...],
|
||||
"slope_supported": True,
|
||||
"job_refs": {},
|
||||
"failed_metrics": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9) Celery workflow در `tasks.py`
|
||||
|
||||
### تسک قدیمی
|
||||
|
||||
- `fetch_soil_data_task`
|
||||
|
||||
برای خاک legacy است.
|
||||
|
||||
### workflow جدید remote sensing
|
||||
|
||||
تابع/تسکهای اصلی:
|
||||
|
||||
- `run_remote_sensing_analysis(...)`
|
||||
- `run_remote_sensing_analysis_task.delay(...)`
|
||||
|
||||
### ورودی task
|
||||
|
||||
- `soil_location_id`
|
||||
- optional `block_code`
|
||||
- `temporal_start`
|
||||
- `temporal_end`
|
||||
- optional `force_refresh`
|
||||
- optional `run_id`
|
||||
|
||||
### رفتار task
|
||||
|
||||
1. `SoilLocation` را پیدا میکند
|
||||
2. `BlockSubdivision` را اگر لازم باشد resolve میکند
|
||||
3. `RemoteSensingRun` را create/update میکند
|
||||
4. `AnalysisGridCell`ها را ensure میکند
|
||||
5. اگر observation برای همان range قبلاً باشد و `force_refresh=False`، دوباره process نمیکند
|
||||
6. در غیر این صورت، `compute_remote_sensing_metrics()` را صدا میزند
|
||||
7. `AnalysisGridObservation`ها را upsert میکند
|
||||
8. status run را success/failure میکند
|
||||
|
||||
### idempotency
|
||||
|
||||
اگر observation قبلاً برای همان:
|
||||
- cell
|
||||
- temporal_start
|
||||
- temporal_end
|
||||
|
||||
وجود داشته باشد، duplicate ساخته نمیشود.
|
||||
|
||||
### retry behavior
|
||||
|
||||
task روی خطاهای transient مثل:
|
||||
- `OpenEOExecutionError`
|
||||
- `OpenEOServiceError`
|
||||
- request-level failures
|
||||
|
||||
retry میکند.
|
||||
|
||||
روی auth failure retry نمیکند.
|
||||
|
||||
---
|
||||
|
||||
## 10) APIهای فعلی `location_data`
|
||||
|
||||
## 10.1) `GET /api/soil-data/`
|
||||
|
||||
کاربرد:
|
||||
- فقط اطلاعات ذخیرهشده location را برمیگرداند
|
||||
- subdivision را rerun نمیکند
|
||||
|
||||
ورودی:
|
||||
- `lat`
|
||||
- `lon`
|
||||
- optional `block_code`
|
||||
|
||||
خروجی:
|
||||
- location data
|
||||
- block layout
|
||||
- block subdivisions
|
||||
- depths
|
||||
|
||||
---
|
||||
|
||||
## 10.2) `POST /api/soil-data/`
|
||||
|
||||
کاربرد:
|
||||
- `SoilLocation` را create/get میکند
|
||||
- در صورت نیاز `BlockSubdivision` میسازد
|
||||
|
||||
ورودی:
|
||||
- `lat`
|
||||
- `lon`
|
||||
- `block_count`
|
||||
- `block_code`
|
||||
- `farm_boundary`
|
||||
|
||||
خروجی:
|
||||
- location کامل
|
||||
- `source` = `created` یا `database`
|
||||
|
||||
---
|
||||
|
||||
## 10.3) `GET /api/soil-data/tasks/<task_id>/status/`
|
||||
|
||||
کاربرد:
|
||||
- status task قدیمی fetch خاک
|
||||
|
||||
---
|
||||
|
||||
## 10.4) `POST /api/soil-data/ndvi-health/`
|
||||
|
||||
کاربرد:
|
||||
- NDVI health مستقل برای farm
|
||||
|
||||
---
|
||||
|
||||
## 10.5) `POST /api/soil-data/remote-sensing/`
|
||||
|
||||
کاربرد:
|
||||
- remote sensing analysis را queue میکند
|
||||
- heavy work را sync اجرا نمیکند
|
||||
|
||||
ورودی:
|
||||
- `lat`
|
||||
- `lon`
|
||||
- optional `block_code`
|
||||
- `start_date`
|
||||
- `end_date`
|
||||
- optional `force_refresh`
|
||||
|
||||
رفتار:
|
||||
1. location را پیدا میکند
|
||||
2. run میسازد
|
||||
3. Celery task را enqueue میکند
|
||||
4. `202 Accepted` برمیگرداند
|
||||
|
||||
خروجی شامل:
|
||||
- `status=processing`
|
||||
- `source=processing`
|
||||
- `location`
|
||||
- `block_code`
|
||||
- `chunk_size_sqm`
|
||||
- `temporal_extent`
|
||||
- `summary` خالی
|
||||
- `cells=[]`
|
||||
- `run`
|
||||
- `task_id`
|
||||
|
||||
---
|
||||
|
||||
## 10.6) `GET /api/soil-data/remote-sensing/`
|
||||
|
||||
کاربرد:
|
||||
- فقط cache دیتابیسی remote sensing را میخواند
|
||||
- هیچ openEO یا subdivision sync اجرا نمیکند
|
||||
|
||||
ورودی:
|
||||
- `lat`
|
||||
- `lon`
|
||||
- optional `block_code`
|
||||
- `start_date`
|
||||
- `end_date`
|
||||
|
||||
خروجی حالتها:
|
||||
|
||||
### حالت 1: result موجود است
|
||||
- `status=success`
|
||||
- `source=database`
|
||||
- summary metrics
|
||||
- cells list
|
||||
- run info
|
||||
|
||||
### حالت 2: result هنوز نیست ولی job در حال اجراست
|
||||
- `status=processing`
|
||||
- `source=processing`
|
||||
- summary خالی
|
||||
- cells empty
|
||||
- run info
|
||||
|
||||
### حالت 3: location نیست
|
||||
- `404`
|
||||
|
||||
---
|
||||
|
||||
## 11) serializerهای مهم
|
||||
|
||||
### `SoilDataRequestSerializer`
|
||||
برای endpoint اصلی location.
|
||||
|
||||
### `SoilLocationResponseSerializer`
|
||||
برای بازگشت location + blocks + depths.
|
||||
|
||||
### `BlockSubdivisionSerializer`
|
||||
برای بازگشت subdivision data.
|
||||
|
||||
### `RemoteSensingTriggerSerializer`
|
||||
برای trigger API remote sensing.
|
||||
|
||||
### `RemoteSensingCellObservationSerializer`
|
||||
برای بازگشت per-cell remote sensing metrics.
|
||||
|
||||
### `RemoteSensingSummarySerializer`
|
||||
برای بازگشت summary statisticها.
|
||||
|
||||
### `RemoteSensingRunSerializer`
|
||||
برای بازگشت status run.
|
||||
|
||||
### `RemoteSensingResponseSerializer`
|
||||
برای payload کامل remote sensing GET.
|
||||
|
||||
---
|
||||
|
||||
## 12) منطق summary statistics در remote sensing GET
|
||||
|
||||
در response مربوط به `GET /remote-sensing/` این فیلدها برمیگردند:
|
||||
|
||||
- `cell_count`
|
||||
- `ndvi_mean`
|
||||
- `ndwi_mean`
|
||||
- `lst_c_mean`
|
||||
- `soil_vv_db_mean`
|
||||
- `dem_m_mean`
|
||||
- `slope_deg_mean`
|
||||
|
||||
اینها از روی observationهای موجود در DB محاسبه میشوند، نه از openEO live.
|
||||
|
||||
---
|
||||
|
||||
## 13) admin
|
||||
|
||||
در `admin.py` الان موارد زیر رجیستر شدهاند:
|
||||
|
||||
- `SoilLocation`
|
||||
- `SoilDepthData`
|
||||
- `BlockSubdivision`
|
||||
- `RemoteSensingRun`
|
||||
- `AnalysisGridCell`
|
||||
- `AnalysisGridObservation`
|
||||
|
||||
این باعث میشود debugging و inspection از طریق admin ممکن باشد.
|
||||
|
||||
---
|
||||
|
||||
## 14) تستهای فعلی
|
||||
|
||||
### `test_soil_api.py`
|
||||
- ساخت location
|
||||
- ساخت subdivision
|
||||
- رفتار GET/POST location
|
||||
|
||||
### `test_block_subdivision.py`
|
||||
- elbow detection
|
||||
- payload subdivision
|
||||
|
||||
### `test_grid_analysis.py`
|
||||
- ساخت analysis grid 30x30
|
||||
- idempotency grid cells
|
||||
- استفاده از boundary location
|
||||
|
||||
### `test_openeo_service.py`
|
||||
- parse نتیجه aggregate_spatial
|
||||
- merge metricها
|
||||
- conversion به dB
|
||||
|
||||
### `test_remote_sensing_api.py`
|
||||
- queue شدن remote sensing task
|
||||
- processing response
|
||||
- cache read response
|
||||
- not found behavior
|
||||
|
||||
### `test_ndvi_health_api.py`
|
||||
- NDVI health API
|
||||
|
||||
---
|
||||
|
||||
## 15) وابستگیهای مهم
|
||||
|
||||
در `requirements.txt` dependencyهای مهم این بخشها شامل اینها هستند:
|
||||
|
||||
- `scikit-learn`
|
||||
- `matplotlib`
|
||||
- `Pillow`
|
||||
- `numpy`
|
||||
- `openeo`
|
||||
|
||||
### نقش آنها
|
||||
|
||||
- `scikit-learn`: KMeans
|
||||
- `matplotlib`: elbow plot
|
||||
- `Pillow`: ImageField support
|
||||
- `numpy`: وابستگی عددی
|
||||
- `openeo`: ارتباط با backend سنجشازدور
|
||||
|
||||
---
|
||||
|
||||
## 16) migrationهای مهم
|
||||
|
||||
- `0008_soillocation_block_layout.py`
|
||||
- `0009_blocksubdivision.py`
|
||||
- `0010_blocksubdivision_elbow_plot.py`
|
||||
- `0011_remote_sensing_models.py`
|
||||
|
||||
این migrationها ساختار فعلی location/subdivision/remote sensing را ساختهاند.
|
||||
|
||||
---
|
||||
|
||||
## 17) محدودیتها و فرضیات فعلی
|
||||
|
||||
### محدودیتهای فعلی
|
||||
|
||||
1. `block_layout` canonical source نیست و summary است.
|
||||
2. subdivision و analysis grid دو لایه جدا هستند.
|
||||
3. slope ممکن است روی backend همیشه پشتیبانی نشود.
|
||||
4. API GET remote-sensing فقط cache میخواند.
|
||||
5. هنوز endpoint مجزای status run نداریم.
|
||||
6. grid generation از projection محلی استفاده میکند، نه GIS stack سنگین.
|
||||
7. openEO calls فعلاً برای batch metric processing طراحی شدهاند، نه orchestration پیچیده job lifecycle.
|
||||
|
||||
### فرضیات
|
||||
|
||||
1. مزرعهها آنقدر کوچک هستند که local projected approximation مناسب باشد.
|
||||
2. `SUBDIVISION_CHUNK_SQM=900` برای workflow فعلی درست است.
|
||||
3. `cell_code` deterministic بودن برای idempotency کافی است.
|
||||
4. `AnalysisGridObservation` cache اصلی remote sensing است.
|
||||
|
||||
---
|
||||
|
||||
## 18) جریان کامل داده از ابتدا تا نتیجه remote sensing
|
||||
|
||||
### مرحله 1: ایجاد location
|
||||
|
||||
کاربر `POST /api/soil-data/` را صدا میزند.
|
||||
|
||||
نتیجه:
|
||||
- `SoilLocation` ساخته میشود
|
||||
- `farm_boundary` ذخیره میشود
|
||||
- block layout ساخته میشود
|
||||
- در صورت نیاز `BlockSubdivision` ساخته میشود
|
||||
|
||||
### مرحله 2: تولید analysis grid
|
||||
|
||||
وقتی task remote sensing اجرا میشود:
|
||||
- اگر cellها قبلاً نباشند، `AnalysisGridCell`ها ساخته میشوند
|
||||
|
||||
### مرحله 3: اجرای openEO
|
||||
|
||||
Celery task:
|
||||
- FeatureCollection از cellها میسازد
|
||||
- metricها را batch اجرا میکند
|
||||
- نتیجه را parse میکند
|
||||
|
||||
### مرحله 4: ذخیره observation
|
||||
|
||||
برای هر cell:
|
||||
- یک `AnalysisGridObservation` برای بازه زمانی موردنظر ذخیره/آپدیت میشود
|
||||
|
||||
### مرحله 5: بازگشت نتیجه از API
|
||||
|
||||
کاربر `GET /api/soil-data/remote-sensing/` را صدا میزند.
|
||||
|
||||
سیستم:
|
||||
- فقط DB را میخواند
|
||||
- summary میسازد
|
||||
- cells را برمیگرداند
|
||||
|
||||
---
|
||||
|
||||
## 19) پیشنهاد توسعه بعدی
|
||||
|
||||
برای ادامه توسعه، اینها منطقیترین قدمها هستند:
|
||||
|
||||
1. ساخت endpoint مستقل status برای `RemoteSensingRun`
|
||||
2. اضافه کردن pagination برای cell responseها
|
||||
3. اضافه کردن job reference واقعی openEO در metadata
|
||||
4. پشتیبانی از چند resolution دیگر غیر از 30x30
|
||||
5. ساخت serializer/model جدا برای summaryهای precomputed
|
||||
6. اضافه کردن نمودارها یا aggregationهای block-level
|
||||
7. اتصال remote sensing resultها به recommendation engine
|
||||
|
||||
---
|
||||
|
||||
## 20) جمعبندی نهایی
|
||||
|
||||
اپ `location_data` الان یک سیستم چندلایه است:
|
||||
|
||||
### لایه مکانی پایه
|
||||
- `SoilLocation`
|
||||
- `farm_boundary`
|
||||
- `block_layout`
|
||||
|
||||
### لایه subdivision
|
||||
- `BlockSubdivision`
|
||||
- KMeans
|
||||
- elbow plot
|
||||
|
||||
### لایه grid analysis
|
||||
- `AnalysisGridCell`
|
||||
|
||||
### لایه observation
|
||||
- `AnalysisGridObservation`
|
||||
- `RemoteSensingRun`
|
||||
|
||||
### لایه سرویس
|
||||
- `block_subdivision.py`
|
||||
- `grid_analysis.py`
|
||||
- `openeo_service.py`
|
||||
- `tasks.py`
|
||||
|
||||
### لایه API
|
||||
- `SoilDataView`
|
||||
- `RemoteSensingAnalysisView`
|
||||
- `NdviHealthView`
|
||||
|
||||
در نتیجه، `location_data` الان از یک app ساده location عبور کرده و به یک زیرسیستم کامل spatial + remote sensing تبدیل شده است.
|
||||
Reference in New Issue
Block a user