Skip to content

Commit

Permalink
fix TreeFromDb function and make taintnodes function robust against h…
Browse files Browse the repository at this point in the history
…oles of time
  • Loading branch information
rwcarlsen committed May 6, 2016
1 parent 543ca6d commit 29bf230
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 61 deletions.
94 changes: 45 additions & 49 deletions cmd/cyan/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/rwcarlsen/cyan/nuc"
"github.com/rwcarlsen/cyan/post"
"github.com/rwcarlsen/cyan/query"
"github.com/rwcarlsen/cyan/taint"
_ "github.com/rwcarlsen/go-sqlite3"
)

Expand Down Expand Up @@ -857,7 +858,13 @@ func doFlowGraph(cmd string, args []string) {
fmt.Println(" nodesep=1.0;")
fmt.Println(" edge [fontsize=9];")
for _, arc := range arcs {
fmt.Printf(" \"%v\" -> \"%v\" [label=\"%v\\n(%.3g kg)\"];\n", arc.Src, arc.Dst, arc.Commod, arc.Quantity)
srcname := arc.SrcProto
dstname := arc.DstProto
if !*proto {
srcname = fmt.Sprintf("%v %v", arc.SrcProto, arc.SrcId)
dstname = fmt.Sprintf("%v %v", arc.DstProto, arc.DstId)
}
fmt.Printf(" \"%v\" -> \"%v\" [label=\"%v\\n(%.3g kg)\"];\n", srcname, dstname, arc.Commod, arc.Quantity)
}
fmt.Println("}")
}
Expand Down Expand Up @@ -990,63 +997,52 @@ func doTaint(cmd string, args []string) {
log.Printf("%v\n", cmds.Help(cmd))
fs.PrintDefaults()
}
t := fs.Int("time", -1, "time step for which to print taint")
t := fs.Int("t", -1, "time step for which to print taint")
res := fs.Int("res", -1, "resource ID of object to track")
fs.Parse(args)
initdb()

if *t == -1 || *res == -1 {
log.Fatalf("'-t' and '-res' flags are both required")
log.Fatalf("'-t' and '-res' flags are both required and cannot be negative")
}

s := `
SELECT t.time AS Time,t.SenderId AS SenderId,send.Prototype AS SenderProto,t.ReceiverId AS ReceiverId,recv.Prototype AS ReceiverProto,t.Commodity AS Commodity,SUM(r.Quantity*c.MassFrac) AS Quantity
FROM transactions AS t
JOIN resources AS r ON t.resourceid=r.resourceid AND r.simid=t.simid
JOIN agents AS send ON t.senderid=send.agentid AND send.simid=t.simid
JOIN agents AS recv ON t.receiverid=recv.agentid AND recv.simid=t.simid
JOIN compositions AS c ON c.qualid=r.qualid AND c.simid=t.simid
WHERE t.simid=? {{index . 0}} {{index . 1}} {{index . 2}} {{index . 3}}
GROUP BY t.transactionid
`

