Skip to content

Commit

Permalink
Merge pull request #4180 from NREL/issue-4175
Browse files Browse the repository at this point in the history
Addresses #4175, issues with ft for ElectricLoadCenter:Distribution
  • Loading branch information
joseph-robertson authored Jan 29, 2021
2 parents ae47a41 + 9447787 commit 3d83fc2
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 123 deletions.
4 changes: 2 additions & 2 deletions ruby/test/ElectricLoadCenterDistribution_Test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ def test_ElectricLoadCenterDistribution_Photovoltaics
assert(elcd.inverter.empty?)

simple_panel = OpenStudio::Model::GeneratorPhotovoltaic::simple(model)
assert(!simple_panel.electricLoadCenterDistribution.empty?)
assert(simple_panel.electricLoadCenterDistribution.empty?)

elcd.addGenerator(simple_panel)
assert(!simple_panel.electricLoadCenterDistribution.empty?)
assert_equal(elcd.generators.size, 1)
assert(elcd.inverter.empty?)

eod_panel = OpenStudio::Model::GeneratorPhotovoltaic::equivalentOneDiode(model)
assert(!eod_panel.electricLoadCenterDistribution.empty?)
assert(eod_panel.electricLoadCenterDistribution.empty?)

elcd.addGenerator(eod_panel)
assert(!eod_panel.electricLoadCenterDistribution.empty?)
Expand Down
1 change: 1 addition & 0 deletions src/energyplus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ set(${target_name}_test_src
Test/DesignSpecificationOutdoorAir_GTest.cpp
Test/ElectricEquipment_GTest.cpp
Test/ElectricEquipmentITEAirCooled_GTest.cpp
Test/ElectricLoadCenterDistribution_GTest.cpp
Test/ElectricLoadCenterTransformer_GTest.cpp
Test/EMS_GTest.cpp
Test/EvaporativeCoolerDirectResearchSpecial_GTest.cpp
Expand Down
15 changes: 1 addition & 14 deletions src/energyplus/ForwardTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,20 +419,7 @@ namespace energyplus {
}
}

// Remove empty electric load center distribution objects (e.g. with no generators)
// requested by jmarrec, https://github.com/NREL/OpenStudio/pull/1927
// add check for transformers
for (auto& elcd : model.getConcreteModelObjects<ElectricLoadCenterDistribution>()) {
if ((elcd.generators().empty()) && (!elcd.transformer())) {
LOG(Warn, "ElectricLoadCenterDistribution " << elcd.name().get()
<< " is not referenced by any generators or transformers, it will not be translated.");
if (auto inverter = elcd.inverter()) {
inverter->remove();
}
elcd.remove();
}
}

// Remove orphan Inverters
for (auto& inverter : model.getModelObjects<Inverter>()) {
if (!inverter.electricLoadCenterDistribution()) {
LOG(Warn, "Inverter " << inverter.name().get() << " is not referenced by any ElectricLoadCenterDistribution, it will not be translated.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,64 +63,71 @@ namespace energyplus {

IdfObject idfObject = createRegisterAndNameIdfObject(openstudio::IddObjectType::ElectricLoadCenter_Distribution, modelObject);

IdfObject generatorsIdf(openstudio::IddObjectType::ElectricLoadCenter_Generators);
generatorsIdf.setName(idfObject.name().get() + " Generators");
m_idfObjects.push_back(generatorsIdf);
/// Generator Fields
if (!modelObject.generators().empty()) {
IdfObject generatorsIdf(openstudio::IddObjectType::ElectricLoadCenter_Generators);

idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorListName, generatorsIdf.name().get());
m_idfObjects.push_back(generatorsIdf);

idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorOperationSchemeType, modelObject.generatorOperationSchemeType());
generatorsIdf.setName(idfObject.name().get() + " Generators");

if ((optD = modelObject.demandLimitSchemePurchasedElectricDemandLimit())) {
idfObject.setDouble(ElectricLoadCenter_DistributionFields::GeneratorDemandLimitSchemePurchasedElectricDemandLimit, optD.get());
}
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorListName, generatorsIdf.name().get());

if ((schedule = modelObject.trackScheduleSchemeSchedule())) {
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorTrackScheduleNameSchemeScheduleName, schedule->name().get());
}
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorOperationSchemeType, modelObject.generatorOperationSchemeType());

if ((optS = modelObject.trackMeterSchemeMeterName())) {
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorTrackMeterSchemeMeterName, (*optS));
}
if ((optD = modelObject.demandLimitSchemePurchasedElectricDemandLimit())) {
idfObject.setDouble(ElectricLoadCenter_DistributionFields::GeneratorDemandLimitSchemePurchasedElectricDemandLimit, optD.get());
}

