47 const std::array<int64_t, d> ncoeffs,
48 const std::array<int64_t, d> npatches,
49 const std::array<T, d> dimensions)
52 if constexpr (d == 1) {
53 gismo::gsKnotVector<T> KV0(0, 1, ncoeffs[0] - degrees[0] - 1, degrees[0] + 1);
55 gismo::gsMatrix<T> C(ncoeffs[0], 3), P;
57 for (int64_t i = 0; i < ncoeffs[0]; ++i) {
58 C(i, 0) = ((T)i) / (T)(ncoeffs[0] - 1);
63 for (int64_t i = 0; i < npatches[0]; ++i) {
66 P.col(0) *= dimensions[0] / npatches[0];
68 P.col(0).array() += (T)(i) / (T)npatches[0];
70 geo_.addPatch(gismo::gsBSpline<T>(KV0, give(P)));
72 geo_.computeTopology();
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);
78 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1], 3), P;
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);
89 for (int64_t j = 0; j < npatches[1]; ++j)
90 for (int64_t i = 0; i < npatches[0]; ++i) {
93 P.col(0) *= dimensions[0] / (T)npatches[0];
94 P.col(1) *= dimensions[1] / (T)npatches[1];
96 P.col(0).array() += (T)(i) / (T)npatches[0];
97 P.col(1).array() += (T)(j) / (T)npatches[1];
99 geo_.addPatch(gismo::gsTensorBSpline<2, T>(KV0, KV1, give(P)));
101 geo_.computeTopology();
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);
108 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1] * ncoeffs[2], 3), P;
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);
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) {
125 P.col(0) *= dimensions[0] / npatches[0];
126 P.col(1) *= dimensions[1] / npatches[1];
127 P.col(2) *= dimensions[2] / npatches[2];
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];
133 geo_.addPatch(gismo::gsTensorBSpline<3, T>(KV0, KV1, KV2, give(P)));
135 geo_.computeTopology();
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);
143 gismo::gsMatrix<T> C(ncoeffs[0] * ncoeffs[1] * ncoeffs[2] * ncoeffs[3], 4), P;
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);
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) {
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];
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];
173 geo_.addPatch(gismo::gsTensorBSpline<4, T>(KV0, KV1, KV2, KV3, give(P)));
175 geo_.computeTopology();
334 nlohmann::json
to_json(
const std::string &patch,
const std::string &component,
335 const std::string &attribute)
const override {
337 if (component ==
"geometry" || component ==
"") {
339 if (patch ==
"" && attribute ==
"") {
345 else if (patch !=
"") {
351 patchIndex = stoi(patch);
354 return R
"({ INVALID REQUEST })"_json;
357 if (patchIndex >=
geo_.nPatches())
358 return R
"({ INVALID REQUEST })"_json;
360 if (attribute ==
"") {
370 if (attribute ==
"degrees") {
371 json[
"degrees"] = nlohmann::json::array();
373 for (std::size_t i = 0; i <
geo_.patch(patchIndex).parDim(); ++i)
374 json[
"degrees"].push_back(
geo_.patch(patchIndex).degree(i));
377 else if (attribute ==
"geoDim")
378 json[
"geoDim"] =
geo_.patch(patchIndex).geoDim();
380 else if (attribute ==
"parDim")
381 json[
"parDim"] =
geo_.patch(patchIndex).parDim();
383 else if (attribute ==
"ncoeffs") {
384 json[
"ncoeffs"] = nlohmann::json::array();
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));
395 return R
"({ INVALID REQUEST })"_json;
399 else if (attribute ==
"nknots") {
400 json[
"nknots"] = nlohmann::json::array();
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());
411 return R
"({ INVALID REQUEST })"_json;
414 else if (attribute ==
"coeffs") {
417 dynamic_cast<const gismo::gsBSpline<T> *
>(&
geo_.patch(patchIndex)))
419 else if (
auto bspline =
dynamic_cast<const gismo::gsTensorBSpline<d, T> *
>(
420 &
geo_.patch(patchIndex)))
423 return R
"({ INVALID REQUEST })"_json;
427 else if (attribute ==
"knots") {
428 json[
"knots"] = nlohmann::json::array();
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));
439 return R
"({ INVALID REQUEST })"_json;
444 return R
"({ INVALID REQUEST })"_json;
451 return R
"({ INVALID REQUEST })"_json;
460 const std::string &component,
461 const std::string &attribute,
462 const nlohmann::json &json)
override {
467 patchIndex = stoi(patch);
469 return R
"({ INVALID REQUEST })"_json;
472 if (attribute ==
"coeffs") {
473 if (!json.contains(
"data"))
475 if (!json[
"data"].contains(
"indices") || !json[
"data"].contains(
"coeffs"))
478 auto indices = json[
"data"][
"indices"].get<std::vector<int64_t>>();
479 auto ncoeffs =
geo_.patch(patchIndex).coefs().rows();
481 switch (
geo_.geoDim()) {
483 auto coords = json[
"data"][
"coeffs"].get<std::vector<std::tuple<T>>>();
486 if (index < 0 || index >= ncoeffs)
489 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
495 json[
"data"][
"coeffs"].get<std::vector<std::tuple<T, T>>>();
498 if (index < 0 || index >= ncoeffs)
501 geo_.patch(patchIndex).coef(index, 0) = std::get<0>(coord);
502 geo_.patch(patchIndex).coef(index, 1) = std::get<1>(coord);
508 json[
"data"][
"coeffs"].get<std::vector<std::tuple<T, T, T>>>();
511 if (index < 0 || index >= ncoeffs)
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);
522 json[
"data"][
"coeffs"].get<std::vector<std::tuple<T, T, T, T>>>();
525 if (index < 0 || index >= ncoeffs)
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);
545 nlohmann::json
eval(
const std::string &patch,
const std::string &component,
546 const nlohmann::json &json)
const override {
551 patchIndex = stoi(patch);
553 return R
"({ INVALID REQUEST })"_json;
556 nlohmann::json result;
559 result[
"degrees"] = nlohmann::json::array();
561 for (std::size_t i = 0; i <
geo_.patch(patchIndex).parDim(); ++i)
562 result[
"degrees"].push_back(
geo_.patch(patchIndex).degree(i));
565 result[
"ncoeffs"] = nlohmann::json::array();
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));
576 return R
"({ INVALID REQUEST })"_json;
579 result[
"nknots"] = nlohmann::json::array();
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());
590 return R
"({ INVALID REQUEST })"_json;
593 result[
"knots"] = nlohmann::json::array();
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));
604 return R
"({ INVALID REQUEST })"_json;
607 if (component ==
"ScaledJacobian" || component ==
"UniformityMetric") {
609 gismo::gsMultiBasis<T> basis(
geo_);
610 gismo::gsExprEvaluator<T> ev;
611 ev.setIntegrationElements(basis);
612 auto G = ev.getMap(
geo_);
614 if (component ==
"ScaledJacobian") {
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());
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());
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());
637 auto jac = basis.interpolateAtAnchors(
eval);
641 else if (component ==
"UniformityMetric") {
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);
648 auto &basis =
geo_.patch(patchIndex).basis();
649 auto pts = basis.anchors();
650 gismo::gsMatrix<T>
eval(1, pts.cols());
652 for (std::size_t i = 0; i < pts.cols(); i++)
653 eval(0, i) = ev.eval(expr, pts.col(i))(0);
655 auto uniform = basis.interpolateAtAnchors(
eval);
659 return R
"({ INVALID REQUEST })"_json;
733 const nlohmann::json &json = NULL)
override {
734 std::string type(
"volume");
735 bool patchwise(
false);
736 T lambda1(1), lambda2(1);
738 if (json.contains(
"data")) {
739 if (json[
"data"].contains(
"type"))
740 type = json[
"data"][
"type"].get<std::string>();
742 if (json[
"data"].contains(
"patchwise"))
743 patchwise = json[
"data"][
"patchwise"].get<bool>();
745 if (json[
"data"].contains(
"orthogonality"))
746 lambda1 = std::stod(json[
"data"][
"orthogonality"].get<std::string>());
748 if (json[
"data"].contains(
"unitarity"))
749 lambda2 = std::stod(json[
"data"][
"unitarity"].get<std::string>());
752 if (type ==
"surface") {
754 if (
geo_.parDim() == 2) {
756 gismo::gsHLBFGS<T> optimizer;
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);
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);
775 else if (
geo_.parDim() == 3) {
777 gismo::gsHLBFGS<T> optimizer;
779 geo_.computeTopology();
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);
788 gismo::gsMatrix<T> ind =
geo_.patch(bdr.patch).basis().boundary(bdr.side());
789 for (
int i = 0; i != ind.size(); i++ )
791 geo_.patch(bdr.patch).coef( ind(i,0) ) = b->coef(i);
797 }
else if (type ==
"volume") {
799 if (
geo_.parDim() == 2 &&
geo_.geoDim() == 3) {
803 gismo::gsBarrierPatch<2, T> opt(
geo_, patchwise);
804 opt.options().setInt(
"ParamMethod", 1);
811 patchIndex = stoi(patch);
812 gismo::gsMultiPatch<T> mp; mp.addPatch(
geo_[patchIndex]);
814 gismo::gsBarrierPatch<2, T> opt(mp,
true);
815 opt.options().setInt(
"ParamMethod", 1);
819 geo_.patch(patchIndex) = mp.patch(0);
824 else if (
geo_.parDim() == 3 &&
geo_.geoDim() == 3) {
827 gismo::gsBarrierPatch<d, T> opt(
geo_, patchwise);
828 opt.options().setInt(
"ParamMethod", 1);
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);
840 geo_.patch(patchIndex) = mp.patch(0);