Ejemplo n.º 1
0
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        """
        log a bunch of stuff for debugging
        save message: error and outputs: Scenario: status
        need to stop rest of chain!?
        :param exc: The exception raised by the task.
        :param task_id: Unique id of the failed task. (not the run_uuid)
        :param args: Original arguments for the task that failed.
        :param kwargs: Original keyword arguments for the task that failed.
        :param einfo: ExceptionInfo instance, containing the traceback.
        :return: None, The return value of this handler is ignored.
        """
        if not isinstance(exc, REoptError):
            exc_type, exc_value, exc_traceback = sys.exc_info()
            exc = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  exc_traceback,
                                  task=self.name,
                                  run_uuid=kwargs['run_uuid'],
                                  user_uuid=kwargs['data']['inputs']
                                  ['Scenario'].get('user_uuid'))
        msg = exc.message
        exc.save_to_db()
        self.data["messages"]["error"] = msg
        self.data["outputs"]["Scenario"][
            "status"] = "An error occurred. See messages for more."
        ModelManager.update_scenario_and_messages(self.data,
                                                  run_uuid=self.run_uuid)

        self.request.chain = None  # stop the chain?
        self.request.callback = None
        self.request.chord = None  # this seems to stop the infinite chord_unlock call
Ejemplo n.º 2
0
def proforma(request, run_uuid):

    try:
        uuid.UUID(run_uuid)  # raises ValueError if not valid uuid

    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            resp = {"Error": e.args[0]}
            return JsonResponse(resp, status=400)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value,
                                  exc_traceback,
                                  task='proforma',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.message)}, status=400)

    try:
        scenario = ScenarioModel.objects.get(run_uuid=run_uuid)

        if scenario.status.lower() == "optimizing...":
            return HttpResponse(
                "Problem is still solving. Please try again later.",
                status=425)  # too early status

        try:  # see if Proforma already created
            pf = ProForma.objects.get(scenariomodel=scenario)
        except:
            pf = ProForma.create(scenariomodel=scenario)

        pf.generate_spreadsheet()
        pf.save()

        wrapper = FileWrapper(open(pf.output_file, "rb"))

        response = HttpResponse(
            wrapper,
            content_type='application/vnd.ms-excel.sheet.macroEnabled.12')
        response['Content-Length'] = os.path.getsize(pf.output_file)
        response['Content-Disposition'] = 'attachment; filename=%s' % (
            pf.output_file_name)
        return response

    except Exception as e:

        if type(e).__name__ == 'DoesNotExist':
            msg = "Scenario {} does not exist.".format(run_uuid)
            return HttpResponse(msg, status=404)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value,
                                  exc_traceback,
                                  task='proforma',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return HttpResponse({"Error": str(err.message)}, status=400)
Ejemplo n.º 3
0
def validate_run_uuid(run_uuid):
    try:
        uuid.UUID(run_uuid)  # raises ValueError if not valid uuid
    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            raise ValidationError("Error:" + str(e.args[0]))
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type, exc_value.args[0], exc_traceback, task='resilience_stats', run_uuid=run_uuid)
            err.save_to_db()
            raise ValidationError("Error" + str(err.message))
Ejemplo n.º 4
0
def load_builder(request):
    """
    Convert the SolarResilient Component Load Builder CSV into an 8760 Load
    :param request:
    :return: 8760 list for critical_load_kw input into REOpt
    """
    try:
        if request.method == 'POST':
            post = request.body
            try:
                # Try to import JSON, then try to import CSV
                try:
                    loads_table = json.loads(post)
                except:
                    loads_table = unicode(post, "utf-8")
                finally:
                    if not isinstance(loads_table, list):
                        csv_reader = csv.DictReader(io.StringIO(loads_table))
                        loads_table = list(csv_reader)

            except:
                return JsonResponse({"Error": "Invalid JSON or CSV"})

            # Validation
            if not check_load_builder_inputs(loads_table):
                return JsonResponse({
                    "Error":
                    "There are missing required inputs. Must include the following: 'Power (W)', 'Quantity', '% Run Time', 'Start Mo.', 'Stop Mo.', 'Start Hr.', 'Stop Hr.'"
                })
            if not validate_load_builder_inputs(loads_table):
                return JsonResponse({"Error": "Some input values are invalid"})

            # Run conversion and respond
            loads_kw = convert_loads(loads_table)
            return JsonResponse({"critical_loads_kw": loads_kw})

        else:
            return JsonResponse({
                "Error":
                "Must POST a JSON based on the SolarResilient component based load builder downloadable CSV"
            })

    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type,
                              exc_value,
                              exc_traceback,
                              task='load_builder')
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=500)
Ejemplo n.º 5
0
def remove(request, run_uuid):
    try:
        ModelManager.remove(
            run_uuid)  # ModelManager has some internal exception handling
        return JsonResponse({"Success": True}, status=204)

    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type,
                              exc_value.args[0],
                              tb.format_tb(exc_traceback),
                              task='reo.views.results',
                              run_uuid=run_uuid)
        err.save_to_db()
        resp = make_error_resp(err.message)
        return JsonResponse(resp)