boost::optional<ElectricLoadCenterTransformer> transformer = modelObject.transformer();
if (transformer) {
boost::optional<IdfObject> transformerIdf = translateAndMapModelObject(transformer.get());
if (transformerIdf) {
idfObject.setString(ElectricLoadCenter_DistributionFields::TransformerObjectName, transformerIdf->name().get());
if ((schedule = modelObject.trackScheduleSchemeSchedule())) {
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorTrackScheduleNameSchemeScheduleName, schedule->name().get());
}
}

for (auto& generator : modelObject.generators()) {
boost::optional<IdfObject> generatorIdf = translateAndMapModelObject(generator);
if ((optS = modelObject.trackMeterSchemeMeterName())) {
idfObject.setString(ElectricLoadCenter_DistributionFields::GeneratorTrackMeterSchemeMeterName, (*optS));
}

if (generatorIdf) {
IdfExtensibleGroup generatorGroup = generatorsIdf.pushExtensibleGroup();
/// ElectricLoadCenter:Generators
for (auto& generator : modelObject.generators()) {
boost::optional<IdfObject> generatorIdf = translateAndMapModelObject(generator);

generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorName, generatorIdf->name().get());
if (generatorIdf) {
IdfExtensibleGroup generatorGroup = generatorsIdf.pushExtensibleGroup();

generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorObjectType, generator.generatorObjectType());
generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorName, generatorIdf->name().get());

optD = generator.ratedElectricPowerOutput();
if (optD) {
generatorGroup.setDouble(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorRatedElectricPowerOutput, *optD);
}
generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorObjectType, generator.generatorObjectType());

schedule = generator.availabilitySchedule();
if (schedule) {
boost::optional<IdfObject> scheduleIdf = translateAndMapModelObject(*schedule);
if (scheduleIdf) {
generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorAvailabilityScheduleName, scheduleIdf->name().get());
optD = generator.ratedElectricPowerOutput();
if (optD) {
generatorGroup.setDouble(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorRatedElectricPowerOutput, *optD);
}
}

optD = generator.ratedThermaltoElectricalPowerRatio();
if (optD) {
generatorGroup.setDouble(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorRatedThermaltoElectricalPowerRatio, *optD);
schedule = generator.availabilitySchedule();
if (schedule) {
boost::optional<IdfObject> scheduleIdf = translateAndMapModelObject(*schedule);
if (scheduleIdf) {
generatorGroup.setString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorAvailabilityScheduleName, scheduleIdf->name().get());
}
}

optD = generator.ratedThermaltoElectricalPowerRatio();
if (optD) {
generatorGroup.setDouble(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorRatedThermaltoElectricalPowerRatio, *optD);
}
} else {
LOG(Warn, "Could not translate generator '" << generator.name().get() << "' on ElectricLoadCenter:Distribution '" << idfObject.name().get()
<< "'")
}
} else {
LOG(Warn,
"Could not translate generator '" << generator.name().get() << "' on ElectricLoadCenter:Distribution '" << idfObject.name().get() << "'")
}
}

/// Transformer Object
boost::optional<ElectricLoadCenterTransformer> transformer = modelObject.transformer();
if (transformer) {
boost::optional<IdfObject> transformerIdf = translateAndMapModelObject(transformer.get());
if (transformerIdf) {
idfObject.setString(ElectricLoadCenter_DistributionFields::TransformerObjectName, transformerIdf->name().get());
}
}

Expand Down Expand Up @@ -156,7 +163,7 @@ namespace energyplus {
}
// Case 4: there's no inverter and a buss type without inverter: nothing needs to be done

/// Storage & Buss Type
/// Storage and Buss Type
boost::optional<ElectricalStorage> electricalStorage = modelObject.electricalStorage();
bool bussWithStorage = (bussType == "AlternatingCurrentWithStorage" || bussType == "DirectCurrentWithInverterDCStorage"
|| bussType == "DirectCurrentWithInverterACStorage");
Expand Down Expand Up @@ -298,7 +305,7 @@ namespace energyplus {
LOG(Error, modelObject.briefDescription() << ": Your Electric Buss Type '" << bussType
<< "' Requires an electrical Storage object but you didn't specify one");
}
// Case 4: there's no inverter and a buss type without inverter: nothing needs to be done
// Case 4: there's no Storage object and the buss is not compatible: nothing needs to be done

