-
Notifications
You must be signed in to change notification settings - Fork 3
Custom Objectives
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
}