Ejemplo n.º 6
0
def unlink(request, user_uuid, run_uuid):
    """
    Retrieve a summary of scenarios for given user_uuid
    :param request:
    :param user_uuid:
    :return 
        True, bool
    """
    content = {'user_uuid':user_uuid, 'run_uuid':run_uuid}
    for name, check_id in content.items():
        try:
            uuid.UUID(check_id)  # raises ValueError if not valid uuid

        except ValueError as e:
            if e.args[0] == "badly formed hexadecimal UUID string":
                return JsonResponse({"Error": "{} {}".format(name, e.args[0]) }, status=400)
            else:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                if name == 'user_uuid':
                    err = UnexpectedError(exc_type, exc_value, exc_traceback, task='unlink', user_uuid=check_id)
                if name == 'run_uuid':
                    err = UnexpectedError(exc_type, exc_value, exc_traceback, task='unlink', run_uuid=check_id)
                err.save_to_db()
                return JsonResponse({"Error": str(err.message)}, status=400)

    try:
        
        if not ScenarioModel.objects.filter(user_uuid=user_uuid).exists():
            return JsonResponse({"Error":"User {} does not exist".format(user_uuid)}, status=400)

        if not ScenarioModel.objects.filter(run_uuid=run_uuid).exists():
            return JsonResponse({"Error":"Run {} does not exist".format(run_uuid)}, status=400)

        runs = ScenarioModel.objects.filter(run_uuid=run_uuid)
        if runs.exists():
            if runs[0].user_uuid != user_uuid:
                return JsonResponse({"Error":"Run {} is not associated with user {}".format(run_uuid, user_uuid)}, status=400)

        if not UserUnlinkedRuns.objects.filter(run_uuid=run_uuid).exists():
            UserUnlinkedRuns.create(**content)

        return JsonResponse({"Success":True}, status=204)
    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type, exc_value, exc_traceback, task='unlink', user_uuid=user_uuid)
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=404)
Ejemplo n.º 7
0
def add_user_uuid(request):
    """
    update the user_uuid associated with a Scenario run_uuid
    :param request POST:
        {
            "user_uuid",
            "run_uuid"
        }
    :return: None
    """
    try:
        if request.method == 'POST':
            post = request.body
            # Try to import JSON
            try:
                data = json.loads(post)
                try:
                    user_uuid = str(data['user_uuid'])
                    run_uuid = str(data['run_uuid'])
                    uuid.UUID(user_uuid)  # raises ValueError if not valid uuid
                    uuid.UUID(run_uuid)  # raises ValueError if not valid uuid
                    try:
                        scenario = ScenarioModel.objects.filter(run_uuid=run_uuid).first()
                        print (scenario.user_uuid)
                        if scenario.user_uuid is None:
                            ModelManager.add_user_uuid(user_uuid, run_uuid)
                            response = JsonResponse(
                                {"Success": "user_uuid for run_uuid {} has been set to {}".format(run_uuid, user_uuid)})
                            return response
                        else:
                            return JsonResponse({"Error": "a user_uuid already exists for run_uuid {}".format(run_uuid)})
                    except:
                        return JsonResponse({"Error": "run_uuid does not exist"})
                except:
                    return JsonResponse({"Error": "Invalid inputs: must provide user_uuid and run_uuid key value pairs as valid UUIDs"})
            except:
                return JsonResponse({"Error": "Invalid JSON"})
        else:
            return JsonResponse({"Error": "Must POST a JSON with user_uuid and run_uuid key value pairs"})

    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type, exc_value, exc_traceback, task='add_user_uuid')
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=500)
Ejemplo n.º 8
0
def results(request, run_uuid):
    try:
        uuid.UUID(run_uuid)  # raises ValueError if not valid uuid

    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            resp = make_error_resp(e.args[0])
            return JsonResponse(resp, status=400)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  tb.format_tb(exc_traceback),
                                  task='results',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.args[0])}, status=400)

    try:
        d = ModelManager.make_response(
            run_uuid)  # ModelManager has some internal exception handling

        response = JsonResponse(d)
        return response

    except Exception:

        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type,
                              exc_value.args[0],
                              tb.format_tb(exc_traceback),
                              task='reo.views.results',
                              run_uuid=run_uuid)
        err.save_to_db()
        resp = make_error_resp(err.message)
        return JsonResponse(resp)
