def clean(self, *args, **kwargs): # add custom validation here print(self.geo_field, '\n New line') geos_field = GEOSGeometry(self.geo_field) print(self.geo_field, '\n New line') farm_s = farm.objects.get(farm_name=self.farm) geos_farm = GEOSGeometry(farm_s.geo_farm) if not ( geos_field.within(geos_farm) ): # GEOS method check if field is within the farm, returns a T or F. raise ValidationError(_('Field is not inside the selected farm'), #params={'farm': farm_s.farm_name }, ) super(field, self).clean(*args, **kwargs)
def point_source_pollution(geojson): """ Given a GeoJSON shape, retrieve point source pollution data from the `ms_pointsource` or `ms_pointsource_drb` table to display in the Analyze tab. Returns a dictionary to append to the outgoing JSON for analysis results. """ geom = GEOSGeometry(geojson, srid=4326) drb = geom.within(DRB) table_name = get_point_source_table(drb) sql = ''' SELECT city, state, npdes_id, mgd, kgn_yr, kgp_yr, latitude, longitude, {facilityname} FROM {table_name} WHERE ST_Intersects(geom, ST_SetSRID(ST_GeomFromText(%s), 4326)) '''.format(facilityname='facilityname' if drb else 'null', table_name=table_name) with connection.cursor() as cursor: cursor.execute(sql, [geom.wkt]) if cursor.rowcount != 0: columns = [col[0] for col in cursor.description] point_source_results = [ dict( zip(columns, [ row[0], row[1], row[2], float(row[3]) if row[3] else None, float(row[4]) if row[4] else None, float(row[5]) if row[5] else None, float(row[6]) if row[6] else None, float(row[7]) if row[7] else None, row[8] ])) for row in cursor.fetchall() ] else: point_source_results = [] return { 'displayName': 'Point Source', 'name': 'pointsource', 'categories': point_source_results }
def collect_data(geop_results, geojson, watershed_id=None, weather=None): geop_result = {k: v for r in geop_results for k, v in r.items()} geom = GEOSGeometry(geojson, srid=4326) area = geom.transform(5070, clone=True).area # Square Meters # Data Model is called z by convention z = settings.GWLFE_DEFAULTS.copy() z['watershed_id'] = watershed_id # Statically calculated lookup values z['DayHrs'] = day_lengths(geom) # Data from the Weather Stations dataset if weather is not None: ws, wd = weather else: ws = nearest_weather_stations([(None, watershed_id, geojson)]) z['Grow'] = growing_season(ws) z['Acoef'] = erosion_coeff(ws, z['Grow']) z['PcntET'] = et_adjustment(ws) z['WxYrBeg'] = int(max([w.begyear for w in ws])) z['WxYrEnd'] = int(min([w.endyear for w in ws])) z['WxYrs'] = z['WxYrEnd'] - z['WxYrBeg'] + 1 # Data from the County Animals dataset ag_lscp = ag_ls_c_p(geom) z['C'][0] = ag_lscp.hp_c z['C'][1] = ag_lscp.crop_c livestock_aeu, poultry_aeu, population = animal_energy_units(geom) z['AEU'] = livestock_aeu / (area * ACRES_PER_SQM) z['n41j'] = livestock_aeu z['n41k'] = poultry_aeu z['n41l'] = livestock_aeu + poultry_aeu z['NumAnimals'] = [int(population.get(animal, 0)) for animal in ANIMAL_KEYS] z['ManNitr'], z['ManPhos'] = manure_spread(z['AEU']) # Data from Streams dataset z['StreamLength'] = stream_length(geom) or 10 # Meters z['n42b'] = round(z['StreamLength'] / 1000, 1) # Kilometers # Data from Point Source Discharge dataset n_load, p_load, discharge = point_source_discharge(geom, area, drb=geom.within(DRB)) z['PointNitr'] = n_load z['PointPhos'] = p_load z['PointFlow'] = discharge # Data from National Weather dataset if weather is None: wd = weather_data(ws, z['WxYrBeg'], z['WxYrEnd']) temps_dict, prcps_dict = wd temps = average_weather_data(temps_dict.values()) prcps = average_weather_data(prcps_dict.values()) else: temps, prcps = wd z['Temp'] = temps z['Prec'] = prcps # Begin processing geop_result # Set stream related variables to zero if AoI does not contain # any streams. if 'ag_stream_pct' in geop_result: z['AgLength'] = geop_result['ag_stream_pct'] * z['StreamLength'] z['UrbLength'] = z['StreamLength'] - z['AgLength'] z['n42'] = round(z['AgLength'] / 1000, 1) z['n46e'] = (geop_result['med_high_urban_stream_pct'] * z['StreamLength'] / 1000) z['n46f'] = (geop_result['low_urban_stream_pct'] * z['StreamLength'] / 1000) else: z['AgLength'] = 0 z['UrbLength'] = 0 z['n42'] = 0 z['n46e'] = 0 z['n46f'] = 0 z['CN'] = geop_result['cn'] z['SedPhos'] = geop_result['soilp'] z['Area'] = [percent * area * HECTARES_PER_SQM for percent in geop_result['landuse_pcts']] # Immediately return an error if z['Area'] is a list of 0s if sum(z['Area']) == 0: raise Exception(NO_LAND_COVER) z['UrbAreaTotal'] = sum(z['Area'][NRur:]) z['PhosConc'] = phosphorus_conc(z['SedPhos']) z['NumNormalSys'] = num_normal_sys(z['Area']) z['AgSlope3'] = geop_result['ag_slope_3_pct'] * area * HECTARES_PER_SQM z['AgSlope3To8'] = (geop_result['ag_slope_3_8_pct'] * area * HECTARES_PER_SQM) z['n41'] = geop_result['n41'] z['AvSlope'] = geop_result['avg_slope'] z['AvKF'] = geop_result['avg_kf'] z['KF'] = geop_result['kf'] z['KV'] = kv_coefficient(geop_result['landuse_pcts'], z['Grow']) # Original at [email protected]:9803-9807 z['n23'] = z['Area'][1] # Row Crops Area z['n23b'] = z['Area'][13] # High Density Mixed Urban Area z['n24'] = z['Area'][0] # Hay/Pasture Area z['n24b'] = z['Area'][11] # Low Density Mixed Urban Area z['SedDelivRatio'] = sediment_delivery_ratio(area * SQKM_PER_SQM) z['TotArea'] = area * HECTARES_PER_SQM z['GrNitrConc'] = geop_result['gr_nitr_conc'] z['GrPhosConc'] = geop_result['gr_phos_conc'] z['MaxWaterCap'] = geop_result['avg_awc'] z['SedAFactor'] = sed_a_factor(geop_result['landuse_pcts'], z['CN'], z['AEU'], z['AvKF'], z['AvSlope']) # Use zeroed out stream variables if there are no streams in the AoI if 'lu_stream_pct' in geop_result: z['LS'] = ls_factors(geop_result['lu_stream_pct'], z['StreamLength'], z['Area'], z['AvSlope'], ag_lscp) else: zeroed_lu_stream_pct = [0.0] * 16 z['LS'] = ls_factors(zeroed_lu_stream_pct, 0, z['Area'], z['AvSlope'], ag_lscp) z['P'] = p_factors(z['AvSlope'], ag_lscp) z['SedNitr'] = geop_result['soiln'] z['RecessionCoef'] = geop_result['recess_coef'] return z
def start_analyze_drb_2100_land(request, key=None, format=None): """ Starts a job to get a land-use histogram for an area within DRB in 2100. Uses simulations of change in land use over the 20-year period 2080-2099 based on two urban growth scenarios: centers and corridors. Generated by Shippensburg University, serviced via APIs by Drexel University and the Academy of Natural Sciences. For more information, see the [technical documentation](https://wikiwatershed.org/ documentation/mmw-tech/#overlays-tab-coverage). ## Response You can use the URL provided in the response's `Location` header to poll for the job's results. <summary> **Example of a completed job's `result`** </summary> <details> { "survey": { "displayName": "DRB 2100 land forecast (corridors)", "name": "drb_2100_land_corridors", "categories": [ { "area": 3572379, "code": "open_water", "coverage": 0.041698374846361526, "nlcd": 11, "type": "Open Water" }, { "area": 0, "code": "perennial_ice", "coverage": 0.0, "nlcd": 12, "type": "Perennial Ice/Snow" }, { "area": 10355769, "code": "developed_open", "coverage": 0.12087707871542477, "nlcd": 21, "type": "Developed, Open Space" }, { "area": 11455623, "code": "developed_low", "coverage": 0.13371505709573384, "nlcd": 22, "type": "Developed, Low Intensity" }, { "area": 27048582, "code": "developed_med", "coverage": 0.3157229149814583, "nlcd": 23, "type": "Developed, Medium Intensity" }, { "area": 29183382, "code": "developed_high", "coverage": 0.3406412370917419, "nlcd": 24, "type": "Developed, High Intensity" }, { "area": 11187, "code": "barren_land", "coverage": 0.00013057957159815528, "nlcd": 31, "type": "Barren Land (Rock/Sand/Clay)" }, { "area": 2684196, "code": "deciduous_forest", "coverage": 0.03133111323549495, "nlcd": 41, "type": "Deciduous Forest" }, { "area": 14301, "code": "evergreen_forest", "coverage": 0.00016692754567133446, "nlcd": 42, "type": "Evergreen Forest" }, { "area": 93402, "code": "mixed_forest", "coverage": 0.001090229118298999, "nlcd": 43, "type": "Mixed Forest" }, { "area": 114768, "code": "shrub", "coverage": 0.001339622443298211, "nlcd": 52, "type": "Shrub/Scrub" }, { "area": 55143, "code": "grassland", "coverage": 0.000643653286550199, "nlcd": 71, "type": "Grassland/Herbaceous" }, { "area": 59643, "code": "pasture", "coverage": 0.0006961792606443887, "nlcd": 81, "type": "Pasture/Hay" }, { "area": 14193, "code": "cultivated_crops", "coverage": 0.0001656669222930739, "nlcd": 82, "type": "Cultivated Crops" }, { "area": 574722, "code": "woody_wetlands", "coverage": 0.006708407307413516, "nlcd": 90, "type": "Woody Wetlands" }, { "area": 434610, "code": "herbaceous_wetlands", "coverage": 0.0050729585780168295, "nlcd": 95, "type": "Emergent Herbaceous Wetlands" } ] } } </details> """ user = request.user if request.user.is_authenticated else None area_of_interest, wkaoi = _parse_input(request) errs = [] if not key: errs.append('`key` must be specified') if key not in settings.DREXEL_FAST_ZONAL_API['keys']: errs.append('`key` must be one of "{}".'.format('", "'.join( settings.DREXEL_FAST_ZONAL_API['keys']))) # A little redundant since GeoJSON -> GEOSGeometry is already done once # within _parse_input, but it is not returned from there and changing # that API could break many things. geom = GEOSGeometry(area_of_interest, srid=4326) # In the front-end, we use DRB_SIMPLE_PERIMETER. This is sent from the # back-end on every page render, and is considerably lighter ~0.2% than # the actual perimeter. We use the same here for consistency. if not geom.within(settings.DRB_SIMPLE_PERIMETER): errs.append('The area of interest must be within the' ' Delaware River Basin.') if errs: return Response({'errors': errs}, status=status.HTTP_400_BAD_REQUEST) return start_celery_job( [tasks.analyze_drb_2100_land.s(area_of_interest, key)], area_of_interest, user)