filters := make([]string, 4)
iargs := []interface{}{simid}
if *from != "" {
if *byagent {
filters[0] = "AND t.senderid=?"
fromid, err := strconv.Atoi(*from)
if err != nil {
log.Fatalf("invalid agent ID (-from=%v)", *from)
}
iargs = append(iargs, fromid)
} else {
filters[0] = "AND send.prototype=?"
iargs = append(iargs, *from)
}
}
if *to != "" {
if *byagent {
filters[1] = "AND t.receiverid=?"
toid, err := strconv.Atoi(*to)
if err != nil {
log.Fatalf("invalid agent ID (-to=%v)", *to)
}
iargs = append(iargs, toid)
} else {
filters[1] = "AND recv.prototype=?"
iargs = append(iargs, *to)
roots := taint.TreeFromDb(db, simid)
var base *taint.Node
for _, root := range roots {
if base = root.Locate(*res); base != nil {
break
}
}
if *commod != "" {
filters[2] = "AND t.commodity=?"
iargs = append(iargs, *commod)
if base == nil {
log.Fatalf("couldn't find resource id %v in graph", *res)
}
filters[3] = nuclidefilter(*nucs)

tmpl := template.Must(template.New("sql").Parse(s))
var buf bytes.Buffer
tmpl.Execute(&buf, filters)
customSql[cmd] = buf.String()
doCustom(os.Stdout, cmd, iargs...)
taints := base.Taint()

// print graph dot file
byproto := false
t1, t2 := 0, -1
arcs, err := query.FlowGraph(db, simid, t1, t2, byproto)
fatalif(err)

fmt.Println("digraph ResourceFlows {")
fmt.Println(" overlap = false;")
fmt.Println(" nodesep=1.0;")
fmt.Println(" edge [fontsize=9];")
for _, arc := range arcs {
var srctaint taint.TaintVal
if ts := taints[arc.SrcId]; *t < len(ts) {
srctaint = ts[*t]
}
var dsttaint taint.TaintVal
if ts := taints[arc.DstId]; *t < len(ts) {
dsttaint = ts[*t]
}
//srccolor := (srctaint.Taint * srctaint.Quantity) / base.Quantity
//dstcolor := (dsttaint.Taint * dsttaint.Quantity) / base.Quantity
srcname := fmt.Sprintf("%v %v\\n(%.5g kg of %.5g taint)", arc.SrcProto, arc.SrcId, srctaint.Quantity, srctaint.Taint)
dstname := fmt.Sprintf("%v %v\\n(%.5g kg of %.5g taint)", arc.DstProto, arc.DstId, dsttaint.Quantity, dsttaint.Taint)
fmt.Printf(" \"%v\" -> \"%v\" [label=\"%v\"];\n", srcname, dstname, arc.Commod)
}
fmt.Println("}")
}
13 changes: 8 additions & 5 deletions query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,11 @@ func InvMassAt(db *sql.DB, simid []byte, t int, agents ...int) (mass float64, er
}

type FlowArc struct {
Src string
Dst string
SrcId int
DstId int
SrcProto string
DstProto string
AgentId int
Commod string
Quantity float64
}
Expand All @@ -262,7 +265,7 @@ func FlowGraph(db *sql.DB, simid []byte, t0, t1 int, groupByProto bool) (arcs []

var sql string
if !groupByProto {
sql = `SELECT snd.Prototype || " " || tr.SenderId,rcv.Prototype || " " || tr.ReceiverId,tr.Commodity,SUM(res.Quantity) FROM (
sql = `SELECT snd.AgentId,rcv.AgentId,snd.Prototype,rcv.Prototype,tr.Commodity,SUM(res.Quantity) FROM (
Resources AS res
INNER JOIN Transactions AS tr ON tr.ResourceId = res.ResourceId
INNER JOIN Agents AS snd ON snd.AgentId = tr.SenderId
Expand All @@ -272,7 +275,7 @@ func FlowGraph(db *sql.DB, simid []byte, t0, t1 int, groupByProto bool) (arcs []
AND tr.Time >= ? AND tr.Time < ?
) GROUP BY tr.SenderId,tr.ReceiverId,tr.Commodity;`
} else {
sql = `SELECT snd.Prototype,rcv.Prototype,tr.Commodity,SUM(res.Quantity) FROM (
sql = `SELECT snd.AgentId,rcv.AgentId,snd.Prototype,rcv.Prototype,tr.Commodity,SUM(res.Quantity) FROM (
Resources AS res
INNER JOIN Transactions AS tr ON tr.ResourceId = res.ResourceId
INNER JOIN Agents AS snd ON snd.AgentId = tr.SenderId
Expand All @@ -289,7 +292,7 @@ func FlowGraph(db *sql.DB, simid []byte, t0, t1 int, groupByProto bool) (arcs []
}
for rows.Next() {
arc := FlowArc{}
if err := rows.Scan(&arc.Src, &arc.Dst, &arc.Commod, &arc.Quantity); err != nil {
if err := rows.Scan(&arc.SrcId, &arc.DstId, &arc.SrcProto, &arc.DstProto, &arc.Commod, &arc.Quantity); err != nil {
return nil, err
}
arcs = append(arcs, arc)
Expand Down
85 changes: 78 additions & 7 deletions taint/taint.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"database/sql"
"fmt"
"sort"
"strings"
)

Expand All @@ -23,6 +24,21 @@ type Node struct {
par2mark bool
}

type bytime []*NodeData

func (ns bytime) Len() int { return len(ns) }
func (ns bytime) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
func (ns bytime) Less(i, j int) bool {
if ns[i].Time != ns[j].Time {
return ns[i].Time < ns[j].Time
} else if ns[i].ResId != ns[j].ResId {
return ns[i].ResId < ns[j].ResId
} else if ns[i].AgentId != -1 && ns[j].AgentId != -1 {
return ns[i].AgentId < ns[j].AgentId
}
return false
}

func (n *Node) String() string {
var buf bytes.Buffer
n.str(&buf, 0)
Expand Down Expand Up @@ -65,6 +81,7 @@ type NodeData struct {
type nodeMap map[int][]*Node

func Tree(nodes []*NodeData) (roots []*Node) {
sort.Sort(bytime(nodes))
nodemap := nodeMap{}
nextid := 0

Expand Down Expand Up @@ -111,9 +128,34 @@ func Tree(nodes []*NodeData) (roots []*Node) {
roots = append(roots, node)
}
}

for _, root := range roots {
root.fixagentid()
}
return roots
}

// fixagentid assigns missing AgentId's to nodes. some nodes if generated from a cyclus database query don't have AgentId's
// associated with them and had them marked as -1. These are ommitted from
// the db because they don't affect inventories (i.e. intra-time-step,
// intra-agent modifications). So we can fill these in by assigning the same
// agentid as the parent node(s).
func (n *Node) fixagentid() {
if n == nil {
return
}

if n.AgentId == -1 {
if n.Parent1 != nil {
n.AgentId = n.Parent1.AgentId
} else {
// give up?
}
}
n.Child1.fixagentid()
n.Child2.fixagentid()
}

type TaintVal struct {
Taint float64
Quantity float64
Expand Down Expand Up @@ -154,11 +196,18 @@ func (n *Node) Taint() map[int][]TaintVal {

n.ResetTaint()
n.taintfrac = 1.0

// mark dirty edges
n.Child1.mark()
n.Child2.mark()

// calculate taintfracs
n.Child1.taint()
n.Child2.taint()

// aggregate by agent id and time
n.taintnodes(all)

return all
}

Expand Down Expand Up @@ -203,7 +252,6 @@ func (n *Node) taint() {
n.Parent2.taintfrac*n.Parent2.Quantity) / n.Quantity
}

fmt.Printf("agent %v, t %v: taint=%v\n", n.AgentId, n.Time, n.taintfrac)
n.Child1.taint()
n.Child2.taint()
}
Expand All @@ -227,6 +275,23 @@ func (n *Node) taintnodes(all map[int][]TaintVal) {
Taint: taintqty / qty,
Quantity: qty,
}

// fill in blank times between this node and its next child
if n.Child1 != nil {
for len(all[n.AgentId]) < n.Child1.Time+1 {
all[n.AgentId] = append(all[n.AgentId], TaintVal{})
}
for t := n.Time + 1; t < n.Child1.Time; t++ {
prev := all[n.AgentId][t]
qty := prev.Quantity + n.Quantity
taintqty := prev.Taint*prev.Quantity + n.taintfrac*n.Quantity
all[n.AgentId][t] = TaintVal{
Taint: taintqty / qty,
Quantity: qty,
}

}
}
}

if n.Child1 != nil {
Expand All @@ -240,22 +305,23 @@ func (n *Node) taintnodes(all map[int][]TaintVal) {
func TreeFromDb(db *sql.DB, simid []byte) (roots []*Node) {
s := `SELECT r.ResourceId,r.TimeCreated,inv.StartTime,r.Quantity,r.QualId,r.Parent1,r.Parent2,inv.AgentId
FROM resources AS r
INNER JOIN Inventories AS inv ON inv.SimId = r.SimId AND inv.ResourceId = r.ResourceId
LEFT JOIN Inventories AS inv ON inv.SimId = r.SimId AND inv.ResourceId = r.ResourceId
WHERE r.SimId = ?
ORDER BY r.TimeCreated,r.ResourceId,inv.StartTime`
ORDER BY r.ResourceId,r.TimeCreated,inv.StartTime`
rows, err := db.Query(s, simid)
if err != nil {
panic(err.Error())
}
defer rows.Close()

nodes := []*NodeData{}
var time2 int
var time2 sql.NullInt64
var agentid sql.NullInt64

for rows.Next() {
n := &NodeData{}

err := rows.Scan(&n.ResId, &n.Time, &time2, &n.Quantity, &n.QualId, &n.Parent1, &n.Parent2, &n.AgentId)
err := rows.Scan(&n.ResId, &n.Time, &time2, &n.Quantity, &n.QualId, &n.Parent1, &n.Parent2, &agentid)
if err != nil {
panic(err.Error())
}
Expand All @@ -264,8 +330,13 @@ func TreeFromDb(db *sql.DB, simid []byte) (roots []*Node) {
// its current state, then the node must be associated with the time
// when the resource moved into that agent rather than when it was
// created.
if time2 > n.Time {
n.Time = time2
if time2.Valid && int(time2.Int64) > n.Time {
n.Time = int(time2.Int64)
}

n.AgentId = -1
if agentid.Valid {
n.AgentId = int(agentid.Int64)
}

nodes = append(nodes, n)
Expand Down

0 comments on commit 29bf230

Please sign in to comment.