Ejemplo n.º 9
0
def resilience_stats(request, run_uuid=None, financial_check=None):
    """
    Run outage simulator for given run_uuid
    :param request:
    :param run_uuid:
    :return: {"resilience_by_timestep",
              "resilience_hours_min",
              "resilience_hours_max",
              "resilience_hours_avg",
              "outage_durations",
              "probs_of_surviving",
             }
    """
    try:
        uuid.UUID(run_uuid)  # raises ValueError if not valid uuid
    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            return JsonResponse({"Error": str(e.args[0])}, status=400)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  exc_traceback,
                                  task='resilience_stats',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.message)}, status=400)

    try:  # to run outage simulator
        scenario = ScenarioModel.objects.get(run_uuid=run_uuid)
        if scenario.status == "Optimizing...":
            raise ScenarioOptimizing
        elif "error" in scenario.status.lower():
            raise ScenarioErrored

        if financial_check == "financial_check":
            query = request.GET
            financial_uuid = query['financial_uuid']

            scenario = ScenarioModel.objects.get(run_uuid=financial_uuid)
            if scenario.status == "Optimizing...":
                raise ScenarioOptimizing
            elif "error" in scenario.status.lower():
                raise ScenarioErrored

            ## retrieve sizes from db
            resilience_result = ModelManager.make_response(run_uuid)
            financial_result = ModelManager.make_response(financial_uuid)

            resilience_size = parse_system_sizes(
                resilience_result["outputs"]["Scenario"]["Site"])
            financial_size = parse_system_sizes(
                financial_result["outputs"]["Scenario"]["Site"])

            results = simulate_outage(
                resilience_run_site_result=resilience_size,
                financial_run_site_result=financial_size,
                financial_check=financial_check)

            results = {"survives_specified_outage": results}

        else:
            try:
                query = request.GET
                bau = query['bau'] in ["True", "true", "1"]
            except:
                bau = False

            wtch = True
            try:  # see if ResilienceModel already created
                rm = ResilienceModel.objects.get(scenariomodel=scenario)
                results = model_to_dict(rm)

                if bau and "probs_of_surviving_bau" not in results:
                    wtch = False
                    raise Exception('no resilience_stat_bau in database')

                if not bau:
                    for k, v in results.items():
                        if k[-4:] == "_bau":
                            results.pop(k)

                # remove items that user does not need
                del results['scenariomodel']
                del results['id']

            except:
                load_profile = LoadProfileModel.objects.filter(
                    run_uuid=scenario.run_uuid).first()
                gen = GeneratorModel.objects.filter(
                    run_uuid=scenario.run_uuid).first()
                batt = StorageModel.objects.filter(
                    run_uuid=scenario.run_uuid).first()
                pv = PVModel.objects.filter(run_uuid=scenario.run_uuid).first()
                financial = FinancialModel.objects.filter(
                    run_uuid=scenario.run_uuid).first()
                wind = WindModel.objects.filter(
                    run_uuid=scenario.run_uuid).first()

                batt_roundtrip_efficiency = batt.internal_efficiency_pct \
                                            * batt.inverter_efficiency_pct \
                                            * batt.rectifier_efficiency_pct
                results = dict()
                kwargs_dict = dict()
                # if wtch and bau:
                pool = Pool(processes=2 if wtch and bau else 1)
                # else:
                #     pool = Pool(processes=1)

                if wtch:
                    kwargs = {
                        "batt_kwh": batt.size_kwh or 0,
                        "batt_kw": batt.size_kw or 0,
                        "pv_kw_ac_hourly":
                        pv.year_one_power_production_series_kw,
                        "wind_kw_ac_hourly":
                        wind.year_one_power_production_series_kw,
                        "init_soc": batt.year_one_soc_series_pct,
                        "critical_loads_kw":
                        load_profile.critical_load_series_kw,
                        "batt_roundtrip_efficiency": batt_roundtrip_efficiency,
                        "diesel_kw": gen.size_kw or 0,
                        "fuel_available": gen.fuel_avail_gal,
                        "b": gen.fuel_intercept_gal_per_hr,
                        "m": gen.fuel_slope_gal_per_kwh,
                        "diesel_min_turndown": gen.min_turn_down_pct
                    }
                    kwargs_dict["wtch"] = kwargs

                if bau:
                    # only PV and diesel generator may have existing size
                    kwargs = {
                        "batt_kwh":
                        0,
                        "batt_kw":
                        0,
                        "pv_kw_ac_hourly": [
                            p * pv.size_kw * pv.existing_kw
                            for p in pv.year_one_power_production_series_kw
                        ],
                        "critical_loads_kw":
                        load_profile.critical_load_series_kw,
                        "diesel_kw":
                        gen.existing_kw or 0,
                        "fuel_available":
                        gen.fuel_avail_gal,
                        "b":
                        gen.fuel_intercept_gal_per_hr,
                        "m":
                        gen.fuel_slope_gal_per_kwh,
                        "diesel_min_turndown":
                        gen.min_turn_down_pct
                    }
                    kwargs_dict["bau"] = kwargs

                p = {
                    k: pool.apply_async(simulate_outage, tuple(), v)
                    for k, v in kwargs_dict.items()
                }
                pool.close()
                pool.join()

                for k, v in p.items():
                    if k == 'wtch':
                        results.update(v.get())
                    if k == 'bau':
                        results.update({
                            key + '_bau': val
                            for key, val in v.get().items()
                        })
                """ add avg_crit_ld and pwf to results so that avoided outage cost can be determined as:
                        avoided_outage_costs_us_dollars = resilience_hours_avg * 
                                                          value_of_lost_load_us_dollars_per_kwh * 
                                                          avg_crit_ld *
                                                          present_worth_factor 
                """
                avg_critical_load = round(
                    sum(load_profile.critical_load_series_kw) /
                    len(load_profile.critical_load_series_kw), 5)

                if load_profile.outage_is_major_event:
                    # assume that outage occurs only once in analysis period
                    present_worth_factor = 1
                else:
                    present_worth_factor = annuity(
                        financial.analysis_years, financial.escalation_pct,
                        financial.offtaker_discount_pct)

                results.update({
                    "present_worth_factor": present_worth_factor,
                    "avg_critical_load": avg_critical_load,
                })

                try:
                    # new model
                    try:
                        rm = ResilienceModel.create(scenariomodel=scenario)
                    except Exception as e:
                        if isinstance(e, REoptError):
                            return JsonResponse({"Error": e.message},
                                                status=500)
                        raise e
                    ResilienceModel.objects.filter(id=rm.id).update(**results)

                except IntegrityError:
                    # have run resiliense_stat & bau=false
                    # return both w/tech and bau
                    ResilienceModel.objects.filter(id=rm.id).update(**results)
                    rm = ResilienceModel.objects.get(scenariomodel=scenario)
                    results = model_to_dict(rm)

                    # remove items that user does not need
                    del results['scenariomodel']
                    del results['id']

                results.update({
                    "help_text":
                    "The present_worth_factor and avg_critical_load are provided such that one can calculate an avoided outage cost in dollars by multiplying a value of load load ($/kWh) times the avg_critical_load, resilience_hours_avg, and present_worth_factor. Note that if the outage event is 'major', i.e. only occurs once, then the present_worth_factor is 1."
                })

        response = JsonResponse(results)
        return response

    except ScenarioOptimizing:
        return JsonResponse(
            {
                "Error":
                "The scenario is still optimizing. Please try again later."
            },
            content_type='application/json',
            status=500)

    except ScenarioErrored:
        return JsonResponse(
            {
                "Error":
                "An error occured in the scenario. Please check the messages from your results."
            },
            content_type='application/json',
            status=500)

    except Exception as e:

        if type(e).__name__ == 'DoesNotExist':
            msg = "Scenario {} does not exist.".format(run_uuid)
            return JsonResponse({"Error": msg},
                                content_type='application/json',
                                status=404)

        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  exc_traceback,
                                  task='resilience_stats',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return JsonResponse({"Error": err.message}, status=500)
