IgANet
IgANets - Isogeometric Analysis Networks
Loading...
Searching...
No Matches
GismoGeometryModel.hpp
Go to the documentation of this file.
1
15#pragma once
16
17#include <GismoModel.hpp>
18
19namespace iganet {
20
21namespace webapp {
22
24template <short_t d, class T>
26 public ModelAddPatch,
27 public ModelElevate,
28 public ModelEval,
29 public ModelIncrease,
30 public ModelRefine,
32 public ModelRemovePatch,
33 public ModelXML {
34
35 static_assert(d >= 1 && d <= 4, "Spatial dimension must be between 1 and 4");
36
37protected:
39 gismo::gsMultiPatch<T> geo_;
40
41public:
43 GismoGeometryModel() = default;
44
46 GismoGeometryModel(const std::array<short_t, d> degrees,
47 const std::array<int64_t, d> ncoeffs,
48 const std::array<int64_t, d> npatches,
49 const std::array<T, d> dimensions)
50 : GismoModel<T>() {
51
52 if constexpr (d == 1) {
53 gismo::gsKnotVector<T> KV0(0, 1, ncoeffs[0] - degrees[0] - 1, degrees[0] + 1);
54
55 gismo::gsMatrix<T> C(ncoeffs[0], 3), P;
56
57 for (int64_t i = 0; i < ncoeffs[0]; ++i) {
58 C(i, 0) = ((T)i) / (T)(ncoeffs[0] - 1);
59 C(i, 1) = (T)0;
60 C(i, 2) = (T)0;
61 }
62
63 for (int64_t i = 0; i < npatches[0]; ++i) {
64 P = C;
65
66 P.col(0) *= dimensions[0] / npatches[0];
67
68 P.col(0).array() += (T)(i) / (T)npatches[0];
69
70 geo_.addPatch(gismo::gsBSpline<T>(KV0, give(P)));
71 }
72 geo_.computeTopology();
73
74 } else if constexpr (d == 2) {
75 gismo::gsKnotVector<T> KV0(0, 1, ncoeffs[0] - degrees[0] - 1, degrees[0] + 1);
76 gismo::gsKnotVector<T> KV1(0, 1, ncoeffs[1] - degrees[1] - 1, degrees[1] + 1);
77
78 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1], 3), P;
79
80 int64_t r = 0;
81 for (int64_t j = 0; j < ncoeffs[1]; ++j)
82 for (int64_t i = 0; i < ncoeffs[0]; ++i) {
83 C(r, 0) = ((T)i) / (T)(ncoeffs[0] - 1);
84 C(r, 1) = ((T)j) / (T)(ncoeffs[1] - 1);
85 C(r, 2) = (T)0;
86 ++r;
87 }
88
89 for (int64_t j = 0; j < npatches[1]; ++j)
90 for (int64_t i = 0; i < npatches[0]; ++i) {
91 P = C;
92
93 P.col(0) *= dimensions[0] / (T)npatches[0];
94 P.col(1) *= dimensions[1] / (T)npatches[1];
95
96 P.col(0).array() += (T)(i) / (T)npatches[0];
97 P.col(1).array() += (T)(j) / (T)npatches[1];
98
99 geo_.addPatch(gismo::gsTensorBSpline<2, T>(KV0, KV1, give(P)));
100 }
101 geo_.computeTopology();
102
103 } else if constexpr (d == 3) {
104 gismo::gsKnotVector<T> KV0(0, 1, ncoeffs[0] - degrees[0] - 1, degrees[0] + 1);
105 gismo::gsKnotVector<T> KV1(0, 1, ncoeffs[1] - degrees[1] - 1, degrees[1] + 1);
106 gismo::gsKnotVector<T> KV2(0, 1, ncoeffs[2] - degrees[2] - 1, degrees[2] + 1);
107
108 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1] * ncoeffs[2], 3), P;
109
110 int64_t r = 0;
111 for (int64_t k = 0; k < ncoeffs[2]; ++k)
112 for (int64_t j = 0; j < ncoeffs[1]; ++j)
113 for (int64_t i = 0; i < ncoeffs[0]; ++i) {
114 C(r, 0) = ((T)i) / (T)(ncoeffs[0] - 1);
115 C(r, 1) = ((T)j) / (T)(ncoeffs[1] - 1);
116 C(r, 2) = ((T)k) / (T)(ncoeffs[2] - 1);
117 ++r;
118 }
119
120 for (int64_t k = 0; k < npatches[2]; ++k)
121 for (int64_t j = 0; j < npatches[1]; ++j)
122 for (int64_t i = 0; i < npatches[0]; ++i) {
123 P = C;
124
125 P.col(0) *= dimensions[0] / npatches[0];
126 P.col(1) *= dimensions[1] / npatches[1];
127 P.col(2) *= dimensions[2] / npatches[2];
128
129 P.col(0).array() += (T)(i) / (T)npatches[0];
130 P.col(1).array() += (T)(j) / (T)npatches[1];
131 P.col(2).array() += (T)(k) / (T)npatches[2];
132
133 geo_.addPatch(gismo::gsTensorBSpline<3, T>(KV0, KV1, KV2, give(P)));
134 }
135 geo_.computeTopology();
136
137 } else if constexpr (d == 4) {
138 gismo::gsKnotVector<T> KV0(0, 1, ncoeffs[0] - degrees[0] - 1, degrees[0] + 1);
139 gismo::gsKnotVector<T> KV1(0, 1, ncoeffs[1] - degrees[1] - 1, degrees[1] + 1);
140 gismo::gsKnotVector<T> KV2(0, 1, ncoeffs[2] - degrees[2] - 1, degrees[2] + 1);
141 gismo::gsKnotVector<T> KV3(0, 1, ncoeffs[3] - degrees[3] - 1, degrees[3] + 1);
142
143 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1] * ncoeffs[2] * ncoeffs[3], 4), P;
144
145 int64_t r = 0;
146 for (int64_t l = 0; l < ncoeffs[3]; ++l)
147 for (int64_t k = 0; k < ncoeffs[2]; ++k)
148 for (int64_t j = 0; j < ncoeffs[1]; ++j)
149 for (int64_t i = 0; i < ncoeffs[0]; ++i) {
150 C(r, 0) = ((T)i) / (T)(ncoeffs[0] - 1);
151 C(r, 1) = ((T)j) / (T)(ncoeffs[1] - 1);
152 C(r, 2) = ((T)k) / (T)(ncoeffs[2] - 1);
153 C(r, 3) = ((T)l) / (T)(ncoeffs[3] - 1);
154 ++r;
155 }
156
157 for (int64_t l = 0; l < npatches[3]; ++l)
158 for (int64_t k = 0; k < npatches[2]; ++k)
159 for (int64_t j = 0; j < npatches[1]; ++j)
160 for (int64_t i = 0; i < npatches[0]; ++i) {
161 P = C;
162
163 P.col(0) *= dimensions[0] / npatches[0];
164 P.col(1) *= dimensions[1] / npatches[1];
165 P.col(2) *= dimensions[2] / npatches[2];
166 P.col(3) *= dimensions[3] / npatches[3];
167
168 P.col(0).array() += (T)(i) / (T)npatches[0];
169 P.col(1).array() += (T)(j) / (T)npatches[1];
170 P.col(2).array() += (T)(k) / (T)npatches[2];
171 P.col(3).array() += (T)(l) / (T)npatches[3];
172
173 geo_.addPatch(gismo::gsTensorBSpline<4, T>(KV0, KV1, KV2, KV3, give(P)));
174 }
175 geo_.computeTopology();
176 }
177 }
178
180 GismoGeometryModel(const pugi::xml_node root)
181 : GismoModel<T>() {
182 }
183
185 nlohmann::json getOptions() const override {
186 if constexpr (d == 1)
187 return R"([{
188 "name" : "npatches",
189 "label" : "Number of patches",
190 "description" : "Number of patches per spatial dimension",
191 "type" : ["int"],
192 "value" : [1],
193 "default" : [1],
194 "uiid" : 0},{
195 "name" : "degree",
196 "label" : "Spline degree",
197 "description" : "Spline degree",
198 "type" : ["int"],
199 "value" : [2],
200 "default" : [2],
201 "uiid" : 1},{
202 "name" : "ncoeffs",
203 "label" : "Number of coefficients",
204 "description" : "Number of coefficients per parametric dimension",
205 "type" : ["int"],
206 "value" : [3],
207 "default" : [3],
208 "uiid" : 2},{
209 "name" : "dimension",
210 "label" : "Dimension [width]",
211 "description" : "Dimension in physical space",
212 "type" : ["float"],
213 "value" : [1.0],
214 "default" : [1.0],
215 "uiid" : 3}])"_json;
216
217 else if constexpr (d == 2)
218 return R"([{
219 "name" : "npatches",
220 "label" : "Number of patches",
221 "description" : "Number of patches per spatial dimension",
222 "type" : ["int","int"],
223 "value" : [1,1],
224 "default" : [1,1],
225 "uiid" : 0},{
226 "name" : "degrees",
227 "label" : "Spline degrees",
228 "description" : "Spline degrees per parametric dimension",
229 "type" : ["int","int"],
230 "value" : [2,2],
231 "default" : [2,2],
232 "uiid" : 1},{
233 "name" : "ncoeffs",
234 "label" : "Number of coefficients",
235 "description" : "Number of coefficients per parametric dimension",
236 "type" : ["int","int"],
237 "value" : [3,3],
238 "default" : [3,3],
239 "uiid" : 2},{
240 "name" : "dimensions",
241 "label" : "Dimensions [width, height]",
242 "description" : "Dimensions in physical space",
243 "type" : ["float", "float"],
244 "value" : [1.0, 1.0],
245 "default" : [1.0, 1.0],
246 "uiid" : 3}])"_json;
247
248 else if constexpr (d == 3)
249 return R"([{
250 "name" : "npatches",
251 "label" : "Number of patches",
252 "description" : "Number of patches per spatial dimension",
253 "type" : ["int","int","int"],
254 "value" : [1,1,1],
255 "default" : [1,1,1],
256 "uiid" : 0},{
257 "name" : "degrees",
258 "label" : "Spline degrees",
259 "description" : "Spline degrees per parametric dimension",
260 "type" : ["int","int","int"],
261 "value" : [2,2,2],
262 "default" : [2,2,2],
263 "uiid" : 1},{
264 "name" : "ncoeffs",
265 "label" : "Number of coefficients",
266 "description" : "Number of coefficients per parametric dimension",
267 "type" : ["int","int","int"],
268 "value" : [3,3,3],
269 "default" : [3,3,3],
270 "uiid" : 2},{
271 "name" : "dimensions",
272 "label" : "Dimensions [width, height, depth]",
273 "description" : "Dimensions in physical space",
274 "type" : ["float", "float", "float"],
275 "value" : [1.0, 1.0, 1.0],
276 "default" : [1.0, 1.0, 1.0],
277 "uiid" : 3}])"_json;
278
279 else if constexpr (d == 4)
280 return R"([{
281 "name" : "npatches",
282 "label" : "Number of patches",
283 "description" : "Number of patches per spatial dimension",
284 "type" : ["int","int","int","int"],
285 "value" : [1,1,1,1],
286 "default" : [1,1,1,1],
287 "uiid" : 0},{
288 "name" : "degrees",
289 "label" : "Spline degrees",
290 "description" : "Spline degrees per parametric dimension",
291 "type" : ["int","int","int","int"],
292 "value" : [2,2,2,2],
293 "default" : [2,2,2,2],
294 "uiid" : 1},{
295 "name" : "ncoeffs",
296 "label" : "Number of coefficients",
297 "description" : "Number of coefficients per parametric dimension",
298 "type" : ["int","int","int","int"],
299 "value" : [3,3,3,3],
300 "default" : [3,3,3,3],
301 "uiid" : 2},{
302 "name" : "dimensions",
303 "label" : "Dimensions [width, height, depth, time]",
304 "description" : "Dimensions in physical space",
305 "type" : ["float", "float", "float", "float"],
306 "value" : [1.0, 1.0, 1.0, 1.0],
307 "default" : [1.0, 1.0, 1.0, 1.0],
308 "uiid" : 3}])"_json;
309
310 else
311 return R"({ INVALID REQUEST })"_json;
312 }
313
315 nlohmann::json getInputs() const override {
316 return R"([{
317 "name" : "geometry",
318 "description" : "Geometry",
319 "type" : 2}])"_json;
320 }
321
323 nlohmann::json getOutputs() const override {
324 return R"([{
325 "name" : "ScaledJacobian",
326 "description" : "Scaled Jacobian of the geometry mapping as quality measure for orthogonality",
327 "type" : 1},{
328 "name" : "UniformityMetric",
329 "description" : "Uniformity metric quality measure for area distortion of the geometry map",
330 "type" : 1}])"_json;
331 }
332
334 nlohmann::json to_json(const std::string &patch, const std::string &component,
335 const std::string &attribute) const override {
336
337 if (component == "geometry" || component == "") {
338
339 if (patch == "" && attribute == "") {
340
341 // Return solution as multipatch structure
342 return utils::to_json(geo_);
343 }
344
345 else if (patch != "") {
346
347 // Return individual patch of the solution
348 int patchIndex(-1);
349
350 try {
351 patchIndex = stoi(patch);
352 } catch (...) {
353 // Invalid patchIndex
354 return R"({ INVALID REQUEST })"_json;
355 }
356
357 if (patchIndex >= geo_.nPatches())
358 return R"({ INVALID REQUEST })"_json;
359
360 if (attribute == "") {
361
362 // Return all attributes
363 return utils::to_json(geo_.patch(patchIndex));
364
365 } else {
366
367 nlohmann::json json;
368
369 // Return an individual attribute
370 if (attribute == "degrees") {
371 json["degrees"] = nlohmann::json::array();
372
373 for (std::size_t i = 0; i < geo_.patch(patchIndex).parDim(); ++i)
374 json["degrees"].push_back(geo_.patch(patchIndex).degree(i));
375 }
376
377 else if (attribute == "geoDim")
378 json["geoDim"] = geo_.patch(patchIndex).geoDim();
379
380 else if (attribute == "parDim")
381 json["parDim"] = geo_.patch(patchIndex).parDim();
382
383 else if (attribute == "ncoeffs") {
384 json["ncoeffs"] = nlohmann::json::array();
385
386 if (auto bspline =
387 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
388 for (std::size_t i = 0; i < bspline->parDim(); ++i)
389 json["ncoeffs"].push_back(bspline->basis().size(i));
390 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
391 &geo_.patch(patchIndex)))
392 for (std::size_t i = 0; i < bspline->parDim(); ++i)
393 json["ncoeffs"].push_back(bspline->basis().size(i));
394 else
395 return R"({ INVALID REQUEST })"_json;
396
397 }
398
399 else if (attribute == "nknots") {
400 json["nknots"] = nlohmann::json::array();
401
402 if (auto bspline =
403 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
404 for (std::size_t i = 0; i < bspline->parDim(); ++i)
405 json["nknots"].push_back(bspline->knots(i).size());
406 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
407 &geo_.patch(patchIndex)))
408 for (std::size_t i = 0; i < bspline->parDim(); ++i)
409 json["nknots"].push_back(bspline->knots(i).size());
410 else
411 return R"({ INVALID REQUEST })"_json;
412 }
413
414 else if (attribute == "coeffs") {
415
416 if (auto bspline =
417 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
418 json["coeffs"] = utils::to_json(bspline->coefs());
419 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
420 &geo_.patch(patchIndex)))
421 json["coeffs"] = utils::to_json(bspline->coefs());
422 else
423 return R"({ INVALID REQUEST })"_json;
424
425 }
426
427 else if (attribute == "knots") {
428 json["knots"] = nlohmann::json::array();
429
430 if (auto bspline =
431 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
432 for (std::size_t i = 0; i < bspline->parDim(); ++i)
433 json["knots"].push_back(bspline->knots(i));
434 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
435 &geo_.patch(patchIndex)))
436 for (std::size_t i = 0; i < bspline->parDim(); ++i)
437 json["knots"].push_back(bspline->knots(i));
438 else
439 return R"({ INVALID REQUEST })"_json;
440 }
441
442 else
443 // Invalid attribute
444 return R"({ INVALID REQUEST })"_json;
445
446 return json;
447 }
448 }
449
450 else
451 return R"({ INVALID REQUEST })"_json;
452 }
453
454 // Handle component != "geometry"
456 }
457
459 nlohmann::json updateAttribute(const std::string &patch,
460 const std::string &component,
461 const std::string &attribute,
462 const nlohmann::json &json) override {
463
464 int patchIndex(-1);
465
466 try {
467 patchIndex = stoi(patch);
468 } catch (...) {
469 return R"({ INVALID REQUEST })"_json;
470 }
471
472 if (attribute == "coeffs") {
473 if (!json.contains("data"))
475 if (!json["data"].contains("indices") || !json["data"].contains("coeffs"))
477
478 auto indices = json["data"]["indices"].get<std::vector<int64_t>>();
479 auto ncoeffs = geo_.patch(patchIndex).coefs().rows();
480
481 switch (geo_.geoDim()) {
482 case (1): {
483 auto coords = json["data"]["coeffs"].get<std::vector<std::tuple<T>>>();
484
485 for (const auto &[index, coord] : iganet::utils::zip(indices, coords)) {
486 if (index < 0 || index >= ncoeffs)
488
489 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
490 }
491 break;
492 }
493 case (2): {
494 auto coords =
495 json["data"]["coeffs"].get<std::vector<std::tuple<T, T>>>();
496
497 for (const auto &[index, coord] : iganet::utils::zip(indices, coords)) {
498 if (index < 0 || index >= ncoeffs)
500
501 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
502 geo_.patch(patchIndex).coef(index, 1) = std::get<1>(coord);
503 }
504 break;
505 }
506 case (3): {
507 auto coords =
508 json["data"]["coeffs"].get<std::vector<std::tuple<T, T, T>>>();
509
510 for (const auto &[index, coord] : iganet::utils::zip(indices, coords)) {
511 if (index < 0 || index >= ncoeffs)
513
514 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
515 geo_.patch(patchIndex).coef(index, 1) = std::get<1>(coord);
516 geo_.patch(patchIndex).coef(index, 2) = std::get<2>(coord);
517 }
518 break;
519 }
520 case (4): {
521 auto coords =
522 json["data"]["coeffs"].get<std::vector<std::tuple<T, T, T, T>>>();
523
524 for (const auto &[index, coord] : iganet::utils::zip(indices, coords)) {
525 if (index < 0 || index >= ncoeffs)
527
528 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
529 geo_.patch(patchIndex).coef(index, 1) = std::get<1>(coord);
530 geo_.patch(patchIndex).coef(index, 2) = std::get<2>(coord);
531 geo_.patch(patchIndex).coef(index, 3) = std::get<3>(coord);
532 }
533 break;
534 }
535 default:
537 }
538
539 return R"({})"_json;
540 } else
542 }
543
545 nlohmann::json eval(const std::string &patch, const std::string &component,
546 const nlohmann::json &json) const override {
547
548 int patchIndex(-1);
549
550 try {
551 patchIndex = stoi(patch);
552 } catch (...) {
553 return R"({ INVALID REQUEST })"_json;
554 }
555
556 nlohmann::json result;
557
558 // degrees
559 result["degrees"] = nlohmann::json::array();
560
561 for (std::size_t i = 0; i < geo_.patch(patchIndex).parDim(); ++i)
562 result["degrees"].push_back(geo_.patch(patchIndex).degree(i));
563
564 // ncoeffs
565 result["ncoeffs"] = nlohmann::json::array();
566
567 if (auto bspline =
568 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
569 for (std::size_t i = 0; i < bspline->parDim(); ++i)
570 result["ncoeffs"].push_back(bspline->basis().size(i));
571 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
572 &geo_.patch(patchIndex)))
573 for (std::size_t i = 0; i < bspline->parDim(); ++i)
574 result["ncoeffs"].push_back(bspline->basis().size(i));
575 else
576 return R"({ INVALID REQUEST })"_json;
577
578 // nknots
579 result["nknots"] = nlohmann::json::array();
580
581 if (auto bspline =
582 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
583 for (std::size_t i = 0; i < bspline->parDim(); ++i)
584 result["nknots"].push_back(bspline->knots(i).size());
585 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
586 &geo_.patch(patchIndex)))
587 for (std::size_t i = 0; i < bspline->parDim(); ++i)
588 result["nknots"].push_back(bspline->knots(i).size());
589 else
590 return R"({ INVALID REQUEST })"_json;
591
592 // knots
593 result["knots"] = nlohmann::json::array();
594
595 if (auto bspline =
596 dynamic_cast<const gismo::gsBSpline<T> *>(&geo_.patch(patchIndex)))
597 for (std::size_t i = 0; i < bspline->parDim(); ++i)
598 result["knots"].push_back(bspline->knots(i));
599 else if (auto bspline = dynamic_cast<const gismo::gsTensorBSpline<d, T> *>(
600 &geo_.patch(patchIndex)))
601 for (std::size_t i = 0; i < bspline->parDim(); ++i)
602 result["knots"].push_back(bspline->knots(i));
603 else
604 return R"({ INVALID REQUEST })"_json;
605
606 // coeffs
607 if (component == "ScaledJacobian" || component == "UniformityMetric") {
608
609 gismo::gsMultiBasis<T> basis(geo_);
610 gismo::gsExprEvaluator<T> ev;
611 ev.setIntegrationElements(basis);
612 auto G = ev.getMap(geo_);
613
614 if (component == "ScaledJacobian") {
615
616 auto parDim = geo_.parDim();
617 auto &basis = geo_.patch(patchIndex).basis();
618 auto pts = basis.anchors();
619 gismo::gsMatrix<T> eval(1, pts.cols());
620
621 if (parDim == 2 && geo_.geoDim() == 3) {
622 for (std::size_t i = 0; i < pts.cols(); i++) {
623 auto jac = ev.eval(gismo::expr::jac(G), pts.col(i));
624 eval(0, i) = jac.col(0).dot(jac.col(1));
625 for (std::size_t j = 0; j < parDim; j++)
626 eval(0, i) /= (jac.col(j).norm());
627 }
628 } else {
629 for (std::size_t i = 0; i < pts.cols(); i++) {
630 auto jac = ev.eval(gismo::expr::jac(G), pts.col(i));
631 eval(0, i) = jac.determinant();
632 for (std::size_t j = 0; j < parDim; j++)
633 eval(0, i) /= (jac.col(j).norm());
634 }
635 }
636
637 auto jac = basis.interpolateAtAnchors(eval);
638 result["coeffs"] = utils::to_json(jac->coefs(), true, false);
639 }
640
641 else if (component == "UniformityMetric") {
642
643 T areaTotal = ev.integral(gismo::expr::meas(G));
644 gismo::gsConstantFunction<T> areaConstFunc(areaTotal, geo_.parDim());
645 auto area = ev.getVariable(areaConstFunc);
646 auto expr = gismo::expr::pow((gismo::expr::meas(G) - area.val()) / area.val(), 2);
647
648 auto &basis = geo_.patch(patchIndex).basis();
649 auto pts = basis.anchors();
650 gismo::gsMatrix<T> eval(1, pts.cols());
651
652 for (std::size_t i = 0; i < pts.cols(); i++)
653 eval(0, i) = ev.eval(expr, pts.col(i))(0);
654
655 auto uniform = basis.interpolateAtAnchors(eval);
656 result["coeffs"] = utils::to_json(uniform->coefs(), true, false);
657 }
658 else
659 return R"({ INVALID REQUEST })"_json;
660
661 } else {
662 result["coeffs"] = utils::to_json(geo_.patch(patchIndex).coefs(), true, false);
663 }
664
665 return result;
666 }
667
669 void elevate(const nlohmann::json &json = NULL) override {
670 int num(1), dim(-1), patchIndex(-1);
671
672 if (json.contains("data")) {
673 if (json["data"].contains("num"))
674 num = json["data"]["num"].get<int>();
675
676 if (json["data"].contains("dim"))
677 dim = json["data"]["dim"].get<int>();
678
679 if (json["data"].contains("patch"))
680 patchIndex = json["data"]["patch"].get<int>();
681 }
682
683 if (patchIndex == -1)
684 geo_.degreeElevate(num, dim);
685 else
686 geo_.patch(patchIndex).degreeElevate(num, dim);
687 }
688
690 void increase(const nlohmann::json &json = NULL) override {
691 int num(1), dim(-1), patchIndex(-1);
692
693 if (json.contains("data")) {
694 if (json["data"].contains("num"))
695 num = json["data"]["num"].get<int>();
696
697 if (json["data"].contains("dim"))
698 dim = json["data"]["dim"].get<int>();
699
700 if (json["data"].contains("patch"))
701 patchIndex = json["data"]["patch"].get<int>();
702 }
703
704 if (patchIndex == -1)
705 geo_.degreeIncrease(num, dim);
706 else
707 geo_.patch(patchIndex).degreeIncrease(num, dim);
708 }
709
711 void refine(const nlohmann::json &json = NULL) override {
712 int num(1), dim(-1), patchIndex(-1);
713
714 if (json.contains("data")) {
715 if (json["data"].contains("num"))
716 num = json["data"]["num"].get<int>();
717
718 if (json["data"].contains("dim"))
719 dim = json["data"]["dim"].get<int>();
720
721 if (json["data"].contains("patch"))
722 patchIndex = json["data"]["patch"].get<int>();
723 }
724
725 if (patchIndex == -1)
726 geo_.uniformRefine(num, 1, dim);
727 else
728 geo_.patch(patchIndex).uniformRefine(num, 1, dim);
729 }
730
732 void reparameterize(const std::string &patch,
733 const nlohmann::json &json = NULL) override {
734 std::string type("volume");
735 bool patchwise(false);
736 T lambda1(1), lambda2(1);
737
738 if (json.contains("data")) {
739 if (json["data"].contains("type"))
740 type = json["data"]["type"].get<std::string>();
741
742 if (json["data"].contains("patchwise"))
743 patchwise = json["data"]["patchwise"].get<bool>();
744
745 if (json["data"].contains("orthogonality"))
746 lambda1 = std::stod(json["data"]["orthogonality"].get<std::string>());
747
748 if (json["data"].contains("unitarity"))
749 lambda2 = std::stod(json["data"]["unitarity"].get<std::string>());
750 }
751
752 if (type == "surface") {
753
754 if (geo_.parDim() == 2) {
755 // bivariate surface
756 gismo::gsHLBFGS<T> optimizer;
757
758 if (patch == "") {
759 for (auto& p : geo_) {
760 gismo::gsMultiPatch<T> mp; mp.addPatch(*p);
761 gismo::SurfaceReparameterization<T> reparam(mp, optimizer);
762 *p = reparam.solve(lambda1, lambda2).patch(0);
763 }
764 } else {
765 int patchIndex(-1);
766 try {
767 patchIndex = stoi(patch);
768 gismo::gsMultiPatch<T> mp; mp.addPatch(geo_[patchIndex]);
769 gismo::SurfaceReparameterization<T> reparam(mp, optimizer);
770 geo_.patch(patchIndex) = reparam.solve(lambda1, lambda2).patch(0);
771 } catch (...) {}
772 }
773 }
774
775 else if (geo_.parDim() == 3) {
776 // trivariate surface
777 gismo::gsHLBFGS<T> optimizer;
778
779 geo_.computeTopology();
780
781 if (patch == "") {
782 for (auto& bdr : geo_.boundaries()) {
783 auto b = geo_.patch(bdr.patch).boundary(bdr.side());
784 gismo::gsMultiPatch<T> mp; mp.addPatch(*b);
785 gismo::SurfaceReparameterization<T> reparam(mp, optimizer);
786 *b = reparam.solve(lambda1, lambda2).patch(0);
787
788 gismo::gsMatrix<T> ind = geo_.patch(bdr.patch).basis().boundary(bdr.side());
789 for (int i = 0; i != ind.size(); i++ )
790 {
791 geo_.patch(bdr.patch).coef( ind(i,0) ) = b->coef(i);
792 }
793 }
794 }
795 }
796
797 } else if (type == "volume") {
798
799 if (geo_.parDim() == 2 && geo_.geoDim() == 3) {
800 // bivariate surface
801 if (patch == "") {
802 geo_.embed(2);
803 gismo::gsBarrierPatch<2, T> opt(geo_, patchwise);
804 opt.options().setInt("ParamMethod", 1); // penalty
805 opt.compute();
806 geo_ = opt.result();
807 geo_.embed(3);
808 } else {
809 int patchIndex(-1);
810 try {
811 patchIndex = stoi(patch);
812 gismo::gsMultiPatch<T> mp; mp.addPatch(geo_[patchIndex]);
813 mp.embed(2);
814 gismo::gsBarrierPatch<2, T> opt(mp, true);
815 opt.options().setInt("ParamMethod", 1); // penalty
816 opt.compute();
817 mp = opt.result();
818 mp.embed(3);
819 geo_.patch(patchIndex) = mp.patch(0);
820 } catch (...) {}
821 }
822 }
823
824 else if (geo_.parDim() == 3 && geo_.geoDim() == 3) {
825 // trivariate volume
826 if (patch == "") {
827 gismo::gsBarrierPatch<d, T> opt(geo_, patchwise);
828 opt.options().setInt("ParamMethod", 1); // penalty
829 opt.compute();
830 geo_ = opt.result();
831 } else {
832 int patchIndex(-1);
833 try {
834 patchIndex = stoi(patch);
835 gismo::gsMultiPatch<T> mp; mp.addPatch(geo_[patchIndex]);
836 gismo::gsBarrierPatch<d, T> opt(mp, true);
837 opt.options().setInt("ParamMethod", 1); // penalty
838 opt.compute();
839 mp = opt.result();
840 geo_.patch(patchIndex) = mp.patch(0);
841 } catch (...) {}
842 }
843 }
844 }
845 }
846
848 void addPatch(const nlohmann::json &json = NULL) override {
849
850 throw std::runtime_error("Adding patches is not yet implemented in G+Smo");
851 }
852
854 void removePatch(const std::string &patch,
855 const nlohmann::json &json = NULL) override {
856 int patchIndex(-1);
857
858 try {
859 patchIndex = stoi(patch);
860 } catch (...) {}
861
862 gismo::gsMultiPatch<T> geo;
863 for (int i=0; i<geo_.nPatches(); ++i) {
864 if (i != patchIndex)
865 geo.addPatch(geo_.patch(i));
866 }
867
868 geo.topology();
869 geo_.swap(geo);
870 }
871
873 void importXML(const std::string &patch,
874 const std::string &component,
875 const nlohmann::json &json,
876 int id) override {
877
878 if (json.contains("data")) {
879 if (json["data"].contains("xml")) {
880
881 std::string xml_str = json["data"]["xml"].get<std::string>();
882
883 gismo::internal::gsXmlTree xml;
884 xml.parse<0>(const_cast<char*>(xml_str.c_str()));
885
886 importXML(patch, component, xml, id);
887
888 return;
889 }
890 }
891
892 throw std::runtime_error("No XML node in JSON object");
893 }
894
896 void importXML(const std::string &patch,
897 const std::string &component,
898 const pugi::xml_node &xml,
899 int id) override {
900
901 gsWarn << "Using generic importXML implementation\n";
902
903 if (component == "geometry" || component == "") {
904
905 if (patch == "") {
906
907 } else {
908
909 }
910 }
911 else
912 throw std::runtime_error("Unsupported component");
913 }
914
916 void importXML(const std::string &patch,
917 const std::string &component,
918 const gismo::internal::gsXmlTree &xml,
919 int id) {
920
921 if (component == "geometry" || component == "") {
922
923 if (patch == "") {
924
925 auto * geo = gismo::internal::gsXml<gismo::gsMultiPatch<T>>::getFirst(xml.getRoot());
926 geo_ = give(*geo);
927 delete geo;
928
929 } else {
930
931 auto * p = gismo::internal::gsXml<gismo::gsGeometry<T>>::getFirst(xml.getRoot());
932 geo_.patch(stoi(patch)) = give(*p);
933 delete p;
934 }
935
936 geo_.topology();
937 }
938 else
939 throw std::runtime_error("Unsupported component");
940 }
941
943 nlohmann::json exportXML(const std::string &patch, const std::string &component, int id) override {
944 gismo::internal::gsXmlTree xml;
945 xml.makeRoot();
946
947 exportXML(patch, component, xml, id);
948
949 std::string xml_str;
950 rapidxml::print(std::back_inserter(xml_str), xml, 0);
951
952 return xml_str;
953
954 // pugi::xml_document doc;
955 // pugi::xml_node xml = doc.append_child("xml");
956 // xml = exportXML(patch, component, xml, id);
957
958 // // serialize to JSON
959 // std::ostringstream oss;
960 // doc.save(oss);
961
962 // return oss.str();
963 }
964
966 pugi::xml_node &exportXML(const std::string &patch,
967 const std::string &component,
968 pugi::xml_node &xml,
969 int id) override {
970
971 gsWarn << "Using generic exportXML implementation\n";
972
973 if (component == "geometry" || component == "") {
974
975 gismo::internal::gsXmlTree data;
976 data.makeRoot();
977
978 gismo::internal::gsXmlNode *node = (patch == ""
979 ?
980 gismo::internal::gsXml<gismo::gsMultiPatch<T>>::put(geo_, data)
981 :
982 gismo::internal::gsXml<gismo::gsGeometry<T>>::put(geo_.patch(stoi(patch)), data));
983
984 if (node)
985 data.appendToRoot(node, -1);
986
987 std::string xml_str;
988 rapidxml::print(std::back_inserter(xml_str), data, 1);
989
990 pugi::xml_document doc;
991 pugi::xml_parse_result result = doc.load_string(xml_str.c_str());
992
993 if (result)
994 for (auto node : doc.first_child())
995 xml.append_copy(node);
996 }
997 else
998 throw std::runtime_error("Unsupported component");
999
1000 return xml;
1001 }
1002
1004 gismo::internal::gsXmlTree &exportXML(const std::string &patch,
1005 const std::string &component,
1006 gismo::internal::gsXmlTree &xml,
1007 int id) {
1008
1009 if (component == "geometry" || component == "") {
1010
1011 gismo::internal::gsXmlNode *node = (patch == ""
1012 ?
1013 gismo::internal::gsXml<gismo::gsMultiPatch<T>>::put(geo_, xml)
1014 :
1015 gismo::internal::gsXml<gismo::gsGeometry<T>>::put(geo_.patch(stoi(patch)), xml));
1016
1017 if (node)
1018 xml.appendToRoot(node, -1);
1019 }
1020 else
1021 throw std::runtime_error("Unsupported component");
1022
1023 return xml;
1024 }
1025
1026
1027};
1028
1029} // namespace webapp
1030} // namespace iganet
G+Smo model.
Model add patch.
Definition model.hpp:47
Model degree elevation.
Definition model.hpp:86
Model evaluator.
Definition model.hpp:98
Model degree increase.
Definition model.hpp:112
Model refinement.
Definition model.hpp:124
Model remove patch.
Definition model.hpp:59
Model reparameterization.
Definition model.hpp:136
Model XML serialization.
Definition model.hpp:163
G+Smo geometry model.
Definition GismoGeometryModel.hpp:33
nlohmann::json getOutputs() const override
Returns the model's outputs.
Definition GismoGeometryModel.hpp:323
void reparameterize(const std::string &patch, const nlohmann::json &json=NULL) override
Reparameterize the model.
Definition GismoGeometryModel.hpp:732
gismo::gsMultiPatch< T > geo_
Multi-patch geometry.
Definition GismoGeometryModel.hpp:39
nlohmann::json eval(const std::string &patch, const std::string &component, const nlohmann::json &json) const override
Evaluates the model.
Definition GismoGeometryModel.hpp:545
nlohmann::json getInputs() const override
Returns the model's inputs.
Definition GismoGeometryModel.hpp:315
nlohmann::json to_json(const std::string &patch, const std::string &component, const std::string &attribute) const override
Serializes the model to JSON.
Definition GismoGeometryModel.hpp:334
nlohmann::json getOptions() const override
Returns the model's options.
Definition GismoGeometryModel.hpp:185
GismoGeometryModel(const pugi::xml_node root)
Constructor from XML.
Definition GismoGeometryModel.hpp:180
nlohmann::json updateAttribute(const std::string &patch, const std::string &component, const std::string &attribute, const nlohmann::json &json) override
Updates the attributes of the model.
Definition GismoGeometryModel.hpp:459
void refine(const nlohmann::json &json=NULL) override
Refines the model.
Definition GismoGeometryModel.hpp:711
nlohmann::json exportXML(const std::string &patch, const std::string &component, int id) override
Exports the model to XML (as JSON object)
Definition GismoGeometryModel.hpp:943
void increase(const nlohmann::json &json=NULL) override
Increases the model's degrees, preserves multiplicity.
Definition GismoGeometryModel.hpp:690
void removePatch(const std::string &patch, const nlohmann::json &json=NULL) override
Remove existing patch from the model.
Definition GismoGeometryModel.hpp:854
pugi::xml_node & exportXML(const std::string &patch, const std::string &component, pugi::xml_node &xml, int id) override
Exports the model to XML (as XML object)
Definition GismoGeometryModel.hpp:966
gismo::internal::gsXmlTree & exportXML(const std::string &patch, const std::string &component, gismo::internal::gsXmlTree &xml, int id)
Exports the model to XML (as XML object) optimized for G+Smo.
Definition GismoGeometryModel.hpp:1004
GismoGeometryModel()=default
Default constructor.
void importXML(const std::string &patch, const std::string &component, const nlohmann::json &json, int id) override
Imports the model from XML (as JSON object)
Definition GismoGeometryModel.hpp:873
void importXML(const std::string &patch, const std::string &component, const pugi::xml_node &xml, int id) override
Imports the model from XML (as XML object)
Definition GismoGeometryModel.hpp:896
void addPatch(const nlohmann::json &json=NULL) override
Add new patch to the model.
Definition GismoGeometryModel.hpp:848
void elevate(const nlohmann::json &json=NULL) override
Elevates the model's degrees, preserves smoothness.
Definition GismoGeometryModel.hpp:669
void importXML(const std::string &patch, const std::string &component, const gismo::internal::gsXmlTree &xml, int id)
Imports the model from XML (as XML object) optimized for G+Smo.
Definition GismoGeometryModel.hpp:916
GismoGeometryModel(const std::array< short_t, d > degrees, const std::array< int64_t, d > ncoeffs, const std::array< int64_t, d > npatches, const std::array< T, d > dimensions)
Constructor for equidistant knot vectors.
Definition GismoGeometryModel.hpp:46
G+Smo base model.
Definition GismoModel.hpp:75
virtual nlohmann::json to_json(const std::string &patch, const std::string &component, const std::string &attribute) const override
Serializes the model to JSON.
Definition GismoModel.hpp:85
virtual nlohmann::json updateAttribute(const std::string &patch, const std::string &component, const std::string &attribute, const nlohmann::json &json) override
Updates the attributes of the model.
Definition GismoModel.hpp:93
auto to_json(const torch::TensorAccessor< T, N > &accessor)
Converts a torch::TensorAccessor object to a JSON object.
Definition serialize.hpp:41
auto zip(T &&...seqs)
Definition zip.hpp:97
Definition boundary.hpp:22
constexpr bool is_SplineType_v
Alias to the value of is_SplineType.
Definition bspline.hpp:3243
IndexOutOfBounds exception.
Definition model.hpp:32
InvalidModelAttribute exception.
Definition model.hpp:42