Skip to content

Commit

Permalink
Merge pull request #1459 from quintel/plexos-coupling
Browse files Browse the repository at this point in the history
New must run adapter types import/export
  • Loading branch information
louispt1 authored Sep 10, 2024
2 parents 75920d1 + 7c52dec commit c2e81e8
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 20 deletions.
27 changes: 13 additions & 14 deletions app/controllers/api/v3/scenarios_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def dashboard
end

if serializer.errors.any?
render json: { errors: serializer.errors }, status: 422
render json: { errors: serializer.errors }, status: :unprocessable_entity
else
render json: serializer
end
Expand Down Expand Up @@ -188,7 +188,7 @@ def create

render json: ScenarioSerializer.new(self, @scenario)
rescue ActiveRecord::RecordInvalid
render json: { errors: @scenario.errors }, status: 422
render json: { errors: @scenario.errors }, status: :unprocessable_entity
end

# POST /api/v3/scenarios/interpolate
Expand Down Expand Up @@ -267,7 +267,7 @@ def update
end

if serializer.errors.any?
render json: { errors: serializer.errors }, status: 422
render json: { errors: serializer.errors }, status: :unprocessable_entity
else
render json: serializer
end
Expand All @@ -288,7 +288,7 @@ def destroy
def merge
authorize!(:create, Scenario)

merge_params = params.permit(scenarios: [:scenario_id, :weight])
merge_params = params.permit(scenarios: %i[scenario_id weight])

merge_params[:scenarios].each do |scenario|
authorize!(:read, Scenario.find(scenario[:scenario_id]))
Expand All @@ -301,10 +301,10 @@ def merge
# redirect_to api_v3_scenario_url(scenario)
render json: ScenarioSerializer.new(self, scenario)
else
render json: { errors: merger.errors }, status: 422
render json: { errors: merger.errors }, status: :unprocessable_entity
end
rescue ScenarioMerger::Error => ex
render json: { errors: { base: [ex.message] } }, status: 400
rescue ScenarioMerger::Error => e
render json: { errors: { base: [e.message] } }, status: :bad_request
end

# POST /api/v3/scenarios/:id/couple
Expand Down Expand Up @@ -332,7 +332,6 @@ def uncouple
#
def couple
coupling_parameters[:groups].each { |coupling| @scenario.activate_coupling(coupling) }

if @scenario.save
render json: ScenarioSerializer.new(self, @scenario)
else
Expand Down Expand Up @@ -423,12 +422,12 @@ def filtered_metadata(scenario)
#
# Returns a hash.
def scaler_attributes
if params[:scenario] && params[:scenario][:scale]
params[:scenario].require(:scale).permit(
:area_attribute, :value,
:has_agriculture, :has_energy, :has_industry
)
end
return unless params[:scenario] && params[:scenario][:scale]

params[:scenario].require(:scale).permit(
:area_attribute, :value,
:has_agriculture, :has_energy, :has_industry
)
end

# Internal: Parameters for coupling and uncoupling
Expand Down
4 changes: 2 additions & 2 deletions app/models/curve_handler/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def initialize(
@key = key
@processor_key = processor_key.to_sym
@reducer_key = reducer_key&.to_sym
@input_keys = reducer_key && input_keys || []
@input_keys = (reducer_key && input_keys) || []
@display_group = display_group&.to_sym
@internal = !!internal
@disables = disables
Expand Down Expand Up @@ -152,7 +152,7 @@ def reducer

# Public: Returns whether the processor should set any input values for the scenario.
def sets_inputs?
@reducer_key && @input_keys.any? || false
(@reducer_key && @input_keys.any?) || false
end

# Public: Returns if the curve is for internal use and experienced users only.
Expand Down
2 changes: 1 addition & 1 deletion app/models/qernel/merit_facade/always_on_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def producer_class

case @config.subtype
when :volatile then Merit::VolatileProducer
when :must_run then Merit::MustRunProducer
when :must_run, :import_must_run then Merit::MustRunProducer
else
raise "Unknown producer class for node '#{@node.key}'"
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/qernel/merit_facade/consumer_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ def self.factory(node, context)
case context.node_config(node).subtype
when :pseudo
PseudoConsumerAdapter
when :export_must_run
ExportConsumerAdapter
when :consumption_loss
ConsumptionLossAdapter
when :electricity_loss
Expand Down
28 changes: 28 additions & 0 deletions app/models/qernel/merit_facade/export_consumer_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module Qernel
module MeritFacade
# This class adapts an export consumer to act as must run. It uses the same methods for flexible edges as the export adapter.
class ExportConsumerAdapter < ConsumerAdapter
def inject!
input_edge = target_api.node.input(@context.carrier).edges.first
demand = participant.production(:mj)

target_api.demand = demand

if input_edge.edge_type == :inversed_flexible
# We need to override the calculation of an inversed flexible edge.
# and set the demand explicitly.
input_edge.dataset_set(:value, demand)
input_edge.dataset_set(:calculated, true)
end

super
end

def input_of_carrier
source_api.full_load_hours * source_api.input_capacity * MJ_TO_MHW
end
end
end
end
20 changes: 20 additions & 0 deletions app/models/qernel/merit_facade/import_always_on_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Qernel
module MeritFacade
# This class adapts an import producer to act as must run. It uses the same methods for flexible edges as the import adapter.
class ImportAlwaysOnAdapter < AlwaysOnAdapter
def inject!
super
elec_edge = target_api.node.output(:electricity).edges.first

return unless elec_edge.edge_type == :flexible

# We need to override the calculation of the flexible edge and set the
# demand explicitly.
elec_edge.dataset_set(:value, target_api.demand)
elec_edge.dataset_set(:calculated, true)
end
end
end
end
2 changes: 2 additions & 0 deletions app/models/qernel/merit_facade/producer_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def self.factory(node, context)
ElectrolyserAdapter
when :import
ImportAdapter
when :import_must_run
ImportAlwaysOnAdapter
when :backup
BackupAdapter
when :always_on_battery_park
Expand Down
4 changes: 2 additions & 2 deletions app/models/scenario/user_updates.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ def inputs
#
def update_inputs_for_api(params)
params.each_pair do |input_id, value|
if input = Input.get(input_id)
if (input = Input.get(input_id))
if value == 'reset'
delete_from_user_values(input.key)
elsif typed_value = value.to_f
elsif (typed_value = value.to_f)
update_input(input, typed_value)
end
else
Expand Down
2 changes: 1 addition & 1 deletion app/views/inspect/scenarios/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
The scenario will be migrated when the model is updated, regardless of how long hash
passed since it was last updated by a user.

= f.input :active_couplings, label: 'Active couplings', as: :text, input_html: { value: @scenario.active_couplings.join("\n") }
= f.input :active_couplings, label: 'Active couplings', as: :text, input_html: { value: @scenario.active_couplings.join("\n"), data: { codemirror: 'yaml' } }
%dl.hint{ style: 'margin: 0 0 10px' }
%dt Currently inactive:
%dd
Expand Down

0 comments on commit c2e81e8

Please sign in to comment.