def __init__(self, 
              proposal_set,
              sampler="opus_core.samplers.weighted_sampler",
              weight_string = None,
              run_config=None, 
              estimate_config=None,
              debuglevel=0, 
              dataset_pool=None,
              filter="development_project_proposal.status_id==%s" % DevelopmentProjectProposalDataset.id_tentative,
              choice_attribute_name='is_chosen', 
              **kwargs):
     self.id_selected = 9
     self.proposal_set = proposal_set
     self.filter = filter
     self.choice_attribute_name = copy.copy(choice_attribute_name)
     ChoiceModel.__init__(self, [1, 2], 
                          choice_attribute_name=choice_attribute_name, 
                          **kwargs)
     DevelopmentProjectProposalSamplingModel.__init__(self, 
                                                      proposal_set,
                                                      sampler="opus_core.samplers.weighted_sampler",
                                                      weight_string = "development_project_proposal.status_id==%s" % self.id_selected,
                                                      #weight_string = "development_project_proposal.status_id==%s" % self.id_selected, 
                                                      run_config=run_config, 
                                                      estimate_config=estimate_config,
                                                      debuglevel=debuglevel, 
                                                      dataset_pool=dataset_pool)
    def run(self, **kwargs):
        """Runs the parent model for each subarea separately.
        """
        buildings = self.dataset_pool.get_dataset("building")
        buildings.compute_variables([
                                "occupied_units_for_jobs = urbansim_parcel.building.number_of_non_home_based_jobs",
                                "units_for_jobs = urbansim_parcel.building.total_non_home_based_job_space",
                                "occupied_residential_units = urbansim_parcel.building.number_of_households",
                                "urbansim_parcel.building.existing_units",
                                    ], dataset_pool=self.dataset_pool)
        buildings.compute_one_variable_with_unknown_package(variable_name="%s" % (self.subarea_id_name), dataset_pool=self.dataset_pool)
        # keep copy of the weights
        original_weight = self.weight.copy()
        self.all_demolished_buildings = array([], dtype='int32')
        
        regions = self.proposal_set.compute_one_variable_with_unknown_package(variable_name="%s" % (self.subarea_id_name), dataset_pool=self.dataset_pool)

        unique_regions = unique(regions)
        original_status = self.proposal_set.get_attribute("status_id").copy()
        bldgs_regions = buildings.get_attribute(self.subarea_id_name)
        for area_index in range(unique_regions.size):
            self.area_id = unique_regions[area_index]            
            status = self.proposal_set.get_attribute("status_id")
            where_area = regions == self.area_id
            idx_area_in_proposal = where(where_area)[0]
            if idx_area_in_proposal.size <= 0:
                logger.log_status("No proposals for area %s" % self.area_id)
                continue
            bldgs_area_idx = where(bldgs_regions == self.area_id)[0]
            bldgs_subset = DatasetSubset(buildings, index=bldgs_area_idx)
            self.dataset_pool.replace_dataset('building', bldgs_subset)
            idx_out_area_not_active_not_refused = where(logical_and(logical_and(status != self.proposal_set.id_active, 
                                                                               status != self.proposal_set.id_refused),
                                                                    logical_not(where_area)))[0]
            status[idx_area_in_proposal] = original_status[idx_area_in_proposal]
            status[idx_out_area_not_active_not_refused] = self.proposal_set.id_not_available
            self.proposal_set.modify_attribute(name="status_id", data=status)
            self.weight[:] = original_weight[:]
            
            logger.log_status("\nDPSM for area %s" % self.area_id)
            dummy, demolished_bldgs = DevelopmentProjectProposalSamplingModel.run(self, **kwargs)
                
            self.all_demolished_buildings = concatenate((self.all_demolished_buildings, demolished_bldgs))
            status = self.proposal_set.get_attribute("status_id")
            where_not_active = where(status[idx_area_in_proposal] != self.proposal_set.id_active)[0]
            status[idx_area_in_proposal[where_not_active]] = self.proposal_set.id_refused
            self.proposal_set.modify_attribute(name="status_id", data=status)
                
        # set all proposals that were not set to 'active' to their original status
        idx = where(status != self.proposal_set.id_active)[0]
        self.proposal_set.set_values_of_one_attribute("status_id", original_status[idx], idx)
        self.dataset_pool.replace_dataset('building', buildings)
        return (self.proposal_set, self.all_demolished_buildings)
    def run(self, zones, zone_ids_to_process=None, type=None, year=2000, **kwargs):
        """If 'type' is None, the model runs for both, residential and non-residential space. Alternatively,
        it can be set to 'residential' or 'non_residential'.
        """
        self.type = {"residential": False, "non_residential": False}
        if (type is None) or (type == "residential"):
            self.type["residential"] = True
        if (type is None) or (type == "non_residential"):
            self.type["non_residential"] = True

        target_vacancies = self.dataset_pool.get_dataset("target_vacancy")
        tv_building_types = unique(target_vacancies.get_attribute("building_type_id"))

        bts = self.dataset_pool.get_dataset("building_type")
        all_building_types = bts.get_id_attribute()

        self.bt_do_not_count = array(map(lambda x: x not in tv_building_types, all_building_types))
        self.bt_do_not_count = all_building_types[self.bt_do_not_count]
        self.do_not_count_residential_units = self.get_do_not_count_residential_units(zones)

        zones.compute_variables(
            [
                "existing_residential_units = zone.aggregate(building.residential_units, [parcel])",
                "existing_job_spaces = zone.aggregate(psrc_parcel.building.total_non_home_based_job_space, [parcel])",
            ],
            dataset_pool=self.dataset_pool,
        )

        if self.type["residential"]:
            occupied_residential_units = (
                zones.compute_variables(["zone.number_of_agents(household)"], dataset_pool=self.dataset_pool)
                - self.do_not_count_residential_units
            )
            maxiter = 20
        if self.type["non_residential"]:
            zones.compute_variables(
                [
                    "number_of_all_nhb_jobs = zone.aggregate(job.home_based_status==0)",
                    "number_of_placed_nhb_jobs = zone.aggregate(psrc_parcel.building.number_of_non_home_based_jobs)",
                ],
                dataset_pool=self.dataset_pool,
            )

            occupied_building_sqft = zones.compute_variables(
                ["zone.aggregate(urbansim_parcel.building.occupied_building_sqft_by_non_home_based_jobs)"],
                dataset_pool=self.dataset_pool,
            )
            existing_building_sqft = zones.compute_variables(
                ["zone.aggregate(building.non_residential_sqft)"], dataset_pool=self.dataset_pool
            )
            to_be_used_sqft = existing_building_sqft - occupied_building_sqft
            to_be_placed_sqft = (
                zones.get_attribute("number_of_all_nhb_jobs") - zones.get_attribute("number_of_placed_nhb_jobs")
            ) * self.get_weighted_job_sqft()[zones.get_id_attribute()]
            maxiter = 1

        existing_residential_units = (
            zones.get_attribute("existing_residential_units") - self.do_not_count_residential_units
        )
        existing_job_spaces = zones.get_attribute("existing_job_spaces")

        zone_ids_in_proposals = self.proposal_set.compute_variables(
            "zone_id = development_project_proposal.disaggregate(urbansim_parcel.parcel.zone_id)",
            dataset_pool=self.dataset_pool,
        )
        zone_ids = zones.get_id_attribute()
        # keep copy of the weights
        original_weight = self.weight.copy()
        # this is a hack: we want buildings to be built in 2000, but the simulation is running for different year
        # start_year = SimulationState().get_current_time() - 1
        start_year = year
        self.proposal_set.modify_attribute(name="start_year", data=array(self.proposal_set.size() * [start_year]))
        status = self.proposal_set.get_attribute("status_id")
        for zone_index in range(zone_ids.size):
            self.zone = zone_ids[zone_index]
            if (zone_ids_to_process is not None) and (self.zone not in zone_ids_to_process):
                continue
            self.build_in_zone = {"residential": False, "non_residential": False}
            if self.type["residential"]:
                if occupied_residential_units[zone_index] > 0:
                    self.existing_to_occupied_ratio_residential = max(
                        existing_residential_units[zone_index], 1
                    ) / float(occupied_residential_units[zone_index])
                    self.build_in_zone["residential"] = True
            if self.type["non_residential"]:
                if to_be_placed_sqft[zone_index] > 0:
                    self.existing_to_occupied_ratio_non_residential = max(to_be_used_sqft[zone_index], 1) / float(
                        to_be_placed_sqft[zone_index]
                    )
                    self.build_in_zone["non_residential"] = True
            if not self.build_in_zone["residential"] and not self.build_in_zone["non_residential"]:
                continue
            where_zone = zone_ids_in_proposals == self.zone
            idx_zone = where(where_zone)[0]
            if (self.proposal_set.id_active in status[idx_zone]) or (self.proposal_set.id_refused in status[idx_zone]):
                continue  # this zone was handled previously
            if idx_zone.size <= 0:
                logger.log_status("No proposals for zone %s" % self.zone)
                continue
            idx_out_zone_not_active_not_refused = where(
                logical_and(
                    logical_and(status != self.proposal_set.id_active, status != self.proposal_set.id_refused),
                    logical_not(where_zone),
                )
            )[0]
            status[idx_zone] = self.proposal_set.id_proposed
            status[idx_out_zone_not_active_not_refused] = self.proposal_set.id_not_available
            self.proposal_set.modify_attribute(name="status_id", data=status)
            self.weight[:] = original_weight[:]
            self.proposed_units_from_previous_iterations = {}

            logger.log_status("\nDPSM for zone %s" % self.zone)
            for iter in range(maxiter):
                self.weight[:] = original_weight[:]
                if self.weight[idx_zone].sum() <= 0:
                    logger.log_status("No non-zero weights for zone %s in iteration %s." % (self.zone, iter))
                    break
                while isinf(self.weight[idx_zone].sum()):
                    self.weight[idx_zone] = self.weight[idx_zone] / 10
                DevelopmentProjectProposalSamplingModel.run(self, **kwargs)
                if self.type["residential"]:
                    if (len(self.accepted_proposals) <= 0) or self.vacancy_rate_met(
                        existing_residential_units[zone_index], occupied_residential_units[zone_index]
                    ):
                        break
                    # print "ratio:", self.existing_to_occupied_ratio_residential

            status = self.proposal_set.get_attribute("status_id")
            where_not_active = where(status[idx_zone] != self.proposal_set.id_active)[0]
            status[idx_zone[where_not_active]] = self.proposal_set.id_refused
            self.proposal_set.modify_attribute(name="status_id", data=status)
            if ((zone_index + 1) % 50) == 0:  # flush every 50th zone
                self.proposal_set.flush_dataset()

        self.proposal_set.set_values_of_one_attribute(
            "status_id", self.proposal_set.id_not_available, where(status != self.proposal_set.id_active)[0]
        )
        return (self.proposal_set, [])