Ejemplo n.º 10
0
def summary(request, user_uuid):
    """
    Retrieve a summary of scenarios for given user_uuid
    :param request:
    :param user_uuid:
    :return:
        {
            "user_uuid",
            "scenarios":
                [{
                  "run_uuid",                   # Run ID
                  "status",                     # Status
                  "created",                    # Date
                  "description",                # Description
                  "focus",                      # Focus
                  "address",                    # Address
                  "urdb_rate_name",             # Utility Tariff
                  "doe_reference_name",         # Load Profile
                  "npv_us_dollars",             # Net Present Value ($)
                  "net_capital_costs",          # DG System Cost ($)
                  "year_one_savings_us_dollars",# Year 1 Savings ($)
                  "pv_kw",                      # PV Size (kW)
                  "wind_kw",                    # Wind Size (kW)
                  "gen_kw",                     # Generator Size (kW)
                  "batt_kw",                    # Battery Power (kW)
                  "batt_kwh"                    # Battery Capacity (kWh)
                  ""
                }]
        }
    """
    try:
        uuid.UUID(user_uuid)  # raises ValueError if not valid uuid

    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            return JsonResponse({"Error": str(e.message)}, status=404)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type, exc_value, exc_traceback, task='summary', user_uuid=user_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.message)}, status=404)

    try:
        scenarios = ScenarioModel.objects.filter(user_uuid=user_uuid).order_by('-created')
        unlinked_run_uuids = [i.run_uuid for i in UserUnlinkedRuns.objects.filter(user_uuid=user_uuid)]
        scenarios = [s for s in scenarios if s.run_uuid not in unlinked_run_uuids]

        json_response = {"user_uuid": user_uuid, "scenarios": []}

        if len(scenarios) == 0:
            response = JsonResponse({"Error": "No scenarios found for user '{}'".format(user_uuid)}, content_type='application/json', status=404)
            return response
        
        scenario_run_uuids =  [s.run_uuid for s in scenarios]
        scenario_run_ids =  [s.id for s in scenarios]

        #saving time by only calling each table once
        messages = MessageModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','message_type','message')
        sites = SiteModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','address')
        loads = LoadProfileModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','outage_start_hour','loads_kw','doe_reference_name')
        batts = StorageModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','max_kw','size_kw','size_kwh')
        pvs = PVModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','max_kw','size_kw')
        winds = WindModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','max_kw','size_kw')
        gens = GeneratorModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid', 'max_kw', 'size_kw')
        financials = FinancialModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','npv_us_dollars','net_capital_costs','lcc_us_dollars','lcc_bau_us_dollars','net_capital_costs_plus_om_us_dollars', 'net_capital_costs','net_om_us_dollars_bau')
        tariffs = ElectricTariffModel.objects.filter(run_uuid__in=scenario_run_uuids).values('run_uuid','urdb_rate_name','year_one_energy_cost_us_dollars','year_one_demand_cost_us_dollars','year_one_fixed_cost_us_dollars','year_one_min_charge_adder_us_dollars','year_one_bill_us_dollars','year_one_energy_cost_bau_us_dollars','year_one_demand_cost_bau_us_dollars','year_one_fixed_cost_bau_us_dollars','year_one_min_charge_adder_bau_us_dollars','year_one_bill_bau_us_dollars')
        resiliences = ResilienceModel.objects.filter(scenariomodel_id__in=scenario_run_ids).values('scenariomodel_id','resilience_hours_avg','resilience_hours_max','resilience_hours_min')

        def get_scenario_data(data, run_uuid):
            if type(data)==dict:
                if str(data.get('run_uuid')) == str(run_uuid):
                    return data
                if str(data.get('scenariomodel_id')) == str(run_uuid):
                    return data
            result = [s for s in data if str(s.get('run_uuid')) == str(run_uuid)]
            if len(result) > 0:
                return result
            result = [s for s in data if str(s.get('scenariomodel_id')) == str(run_uuid)]
            if len(result) > 0:
                return result
            return [{}]

        for scenario in scenarios:
            results = {}
            
            message_set = get_scenario_data(messages, scenario.run_uuid)
            if not type(message_set) == list:
                message_set = [message_set]
            
            site = get_scenario_data(sites, scenario.run_uuid)[0]
            load = get_scenario_data(loads, scenario.run_uuid)[0]
            batt = get_scenario_data(batts, scenario.run_uuid)[0]
            pv = get_scenario_data(pvs, scenario.run_uuid)[0]
            wind = get_scenario_data(winds, scenario.run_uuid)[0]
            gen = get_scenario_data(gens, scenario.run_uuid)[0]
            financial = get_scenario_data(financials, scenario.run_uuid)[0]
            tariff = get_scenario_data(tariffs, scenario.run_uuid)[0]
            resilience = get_scenario_data(resiliences, scenario.id)[0]
            
            # Messages
            results['messages'] = {}
            for message in message_set:
                if len(message.keys()) > 0:
                    results['messages'][message.get('message_type') or "type"] = message.get('message') or ""
            
            # Run ID
            results['run_uuid'] = str(scenario.run_uuid)

            # Status
            results['status'] = scenario.status

            # Date
            results['created'] = scenario.created

            if site:

                # Description
                results['description'] = scenario.description

                # Focus
                if load['outage_start_hour']:
                    results['focus'] = "Resilience"
                else:
                    results['focus'] = "Financial"

                # Address
                results['address'] = site.get('address')

                # Utility Tariff
                if tariff['urdb_rate_name']:
                    results['urdb_rate_name'] = tariff.get('urdb_rate_name')
                else:
                    results['urdb_rate_name'] = "Custom"

                # Load Profile
                if load['loads_kw']:
                    results['doe_reference_name'] = "Custom"
                else:
                    results['doe_reference_name'] = load.get('doe_reference_name')

                # NPV
                results['npv_us_dollars'] = financial.get('npv_us_dollars')

                # DG System Cost
                results['net_capital_costs'] = financial.get('net_capital_costs')

                # Lifecycle Costs
                results['lcc_us_dollars'] = financial.get('lcc_us_dollars')

                 # Lifecycle Costs BAU
                results['lcc_bau_us_dollars'] = financial.get('lcc_bau_us_dollars')

                #Other Financials
                results['net_capital_costs_plus_om_us_dollars'] = financial.get('net_capital_costs_plus_om_us_dollars')
                results['net_om_us_dollars_bau'] = financial.get('net_om_us_dollars_bau')
                results['net_capital_costs'] = financial.get('net_capital_costs')

                # Year 1 Savings
                year_one_costs = sum(filter(None, [
                    tariff.get('year_one_energy_cost_us_dollars') or 0,
                    tariff.get('year_one_demand_cost_us_dollars') or 0,
                    tariff.get('year_one_fixed_cost_us_dollars') or 0,
                    tariff.get('year_one_min_charge_adder_us_dollars') or 0,
                    tariff.get('year_one_bill_us_dollars') or 0
                    ]))
                
                year_one_costs_bau = sum(filter(None, [
                    tariff.get('year_one_energy_cost_bau_us_dollars') or 0,
                    tariff.get('year_one_demand_cost_bau_us_dollars') or 0,
                    tariff.get('year_one_fixed_cost_bau_us_dollars') or 0,
                    tariff.get('year_one_min_charge_adder_bau_us_dollars') or 0,
                    tariff.get('year_one_bill_bau_us_dollars') or 0
                    ]))
                #Resilience Stats
                results['resilience_hours_min'] = resilience.get('resilience_hours_min') 
                results['resilience_hours_max'] = resilience.get('resilience_hours_max') 
                results['resilience_hours_avg'] = resilience.get('resilience_hours_avg') 

                if results['resilience_hours_max'] is None:
                    results['resilience_hours_max'] = 'not evaluated'
                if results['resilience_hours_min'] is None:
                    results['resilience_hours_min'] = 'not evaluated'
                if results['resilience_hours_avg'] is None:
                    results['resilience_hours_avg'] = 'not evaluated'
                
                results['year_one_savings_us_dollars'] = year_one_costs_bau - year_one_costs

                # PV Size
                if pv is not None:
                    if pv['max_kw'] > 0:
                        results['pv_kw'] = pv.get('size_kw')
                    else:
                        results['pv_kw'] = 'not evaluated'
                else:
                    results['pv_kw'] = 'not evaluated'

                # Wind Size
                if wind is not None:
                    if wind.get('max_kw') or -1 > 0:
                        results['wind_kw'] = wind.get('size_kw')
                    else:
                        results['wind_kw'] = 'not evaluated'
                else:
                    results['wind_kw'] = 'not evaluated'

                # Generator Size
                if gen is not None:
                    if gen.get('max_kw') or -1 > 0:
                        results['gen_kw'] = gen.get('size_kw')
                    else:
                        results['gen_kw'] = 'not evaluated'
                else:
                    results['gen_kw'] = 'not evaluated'

                # Battery Size
                if batt is not None:
                    if batt.get('max_kw') or -1 > 0:
                        results['batt_kw'] = batt.get('size_kw')
                        results['batt_kwh'] = batt.get('size_kwh')
                    else:
                        results['batt_kw'] = 'not evaluated'
                        results['batt_kwh'] = 'not evaluated'
                else:
                    results['batt_kw'] = 'not evaluated'
                    results['batt_kwh'] = 'not evaluated'

            json_response['scenarios'].append(results)
        response = JsonResponse(json_response, status=200)
        return response

    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type, exc_value, exc_traceback, task='summary', user_uuid=user_uuid)
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=404)
Ejemplo n.º 11
0
    def obj_create(self, bundle, **kwargs):
        run_uuid = str(uuid.uuid4())
        data = dict()
        data["outputs"] = {"Scenario": {'run_uuid': run_uuid, 'api_version': api_version,
                                        'Profile': {'pre_setup_scenario_seconds': 0, 'setup_scenario_seconds': 0,
                                                        'reopt_seconds': 0, 'reopt_bau_seconds': 0,
                                                        'parse_run_outputs_seconds': 0},                                            
                                       }
                           }
        # Setup and start profile
        profiler = Profiler()
        uuidFilter = UUIDFilter(run_uuid)
        log.addFilter(uuidFilter)
        log.info('Beginning run setup')

        try:
            input_validator = ValidateNestedInput(bundle.data)
        except Exception as e:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ValidateNestedInput', run_uuid=run_uuid)
            err.save_to_db()
            set_status(data, 'Internal Server Error during input validation. No optimization task has been created. Please check your POST for bad values.')
            data['inputs'] = bundle.data
            data['messages'] = {}
            data['messages']['error'] = err.message  # "Unexpected Error."
            log.error("Internal Server error: " + err.message)
            raise ImmediateHttpResponse(HttpResponse(json.dumps(data),
                                                     content_type='application/json',
                                                     status=500))  # internal server error
        data["inputs"] = input_validator.input_dict
        data["messages"] = input_validator.messages

        if not input_validator.isValid:  # 400 Bad Request
            log.debug("input_validator not valid")
            log.debug(json.dumps(data))
            set_status(data, 'Error. No optimization task has been created. See messages for more information. ' \
                               'Note that inputs have default values filled in.')
            if saveToDb:
                badpost = BadPost(run_uuid=run_uuid, post=json.dumps(bundle.data), errors=str(data['messages']))
                badpost.save()

            raise ImmediateHttpResponse(HttpResponse(json.dumps(data),
                                                     content_type='application/json',
                                                     status=400))
        log.info('Entering ModelManager')
        model_manager = ModelManager()
        profiler.profileEnd()

        if saveToDb:
            set_status(data, 'Optimizing...')
            data['outputs']['Scenario']['Profile']['pre_setup_scenario_seconds'] = profiler.getDuration()
            if bundle.request.META.get('HTTP_X_API_USER_ID') or False:
                if bundle.request.META.get('HTTP_X_API_USER_ID') or '' == '6f09c972-8414-469b-b3e8-a78398874103':
                    data['outputs']['Scenario']['job_type'] = 'REopt Lite Web Tool'
                else:
                    data['outputs']['Scenario']['job_type'] = 'developer.nrel.gov'
            else:
                data['outputs']['Scenario']['job_type'] = 'Internal NREL'
            test_case = bundle.request.META.get('HTTP_USER_AGENT') or ''
            if test_case.startswith('check_http/'):
                data['outputs']['Scenario']['job_type'] = 'Monitoring'
            try:
                model_manager.create_and_save(data)
            except Exception as e:
                log.error("Could not create and save run_uuid: {}\n Data: {}".format(run_uuid,data))
                exc_type, exc_value, exc_traceback = sys.exc_info()
                err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='ModelManager.create_and_save',
                                      run_uuid=run_uuid)
                err.save_to_db()
                set_status(data, "Internal Server Error during saving of inputs. Please see messages.")
                data['messages']['error'] = err.message  # "Unexpected Error."
                log.error("Internal Server error: " + err.message)
                raise ImmediateHttpResponse(HttpResponse(json.dumps(data),
                                                         content_type='application/json',
                                                         status=500))  # internal server error
        setup = setup_scenario.s(run_uuid=run_uuid, data=data, raw_post=bundle.data)
        call_back = process_results.s(data=data, meta={'run_uuid': run_uuid, 'api_version': api_version})
        # (use .si for immutable signature, if no outputs were passed from reopt_jobs)
        rjm = run_jump_model.s(data=data, run_uuid=run_uuid)
        rjm_bau = run_jump_model.s(data=data, run_uuid=run_uuid, bau=True)

        log.info("Starting celery chain")
        try:
            chain(setup | group(rjm, rjm_bau) | call_back)()
        except Exception as e:
            if isinstance(e, REoptError):
                pass  # handled in each task
            else:  # for every other kind of exception
                exc_type, exc_value, exc_traceback = sys.exc_info()
                err = UnexpectedError(exc_type, exc_value.args[0], traceback.format_tb(exc_traceback), task='api.py', run_uuid=run_uuid)
                err.save_to_db()
                set_status(data, 'Internal Server Error. See messages for more.')
                if 'messages' not in data.keys():
                    data['messages'] = {}
                data['messages']['error'] = err.message
                log.error("Internal Server error: " + err.message)
                raise ImmediateHttpResponse(HttpResponse(json.dumps(data),
                                                         content_type='application/json',
                                                         status=500))  # internal server error

        log.info("Returning with HTTP 201")
        raise ImmediateHttpResponse(HttpResponse(json.dumps({'run_uuid': run_uuid}),
                                                 content_type='application/json', status=201))
