1 /**
2  *  \file RMF/Category.h
3  *  \brief Handle read/write of Model data from/to files.
4  *
5  *  Copyright 2007-2021 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #include "RMF/decorator/alternatives.h"
10 #include "RMF/decorator/physics.h"
11 #include "RMF/decorator/sequence.h"
12 #include <numeric>
13 
14 RMF_ENABLE_WARNINGS
15 
16 namespace RMF {
17 namespace decorator {
18 
19 namespace {
get_resolution_metric(double a,double b)20 double get_resolution_metric(double a, double b) {
21   if (a < b) std::swap(a, b);
22   return a / b - 1;
23 }
24 
get_resolution_impl(NodeConstHandle root,IntermediateParticleFactory ipcf,GaussianParticleFactory gpf)25 std::pair<double, bool> get_resolution_impl(NodeConstHandle root,
26                                               IntermediateParticleFactory ipcf,
27                                               GaussianParticleFactory gpf) {
28   std::pair<double, bool> ret(std::numeric_limits<double>::max(), false);
29   RMF_FOREACH(NodeConstHandle ch, root.get_children()) {
30     std::pair<double, bool> cur = get_resolution_impl(ch, ipcf, gpf);
31     ret.first = std::min(ret.first, cur.first);
32     ret.second = ret.second || cur.second;
33   }
34   if (!ret.second) {
35     if (ipcf.get_is(root)) {
36       ret.first = ipcf.get(root).get_radius();
37       ret.second = true;
38     } else if (gpf.get_is(root)) {
39       Vector3 sdfs = gpf.get(root).get_variances();
40       ret.first = std::accumulate(sdfs.begin(), sdfs.end(), 0.0) / 3.0;
41       ret.second = true;
42     }
43   }
44   return ret;
45 }
46 }
47 
AlternativesFactory(FileHandle fh)48 AlternativesFactory::AlternativesFactory(FileHandle fh)
49     : cat_(fh.get_category("alternatives")),
50       types_key_(fh.get_key<IntsTag>(cat_, "types")),
51       roots_key_(fh.get_key<IntsTag>(cat_, "roots")) {}
52 
AlternativesFactory(FileConstHandle fh)53 AlternativesFactory::AlternativesFactory(FileConstHandle fh)
54     : cat_(fh.get_category("alternatives")),
55       types_key_(fh.get_key<IntsTag>(cat_, "types")),
56       roots_key_(fh.get_key<IntsTag>(cat_, "roots")) {}
57 
get_alternative_impl(RepresentationType type,float resolution) const58 NodeID AlternativesConst::get_alternative_impl(RepresentationType type,
59                                                float resolution) const {
60   if (!get_node().get_has_value(types_key_)) return get_node().get_id();
61 
62   double closest_resolution = get_resolution(get_node());
63   int closest_index = -1;
64   Nullable<Ints> types = get_node().get_value(types_key_);
65   if (!types.get_is_null()) {
66     Ints roots = get_node().get_value(roots_key_);
67     for (unsigned int i = 0; i < types.get().size(); ++i) {
68       if (types.get()[i] != type) continue;
69       double cur_resolution =
70           get_resolution(get_node().get_file().get_node(NodeID(roots[i])));
71       if (get_resolution_metric(resolution, cur_resolution) <
72           get_resolution_metric(resolution, closest_resolution)) {
73         closest_index = i;
74         closest_resolution = cur_resolution;
75       }
76     }
77   }
78   if (closest_index == -1) {
79     return get_node().get_id();
80   } else {
81     return NodeID(get_node().get_value(roots_key_).get()[closest_index]);
82   }
83 }
84 
get_alternatives_impl(RepresentationType type) const85 NodeIDs AlternativesConst::get_alternatives_impl(RepresentationType type)
86     const {
87   NodeIDs ret;
88   if (type == PARTICLE) ret.push_back(get_node().get_id());
89 
90   if (get_node().get_has_value(roots_key_)) {
91     Ints roots = get_node().get_value(roots_key_).get();
92     Ints types = get_node().get_value(types_key_).get();
93 
94     for (unsigned int i = 0; i < roots.size(); ++i) {
95       RMF_INTERNAL_CHECK(roots[i] != 0, "The root can't be an alternative rep");
96       if (RepresentationType(types[i]) == type) ret.push_back(NodeID(roots[i]));
97     }
98   }
99   return ret;
100 }
101 
get_resolution(NodeConstHandle root)102 double get_resolution(NodeConstHandle root) {
103   ExplicitResolutionFactory erf(root.get_file());
104   if (erf.get_is(root)) {
105     return erf.get(root).get_static_explicit_resolution();
106   } else {
107     IntermediateParticleFactory ipcf(root.get_file());
108     GaussianParticleFactory gpf(root.get_file());
109     std::pair<double, bool> total = get_resolution_impl(root, ipcf, gpf);
110     RMF_USAGE_CHECK(total.second,
111                   std::string("No particles were found at ") + root.get_name());
112     return 1.0 / total.first;
113   }
114 }
115 
Alternatives(NodeHandle nh,IntsKey types_key,IntsKey roots_key)116 Alternatives::Alternatives(NodeHandle nh, IntsKey types_key, IntsKey roots_key)
117     : AlternativesConst(nh, types_key, roots_key) {}
118 
add_alternative(NodeHandle root,RepresentationType type)119 void Alternatives::add_alternative(NodeHandle root, RepresentationType type) {
120   RMF_USAGE_CHECK(root.get_id() != NodeID(0),
121                   "The root can't be an alternative");
122   get_node()
123       .get_shared_data()
124       ->access_static_value(get_node().get_id(), types_key_)
125       .push_back(type);
126   get_node()
127       .get_shared_data()
128       ->access_static_value(get_node().get_id(), roots_key_)
129       .push_back(root.get_id().get_index());
130 
131   RMF_INTERNAL_CHECK(get_alternatives(type).size() >= 1, "None found");
132 }
133 
get_alternative(RepresentationType type,double resolution) const134 NodeConstHandle AlternativesConst::get_alternative(RepresentationType type,
135                                                    double resolution) const {
136   return get_node().get_file().get_node(get_alternative_impl(type, resolution));
137 }
138 
get_alternatives(RepresentationType type) const139 NodeConstHandles AlternativesConst::get_alternatives(RepresentationType type)
140     const {
141   NodeConstHandles ret;
142   RMF_FOREACH(NodeID nid, get_alternatives_impl(type)) {
143     ret.push_back(get_node().get_file().get_node(nid));
144   }
145   return ret;
146 }
147 
get_representation_type(NodeID id) const148 RepresentationType AlternativesConst::get_representation_type(NodeID id) const {
149   if (id == get_node().get_id()) return PARTICLE;
150 
151   Ints roots = get_node().get_value(roots_key_);
152   for (unsigned int i = 0; i < roots.size(); ++i) {
153     if (roots[i] == static_cast<int>(id.get_index())) {
154       return RepresentationType(get_node().get_value(types_key_).get()[i]);
155     }
156   }
157   RMF_THROW(Message("No such alternative representation"), UsageException);
158 }
159 
160 namespace {
get_resolutions_impl(NodeConstHandle root,AlternativesFactory af,RepresentationType type)161 Floats get_resolutions_impl(NodeConstHandle root, AlternativesFactory af,
162                             RepresentationType type) {
163   Floats ret;
164   if (af.get_is(root)) {
165     RMF_FOREACH(NodeConstHandle a, af.get(root).get_alternatives(type)) {
166       ret.push_back(get_resolution(a));
167     }
168   } else {
169     RMF_FOREACH(NodeConstHandle ch, root.get_children()) {
170       Floats cur = get_resolutions_impl(ch, af, type);
171       ret.insert(ret.end(), cur.begin(), cur.end());
172     }
173   }
174   return ret;
175 }
176 }
177 
get_resolutions(NodeConstHandle root,RepresentationType type,double accuracy)178 Floats get_resolutions(NodeConstHandle root, RepresentationType type,
179                        double accuracy) {
180   AlternativesFactory af(root.get_file());
181   Floats unclustered = get_resolutions_impl(root, af, type);
182   if (unclustered.empty()) unclustered.push_back(1.0);
183   std::sort(unclustered.begin(), unclustered.end());
184   double lb = unclustered[0];
185   double ub = lb;
186   Floats ret;
187   RMF_FOREACH(double r, unclustered) {
188     if (r > lb + accuracy) {
189       ret.push_back(.5 * (lb + ub));
190       lb = r;
191     }
192     ub = r;
193   }
194   ret.push_back(.5 * (lb + ub));
195   return ret;
196 }
197 
198 } /* namespace decorator */
199 } /* namespace RMF */
200 
201 RMF_DISABLE_WARNINGS
202