return idfObject;
}
Expand Down
145 changes: 145 additions & 0 deletions src/energyplus/Test/ElectricLoadCenterDistribution_GTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/***********************************************************************************************************************
* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
*
* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission from the respective party.
*
* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
* written permission from Alliance for Sustainable Energy, LLC.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************************************************************/

#include <gtest/gtest.h>
#include "EnergyPlusFixture.hpp"

#include "../ErrorFile.hpp"
#include "../ForwardTranslator.hpp"

#include "../../model/Model.hpp"
#include "../../model/Model_Impl.hpp"
#include "../../model/Building.hpp"
#include "../../model/Building_Impl.hpp"
#include "../../model/Schedule.hpp"
#include "../../model/Schedule_Impl.hpp"
#include "../../model/OutputMeter.hpp"
#include "../../model/OutputMeter_Impl.hpp"

#include "../../model/ThermalZone.hpp"

#include "../../model/ElectricLoadCenterDistribution.hpp"
#include "../../model/ElectricLoadCenterDistribution_Impl.hpp"
#include "../../model/GeneratorPVWatts.hpp"
#include "../../model/GeneratorPVWatts_Impl.hpp"
#include "../../model/ElectricLoadCenterInverterPVWatts.hpp"
#include "../../model/ElectricLoadCenterInverterPVWatts_Impl.hpp"

#include "../../model/Version.hpp"
#include "../../model/Version_Impl.hpp"

#include "../../utilities/core/Optional.hpp"
#include "../../utilities/core/Checksum.hpp"
#include "../../utilities/core/UUID.hpp"
#include "../../utilities/core/Logger.hpp"
#include "../../utilities/sql/SqlFile.hpp"
#include "../../utilities/idf/IdfFile.hpp"
#include "../../utilities/idf/IdfObject.hpp"
#include "../../utilities/idf/IdfExtensibleGroup.hpp"
#include "../../utilities/idf/WorkspaceExtensibleGroup.hpp"

#include <utilities/idd/ElectricLoadCenter_Distribution_FieldEnums.hxx>
#include <utilities/idd/ElectricLoadCenter_Generators_FieldEnums.hxx>
#include <utilities/idd/Generator_PVWatts_FieldEnums.hxx>
#include <utilities/idd/ElectricLoadCenter_Inverter_PVWatts_FieldEnums.hxx>

#include <utilities/idd/IddEnums.hxx>
#include <utilities/idd/IddFactory.hxx>

#include <boost/algorithm/string/predicate.hpp>

#include <resources.hxx>

#include <sstream>

#include <vector>

using namespace openstudio::energyplus;
using namespace openstudio::model;
using namespace openstudio;

TEST_F(EnergyPlusFixture, ForwardTranslator_ElectricLoadCenterDistribution_NoInverter) {

Model model;

ElectricLoadCenterDistribution elcd(model);

EXPECT_EQ(1u, model.getObjectsByType(ElectricLoadCenterDistribution::iddObjectType()).size());

GeneratorPVWatts gntr(model, 1);
elcd.addGenerator(gntr);

EXPECT_EQ(1u, model.getObjectsByType(ElectricLoadCenterDistribution::iddObjectType()).size());

ForwardTranslator forwardTranslator;
Workspace workspace = forwardTranslator.translateModel(model);

ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Distribution).size());
ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Generators).size());
ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::Generator_PVWatts).size());
EXPECT_EQ(0u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Inverter_PVWatts).size());

WorkspaceObject distribution = workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Distribution)[0];
WorkspaceObject generators = workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Generators)[0];
WorkspaceObject generator = workspace.getObjectsByType(IddObjectType::Generator_PVWatts)[0];

EXPECT_EQ(generators.nameString(), distribution.getString(ElectricLoadCenter_DistributionFields::GeneratorListName, false).get());

ASSERT_EQ(1u, generators.extensibleGroups().size());
WorkspaceExtensibleGroup w_eg = generators.extensibleGroups()[0].cast<WorkspaceExtensibleGroup>();
EXPECT_EQ(generator.nameString(), w_eg.getString(ElectricLoadCenter_GeneratorsExtensibleFields::GeneratorName, false).get());
}

