Skip to content
Robert Carlsen edited this page May 23, 2016 · 1 revision

Custom objective functions can be added to the optimization tooling by writing a little code and rebuilding the cloudlus tools. To add a new objective you need to add some code to the github.com/rwcarlsen/cloudlus/scen package (i.e. the scen directory in the cloudlus repository). The code is written in Go (https://golang.org). You can get a quick tour at https://tour.golang.org.

The first thing you need to do is create a .go extension text file named most any way you like (must be lower case alpha-numeric+underscores, no leading underscores) placed directly inside the scen directory with the following contents:

package scen

import (
    "database/sql"
)

func init() {
    // this registers your custom objective function with the master list of
    // all available objectives.  "myobjname" is the name by which you can
    // select/specify your objective from the scenario configuration file.
    // MyObjFuncName can is the name of the function that you choose below
    ObjFuncs["myobjname"] = MyObjFuncName
}

// This function calculates your the objective value using the scenario
// configuration file parameters (i.e. in the scen arg) and a Cyclus database
// accessible via the db arg. The simid arg can be ignored unless the database
// might have more than one simulation in it.  The function then returns the
// objective value and an error if any occured.  This function can be named
// anything you like but should start with an upper case letter; be sure the
// ObjFuncs map assignment has this name on the right hand side.
//
// Documentation for the fields/info available in the scen struct can be found
// at https://godoc.org/github.com/rwcarlsen/cloudlus/scen#Scenario.
// Documentation for using the db object (e.g. running SQL queries) can be
// found at https://golang.org/pkg/database/sql/.
func MyObjFuncName(scen *Scenario, db *sql.DB, simid []byte) (float64, error) {
    
    // insert your objective calculating code here...

}

Then all you need to do is rebuild/install the cloudlus tools:

go install github.com/rwcarlsen/cloudlus/...

Here is an example of one of the built-in objectives:

func ObjSlowVsFastPowerPenalty(scen *Scenario, db *sql.DB, simid []byte) (float64, error) {
    // define query string with place-holders for prototype names and
    // simulation ID
	q1 := `
        SELECT TOTAL(Value) FROM timeseriespower AS p
           JOIN agents AS a ON a.agentid=p.agentid AND a.simid=p.simid
           WHERE a.Prototype IN (?,?) AND p.simid=?
		`

	slowE := 0.0
    // This is a 1-result query so we can use the convenience QueryRow method.
    // We pass our query string and the three fill-in values for the ?
    // placeholders.  We directly scan the result into slowE var.
	err := db.QueryRow(q1, "slow_reactor", "init_slow_reactor", simid).Scan(&slowE)
	if err != nil {
		return math.Inf(1), err
	}

    // do the same thing again for the fast_reactor prototype
	fastE := 0.0
	err = db.QueryRow(q1, "fast_reactor", "fast_reactor", simid).Scan(&fastE)
	if err != nil {
		return math.Inf(1), err
	}

	totE := slowE + fastE

	// use data from the scenario configuration to calculate time integrated
    // installed capacity (i.e. cumulative energy capacity)
	builds := map[string][]Build{}
	for _, b := range scen.Builds {
		builds[b.Proto] = append(builds[b.Proto], b)
	}
	totcap := 0.0
	for t := 0; t < scen.SimDur; t++ {
		totcap += scen.PowerCap(builds, t)
	}

    // use energy generation and capacity values to calculate final objective
	return slowE / totE * totcap / totE, nil
}
Clone this wiki locally