22 KiB
مستند کامل اپ location_data
این سند، وضعیت فعلی اپ location_data را به صورت کامل توضیح میدهد:
- مدلهای داده
- منطق business
- جریان ساخت location و block
- subdivision و خوشهبندی
- تولید analysis grid
- سنجشازدور با openEO
- تسکهای Celery
- APIهای فعلی
- ساختار responseها
- محدودیتها و فرضیات فعلی
این فایل بر اساس کد فعلی پروژه نوشته شده است و هدفش این است که یک مرجع فنی برای توسعهدهندههای بعدی باشد.
1) هدف اپ location_data
اپ location_data در وضعیت فعلی چند نقش اصلی دارد:
- نگهداری موقعیت جغرافیایی زمین با
lat/lon - نگهداری مرز زمین یا مرز blockها
- ساخت ساختار blockهای مزرعه
- اجرای subdivision برای blockها
- تولید grid analysis با ابعاد 30x30 متر
- نگهداری نتایج سنجشازدور روی هر grid cell
- نگهداری دادههای خاک و NDVI سنتی
- فراهم کردن 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را نگه میدارد- مبنای ارتباط با:
SoilDepthDataBlockSubdivisionAnalysisGridCellRemoteSensingRunNdviObservation
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 و بازه زمانی:
ndvindwilst_csoil_vvsoil_vv_dbdem_mslope_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-5cm5-15cm15-30cm
2.7) NdviObservation
این مدل نگهدارنده NDVI سنتی است که جدا از workflow جدید openEO هم هنوز وجود دارد.
3) ساختار فایلهای مهم اپ
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های APIviews.py: endpointهای DRFurls.py: routeهاtasks.py: تسکهای Celeryblock_subdivision.py: subdivision و elbow/kmeansgrid_analysis.py: ساخت analysis grid cellsopeneo_service.py: لایه سرویس openEOremote_sensing.py: منطق قدیمیتر سنجشازدور/NDVI سادهsoil_adapters.py: adapterهای داده خاک
4) تنظیمات مهم
SUBDIVISION_CHUNK_SQM
در config/settings.py:
SUBDIVISION_CHUNK_SQM = int(os.environ.get("SUBDIVISION_CHUNK_SQM", "900"))
مقدار پیشفرض فعلی:
900
معنا:
- grid analysis با سلولهای
30m x 30m
چون:
step_m = sqrt(900) = 30m
5) مدلهای دیتابیس و منطق آنها
5.1) SoilLocation
فیلدهای مهم:
latitudelongitudetask_idfarm_boundaryinput_block_countblock_layoutcreated_atupdated_at
قید مهم
latitude + longitudeیکتا هستند
block_layout
block_layout JSON summary کلی blockها را نگه میدارد.
نمونه:
{
"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_locationblock_codesource_boundarychunk_size_sqmgrid_pointscentroid_pointsgrid_point_countcentroid_countelbow_plotstatusmetadata
نقش
برای هر block_code در هر location، نتیجه subdivision در این مدل ذخیره میشود.
metadata
شامل مواردی مثل:
estimated_area_sqmoptimal_kinertia_curveanalysis_grid
5.3) RemoteSensingRun
فیلدهای مهم:
soil_locationblock_subdivisionblock_codeproviderchunk_size_sqmtemporal_starttemporal_endstatusmetadataerror_messagestarted_atfinished_at
statusها
pendingrunningsuccessfailure
نقش
این جدول وضعیت اجرای async را نگه میدارد.
5.4) AnalysisGridCell
فیلدهای مهم:
soil_locationblock_subdivisionblock_codecell_codechunk_size_sqmgeometrycentroid_latcentroid_lon
نقش
واحد spatial اصلی برای تحلیل remote sensing است.
idempotency
سطح سرویس با این شرط enforce میشود:
- اگر برای یک
SoilLocation + block_code + chunk_size_sqmcellها قبلاً ساخته شده باشند، دوباره ساخته نمیشوند.
geometry
به صورت GeoJSON-like polygon ذخیره میشود.
5.5) AnalysisGridObservation
فیلدهای مهم:
cellruntemporal_starttemporal_endndvindwilst_csoil_vvsoil_vv_dbdem_mslope_degmetadata
uniqueness
برای جلوگیری از duplicate:
- روی
cell + temporal_start + temporal_endconstraint داریم.
این باعث میشود 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
رفتار
- chunk size را تعیین میکند
- boundary را resolve میکند
- polygon را extract میکند
- اگر قبلاً برای همان
location + block_code + chunk_sizecell ساخته شده باشد، خروجی existing برمیگرداند - اگر نه، grid cellها ساخته میشوند و
AnalysisGridCellذخیره میشود
نحوه ساخت شبکه
- polygon به دستگاه محلی متری تبدیل میشود
step_m = sqrt(chunk_size_sqm)محاسبه میشود- یک grid مستطیلی روی bounding box ساخته میشود
- هر cell که با polygon intersect داشته باشد نگه داشته میشود
cell_code
فرمت فعلی deterministic است:
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
https://openeofed.dataspace.copernicus.eu
هدف
گرفتن batch metricها برای مجموعهای از AnalysisGridCellها.
جریان کلی
- اتصال و auth به openEO
- ساخت
FeatureCollectionاز cellها - ساخت
spatial_extent - اجرای یک job per metric روی همه cellها
- parse کردن نتیجه aggregate_spatial
- merge کردن metricها روی map keyed by
cell_code
metricهای فعلی
ndviازSENTINEL2_L2AndwiازSENTINEL2_L2Alst_cازSENTINEL3_SLSTR_L2_LSTsoil_vvازSENTINEL1_GRDsoil_vv_dbدر Python ازsoil_vvdem_mازCOPERNICUS_30slope_degاز DEM اگر backend پشتیبانی کند
cloud mask Sentinel-2
کلاسهای معتبر SCL:
456
نکته مهم:
- از
isin()استفاده نمیشود - فقط logical comparison استفاده میشود
aggregate_spatial
فقط از:
aggregate_spatial(geometries=feature_collection, reducer="mean")
استفاده میشود.
slope support
اگر backend slope() را پشتیبانی نکند:
slope_deg = null- و metadata میگوید
slope_supported=False
normalized output
خروجی نهایی به این شکل است:
{
"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_starttemporal_end- optional
force_refresh - optional
run_id
رفتار task
SoilLocationرا پیدا میکندBlockSubdivisionرا اگر لازم باشد resolve میکندRemoteSensingRunرا create/update میکندAnalysisGridCellها را ensure میکند- اگر observation برای همان range قبلاً باشد و
force_refresh=False، دوباره process نمیکند - در غیر این صورت،
compute_remote_sensing_metrics()را صدا میزند AnalysisGridObservationها را upsert میکند- status run را success/failure میکند
idempotency
اگر observation قبلاً برای همان:
- cell
- temporal_start
- temporal_end
وجود داشته باشد، duplicate ساخته نمیشود.
retry behavior
task روی خطاهای transient مثل:
OpenEOExecutionErrorOpenEOServiceError- request-level failures
retry میکند.
روی auth failure retry نمیکند.
10) APIهای فعلی location_data
10.1) GET /api/soil-data/
کاربرد:
- فقط اطلاعات ذخیرهشده location را برمیگرداند
- subdivision را rerun نمیکند
ورودی:
latlon- optional
block_code
خروجی:
- location data
- block layout
- block subdivisions
- depths
10.2) POST /api/soil-data/
کاربرد:
SoilLocationرا create/get میکند- در صورت نیاز
BlockSubdivisionمیسازد
ورودی:
latlonblock_countblock_codefarm_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 اجرا نمیکند
ورودی:
latlon- optional
block_code start_dateend_date- optional
force_refresh
رفتار:
- location را پیدا میکند
- run میسازد
- Celery task را enqueue میکند
202 Acceptedبرمیگرداند
خروجی شامل:
status=processingsource=processinglocationblock_codechunk_size_sqmtemporal_extentsummaryخالیcells=[]runtask_id
10.6) GET /api/soil-data/remote-sensing/
کاربرد:
- فقط cache دیتابیسی remote sensing را میخواند
- هیچ openEO یا subdivision sync اجرا نمیکند
ورودی:
latlon- optional
block_code start_dateend_date
خروجی حالتها:
حالت 1: result موجود است
status=successsource=database- summary metrics
- cells list
- run info
حالت 2: result هنوز نیست ولی job در حال اجراست
status=processingsource=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_countndvi_meanndwi_meanlst_c_meansoil_vv_db_meandem_m_meanslope_deg_mean
اینها از روی observationهای موجود در DB محاسبه میشوند، نه از openEO live.
13) admin
در admin.py الان موارد زیر رجیستر شدهاند:
SoilLocationSoilDepthDataBlockSubdivisionRemoteSensingRunAnalysisGridCellAnalysisGridObservation
این باعث میشود 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-learnmatplotlibPillownumpyopeneo
نقش آنها
scikit-learn: KMeansmatplotlib: elbow plotPillow: ImageField supportnumpy: وابستگی عددیopeneo: ارتباط با backend سنجشازدور
16) migrationهای مهم
0008_soillocation_block_layout.py0009_blocksubdivision.py0010_blocksubdivision_elbow_plot.py0011_remote_sensing_models.py
این migrationها ساختار فعلی location/subdivision/remote sensing را ساختهاند.
17) محدودیتها و فرضیات فعلی
محدودیتهای فعلی
block_layoutcanonical source نیست و summary است.- subdivision و analysis grid دو لایه جدا هستند.
- slope ممکن است روی backend همیشه پشتیبانی نشود.
- API GET remote-sensing فقط cache میخواند.
- هنوز endpoint مجزای status run نداریم.
- grid generation از projection محلی استفاده میکند، نه GIS stack سنگین.
- openEO calls فعلاً برای batch metric processing طراحی شدهاند، نه orchestration پیچیده job lifecycle.
فرضیات
- مزرعهها آنقدر کوچک هستند که local projected approximation مناسب باشد.
SUBDIVISION_CHUNK_SQM=900برای workflow فعلی درست است.cell_codedeterministic بودن برای idempotency کافی است.AnalysisGridObservationcache اصلی 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) پیشنهاد توسعه بعدی
برای ادامه توسعه، اینها منطقیترین قدمها هستند:
- ساخت endpoint مستقل status برای
RemoteSensingRun - اضافه کردن pagination برای cell responseها
- اضافه کردن job reference واقعی openEO در metadata
- پشتیبانی از چند resolution دیگر غیر از 30x30
- ساخت serializer/model جدا برای summaryهای precomputed
- اضافه کردن نمودارها یا aggregationهای block-level
- اتصال remote sensing resultها به recommendation engine
20) جمعبندی نهایی
اپ location_data الان یک سیستم چندلایه است:
لایه مکانی پایه
SoilLocationfarm_boundaryblock_layout
لایه subdivision
BlockSubdivision- KMeans
- elbow plot
لایه grid analysis
AnalysisGridCell
لایه observation
AnalysisGridObservationRemoteSensingRun
لایه سرویس
block_subdivision.pygrid_analysis.pyopeneo_service.pytasks.py
لایه API
SoilDataViewRemoteSensingAnalysisViewNdviHealthView
در نتیجه، location_data الان از یک app ساده location عبور کرده و به یک زیرسیستم کامل spatial + remote sensing تبدیل شده است.