-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstructure.go
133 lines (114 loc) · 3.8 KB
/
structure.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package fragbag
import (
"fmt"
"strings"
"github.com/TuftsBCB/structure"
)
var _ = StructureLibrary(&structureAtoms{})
// structureAtoms represents a Fragbag structural fragment library.
// Fragbag fragment libraries are fixed both in the number of fragments and in
// the size of each fragment.
type structureAtoms struct {
Ident string
Fragments []structureAtomsFrag
FragSize int
}
// Fragment corresponds to a single structural fragment in a fragment library.
// It holds the fragment number identifier and the 3 dimensional coordinates.
type structureAtomsFrag struct {
FragNumber int
FragAtoms []structure.Coords
}
// NewStructureAtoms initializes a new Fragbag structure library with the
// given name and fragments. All fragments given must have exactly the same
// size.
func NewStructureAtoms(
name string,
fragments [][]structure.Coords,
) (StructureLibrary, error) {
lib := new(structureAtoms)
lib.Ident = name
for _, frag := range fragments {
if err := lib.add(frag); err != nil {
return nil, err
}
}
return lib, nil
}
func (lib *structureAtoms) SubLibrary() Library {
return nil
}
// add adds a structural fragment to the library. The first call to Add may
// contain any number of coordinates. All subsequent adds must contain the
// same number of coordinates as the first.
func (lib *structureAtoms) add(coords []structure.Coords) error {
if lib.Fragments == nil || len(lib.Fragments) == 0 {
frag := structureAtomsFrag{0, coords}
lib.Fragments = append(lib.Fragments, frag)
lib.FragSize = len(coords)
return nil
}
frag := structureAtomsFrag{len(lib.Fragments), coords}
if lib.FragSize != len(coords) {
return fmt.Errorf("Fragment %d has length %d; expected length %d.",
frag.FragNumber, len(coords), lib.FragSize)
}
lib.Fragments = append(lib.Fragments, frag)
return nil
}
func (lib *structureAtoms) Tag() string {
return libTagStructureAtoms
}
// Size returns the number of fragments in the library.
func (lib *structureAtoms) Size() int {
return len(lib.Fragments)
}
// FragmentSize returns the size of every fragment in the library.
func (lib *structureAtoms) FragmentSize() int {
return lib.FragSize
}
// String returns a string with the name of the library, the number of
// fragments in the library and the size of each fragment.
func (lib *structureAtoms) String() string {
return fmt.Sprintf("%s (%d, %d)",
lib.Ident, len(lib.Fragments), lib.FragSize)
}
func (lib *structureAtoms) Name() string {
return lib.Ident
}
// rmsdMemory creates reusable memory for use with RMSD calculation with
// suitable size for this fragment library. Only one goroutine can use the
// memory at a time.
func (lib *structureAtoms) rmsdMemory() structure.Memory {
return structure.NewMemory(lib.FragSize)
}
// Best returns the number of the fragment that best corresponds
// to the region of atoms provided.
// The length of `atoms` must be equivalent to the fragment size.
func (lib *structureAtoms) BestStructureFragment(atoms []structure.Coords) int {
var testRmsd float64
mem := lib.rmsdMemory()
bestRmsd, bestFragNum := 0.0, -1
for _, frag := range lib.Fragments {
testRmsd = structure.RMSDMem(mem, atoms, frag.FragAtoms)
if bestFragNum == -1 || testRmsd < bestRmsd {
bestRmsd, bestFragNum = testRmsd, frag.FragNumber
}
}
return bestFragNum
}
func (lib *structureAtoms) Atoms(fragNum int) []structure.Coords {
return lib.Fragments[fragNum].FragAtoms
}
func (lib *structureAtoms) Fragment(fragNum int) interface{} {
return lib.Atoms(fragNum)
}
// String returns the fragment number, library and its corresponding atoms.
func (lib *structureAtoms) FragmentString(fragNum int) string {
atoms := lib.Atoms(fragNum)
satoms := make([]string, len(atoms))
for i, atom := range atoms {
satoms[i] = fmt.Sprintf("\t%s", atom)
}
return fmt.Sprintf("> %d\n%s", fragNum, strings.Join(satoms, "\n"))
}