votca 2024-dev
Loading...
Searching...
No Matches
jobtopology.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2023 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Standard includes
21#include <algorithm>
22#include <numeric>
23#include <stdexcept>
24#include <string>
25
26// Local VOTCA includes
28#include "votca/tools/version.h"
32#include "votca/xtp/qmregion.h"
35
36namespace votca {
37namespace xtp {
38
39std::vector<const tools::Property*> JobTopology::SortRegionsDefbyId(
40 const tools::Property& regions_def) const {
41 std::vector<const tools::Property*> view;
42 for (const auto& child : regions_def) {
43 view.push_back(&child);
44 }
45 std::sort(view.begin(), view.end(),
46 [](const tools::Property* A, const tools::Property* B) {
47 return (A->get("id").as<Index>()) < (B->get("id").as<Index>());
48 });
49 return view;
50}
51
52std::vector<std::string> ModifyRegionOptionsFromJobFileRegion(
53 tools::Property& opt, const tools::Property& job_opt) {
54 std::vector<std::string> modified_options;
55 for (auto& child : opt) {
56 if (child.as<std::string>() == "jobfile") {
57 if (job_opt.exists(child.name())) {
58 const tools::Property& job_opt_child = job_opt.get(child.name());
59 modified_options.push_back(child.path() + "." + child.name());
60 if (job_opt_child.HasChildren()) {
61 child.value() = "";
62 for (const auto& job_childchild : job_opt_child) {
63 child.add(job_childchild);
64 }
65 } else {
66 child.value() = job_opt_child.value();
67 }
68 } else {
69 throw std::runtime_error("Requested to replace:" + child.path() + "." +
70 child.name() +
71 " but no option in jobfile found");
72 }
73 } else if (job_opt.exists(child.name())) {
74 std::vector<std::string> child_modified_options =
76 job_opt.get(child.name()));
77 modified_options.insert(modified_options.end(),
78 child_modified_options.begin(),
79 child_modified_options.end());
80 }
81 }
82 return modified_options;
83}
84
86
87 const tools::Property& prop = job_.getInput();
88 std::vector<const tools::Property*> regions_def_job =
89 prop.Select("regions.*region");
90
91 for (const auto& job_region : regions_def_job) {
92
93 Index job_region_id = job_region->get("id").as<Index>();
94
95 auto found_prop =
96 std::find_if(regions_def.begin(), regions_def.end(),
97 [job_region_id](const tools::Property& p) {
98 return p.get("id").as<Index>() == job_region_id;
99 });
100 if (found_prop == regions_def.end()) {
101 throw std::runtime_error(
102 "Your jobfile options want to modify a region with id " +
103 std::to_string(job_region_id) +
104 " it does not exist in your region specifications.");
105 }
106
107 tools::Property& region = *found_prop;
108 if (region.name() != job_region->name()) {
109 throw std::runtime_error("Types of region with id" +
110 std::to_string(job_region_id) +
111 " do not agree jobfile:" + job_region->name() +
112 " options:" + region.name());
113 }
114
115 std::vector<std::string> changed_options =
116 ModifyRegionOptionsFromJobFileRegion(region, *job_region);
117
118 if (!changed_options.empty()) {
119 XTP_LOG(Log::info, log_) << " Region " << job_region_id
120 << " is modified by jobfile" << std::flush;
122 << " Replacing the following paths with jobfile entries"
123 << std::flush;
124 for (const std::string& path : changed_options) {
125 XTP_LOG(Log::info, log_) << " - " << path << std::flush;
126 }
127 }
128 }
129}
130
132 const Topology& top, std::pair<std::string, tools::Property> options) {
133
134 CheckEnumerationOfRegions(options.second);
135 ModifyOptionsByJobFile(options.second);
136
137 std::vector<std::vector<SegId>> region_seg_ids =
138 PartitionRegions(options.second, top);
139
140 // // around this point the whole jobtopology will be centered
141 CreateRegions(options, top, region_seg_ids);
142 XTP_LOG(Log::error, log_) << " Regions created" << std::flush;
143 for (const auto& region : regions_) {
144 XTP_LOG(Log::error, log_) << *region << std::flush;
145 }
146
147 return;
148}
149
150template <class T>
151void JobTopology::ShiftPBC(const Topology& top, const Eigen::Vector3d& center,
152 T& mol) const {
153 Eigen::Vector3d r_pbc = top.PbShortestConnect(center, mol.getPos());
154 Eigen::Vector3d r = mol.getPos() - center;
155 Eigen::Vector3d shift = r_pbc - r;
156 if (shift.norm() > 1e-9) {
157 mol.Translate(shift);
158 }
159}
160
162 const std::pair<std::string, tools::Property>& options, const Topology& top,
163 const std::vector<std::vector<SegId>>& region_seg_ids) {
164 std::string mapfile = options.first;
165 // around this point the whole jobtopology will be centered for removing pbc
166 Eigen::Vector3d center = top.getSegment(region_seg_ids[0][0].Id()).getPos();
167
168 for (const tools::Property& region_def : options.second) {
169 Index id = region_def.get("id").as<Index>();
170 const std::vector<SegId>& seg_ids = region_seg_ids[id];
171 std::string type = region_def.name();
172 std::unique_ptr<Region> region;
173 QMRegion QMdummy(0, log_, "");
174 StaticRegion Staticdummy(0, log_);
175 PolarRegion Polardummy(0, log_);
176 if (type == QMdummy.identify()) {
177 std::unique_ptr<QMRegion> qmregion =
178 std::make_unique<QMRegion>(id, log_, workdir_);
179 QMMapper qmmapper(log_);
180 qmmapper.LoadMappingFile(mapfile);
181 for (const SegId& seg_index : seg_ids) {
182 const Segment& segment = top.getSegment(seg_index.Id());
183 QMMolecule mol = qmmapper.map(segment, seg_index);
184 mol.setType("qm" + std::to_string(id));
185 ShiftPBC(top, center, mol);
186 qmregion->push_back(mol);
187 }
188 region = std::move(qmregion);
189 } else if (type == Polardummy.identify()) {
190 std::unique_ptr<PolarRegion> polarregion =
191 std::make_unique<PolarRegion>(id, log_);
192 PolarMapper polmap(log_);
193 polmap.LoadMappingFile(mapfile);
194 for (const SegId& seg_index : seg_ids) {
195 const Segment& segment = top.getSegment(seg_index.Id());
196
197 PolarSegment mol = polmap.map(segment, seg_index);
198
199 ShiftPBC(top, center, mol);
200 mol.setType("mm" + std::to_string(id));
201 polarregion->push_back(mol);
202 }
203 region = std::move(polarregion);
204 } else if (type == Staticdummy.identify()) {
205 std::unique_ptr<StaticRegion> staticregion =
206 std::make_unique<StaticRegion>(id, log_);
207 StaticMapper staticmap(log_);
208 staticmap.LoadMappingFile(mapfile);
209 for (const SegId& seg_index : seg_ids) {
210 const Segment& segment = top.getSegment(seg_index.Id());
211 StaticSegment mol = staticmap.map(segment, seg_index);
212 mol.setType("mm" + std::to_string(id));
213 ShiftPBC(top, center, mol);
214 staticregion->push_back(mol);
215 }
216 region = std::move(staticregion);
217
218 } else {
219 throw std::runtime_error("Region type not known!");
220 }
221 region->Initialize(region_def);
222 regions_.push_back(std::move(region));
223 }
224}
225
226void JobTopology::WriteToPdb(std::string filename) const {
227
228 csg::PDBWriter writer;
229 writer.Open(filename, false);
230 writer.WriteHeader("Job:" + std::to_string(this->job_.getId()));
231 for (const std::unique_ptr<Region>& reg : regions_) {
232 reg->WritePDB(writer);
233 }
234 writer.Close();
235}
236
237std::vector<std::vector<SegId>> JobTopology::PartitionRegions(
238 const tools::Property& regions_def, const Topology& top) const {
239
240 std::vector<const tools::Property*> sorted_regions =
241 SortRegionsDefbyId(regions_def);
242
243 std::vector<Index> explicitly_named_segs_per_region;
244 std::vector<std::vector<SegId>> segids_per_region;
245 std::vector<bool> processed_segments =
246 std::vector<bool>(top.Segments().size(), false);
247 for (const tools::Property* region_def : sorted_regions) {
248
249 if (!region_def->exists("segments") && !region_def->exists("cutoff")) {
250 throw std::runtime_error(
251 "Region definition needs either segments or a cutoff to find "
252 "segments");
253 }
254 std::vector<SegId> seg_ids;
255 if (region_def->exists("segments")) {
256 seg_ids = region_def->get("segments").as<std::vector<SegId>>();
257 for (const SegId& seg_id : seg_ids) {
258 if (seg_id.Id() > Index(top.Segments().size() - 1)) {
259 throw std::runtime_error("Segment id is not in topology");
260 }
261 processed_segments[seg_id.Id()] = true;
262 }
263 }
264 explicitly_named_segs_per_region.push_back(Index(seg_ids.size()));
265
266 if (region_def->exists("cutoff")) {
267 double cutoff =
268 tools::conv::nm2bohr * region_def->get("cutoff.radius").as<double>();
269
270 std::string seg_geometry =
271 region_def->get("cutoff.geometry").as<std::string>();
272 double min = top.getBox().diagonal().minCoeff();
273 if (cutoff > 0.5 * min) {
274 throw std::runtime_error(
275 (boost::format("Cutoff is larger than half the box size. Maximum "
276 "allowed cutoff is %1$1.1f") %
277 (tools::conv::bohr2nm * 0.5 * min))
278 .str());
279 }
280 std::vector<SegId> center = seg_ids;
281
282 Index id = region_def->get("cutoff.region").as<Index>();
283 bool only_explicit = region_def->get("cutoff.explicit_segs").as<bool>();
284 if (id < Index(segids_per_region.size())) {
285 center = segids_per_region[id];
286 if (only_explicit) {
287 Index no_of_segs = explicitly_named_segs_per_region[id];
288 if (no_of_segs == 0) {
289 throw std::runtime_error(
290 "Region with id '" + std::to_string(id) +
291 "' does not have explicitly named segments");
292 }
293 center.resize(no_of_segs, SegId(0, "n"));
294 // need the second argument because resize can also increase
295 // capacity of vector and then needs a constructor,
296 // here we shrink, so should not happen
297 }
298 } else if (id != region_def->get("id").as<Index>()) {
299 throw std::runtime_error("Region with id '" + std::to_string(id) +
300 "' used for cutoff does not exist");
301 }
302
303 if (center.empty()) {
304 throw std::runtime_error(
305 "Region needs either a segment or another region to which to "
306 "apply "
307 "the cutoff");
308 }
309 for (const SegId& segid : center) {
310 const Segment& center_seg = top.getSegment(segid.Id());
311 for (const Segment& otherseg : top.Segments()) {
312 if (center_seg.getId() == otherseg.getId() ||
313 processed_segments[otherseg.getId()]) {
314 continue;
315 }
316 if (top.PbShortestConnect(center_seg.getPos(), otherseg.getPos())
317 .norm() < cutoff) {
318 seg_ids.push_back(SegId(otherseg.getId(), seg_geometry));
319 processed_segments[otherseg.getId()] = true;
320 }
321 }
322 }
323 }
324 segids_per_region.push_back(seg_ids);
325 }
326 return segids_per_region;
327}
328
330 const tools::Property& regions_def) const {
331 std::vector<Index> reg_ids;
332 for (const tools::Property& region_def : regions_def) {
333 reg_ids.push_back(region_def.get("id").as<Index>());
334 }
335
336 std::vector<Index> v(reg_ids.size());
337 std::iota(v.begin(), v.end(), 0);
338 if (!std::is_permutation(reg_ids.begin(), reg_ids.end(), v.begin())) {
339 throw std::runtime_error(
340 "Region id definitions are not clear. You must start at id 0 and "
341 "then "
342 "ascending order. i.e. 0 1 2 3.");
343 }
344}
345
346void JobTopology::WriteToHdf5(std::string filename) const {
348 CheckpointWriter a = cpf.getWriter();
349 a(job_.getId(), "jobid");
350 a(votca::tools::ToolsVersionStr(), "XTPVersion");
351 a(jobtopology_version(), "version");
352 for (const auto& region : regions_) {
354 cpf.getWriter("region_" + std::to_string(region->getId()));
355 region->WriteToCpt(w);
356 }
357}
358
359void JobTopology::ReadFromHdf5(std::string filename) {
361 CheckpointReader a = cpf.getReader();
362 Index id = -1;
363 a(id, "jobid");
364 if (id != job_.getId()) {
365 throw std::runtime_error(
366 "Jobid from checkpoint file does not agree with jobid" +
367 std::to_string(id) + ":" + std::to_string(job_.getId()));
368 }
369 regions_.clear();
370 Index no_regions = a.getNumDataSets();
371 regions_.reserve(no_regions);
372
373 QMRegion QMdummy(0, log_, "");
374 StaticRegion Staticdummy(0, log_);
375 PolarRegion Polardummy(0, log_);
376
377 for (Index i = 0; i < no_regions; i++) {
378 CheckpointReader r = cpf.getReader("region_" + std::to_string(i));
379 std::string type;
380 r(type, "type");
381
382 std::unique_ptr<Region> region = nullptr;
383 if (type == QMdummy.identify()) {
384 region = std::make_unique<QMRegion>(i, log_, workdir_);
385 } else if (type == Polardummy.identify()) {
386 region = std::make_unique<PolarRegion>(i, log_);
387 } else if (type == Staticdummy.identify()) {
388 region = std::make_unique<StaticRegion>(i, log_);
389 } else {
390 throw std::runtime_error("Region type:" + type + " not known!");
391 }
392 region->ReadFromCpt(r);
393 if (id != region->getId()) {
394 throw std::runtime_error("read in the wrong region, ids are mismatched.");
395 }
396 regions_.push_back(std::move(region));
397 }
398}
399
400} // namespace xtp
401} // namespace votca
void WriteHeader(std::string header)
Definition pdbwriter.cc:41
void Close() override
Definition pdbwriter.cc:51
void Open(std::string file, bool bAppend=false) override
Definition pdbwriter.cc:33
class to manage program options with xml serialization functionality
Definition property.h:55
Property & get(const std::string &key)
get existing property
Definition property.cc:79
std::string & value()
reference to value of property
Definition property.h:153
iterator end()
end iterator for child properties
Definition property.h:191
bool exists(const std::string &key) const
check whether property exists
Definition property.cc:122
iterator begin()
iterator to first child property
Definition property.h:188
bool HasChildren() const
does the property have children?
Definition property.h:182
std::string & name()
name of property
Definition property.h:159
std::vector< Property * > Select(const std::string &filter)
select property based on a filter
Definition property.cc:185
void push_back(const T &atom)
void setType(std::string type)
const Eigen::Vector3d & getPos() const
CheckpointReader getReader()
CheckpointWriter getWriter()
std::vector< std::unique_ptr< Region > > regions_
void ShiftPBC(const Topology &top, const Eigen::Vector3d &center, T &mol) const
std::vector< const tools::Property * > SortRegionsDefbyId(const tools::Property &regions_def) const
void ReadFromHdf5(std::string filename)
static constexpr int jobtopology_version()
void CreateRegions(const std::pair< std::string, tools::Property > &options, const Topology &top, const std::vector< std::vector< SegId > > &region_seg_ids)
std::vector< std::vector< SegId > > PartitionRegions(const tools::Property &regions_def, const Topology &top) const
void WriteToPdb(std::string filename) const
void CheckEnumerationOfRegions(const tools::Property &regions_def) const
void BuildRegions(const Topology &top, std::pair< std::string, tools::Property > options)
void WriteToHdf5(std::string filename) const
void ModifyOptionsByJobFile(tools::Property &regions_def) const
tools::Property & getInput()
Definition job.h:87
Index getId() const
Definition job.h:85
std::string identify() const override
Definition polarregion.h:48
std::string identify() const override
Definition qmregion.h:66
void LoadMappingFile(const std::string &mapfile)
AtomContainer map(const Segment &seg, const SegId &segid) const
std::string identify() const override
Container for segments and box and atoms.
Definition topology.h:41
Eigen::Vector3d PbShortestConnect(const Eigen::Vector3d &r1, const Eigen::Vector3d &r2) const
Definition topology.cc:129
std::vector< Segment > & Segments()
Definition topology.h:58
const Eigen::Matrix3d & getBox() const
Definition topology.h:64
Segment & getSegment(Index id)
Definition topology.h:55
#define XTP_LOG(level, log)
Definition logger.h:40
const double bohr2nm
Definition constants.h:46
const double nm2bohr
Definition constants.h:47
const std::string & ToolsVersionStr()
Definition version.cc:33
std::vector< std::string > ModifyRegionOptionsFromJobFileRegion(tools::Property &opt, const tools::Property &job_opt)
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26