TEST_F(EnergyPlusFixture, ForwardTranslator_ElectricLoadCenterDistribution_NoGenerators) {

Model model;

ElectricLoadCenterDistribution elcd(model);
elcd.setElectricalBussType("DirectCurrentWithInverter");

EXPECT_EQ(1u, model.getObjectsByType(ElectricLoadCenterDistribution::iddObjectType()).size());

ElectricLoadCenterInverterPVWatts invtr(model);
elcd.setInverter(invtr);

EXPECT_EQ(1u, model.getObjectsByType(ElectricLoadCenterDistribution::iddObjectType()).size());

ForwardTranslator forwardTranslator;
Workspace workspace = forwardTranslator.translateModel(model);

ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Distribution).size());
EXPECT_EQ(0u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Generators).size());
EXPECT_EQ(0u, workspace.getObjectsByType(IddObjectType::Generator_PVWatts).size());
ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Inverter_PVWatts).size());

WorkspaceObject distribution = workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Distribution)[0];
WorkspaceObject inverter = workspace.getObjectsByType(IddObjectType::ElectricLoadCenter_Inverter_PVWatts)[0];

EXPECT_EQ(inverter.nameString(), distribution.getString(ElectricLoadCenter_DistributionFields::InverterName, false).get());
}
12 changes: 10 additions & 2 deletions src/energyplus/Test/FuelCell_GTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ TEST_F(EnergyPlusFixture, ForwardTranslatorFuelCell) {
boost::optional<GeneratorFuelCellStackCooler> fSC = fuelcell.stackCooler();
EXPECT_FALSE(fSC);

ElectricLoadCenterDistribution elcd(model);
elcd.setElectricalBussType("AlternatingCurrent");
elcd.addGenerator(fuelcell);

ForwardTranslator forwardTranslator;
Workspace workspace = forwardTranslator.translateModel(model);

Expand Down Expand Up @@ -212,9 +216,13 @@ TEST_F(EnergyPlusFixture, ForwardTranslatorFuelCell2) {
GeneratorFuelSupply fuelSupply(model);
// create default fuelcell
GeneratorFuelCell fuelcell(model, powerModule, airSupply, waterSupply, auxHeater, exhaustHX, elecStorage, inverter, fuelSupply);
// Stack cooler is optional. For it to be transalted, it needs to be linked to a fuelcell parent
// Stack cooler is optional. For it to be translated, it needs to be linked to a fuelcell parent
fuelcell.setStackCooler(stackCooler);

ElectricLoadCenterDistribution elcd(model);
elcd.setElectricalBussType("AlternatingCurrent");
elcd.addGenerator(fuelcell);

ForwardTranslator forwardTranslator;
Workspace workspace = forwardTranslator.translateModel(model);

Expand Down Expand Up @@ -310,7 +318,7 @@ TEST_F(EnergyPlusFixture, ForwardTranslatorFuelCell4) {

// remove the ELCD
boost::optional<ElectricLoadCenterDistribution> elcd = fuelcell.electricLoadCenterDistribution();
elcd.get().remove();
//elcd.get().remove();
EXPECT_FALSE(fuelcell.electricLoadCenterDistribution());

ForwardTranslator forwardTranslator;
Expand Down
10 changes: 0 additions & 10 deletions src/model/GeneratorFuelCell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@
#include "GeneratorFuelCellStackCooler_Impl.hpp"
#include "GeneratorFuelSupply.hpp"
#include "GeneratorFuelSupply_Impl.hpp"
#include "ElectricLoadCenterDistribution.hpp"
#include "ElectricLoadCenterDistribution_Impl.hpp"
#include "CurveQuadratic.hpp"
#include "CurveQuadratic_Impl.hpp"
#include "CurveCubic.hpp"
Expand Down Expand Up @@ -488,10 +486,6 @@ namespace model {
remove();
LOG_AND_THROW("Unable to set " << briefDescription() << "'s GeneratorFuelCellInverter to " << fCInverter.briefDescription() << ".");
}
//Add ElectricLoadCenterDistribution to get ElectricLoadCenterGenerators
ElectricLoadCenterDistribution elcd(model);
elcd.addGenerator(*this);
elcd.setElectricalBussType("AlternatingCurrent");
}

GeneratorFuelCell::GeneratorFuelCell(const Model& model) : Generator(GeneratorFuelCell::iddObjectType(), model) {
Expand Down Expand Up @@ -553,10 +547,6 @@ namespace model {
remove();
LOG_AND_THROW("Unable to set " << briefDescription() << "'s GeneratorFuelCellInverter");
}
//Add ElectricLoadCenterDistribution to get ElectricLoadCenterGenerators
ElectricLoadCenterDistribution elcd(model);
elcd.addGenerator(*this);
elcd.setElectricalBussType("AlternatingCurrent");
}

IddObjectType GeneratorFuelCell::iddObjectType() {
Expand Down
Loading

0 comments on commit 3d83fc2

Please sign in to comment.