diff --git a/cvs/objects/build/vc10/objects.vcxproj b/cvs/objects/build/vc10/objects.vcxproj
index 2a8afd7d7f..db30b47e0f 100644
--- a/cvs/objects/build/vc10/objects.vcxproj
+++ b/cvs/objects/build/vc10/objects.vcxproj
@@ -741,6 +741,7 @@
+
@@ -1101,6 +1102,7 @@
+
diff --git a/cvs/objects/build/vc10/objects.vcxproj.filters b/cvs/objects/build/vc10/objects.vcxproj.filters
index 091d274f63..078be6fc2d 100644
--- a/cvs/objects/build/vc10/objects.vcxproj.filters
+++ b/cvs/objects/build/vc10/objects.vcxproj.filters
@@ -1058,6 +1058,9 @@
Source Files\emissions
+
+ Source Files\util\base
+
Source Files\util\base
@@ -2179,8 +2182,11 @@
Header Files\emissions
+
+ Header Files\util\base
+
Header Files\util\base
-
\ No newline at end of file
+
diff --git a/cvs/objects/build/xcode3/objects.xcodeproj/project.pbxproj b/cvs/objects/build/xcode3/objects.xcodeproj/project.pbxproj
index 615214cefb..0e7d102cde 100644
--- a/cvs/objects/build/xcode3/objects.xcodeproj/project.pbxproj
+++ b/cvs/objects/build/xcode3/objects.xcodeproj/project.pbxproj
@@ -278,6 +278,7 @@
CD8FDEC91C0647140099C752 /* pass_through_sector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD8FDEC81C0647140099C752 /* pass_through_sector.cpp */; };
CD8FDECC1C0647A20099C752 /* pass_through_technology.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD8FDECB1C0647A20099C752 /* pass_through_technology.cpp */; };
CD966E751D92F1CD00A93938 /* libhector-lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD966E721D92F1BB00A93938 /* libhector-lib.a */; };
+ CDAACD88216C546D00D13FD6 /* supply_demand_curve_saver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDAACD87216C546D00D13FD6 /* supply_demand_curve_saver.cpp */; };
CDAF62F0130DAB6900D93AFB /* MAGICC_array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDAF62EC130DAB6900D93AFB /* MAGICC_array.cpp */; };
CDAF62F1130DAB6900D93AFB /* MAGICC_IO_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDAF62ED130DAB6900D93AFB /* MAGICC_IO_helpers.cpp */; };
CDAF62F2130DAB6900D93AFB /* ObjECTS_MAGICC_others.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDAF62EE130DAB6900D93AFB /* ObjECTS_MAGICC_others.cpp */; };
@@ -993,6 +994,8 @@
CD8FDECA1C0647640099C752 /* pass_through_technology.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pass_through_technology.h; sourceTree = ""; };
CD8FDECB1C0647A20099C752 /* pass_through_technology.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pass_through_technology.cpp; sourceTree = ""; };
CD966E671D92F1BB00A93938 /* hector.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = hector.xcodeproj; path = ../../climate/source/hector/project_files/Xcode/hector.xcodeproj; sourceTree = ""; };
+ CDAACD84216C545F00D13FD6 /* supply_demand_curve_saver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = supply_demand_curve_saver.h; sourceTree = ""; };
+ CDAACD87216C546D00D13FD6 /* supply_demand_curve_saver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = supply_demand_curve_saver.cpp; sourceTree = ""; };
CDAF62EA130DAB6100D93AFB /* MAGICC_array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAGICC_array.h; sourceTree = ""; };
CDAF62EB130DAB6100D93AFB /* ObjECTS_MAGICC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjECTS_MAGICC.h; sourceTree = ""; };
CDAF62EC130DAB6900D93AFB /* MAGICC_array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MAGICC_array.cpp; sourceTree = ""; };
@@ -2229,6 +2232,7 @@
CD4886CA122873C200F5A88A /* include */ = {
isa = PBXGroup;
children = (
+ CDAACD84216C545F00D13FD6 /* supply_demand_curve_saver.h */,
CD2420002162D2250071DB2B /* initialize_tech_vector_helper.hpp */,
0E3C49651EC4BBC6005EDC19 /* iyeared.h */,
0E3C49661EC4BBC6005EDC19 /* manage_state_variables.hpp */,
@@ -2278,6 +2282,7 @@
CD4886EE122873C200F5A88A /* source */ = {
isa = PBXGroup;
children = (
+ CDAACD87216C546D00D13FD6 /* supply_demand_curve_saver.cpp */,
CD2420012162D2310071DB2B /* initialize_tech_vector_helper.cpp */,
0E3C49691EC4BBD8005EDC19 /* manage_state_variables.cpp */,
0E05C9001E435B3600C73D94 /* gcam_fusion.cpp */,
@@ -2538,6 +2543,7 @@
CD488754122873C200F5A88A /* co2_emissions.cpp in Sources */,
CD488755122873C200F5A88A /* emissions_driver_factory.cpp in Sources */,
CD488756122873C200F5A88A /* emissions_summer.cpp in Sources */,
+ CDAACD88216C546D00D13FD6 /* supply_demand_curve_saver.cpp in Sources */,
CD488758122873C200F5A88A /* ghg_factory.cpp in Sources */,
CD693FA01AEFE0CE00805384 /* relative_cost_logit.cpp in Sources */,
CD48875B122873C200F5A88A /* input_driver.cpp in Sources */,
diff --git a/cvs/objects/containers/source/scenario.cpp b/cvs/objects/containers/source/scenario.cpp
index b60d25ece0..beb268a198 100644
--- a/cvs/objects/containers/source/scenario.cpp
+++ b/cvs/objects/containers/source/scenario.cpp
@@ -65,6 +65,7 @@
#include "solution/util/include/solution_info_param_parser.h"
#include "containers/include/imodel_feedback_calc.h"
#include "util/base/include/manage_state_variables.hpp"
+#include "util/base/include/supply_demand_curve_saver.h"
#if GCAM_PARALLEL_ENABLED && PARALLEL_DEBUG
#include
@@ -170,6 +171,9 @@ bool Scenario::XMLParse( const DOMNode* node ){
else if( nodeName == SolutionInfoParamParser::getXMLNameStatic() ) {
parseSingleNode( curr, mSolutionInfoParamParser, new SolutionInfoParamParser );
}
+ else if ( nodeName == SupplyDemandCurveSaver::getXMLNameStatic()) {
+ parseContainerNode( curr, mModelFeedbacks, new SupplyDemandCurveSaver );
+ }
/*!
* \warning Parsing of solution algorithms are a special case. They must be
@@ -467,9 +471,6 @@ bool Scenario::calculatePeriod( const int aPeriod,
bool success = solve( aPeriod ); // solution uses Bisect and NR routine to clear markets
-
- delete mManageStateVars;
- mManageStateVars = 0;
mWorld->postCalc( aPeriod );
@@ -500,6 +501,9 @@ bool Scenario::calculatePeriod( const int aPeriod,
writeDebuggingFiles( aXMLDebugFile, aTabs, aPeriod );
}
+ delete mManageStateVars;
+ mManageStateVars = 0;
+
return success;
}
diff --git a/cvs/objects/solution/util/include/solution_info_set.h b/cvs/objects/solution/util/include/solution_info_set.h
index 515066f17a..6dfc3ac0c1 100644
--- a/cvs/objects/solution/util/include/solution_info_set.h
+++ b/cvs/objects/solution/util/include/solution_info_set.h
@@ -112,7 +112,7 @@ class SolutionInfoSet {
bool hasSingularUnsolved();
void unsetBisectedFlag();
void printUnsolved( std::ostream& out );
- void findAndPrintSD( World* aWorld, Marketplace* aMarketplace, const int aPeriod, ILogger& aLogger );
+ void findAndPrintSD( World* aWorld, Marketplace* aMarketplace, const int aPeriod, std::ostream& aOut );
void printMarketInfo( const std::string& comment, const double worldCalcCount, std::ostream& out ) const;
void printDerivatives( std::ostream& aOut ) const;
diff --git a/cvs/objects/solution/util/source/solution_info_set.cpp b/cvs/objects/solution/util/source/solution_info_set.cpp
index 327263fdd0..c3c9839a6d 100644
--- a/cvs/objects/solution/util/source/solution_info_set.cpp
+++ b/cvs/objects/solution/util/source/solution_info_set.cpp
@@ -626,11 +626,11 @@ void SolutionInfoSet::printMarketInfo( const string& aLocation,
* \param aPeriod Period for which to print supply-demand curves.
* \param aLogger Logger stream to print the curves to.
*/
-void SolutionInfoSet::findAndPrintSD( World* aWorld, Marketplace* aMarketplace, const int aPeriod, ILogger& aLogger ) {
+void SolutionInfoSet::findAndPrintSD( World* aWorld, Marketplace* aMarketplace, const int aPeriod, ostream& aOut) {
const Configuration* conf = Configuration::getInstance();
const int numMarketsToFindSD = conf->getInt( "numMarketsToFindSD", 5 );
const int numPointsForSD = conf->getInt( "numPointsForSD", 5 );
-
+
// Sort the vector so the worst markets are first.
sort( solvable.begin(), solvable.end(), SolutionInfo::GreaterRelativeED() );
@@ -642,7 +642,7 @@ void SolutionInfoSet::findAndPrintSD( World* aWorld, Marketplace* aMarketplace,
}
SupplyDemandCurve sdCurve( i, solvable[ i ].getName() );
sdCurve.calculatePoints( numPointsForSD, *this, aWorld, aMarketplace, aPeriod );
- sdCurve.print( aLogger );
+ sdCurve.print( aOut );
}
}
diff --git a/cvs/objects/util/base/include/auto_file.h b/cvs/objects/util/base/include/auto_file.h
index 37d16deefa..603edc5798 100644
--- a/cvs/objects/util/base/include/auto_file.h
+++ b/cvs/objects/util/base/include/auto_file.h
@@ -93,13 +93,12 @@ class AutoOutputFile {
/*! \brief Open an output file with the given name.
* \details Opens an automatically closing output file with a given filename.
* \param aFileName Name of the file to open.
- * \todo This interface is dangerous because forgetting an argument calls a
- * different function.
+ * \param aOpenMode The file opening mode. Use std::ios_base::app to open in append mode.
*/
- explicit AutoOutputFile( const std::string& aFileName )
+ explicit AutoOutputFile( const std::string& aFileName, std::ios_base::openmode aOpenMode = std::ios_base::out )
:mShouldWrite( true )
{
- boost::iostreams::file_sink fileBuffer( aFileName );
+ boost::iostreams::file_sink fileBuffer( aFileName, aOpenMode );
mWrappedFile.push( fileBuffer );
util::checkIsOpen( fileBuffer, aFileName );
}
diff --git a/cvs/objects/util/base/include/supply_demand_curve.h b/cvs/objects/util/base/include/supply_demand_curve.h
index bfa7ab141f..7ed6e41c3a 100644
--- a/cvs/objects/util/base/include/supply_demand_curve.h
+++ b/cvs/objects/util/base/include/supply_demand_curve.h
@@ -65,10 +65,17 @@ class SupplyDemandCurve {
public:
SupplyDemandCurve( int aMarketNumber, const std::string& aMarketName );
~SupplyDemandCurve();
+
+ void calculatePoints( const std::vector& aPrices, SolutionInfoSet& aSolnSet, World* aWorld,
+ Marketplace* aMarketplace, const int aPeriod, bool aIsPricesRelative );
+
+ // Legacy version
void calculatePoints( const int aNumPoints, SolutionInfoSet& aSolnSet, World* aWorld,
Marketplace* aMarketplace, const int aPeriod );
- void print( ILogger& aSDLog ) const;
-
+
+ void print( std::ostream& aOut ) const;
+ void printCSV( std::ostream& aOut, int period, bool aPrintHeader ) const;
+
private:
//! Index to the market which the curve is calculating for.
int mMarketNumber;
@@ -88,7 +95,7 @@ class SupplyDemandPoint
public:
SupplyDemandPoint( const double aPrice, const double aDemand, const double aSupply, const double aFx );
double getPrice() const;
- void print( ILogger& aSDLog ) const;
+ void print( std::ostream& aOut ) const;
/*!
* \brief Binary comparison operator used for SavePoint pointers to order by increasing price.
diff --git a/cvs/objects/util/base/include/supply_demand_curve_saver.h b/cvs/objects/util/base/include/supply_demand_curve_saver.h
new file mode 100644
index 0000000000..ccb6690235
--- /dev/null
+++ b/cvs/objects/util/base/include/supply_demand_curve_saver.h
@@ -0,0 +1,113 @@
+#ifndef _SUPPLY_DEMAND_CURVE_SAVER_H_
+#define _SUPPLY_DEMAND_CURVE_SAVER_H_
+#if defined(_MSC_VER)
+#pragma once
+#endif
+
+/*
+* LEGAL NOTICE
+* This computer software was prepared by Battelle Memorial Institute,
+* hereinafter the Contractor, under Contract No. DE-AC05-76RL0 1830
+* with the Department of Energy (DOE). NEITHER THE GOVERNMENT NOR THE
+* CONTRACTOR MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
+* LIABILITY FOR THE USE OF THIS SOFTWARE. This notice including this
+* sentence must appear on any copies of this computer software.
+*
+* EXPORT CONTROL
+* User agrees that the Software will not be shipped, transferred or
+* exported into any country or used in any manner prohibited by the
+* United States Export Administration Act or any other applicable
+* export laws, restrictions or regulations (collectively the "Export Laws").
+* Export of the Software may require some form of license or other
+* authority from the U.S. Government, and failure to obtain such
+* export control license may result in criminal liability under
+* U.S. laws. In addition, if the Software is identified as export controlled
+* items under the Export Laws, User represents and warrants that User
+* is not a citizen, or otherwise located within, an embargoed nation
+* (including without limitation Iran, Syria, Sudan, Cuba, and North Korea)
+* and that User is not otherwise prohibited
+* under the Export Laws from receiving the Software.
+*
+* Copyright 2011 Battelle Memorial Institute. All Rights Reserved.
+* Distributed as open-source under the terms of the Educational Community
+* License version 2.0 (ECL 2.0). http://www.opensource.org/licenses/ecl2.php
+*
+* For further details, see: http://www.globalchange.umd.edu/models/gcam/
+*
+*/
+
+/*!
+* \file supply_demand_curve_saver.h
+* \ingroup Objects
+* \brief The SupplyDemandCurveSaver class header file.
+* \author Rich Plevin
+*/
+
+#include
+#include
+#include
+#include "containers/include/imodel_feedback_calc.h"
+
+class SolutionInfo;
+
+/*!
+ * \brief Writes out supply & demand curves for user-designated markets after each
+ * model period has solved.
+ * \details Users can configure via XML parse
+ * - mName The market name to create the Supply/Demand curves for
+ * - mPrices A vector of prices at which to calculate Supply / Demand points.
+ * - mIsPricesRelative A flag to indicate if mPrices are relative to the solved price in each model period.
+ * All results will be written to the output file specified in the Configuration
+ * parameter "supplyDemandCurves". Note that the file will get reset the first
+ * time any instanve of this class needs to write to the file and will append to
+ * it thereafter.
+ *
+ * \sa SupplyDemandCurve
+ * \author Rich Plevin
+ */
+class SupplyDemandCurveSaver : public IModelFeedbackCalc
+{
+public:
+ SupplyDemandCurveSaver();
+ virtual ~SupplyDemandCurveSaver();
+
+ static const std::string& getXMLNameStatic();
+
+ // INamed methods
+ virtual const std::string& getName() const;
+
+ // IParsable methods
+ virtual bool XMLParse( const xercesc::DOMNode* aNode );
+
+ // IModelFeedbackCalc methods
+ virtual void calcFeedbacksBeforePeriod( Scenario* aScenario,
+ const IClimateModel* aClimateModel,
+ const int aPeriod );
+
+ virtual void calcFeedbacksAfterPeriod( Scenario* aScenario,
+ const IClimateModel* aClimateModel,
+ const int aPeriod );
+
+protected:
+ //! The name of this feedback
+ std::string mName;
+
+ //! A flag indicating if a user wanted the mPrices to be relative to the
+ //! the solved price for the configured market in each model period.
+ bool mIsPricesRelative;
+
+ //! The price points for which we should calculate supply and demands
+ std::vector mPrices;
+
+ //! A flag to help us determine if we need to reset the output file (the
+ //! first time around) or simply append to it.
+ static std::ios_base::openmode mOpenMode;
+
+ void printCSV( std::ostream& aOut, Scenario* aScenario, const int aPeriod, bool aPrintHeader );
+
+ int getMarketIndex(const std::string& aMarketName, std::vector &aSolvable );
+
+};
+
+#endif // _SUPPLY_DEMAND_CURVE_SAVER_H_
+
diff --git a/cvs/objects/util/base/source/supply_demand_curve.cpp b/cvs/objects/util/base/source/supply_demand_curve.cpp
index a8cf75cbcf..9dbc13aa8c 100644
--- a/cvs/objects/util/base/source/supply_demand_curve.cpp
+++ b/cvs/objects/util/base/source/supply_demand_curve.cpp
@@ -70,93 +70,108 @@ SupplyDemandCurve::~SupplyDemandCurve() {
}
}
-/*! \brief Calculate given number of supply and demand points.
+/*! \brief Calculate supply and demand points for the given vector of prices.
*
* This function first determines a series of price ratios to use to determine the prices to
* create SupplyDemandPoints for. It then saves the original marketplace information, and perturbs the price
* as specified by the price ratios. Using this new perturbed price, it call World::Calc to determine supply and
-* demand for the market. It saves that point for printing later, and continues to perform this process for each price.
-* Finally it restores the original market information.
+* demand for the given market. It saves that point for printing later, and continues to perform this process
+* for each price. Finally it restores the original market information.
*
-* \param aNumPoints The number of points to calculate.
+* \param aPrices The vector of prices at which to to calculate.
* \param aSolnSet The solution set to interact with markets through.
* \param aWorld The World object to use for World::calc
* \param aMarketplace The marketplace to use to store and restore information.
* \param aPeriod The period to perform the calculations on.
-* \todo Un-hardcode the prices.
+* \param aIsPricesRelative If true, prices are interpreted as relative to the market clearing price.
*/
-
-void SupplyDemandCurve::calculatePoints( const int aNumPoints, SolutionInfoSet& aSolnSet, World* aWorld,
- Marketplace* aMarketplace, const int aPeriod )
+void SupplyDemandCurve::calculatePoints( const std::vector& aPrices, SolutionInfoSet& aSolnSet, World* aWorld,
+ Marketplace* aMarketplace, const int aPeriod, bool aIsPricesRelative )
{
- vector priceMults;
-
- // Determine price ratios.
- const int middle = static_cast( floor( double( aNumPoints ) / double( 2 ) ) );
-
- for( int pointNumber = 0; pointNumber < aNumPoints; pointNumber++ ) {
-
- if( pointNumber < middle ) {
- priceMults.push_back( 1 - double( 1 ) / double( middle - abs( middle - pointNumber ) + 2 ) );
- }
- else if( pointNumber == middle ) {
- priceMults.push_back( 1 );
- }
- else {
- priceMults.push_back( 1 + double( 1 ) / double( middle - abs( middle - pointNumber ) + 2 ) );
- }
- }
-
size_t nsolv = aSolnSet.getNumSolvable();
using UBVECTOR = boost::numeric::ublas::vector;
- UBVECTOR x( nsolv ), fx( nsolv );
+ UBVECTOR x( nsolv );
+ UBVECTOR fx( nsolv );
+ int numPrices = aPrices.size();
+ std::vector scaledPrices(numPrices, 0);
for( size_t i = 0; i < nsolv; ++i ) {
x[i] = aSolnSet.getSolvable( i ).getPrice();
}
-
- // double basePrice = x[ mMarketNumber ];
+
+ // Save raw price for given market.
+ double actualPrice = x[ mMarketNumber ]; // before scaling
// This is the closure that will evaluate the ED function
LogEDFun F(aSolnSet, aWorld, aMarketplace, aPeriod, false);
F.scaleInitInputs( x );
-
+
+ double scaledPrice = x[ mMarketNumber ]; // after scaling
+ double scalingFactor = (aIsPricesRelative ? scaledPrice : scaledPrice / actualPrice);
+
// Call F( x ), store the result in fx
- F(x,fx);
+ F(x, fx);
+
// Have the state manage save the current state as a "clean" state.
scenario->getManageStateVariables()->setPartialDeriv(true);
-
- // iterate through the points and determine supply and demand.
- for ( int pointNumber2 = 0; pointNumber2 < aNumPoints; pointNumber2++ ) {
-
+
+ // iterate through the prices and determine supply and demand.
+ for ( int i = 0; i < numPrices; i++ ) {
F.partial(mMarketNumber);
- // Note x is a scaled price
- // x[ mMarketNumber ] = priceMults[ pointNumber2 ] * basePrice;
- x[ mMarketNumber ] = pointNumber2 * ( double( 10 ) / double( aNumPoints - 1 ) );
+
+ x[ mMarketNumber ] = aPrices[ i ] * scalingFactor;
+
F(x, fx, mMarketNumber);
+
+ SolutionInfo s = aSolnSet.getSolvable( mMarketNumber );
+ mPoints.push_back( new SupplyDemandPoint( s.getPrice(), s.getDemand(), s.getSupply(), fx[ mMarketNumber ] ) );
+ }
+
+ // restore state information for summary.
+ F.partial(-1);
+}
- mPoints.push_back( new SupplyDemandPoint( aSolnSet.getSolvable( mMarketNumber ).getPrice(),
- aSolnSet.getSolvable( mMarketNumber ).getDemand(),
- aSolnSet.getSolvable( mMarketNumber ).getSupply(),
- fx[ mMarketNumber ] ) );
+/*! \brief Calculate given number of supply and demand points.
+*
+* Computes supply and demand points for the given number of prices, spaced evenly in the range [0, 10].
+* Although this legacy approach is of dubious value, it's included here for backward compatibility.
+*
+* \param aNumPoints The number of points to calculate.
+* \param aSolnSet The solution set to interact with markets through.
+* \param aWorld The World object to use for World::calc
+* \param aMarketplace The marketplace to use to store and restore information.
+* \param aPeriod The period to perform the calculations on.
+* \todo Un-hardcode the prices.
+*/
+void SupplyDemandCurve::calculatePoints( const int aNumPoints, SolutionInfoSet& aSolnSet, World* aWorld,
+ Marketplace* aMarketplace, const int aPeriod )
+{
+ vectorprices;
+ double minPrice = 0.0;
+ double maxPrice = 10.0;
+ double increment = maxPrice / (aNumPoints - 1);
- } // Completed iterating through all price points.
+ for (double price = minPrice; price < maxPrice; price += increment)
+ prices.push_back(price);
- // restore state information for summary.
- F.partial(-1);
+ // ensure final price is included (since summing increments may be inexact)
+ prices.push_back(maxPrice);
+
+ bool isRelative = false;
+ calculatePoints( prices, aSolnSet, aWorld, aMarketplace, aPeriod, isRelative );
}
/*! \brief Print the supply demand curve.
*
* This function prints the vector of SupplyDemandPoints created during the calculatePoints function.
* It creates a copy of points and sorts them before printing them. This was done so that the printing function
-* could remain constant. The points are printed to the Logger passed as an argument.
+* could remain constant. The points are printed to the ostream passed as an argument.
*
* \param sdLog Logger to print the points to.
*/
-void SupplyDemandCurve::print( ILogger& aSDLog ) const {
- aSDLog << "Supply and Demand curves for: " << mMarketName << endl;
- aSDLog << "Price,Demand,Supply,Fx" << endl;
+void SupplyDemandCurve::print( std::ostream& aOut ) const {
+ aOut << "Supply and Demand curves for: " << mMarketName << endl;
+ aOut << "Price,Demand,Supply,Fx" << endl;
// Create a copy of the points vector so that we can sort it while keeping the print function constant.
// Since the vector contains pointers to SupplyDemandPoints, this is relatively inexpensive.
@@ -165,12 +180,32 @@ void SupplyDemandCurve::print( ILogger& aSDLog ) const {
// Sort the SupplyDemandPoint object pointers in the pointsCopy vector by increasing price by using the LesserPrice binary operator.
sort( pointsCopy.begin(), pointsCopy.end(), SupplyDemandPoint::LesserPrice() );
for ( vector::const_iterator i = pointsCopy.begin(); i != pointsCopy.end(); i++ ) {
- ( *i )->print( aSDLog );
+ ( *i )->print( aOut );
}
- aSDLog << endl;
+ aOut << endl;
}
+// Same as above but with period and market added in csv format
+void SupplyDemandCurve::printCSV( std::ostream& aOut, int period, bool aPrintHeader ) const {
+ if ( aPrintHeader )
+ aOut << "Market,Period,Price,Demand,Supply,normalizedExcessDemand" << endl;
+
+ // Create a copy of the points vector so that we can sort it while keeping the print function constant.
+ // Since the vector contains pointers to SupplyDemandPoints, this is relatively inexpensive.
+ vector pointsCopy( mPoints );
+
+ // Sort the SupplyDemandPoint object pointers in the pointsCopy vector by increasing price by using the LesserPrice binary operator.
+ sort( pointsCopy.begin(), pointsCopy.end(), SupplyDemandPoint::LesserPrice() );
+ for ( vector::const_iterator i = pointsCopy.begin(); i != pointsCopy.end(); i++ ) {
+ aOut << mMarketName << "," << period << ",";
+ ( *i )->print( aOut );
+ }
+
+ //aOut << endl;
+}
+
+
//! Constructor
SupplyDemandCurve::SupplyDemandPoint::SupplyDemandPoint( const double aPrice, const double aDemand, const double aSupply, const double aFx )
: mPrice( aPrice ), mDemand( aDemand ), mSupply( aSupply ), mFx( aFx )
@@ -191,9 +226,9 @@ double SupplyDemandCurve::SupplyDemandPoint::getPrice() const {
*
* Print the point in a csv format to the specified logger.
*
-* \param sdLog The Logger to print to.
+* \param aOut The ostream to print to.
*/
-void SupplyDemandCurve::SupplyDemandPoint::print( ILogger& aSDLog ) const {
- aSDLog << mPrice << "," << mDemand << "," << mSupply << "," << mFx << endl;
+void SupplyDemandCurve::SupplyDemandPoint::print( std::ostream& aOut ) const {
+ aOut << mPrice << "," << mDemand << "," << mSupply << "," << mFx << endl;
}
diff --git a/cvs/objects/util/base/source/supply_demand_curve_saver.cpp b/cvs/objects/util/base/source/supply_demand_curve_saver.cpp
new file mode 100644
index 0000000000..3fbc998ebd
--- /dev/null
+++ b/cvs/objects/util/base/source/supply_demand_curve_saver.cpp
@@ -0,0 +1,206 @@
+/*
+* LEGAL NOTICE
+* This computer software was prepared by Battelle Memorial Institute,
+* hereinafter the Contractor, under Contract No. DE-AC05-76RL0 1830
+* with the Department of Energy (DOE). NEITHER THE GOVERNMENT NOR THE
+* CONTRACTOR MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
+* LIABILITY FOR THE USE OF THIS SOFTWARE. This notice including this
+* sentence must appear on any copies of this computer software.
+*
+* EXPORT CONTROL
+* User agrees that the Software will not be shipped, transferred or
+* exported into any country or used in any manner prohibited by the
+* United States Export Administration Act or any other applicable
+* export laws, restrictions or regulations (collectively the "Export Laws").
+* Export of the Software may require some form of license or other
+* authority from the U.S. Government, and failure to obtain such
+* export control license may result in criminal liability under
+* U.S. laws. In addition, if the Software is identified as export controlled
+* items under the Export Laws, User represents and warrants that User
+* is not a citizen, or otherwise located within, an embargoed nation
+* (including without limitation Iran, Syria, Sudan, Cuba, and North Korea)
+* and that User is not otherwise prohibited
+* under the Export Laws from receiving the Software.
+*
+* Copyright 2011 Battelle Memorial Institute. All Rights Reserved.
+* Distributed as open-source under the terms of the Educational Community
+* License version 2.0 (ECL 2.0). http://www.opensource.org/licenses/ecl2.php
+*
+* For further details, see: http://www.globalchange.umd.edu/models/gcam/
+*
+*/
+
+/*!
+* \file supply_demand_curve_saver.cpp
+* \ingroup Objects
+* \brief SupplyDemandCurveSaver class source file.
+* \author Rich Plevin
+*/
+
+#include
+#include
+#include
+#include "containers/include/imodel_feedback_calc.h"
+#include "containers/include/scenario.h"
+#include "containers/include/world.h"
+#include "solution/util/include/solution_info_set.h"
+#include "solution/util/include/solution_info.h"
+#include "solution/util/include/solvable_solution_info_filter.h"
+#include "solution/util/include/solution_info_param_parser.h"
+#include "util/base/include/auto_file.h"
+#include "util/base/include/definitions.h"
+#include "util/base/include/supply_demand_curve.h"
+#include "util/base/include/supply_demand_curve_saver.h"
+#include "util/base/include/xml_helper.h"
+#include "util/base/include/model_time.h"
+#include "marketplace/include/market.h"
+#include "marketplace/include/marketplace.h"
+
+using namespace std;
+using namespace xercesc;
+
+SupplyDemandCurveSaver::SupplyDemandCurveSaver() : mIsPricesRelative(true) {
+}
+
+// First open uses "out" mode to overwrite; subsequent calls append
+ios_base::openmode SupplyDemandCurveSaver::mOpenMode = ios_base::out;
+
+SupplyDemandCurveSaver::~SupplyDemandCurveSaver() {
+}
+
+const string& SupplyDemandCurveSaver::getXMLNameStatic() {
+ // This is the string you will use to refer to this object
+ // in input files.
+ const static string XML_NAME = "supply-demand-curve-saver";
+ return XML_NAME;
+}
+
+const string& SupplyDemandCurveSaver::getName() const {
+ return mName;
+}
+
+/* Example XML:
+
+
+ 0.995
+ 1.000
+ 1.005
+
+
+ */
+
+bool SupplyDemandCurveSaver::XMLParse( const DOMNode* aNode ) {
+ /*! \pre Make sure we were passed a valid node. */
+ assert( aNode );
+
+ // get the name attribute.
+ mName = XMLHelper::getAttr( aNode, XMLHelper::name() );
+
+ // get all child nodes.
+ DOMNodeList* nodeList = aNode->getChildNodes();
+
+ // loop through the child nodes.
+ for ( unsigned int i = 0; i < nodeList->getLength(); i++ ){
+ DOMNode* curr = nodeList->item( i );
+ string nodeName = XMLHelper::safeTranscode( curr->getNodeName() );
+
+ if ( nodeName == XMLHelper::text() ) {
+ continue;
+ }
+ else if ( nodeName == "is-price-relative" ) {
+ // defaults to true
+ mIsPricesRelative = XMLHelper::getValue( curr );
+ }
+ else if ( nodeName == "price" ) {
+ double price = XMLHelper::getValue( curr );
+ mPrices.push_back(price);
+ }
+ else {
+ ILogger& mainLog = ILogger::getLogger( "main_log" );
+ mainLog.setLevel( ILogger::ERROR );
+ mainLog << "Unknown element " << nodeName << " encountered while parsing " << getXMLNameStatic() << endl;
+ }
+ }
+
+ return true;
+}
+
+
+/*! \brief Find and print supply-demand curves for designated market.
+*
+* This function creates a SupplyDemandCurve for the designated market by calculating
+* the supply and demand at a series of prices, and prints the resulting curve.
+*
+* \author Rich Plevin (based on SolutionInfoSet::findAndPrintSD)
+* \param aOut Output stream to print the curves to.
+* \param aScenario the scenario to use to find the marketplace
+* \param aPeriod Period for which to print supply-demand curves.
+* \param aPrintHeader whether to print the CSV header (column names)
+*/
+void SupplyDemandCurveSaver::printCSV( ostream& aOut, Scenario* aScenario,
+ const int aPeriod, bool aPrintHeader )
+{
+ World* world = aScenario->getWorld();
+ Marketplace* marketplace = scenario->getMarketplace();
+ SolutionInfoSet solnInfoSet = SolutionInfoSet( marketplace );
+ SolutionInfoParamParser solnParams;
+ solnInfoSet.init( aPeriod, 0.001, 0.001, &solnParams );
+ vector solvable = solnInfoSet.getSolvableSet();
+
+ int market_index = getMarketIndex(mName, solvable);
+
+ if ( market_index < 0 ) {
+ aOut << "# Market for " << mName << " was not found." << endl;
+
+ } else {
+ SupplyDemandCurve sdCurve( market_index, mName );
+
+ sdCurve.calculatePoints( mPrices, solnInfoSet, world, marketplace, aPeriod, mIsPricesRelative );
+ sdCurve.printCSV( aOut, aPeriod, aPrintHeader );
+ }
+}
+
+/*! \brief Find the given marketName in the solvable markets and return its index, if found, else -1.
+ */
+int SupplyDemandCurveSaver::getMarketIndex(const string& marketName, vector &aSolvable ) {
+ for ( int i = 0; i < aSolvable.size(); ++i ) {
+ if ( aSolvable[ i ].getName() == marketName )
+ return i;
+ }
+ return -1;
+}
+
+void SupplyDemandCurveSaver::calcFeedbacksBeforePeriod( Scenario* aScenario,
+ const IClimateModel* aClimateModel,
+ const int aPeriod )
+{
+ // do nothing
+}
+
+void SupplyDemandCurveSaver::calcFeedbacksAfterPeriod( Scenario* aScenario,
+ const IClimateModel* aClimateModel,
+ const int aPeriod )
+{
+ const Configuration* conf = Configuration::getInstance();
+ string confVarName = "supplyDemandCurves";
+
+ if ( ! conf->shouldWriteFile( confVarName ) ) {
+ return;
+ }
+
+ // supply and demand curves are useless for calibration periods, so skip them
+ if ( aPeriod <= aScenario->getModeltime()->getFinalCalibrationPeriod() ) {
+ return;
+ }
+
+ string fileName = conf->getFile( confVarName, "supplyDemandCurves.csv");
+
+ AutoOutputFile outFile(fileName, mOpenMode );
+
+ // First time through (before resetting open mode to append) write header, too.
+ bool printHeader = (mOpenMode == ios_base::out);
+ printCSV( *outFile, scenario, aPeriod, printHeader);
+
+ mOpenMode = ios_base::app; // after first call, append
+}
+
diff --git a/input/extra/supply_demand_curves.xml b/input/extra/supply_demand_curves.xml
new file mode 100644
index 0000000000..9e2befa415
--- /dev/null
+++ b/input/extra/supply_demand_curves.xml
@@ -0,0 +1,33 @@
+
+
+
+ 1
+ 0.500
+ 0.750
+ 0.999
+ 1.000
+ 1.001
+ 1.250
+ 1.500
+
+
+ 1
+ 0.500
+ 0.750
+ 0.999
+ 1.000
+ 1.001
+ 1.250
+ 1.500
+
+
+ 1
+ 0.500
+ 0.750
+ 0.999
+ 1.000
+ 1.001
+ 1.250
+ 1.500
+
+