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 + +