Ejemplo n.º 12
0
def resilience_stats(request: Union[Dict, HttpRequest], run_uuid=None):
    """
    Run outage simulator for given run_uuid
    :param request: optional parameter for 'bau', boolean
    :param run_uuid:
    :return: {"resilience_by_timestep",
              "resilience_hours_min",
              "resilience_hours_max",
              "resilience_hours_avg",
              "outage_durations",
              "probs_of_surviving",
             }
         Also can GET the same values as above with '_bau' appended if 'bau=true' for the site's existing capacities.
    """
    try:
        uuid.UUID(run_uuid)  # raises ValueError if not valid uuid
    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            return JsonResponse({"Error": str(e.args[0])}, status=400)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  exc_traceback,
                                  task='resilience_stats',
                                  run_uuid=run_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.message)}, status=400)

    bau = False  # whether or not user wants outage simulator run with existing sizes
    if isinstance(request, HttpRequest):
        if request.GET.get('bau') in ["True", "true", "1"]:
            bau = True
    elif isinstance(request, dict):
        bau = request.get("bau")
    # Safety check; No exception is expected if called after POST-ing to /outagesimjob end point
    try:
        scenario = ScenarioModel.objects.get(run_uuid=run_uuid)
    except ScenarioModel.DoesNotExist:
        msg = "Scenario {} does not exist.".format(run_uuid)
        return JsonResponse({"Error": msg},
                            content_type='application/json',
                            status=404)

    if scenario.status == "Optimizing...":
        return JsonResponse(
            {
                "Error":
                "The scenario is still optimizing. Please try again later."
            },
            content_type='application/json',
            status=404)
    elif "error" in scenario.status.lower():
        return JsonResponse(
            {
                "Error":
                "An error occurred in the scenario. Please check the messages from your results."
            },
            content_type='application/json',
            status=500)
    try:  # catch all exceptions
        try:  # catch specific exception
            not_ready_msg = (
                'Outage sim results are not ready. '
                'If you have already submitted an outagesimjob, please try again later. '
                'If not, please first submit an outagesimjob by sending a POST request to '
                'v1/outagesimjob/ with run_uuid and bau parameters. This will generate'
                ' outage simulation results that you can access from a GET request to the '
                'v1/job/<run uuid>/resilience_stats endpoint. ')
            not_ready_msg += 'Sample body data for POST-ing to /outagesimjob/: {"run_uuid\": \"6ea30f0f-3723-4fd1-8a3f-bebf8a3e4dbf\", \"bau\": false}'
            rm = ResilienceModel.objects.get(scenariomodel=scenario)
            if rm.resilience_by_timestep is None:
                return JsonResponse({"Error": not_ready_msg},
                                    content_type='application/json',
                                    status=404)
        except ResilienceModel.DoesNotExist:  # case for no resilience_stats generated yet
            return JsonResponse({"Error": not_ready_msg},
                                content_type='application/json',
                                status=404)

        else:  # ResilienceModel does exist
            results = model_to_dict(rm)
            # remove items that user does not need
            del results['scenariomodel']
            del results['id']

            if bau and results[
                    "probs_of_surviving_bau"] is None:  # then need to run outage_sim with existing sizes (BAU)
                bau_results = run_outage_sim(run_uuid,
                                             with_tech=False,
                                             bau=bau)
                ResilienceModel.objects.filter(id=rm.id).update(**bau_results)
                results.update(bau_results)

            if not bau:  # remove BAU results from results dict (if they're there)
                filtered_dict = {
                    k: v
                    for k, v in results.items() if "_bau" not in k
                }
                results = filtered_dict

        results.update({
            "help_text":
            ("The present_worth_factor and avg_critical_load are provided such"
             " that one can calculate an avoided outage cost in dollars by multiplying a value "
             "of load load ($/kWh) by the avg_critical_load, resilience_hours_avg, and present_worth_factor."
             " Note that if the outage event is 'major' (i.e. only occurs once), then the present_worth_factor is 1."
             )
        })
        response = JsonResponse({"outage_sim_results": results},
                                content_type='application/json',
                                status=200)
        return response

    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type,
                              exc_value.args[0],
                              exc_traceback,
                              task='resilience_stats',
                              run_uuid=run_uuid)
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=500)
Ejemplo n.º 13
0
def financial_check(request, run_uuid=None):
    """ Check to see if resilience scenario system sizes are the same as financial scenario sizes """
    resilience_uuid = request.GET.get('resilience_uuid')
    if resilience_uuid is None:  # preserving old behavior
        resilience_uuid = run_uuid
    financial_uuid = request.GET.get('financial_uuid')

    def parse_system_sizes(site):
        size_dict = dict()
        if "Generator" in site:
            size_dict["Generator"] = site["Generator"]["size_kw"]
        if "Storage" in site:
            size_dict["Storage_kw"] = site["Storage"]["size_kw"]
            size_dict["Storage_kwh"] = site["Storage"]["size_kwh"]
        if "Wind" in site:
            size_dict["Wind"] = site["Wind"]["size_kw"]
        if "PV" in site:
            size_dict["PV"] = site["PV"]["size_kw"]
        return size_dict

    # validate uuid's
    try:
        uuid.UUID(str(resilience_uuid))  # raises ValueError if not valid uuid
        uuid.UUID(str(financial_uuid))  # raises ValueError if not valid uuid
    except ValueError as e:
        if e.args[0] == "badly formed hexadecimal UUID string":
            return JsonResponse({"Error": str(e.args[0])}, status=400)
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            err = UnexpectedError(exc_type,
                                  exc_value.args[0],
                                  exc_traceback,
                                  task='resilience_stats',
                                  run_uuid=resilience_uuid)
            err.save_to_db()
            return JsonResponse({"Error": str(err.message)}, status=400)

    try:
        resil_scenario = ScenarioModel.objects.get(run_uuid=resilience_uuid)
    except ScenarioModel.DoesNotExist:
        msg = "Scenario {} does not exist.".format(resilience_uuid)
        return JsonResponse({"Error": msg},
                            content_type='application/json',
                            status=404)
    if resil_scenario.status == "Optimizing...":
        return JsonResponse(
            {
                "Error":
                "The resilience scenario is still optimizing. Please try again later."
            },
            content_type='application/json',
            status=500)
    elif "error" in resil_scenario.status.lower():
        return JsonResponse(
            {
                "Error":
                "An error occurred in the resilience scenario. Please check the messages from your results."
            },
            content_type='application/json',
            status=500)

    try:
        financial_scenario = ScenarioModel.objects.get(run_uuid=financial_uuid)
    except ScenarioModel.DoesNotExist:
        msg = "Scenario {} does not exist.".format(financial_uuid)
        return JsonResponse({"Error": msg},
                            content_type='application/json',
                            status=404)
    if financial_scenario.status == "Optimizing...":
        return JsonResponse(
            {
                "Error":
                "The financial scenario is still optimizing. Please try again later."
            },
            content_type='application/json',
            status=500)
    elif "error" in financial_scenario.status.lower():
        return JsonResponse(
            {
                "Error":
                "An error occurred in the financial scenario. Please check the messages from your results."
            },
            content_type='application/json',
            status=500)
    try:
        # retrieve sizes from db
        resilience_result = ModelManager.make_response(resilience_uuid)
        financial_result = ModelManager.make_response(financial_uuid)
        resilience_sizes = parse_system_sizes(
            resilience_result["outputs"]["Scenario"]["Site"])
        financial_sizes = parse_system_sizes(
            financial_result["outputs"]["Scenario"]["Site"])

        survives = True
        if resilience_sizes.keys() == financial_sizes.keys():
            for tech, resil_size in resilience_sizes.items():
                if float(resil_size - financial_sizes[tech]) / float(
                        max(resil_size, 1)) > 1.0e-3:
                    survives = False
                    break
        else:
            survives = False
        response = JsonResponse({"survives_specified_outage": survives})

    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        err = UnexpectedError(exc_type,
                              exc_value.args[0],
                              exc_traceback,
                              task='resilience_stats',
                              run_uuid=resilience_uuid)
        err.save_to_db()
        return JsonResponse({"Error": err.message}, status=500)

    else:
        return response