/* * */ package au.org.aurin.wif.impl.demand; import java.util.HashSet; import java.util.NavigableSet; import java.util.Set; import java.util.TreeSet; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import au.org.aurin.wif.exception.config.WifInvalidConfigException; import au.org.aurin.wif.exception.validate.WifInvalidInputException; import au.org.aurin.wif.io.GeodataFinder; import au.org.aurin.wif.model.Projection; import au.org.aurin.wif.model.WifProject; import au.org.aurin.wif.model.allocation.AllocationLU; import au.org.aurin.wif.model.demand.AreaRequirement; import au.org.aurin.wif.model.demand.DemandScenario; import au.org.aurin.wif.model.demand.EmploymentDemographicData; import au.org.aurin.wif.model.demand.EmploymentSector; import au.org.aurin.wif.model.demand.LocalAreaRequirement; import au.org.aurin.wif.model.demand.LocalJurisdiction; import au.org.aurin.wif.model.demand.ResidentialDemographicData; import au.org.aurin.wif.model.demand.data.EmploymentData; import au.org.aurin.wif.model.demand.data.LocalData; import au.org.aurin.wif.model.demand.data.ProjectedData; import au.org.aurin.wif.model.demand.info.DemandInfo; import au.org.aurin.wif.model.demand.info.DensityDemandInfo; import au.org.aurin.wif.model.demand.info.EmploymentDemandInfo; import au.org.aurin.wif.model.demand.info.PreservationDemandInfo; import au.org.aurin.wif.model.demand.info.ProjectedDemandInfo; import au.org.aurin.wif.model.demand.info.ResidentialDemandInfo; import au.org.aurin.wif.svc.ProjectService; import au.org.aurin.wif.svc.WifKeys; /** * <b>RequiredAreaAnalyzer.java</b> * * * @author <a href="mailto:marcosnr@unimelb.edu.au"> Marcos Nino-Ruiz * marcosnr@unimelb.edu.au</a> - 2012 */ @Component public class RequiredAreaAnalyzer { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 23463565464653L; /** The geodata finder. */ @Autowired private GeodataFinder geodataFinder; /** the ProjectService. */ @Resource private ProjectService projectService; /** * logger. */ private static final Logger LOGGER = LoggerFactory .getLogger(RequiredAreaAnalyzer.class); /** * to handle initialization. */ @PostConstruct public void init() { LOGGER.trace("Initializing version: " + WifKeys.WIF_KEY_VERSION); } /** * to handle destroy. */ @PreDestroy public void cleanup() { LOGGER.trace(" Service succesfully cleared! "); } /** * Analyse allocation lu demand. * * @param allocationLU * the allocation lu * @param demandScn * the demand scn * @param projections * the projections * @param projectedSet * the projected set * @param localJurisdictions * the local jurisdictions * @return the sets the * @throws WifInvalidInputException * the wif invalid input exception * @throws WifInvalidConfigException */ public Set<AreaRequirement> analyseAllocationLUDemand( final AllocationLU allocationLU, final DemandScenario demandScn, final TreeSet<Projection> projections, final NavigableSet<Projection> projectedSet, final Set<LocalJurisdiction> localJurisdictions) throws WifInvalidInputException, WifInvalidConfigException { LOGGER.info("@@@@@@@@@@@ Analyze the demand information for {}", allocationLU.getLabel()); // /////////////// // ////////////////////// DemandInfo singledemandInfo; final Set<DemandInfo> demandInfos; if (allocationLU.isLocal()) { // To avoid substantial repetition of code, because we need analysis per // projection singledemandInfo = new DemandInfo(); demandInfos = new HashSet<DemandInfo>(); } else { singledemandInfo = allocationLU.getDemandInfoByScenario(demandScn); demandInfos = allocationLU.getDemandInfosByScenario(demandScn); } for (final Projection projection : projectedSet) { LOGGER.debug("calculating the demand for projection year: {}", projection.getLabel()); final ResidentialDemographicData currentDemographic = demandScn .getDemographicTrend().getResidentialDemographicData( projections.lower(projection)); LOGGER.info("%%% Current Residential demographic projection ={}", projections.lower(projection).getLabel()); final ResidentialDemographicData nextDemographic = demandScn .getDemographicTrend().getResidentialDemographicData(projection); Double requiredArea = 0.0; //new for because of land uses like MixedUse which have residential and employmeny demand info at same time. //previously it just considered the employment. for Mixed Use we consider the larger value. Boolean lsw = false; Double newrequiredArea = 0.0; int cnt = 0; for (final DemandInfo demandInfo : demandInfos) { if (demandInfo instanceof ResidentialDemandInfo) { lsw = true; } } if (allocationLU.getLabel().equals("Mixed Use")) { LOGGER.info("%%% Current Residential demographic projection ={}", projections.lower(projection).getLabel()); int ii=0; ii =1; LOGGER.info("Hello Mixed Use"); } LOGGER.info("Demand Info size ={} , and ResidentialDemandInfo is:{} ",demandInfos.size(),lsw); for (final DemandInfo demandInfo : demandInfos) { if (demandInfo instanceof ResidentialDemandInfo) { requiredArea = analyseResidentialInfo(allocationLU, (ResidentialDemandInfo) demandInfo, currentDemographic, nextDemographic); if (lsw == true) { if (newrequiredArea == 0) { newrequiredArea = requiredArea; } else { if ( requiredArea > newrequiredArea) { newrequiredArea = requiredArea; } } } else { newrequiredArea = requiredArea; } } else if (demandInfo instanceof ProjectedDemandInfo) { if (demandInfo instanceof EmploymentDemandInfo) { // requiredArea = analyseEmploymentInfo(allocationLU, // (EmploymentDemandInfo) demandInfo, demandScn, projections, // projection); final EmploymentDemandInfo einf = (EmploymentDemandInfo) demandInfo; final EmploymentDemographicData currentEmployment = demandScn .getDemographicTrend().getEmploymentDemographicData( projections.lower(projection), einf.getSectorLabel()); final EmploymentDemographicData nextEmployment = demandScn .getDemographicTrend().getEmploymentDemographicData(projection, einf.getSectorLabel()); if ( cnt ==0) //new check to make sure it just runs only once for employment related. { LOGGER.info("%%% Current Employment demographic projection ={}", projections.lower(projection).getLabel()); requiredArea = analyseEmploymentInfoNew(allocationLU, (EmploymentDemandInfo) demandInfo, demandScn, projections, projection, currentEmployment, nextEmployment); cnt =1; } if (lsw == true) { if (newrequiredArea == 0) { newrequiredArea = requiredArea; } else { if ( requiredArea > newrequiredArea) { newrequiredArea = requiredArea; } } } else { newrequiredArea = requiredArea; } } else // PreservationDemandInfo { LOGGER.debug("Information for Preservation demand analysis: {}", allocationLU.getLabel()); final PreservationDemandInfo pdinfo = (PreservationDemandInfo) demandInfo; requiredArea = pdinfo.getProjectedDataByProjection(projection) .getReservedArea(); LOGGER.debug("projected preserved area is: {}", requiredArea); } } } if (allocationLU.isLocal()) { LOGGER.debug("Information for local info demand analysis: {}", allocationLU.getLabel()); final Set<LocalAreaRequirement> requirements = analyseLocalLU( allocationLU, localJurisdictions, currentDemographic, nextDemographic, projection, demandScn); for (final LocalAreaRequirement localAreaRequirement : requirements) { allocationLU.addAreaRequirement(localAreaRequirement); localAreaRequirement.setAllocationLU(allocationLU); localAreaRequirement.setDemandScenario(demandScn); LOGGER.info( "==*==* Total required area for land use {} for local jurisdiction " + localAreaRequirement.getLocalJurisdiction().getLabel() + " in projection " + projection.getLabel() + " is : {}", allocationLU.getLabel(), localAreaRequirement.getRequiredArea()); } } else { // because local jurisdiction creates more than one area // requirement, otherwise: AreaRequirement areaRequirement = allocationLU .getAreaRequirementIfExists(projection, demandScn); if (areaRequirement == null) { LOGGER.debug("Area requirement not present, creating 1 for: {}", allocationLU.getLabel()); areaRequirement = new AreaRequirement(); areaRequirement.setProjection(projection); areaRequirement.setDemandScenario(demandScn); allocationLU.addAreaRequirement(areaRequirement); areaRequirement.setAllocationLU(allocationLU); } requiredArea = newrequiredArea; //new change. areaRequirement.setRequiredArea(requiredArea); LOGGER.info("===== Total required area for land use {} in projection " + projection.getLabel() + " is : {}", allocationLU.getLabel(), areaRequirement.getRequiredArea()); } } return allocationLU.getAreaRequirements(); } /** * Analyse local demand info. The logic only requires information from the * global demand config, but the algorithm expects a local demand info to know * that it must analyse local jurisdictions TODO It can be done easier * @param * allocationLU the allocation lu * * @param allocationLU * the allocation lu * @param localJurisdictions * the local jurisdictions * @param currentDemographic * the current demographic * @param nextDemographic * the next demographic * @param projection * the projection * @param demandScn * the demand scn * @return the sets LocalAreaRequirement * @throws WifInvalidInputException * the wif invalid input exception */ public Set<LocalAreaRequirement> analyseLocalLU( final AllocationLU allocationLU, final Set<LocalJurisdiction> localJurisdictions, final ResidentialDemographicData currentDemographic, final ResidentialDemographicData nextDemographic, final Projection projection, final DemandScenario demandScn) throws WifInvalidInputException { LOGGER.debug("Information for a Local demand analysis: {}", allocationLU.getLabel()); double requiredArea = 0.0; final Set<LocalAreaRequirement> requirements = new HashSet<LocalAreaRequirement>( localJurisdictions.size()); for (final LocalJurisdiction localJurisdiction : localJurisdictions) { if (localJurisdiction.getLocalDatas().size() != 0) { final LocalData localData = localJurisdiction.getLocalData(projection); LOGGER .debug( "for local jurisdiction: {} the required density (per 1k habitants): {}", localJurisdiction.getLabel(), localData.getRequiredDensity()); final Long newResidents = nextDemographic.getTotalPopulation() - currentDemographic.getTotalPopulation(); requiredArea += newResidents * (localData.getRequiredDensity() / 1000); LocalAreaRequirement areaRequirement = (LocalAreaRequirement) allocationLU .getAreaRequirementIfExists(projection, demandScn); if (areaRequirement == null) { areaRequirement = new LocalAreaRequirement(); areaRequirement.setProjection(projection); areaRequirement.setLocalJurisdiction(localJurisdiction); } areaRequirement.setRequiredArea(requiredArea); requirements.add(areaRequirement); } else { LOGGER.warn("there is no local demand information for jurisdiction {}", localJurisdiction.getLabel()); } } return requirements; } /** * Analyse employment info. * * @param allocationLU * the allocation lu * @param demandInfo * the demand info * @param demandScn * the demand scn * @param projections * the projections * @param projection * the projection * @return the double * @throws WifInvalidInputException * the wif invalid input exception */ public Double analyseEmploymentInfo(final AllocationLU allocationLU, final EmploymentDemandInfo demandInfo, final DemandScenario demandScn, final TreeSet<Projection> projections, final Projection projection) throws WifInvalidInputException { final ProjectedData currentData = demandInfo.getProjectedData(projections .lower(projection)); final ProjectedData projectedData = demandInfo.getProjectedData(projection); Double requiredArea = 0.0; LOGGER.debug("{} is associated with {} sector(s),", allocationLU.getLabel(), allocationLU.getEmploymentSectors().size()); if (allocationLU.getEmploymentSectors().size() == 1) { LOGGER.debug( "*-1 performing Employment many-to--one demand analysis for: {}", allocationLU.getLabel()); requiredArea = getAreaRequirementPerSector(demandInfo, currentData, projectedData, 1.0, 1.0); } else { LOGGER.debug( "*-* performing Employment Many-to-many demand analysis for: {}", allocationLU.getLabel()); final Set<EmploymentDemandInfo> employmentDemandInfos = demandScn .getEmploymentDemandInfoByLU(allocationLU); for (final EmploymentDemandInfo edi : employmentDemandInfos) { final ProjectedData currentediData = ((ProjectedDemandInfo) edi) .getProjectedData(projections.lower(projection)); final ProjectedData projectedediData = ((ProjectedDemandInfo) edi) .getProjectedData(projection); requiredArea += getAreaRequirementPerSectorMultiple(edi, currentediData, projectedediData, allocationLU.getTotalArea(), 1.0, 1.0); } requiredArea = requiredArea / employmentDemandInfos.size(); LOGGER .debug( "------>... total required area is {}, adjusted for {} associated sectors", requiredArea, employmentDemandInfos.size()); } return requiredArea; } public Double analyseEmploymentInfoNew(final AllocationLU allocationLU, final EmploymentDemandInfo demandInfo, final DemandScenario demandScn, final TreeSet<Projection> projections, final Projection projection, final EmploymentDemographicData currentEmployment, final EmploymentDemographicData nextEmployment) throws WifInvalidInputException, WifInvalidConfigException { Double requiredArea = 0.0; LOGGER.debug("{} is associated with {} sector(s),", allocationLU.getLabel(), allocationLU.getEmploymentSectors().size()); Double futureDensityLU = 0.0; for (final DensityDemandInfo dInfo : demandScn.getDensityDemandInfo()) { if (dInfo.getLanduseID().equals(allocationLU.getId())) { futureDensityLU = dInfo.getFutureDensity(); } } if (allocationLU.getEmploymentSectors().size() == 1) { LOGGER.debug( "*-1 performing Employment many-to--one demand analysis for: {}", allocationLU.getLabel()); // new for claudia Double dPercentage = 0.0; for (final EmploymentSector emps : allocationLU.getEmploymentSectors()) { for (final String landUseKey : emps.getAssociatedALUsPercentage() .keySet()) { if (allocationLU.getId().equals(landUseKey)) { dPercentage = emps.getAssociatedALUsPercentage().get(landUseKey); } } } // new for claudia requiredArea = getAreaRequirementPerSectorNew(demandInfo, currentEmployment, nextEmployment, dPercentage, futureDensityLU); } else { LOGGER.debug( "*-* performing Employment Many-to-many demand analysis for: {}", allocationLU.getLabel()); final Set<EmploymentDemandInfo> employmentDemandInfos = demandScn .getEmploymentDemandInfoByLU(allocationLU); for (final EmploymentDemandInfo edi : employmentDemandInfos) { for (final EmploymentSector emps : allocationLU.getEmploymentSectors()) { if (emps.getLabel().equals(edi.getSectorLabel())) { // new for claudia Double dPercentage = 0.0; for (final String landUseKey : emps.getAssociatedALUsPercentage() .keySet()) { if (allocationLU.getId().equals(landUseKey)) { dPercentage = emps.getAssociatedALUsPercentage() .get(landUseKey); } } // new for claudia final EmploymentDemographicData currentEmployment1 = demandScn .getDemographicTrend().getEmploymentDemographicData( projections.lower(projection), edi.getSectorLabel()); LOGGER.info("%%% Current Employment demographic projection ={}", projections.lower(projection).getLabel()); final EmploymentDemographicData nextEmployment1 = demandScn .getDemographicTrend().getEmploymentDemographicData(projection, edi.getSectorLabel()); final WifProject project = projectService.getProject(allocationLU .getProjectId()); // final Double areaByLU = geodataFinder.getAreaByLUNew(project // .getSuitabilityConfig().getUnifiedAreaZone(), project // .getAreaLabel(), project.getExistingLUAttributeName(), // allocationLU.getFeatureFieldName()); final Double areaByLU = 1.0; requiredArea += getAreaRequirementPerSectorMultipleNew(edi, currentEmployment1, nextEmployment1, areaByLU, dPercentage, futureDensityLU); } } } // // commented below since new formula // requiredArea = requiredArea / employmentDemandInfos.size(); LOGGER .debug( "------>... total required area is {}, adjusted for {} associated sectors", requiredArea, employmentDemandInfos.size()); } return requiredArea; } /** * Analyse residential info. * * @param allocationLU * the allocation lu * @param demandInfo * the demand info * @param currentDemographic * the current demographic * @param nextDemographic * the next demographic * @return the double */ public Double analyseResidentialInfo(final AllocationLU allocationLU, final ResidentialDemandInfo demandInfo, final ResidentialDemographicData currentDemographic, final ResidentialDemographicData nextDemographic) { Double requiredArea = 0.0; LOGGER.debug("performing a residential demand analysis for: {}", allocationLU.getLabel()); requiredArea = DemandProjector.doResidentialDemandArea(demandInfo, currentDemographic, nextDemographic); return requiredArea; } /** * Gets the area requirement per sector. * * @param edi * the edi * @param currentData * the current data * @param projectedData * the projected data * @return the area requirement per sector */ public Double getAreaRequirementPerSector(final EmploymentDemandInfo edi, final ProjectedData currentData, final ProjectedData projectedData, final Double dPercentage, final Double futureDensity) { LOGGER.debug("this Employment LU is associated with sector: {}", edi .getSector().getLabel()); final EmploymentData currentEmployment = (EmploymentData) currentData; final EmploymentData projectedEmployment = (EmploymentData) projectedData; return DemandProjector.projectEmploymentDensityDemand(currentEmployment .getEmployees().longValue(), projectedEmployment.getEmployees() .longValue(), edi.getInfillRate(), edi.getFutureDensity(), Integer .valueOf(edi.getSector().getAssociatedLUs().size()), dPercentage, futureDensity); } public Double getAreaRequirementPerSectorNew(final EmploymentDemandInfo edi, final EmploymentDemographicData currentData, final EmploymentDemographicData projectedData, final Double dPercentage, final Double futureDensity) { LOGGER.debug("this Employment LU is associated with sector: {}", edi .getSector().getLabel()); return DemandProjector .projectEmploymentDensityDemand(currentData.getEmployees().longValue(), projectedData.getEmployees().longValue(), edi.getInfillRate(), edi.getFutureDensity(), Integer.valueOf(edi.getSector().getAssociatedLUs().size()), dPercentage, futureDensity); } /** * Gets the area requirement per sector multiple. * * @param edi * the edi * @param currentData * the current data * @param projectedData * the projected data * @param landUseArea * the land use area * @return the area requirement per sector multiple */ public Double getAreaRequirementPerSectorMultiple( final EmploymentDemandInfo edi, final ProjectedData currentData, final ProjectedData projectedData, final Double landUseArea, final Double dPercentage, final Double futureDensityLU) { LOGGER.debug("this Employment LU is associated with sector: {}", edi .getSector().getLabel()); final EmploymentData currentEmployment = (EmploymentData) currentData; final EmploymentData projectedEmployment = (EmploymentData) projectedData; return DemandProjector.projectEmploymentDensityDemandBySector( currentEmployment.getEmployees().longValue(), projectedEmployment .getEmployees().longValue(), edi.getInfillRate(), edi .getFutureDensity(), landUseArea, dPercentage, futureDensityLU); } public Double getAreaRequirementPerSectorMultipleNew( final EmploymentDemandInfo edi, final EmploymentDemographicData currentEmployment, final EmploymentDemographicData projectedEmployment, final Double landUseArea, final Double dPercentage, final Double futureDensityLU) { LOGGER.debug("this Employment LU is associated with sector: {}", edi .getSector().getLabel()); return DemandProjector.projectEmploymentDensityDemandBySector( currentEmployment.getEmployees().longValue(), projectedEmployment .getEmployees().longValue(), edi.getInfillRate(), edi .getFutureDensity(), landUseArea, dPercentage, futureDensityLU); } }