diff --git a/fpm/_src/fpmw.h b/fpm/_src/fpmw.h index 53f2b18b0db15b196870dc076465365e9fbc49d2..59e1f6abbbd1fc34219e567d8808a5105443ffc5 100644 --- a/fpm/_src/fpmw.h +++ b/fpm/_src/fpmw.h @@ -15,7 +15,6 @@ */ #include "fBody.h" -#include "fLifting.h" #include "fProblem.h" #include "fTimers.h" #include "fWake.h" diff --git a/fpm/_src/fpmw.i b/fpm/_src/fpmw.i index fdb12718a218aa4703b9eb3f457b7b73871671e9..b68248d2b3c6045c12dbdb11b2cb1cf1a4b0b304 100644 --- a/fpm/_src/fpmw.i +++ b/fpm/_src/fpmw.i @@ -68,10 +68,8 @@ def __getitem__(self, name): %include <std_shared_ptr.i> %shared_ptr(fpm::Body); +%immutable fpm::Body::wake; // avoids the creation of the setter method %include "fBody.h" -%shared_ptr(fpm::Lifting); -%immutable fpm::Lifting::wake; // avoids the creation of the setter method -%include "fLifting.h" %shared_ptr(fpm::Wake); %include "fWake.h" diff --git a/fpm/src/fBody.cpp b/fpm/src/fBody.cpp index b09b5569ba7b5af7dd0bcf893f05411a591a7151..10e9200919399c52368a26c8e4866072772ca6c7 100644 --- a/fpm/src/fBody.cpp +++ b/fpm/src/fBody.cpp @@ -15,14 +15,85 @@ */ #include "fBody.h" +#include "fWake.h" +#include "wMshData.h" +#include "wNode.h" +#include "wElement.h" #include "wTag.h" +#include "wQuad4.h" +#include "wGmshExport.h" #include <iomanip> #include <fstream> using namespace tbox; using namespace fpm; -Body::Body(std::shared_ptr<MshData> _msh, std::string const &name) : Group(_msh, name), Cl(0), Cd(0), Cs(0), Cm(0) +Body::Body(std::shared_ptr<MshData> _msh, std::string const &id, + std::vector<std::string> const &teIds, double xF) : Group(_msh, id), Cl(0), Cd(0), Cs(0), Cm(0) { + // If wakes are requested, check if they are already available, otherwise create them + bool hasChanged = false; + size_t j = 0; + for (auto teId : teIds) + { + std::cout << "Creating wake... " << std::flush; + try + { + wakes.push_back(new Wake(_msh, tag->name + "Wake" + std::to_string(j), tag)); + std::cout << *wakes.back() << " already existing, nothing done." << std::endl; + } + catch (const std::out_of_range &) + { + // Notify that mesh needs to be saved + hasChanged = true; + // Create tags + Tag *tagp = new Tag(static_cast<int>(msh->ptags.rbegin()->first + 1), tag->name + "Wake" + std::to_string(j), 2); + Tag *tage = new Tag(static_cast<int>(msh->etags.rbegin()->first + 1), tag->name + "Wake" + std::to_string(j), 2); + msh->ntags[tag->name + "Wake" + std::to_string(j)] = tagp; + msh->ptags[static_cast<int>(msh->ptags.rbegin()->first + 1)] = tagp; + msh->etags[static_cast<int>(msh->etags.rbegin()->first + 1)] = tage; + // Sort TE nodes (ascending along y-coordinate) + Group te(_msh, teId); + std::vector<Node *> teNodes; + for (auto e : te.tag->elems) + for (auto n : e->nodes) + teNodes.push_back(n); + std::sort(teNodes.begin(), teNodes.end(), [](Node *a, Node *b) -> bool { return a->pos(1) < b->pos(1); }); + teNodes.erase(std::unique(teNodes.begin(), teNodes.end()), teNodes.end()); + // Translate TE nodes (along x-coordinate) + std::vector<Node *> wkNodes; + for (auto n : teNodes) + { + // Sanity check + if (xF <= n->pos(0)) + { + std::stringstream err; + err << "fpm::Body: zero or negative length wake requested for " << *tag << "!\n"; + throw std::runtime_error(err.str()); + } + Node *nN = new Node(msh->nodes.back()->no + 1, Eigen::Vector3d(xF, n->pos(1), n->pos(2))); + wkNodes.push_back(nN); + msh->nodes.push_back(nN); + } + // Create wake elements + for (size_t i = 0; i < wkNodes.size() - 1; ++i) + { + std::vector<Node *> qnodes = {teNodes[i], wkNodes[i], wkNodes[i + 1], teNodes[i + 1]}; + msh->elems.push_back(new Quad4(msh->elems.back()->no + 1, tagp, tage, tag->elems[0]->parts, qnodes)); + } + // Create wake + wakes.push_back(new Wake(_msh, tag->name + "Wake" + std::to_string(j), tag)); + std::cout << *wakes.back() << " created. " << std::flush; + } + ++j; + } + // Save the mesh if modified + if (hasChanged) + { + GmshExport writer(_msh); + writer.save(_msh->name); + } + + // Size load vectors cLoadX.resize(tag->elems.size()); cLoadY.resize(tag->elems.size()); cLoadZ.resize(tag->elems.size()); @@ -67,4 +138,7 @@ void Body::save(std::string const &name) void Body::write(std::ostream &out) const { out << "fpm::Body " << *tag << std::endl; + out << "with"; + for (auto w : wakes) + out << "\t" << *w; } diff --git a/fpm/src/fBody.h b/fpm/src/fBody.h index 8d49a02593c9cab53404f7a60863caa597081fe2..7cdea5ad3a2dd2b152f8ff2f60662d2cffeb44b0 100644 --- a/fpm/src/fBody.h +++ b/fpm/src/fBody.h @@ -38,8 +38,9 @@ public: std::vector<double> cLoadX; ///< x-component of aerodynamic load coefficient on boundary std::vector<double> cLoadY; ///< y-component of aerodynamic load coefficient on boundary std::vector<double> cLoadZ; ///< z-component of aerodynamic load coefficient on boundary + std::vector<Wake *> wakes; ///< wake(s) attached to the lifting surface - Body(std::shared_ptr<tbox::MshData> _msh, std::string const &name); + Body(std::shared_ptr<tbox::MshData> _msh, std::string const &name, std::vector<std::string> const &teNames, double xF); ~Body() { std::cout << "~Body()\n"; } virtual void save(std::string const &name); diff --git a/fpm/src/fLifting.cpp b/fpm/src/fLifting.cpp deleted file mode 100644 index 63d51ed17c4cb19b4bbf8300994de803122bf3f5..0000000000000000000000000000000000000000 --- a/fpm/src/fLifting.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2020 University of Liège - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fLifting.h" -#include "fWake.h" -#include "wMshData.h" -#include "wGmshExport.h" -#include "wTag.h" -#include "wElement.h" -#include "wQuad4.h" -#include "wNode.h" -using namespace tbox; -using namespace fpm; - -Lifting::Lifting(std::shared_ptr<MshData> _msh, std::vector<std::string> const &names, double xF) : Body(_msh, names[0]) -{ - // Sanity check - if (names.size() != 2) - { - std::stringstream err; - err << "fpm::Lifting should be built with 2 physical groups but " << names.size() << " were given!\n"; - throw std::runtime_error(err.str()); - } - - // Check if wake is already available and create it otherwise - std::cout << "Creating wake... " << std::flush; - try - { - wake = new Wake(_msh, names[0] + "Wake", tag); - std::cout << *wake << " already existing, nothing done." << std::endl; - } - catch (const std::out_of_range &) - { - // Create tags - Tag *tagp = new Tag(static_cast<int>(msh->ptags.rbegin()->first + 1), tag->name + "Wake", 2); - Tag *tage = new Tag(static_cast<int>(msh->etags.rbegin()->first + 1), tag->name + "Wake", 2); - msh->ntags[tag->name + "Wake"] = tagp; - msh->ptags[static_cast<int>(msh->ptags.rbegin()->first + 1)] = tagp; - msh->etags[static_cast<int>(msh->etags.rbegin()->first + 1)] = tage; - // Sort TE nodes (ascending along y-coordinate) - Group te(_msh, names[1]); - std::vector<Node *> teNodes; - for (auto e : te.tag->elems) - for (auto n : e->nodes) - teNodes.push_back(n); - std::sort(teNodes.begin(), teNodes.end(), [](Node *a, Node *b) -> bool { return a->pos(1) < b->pos(1); }); - teNodes.erase(std::unique(teNodes.begin(), teNodes.end()), teNodes.end()); - // Translate TE nodes (along x-coordinate) - std::vector<Node *> wkNodes; - for (auto n : teNodes) - { - Node *nN = new Node(msh->nodes.back()->no + 1, Eigen::Vector3d(xF, n->pos(1), n->pos(2))); - wkNodes.push_back(nN); - msh->nodes.push_back(nN); - } - // Create wake elements - for (size_t i = 0; i < wkNodes.size() - 1; ++i) - { - std::vector<Node *> qnodes = {teNodes[i], wkNodes[i], wkNodes[i + 1], teNodes[i + 1]}; - msh->elems.push_back(new Quad4(msh->elems.back()->no + 1, tagp, tage, tag->elems[0]->parts, qnodes)); - } - - // Create wake and save modified mesh - wake = new Wake(_msh, names[0] + "Wake", tag); - std::cout << *wake << " created. " << std::flush; - GmshExport writer(_msh); - writer.save(_msh->name); - } -} - -Lifting::~Lifting() -{ - delete wake; - std::cout << "~Lifting()\n"; -} - -void Lifting::write(std::ostream &out) const -{ - out << "fpm::Lifting " << *tag - << " with " << *wake << std::endl; -} diff --git a/fpm/src/fLifting.h b/fpm/src/fLifting.h deleted file mode 100644 index 2cfedc79d4dd26843a6c4f809da14767b4db3980..0000000000000000000000000000000000000000 --- a/fpm/src/fLifting.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2020 University of Liège - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FLIFTING_H -#define FLIFTING_H - -#include "fpm.h" -#include "fBody.h" -#include "fWake.h" - -namespace fpm -{ - -/** - * @brief Manage a lifting body immersed in the fluid - * @authors Adrien Crovato - */ -class FPM_API Lifting : public Body -{ -public: - Wake *wake; ///< wake attached to the lifting surface - - Lifting(std::shared_ptr<tbox::MshData> _msh, std::vector<std::string> const &names, double xF); - ~Lifting(); - -#ifndef SWIG - virtual void write(std::ostream &out) const override; -#endif -}; - -} // namespace fpm - -#endif //FLIFTING_H diff --git a/fpm/src/fProblem.cpp b/fpm/src/fProblem.cpp index 6c2e3497056fc9dee0edd2179323397803228bb0..5ac54291b181be9abdb8f9c0436e77302dfed82e 100644 --- a/fpm/src/fProblem.cpp +++ b/fpm/src/fProblem.cpp @@ -16,15 +16,14 @@ #include "fProblem.h" #include "fBody.h" -#include "fLifting.h" #include "wTag.h" #include "wElement.h" #include "wMem.h" using namespace tbox; using namespace fpm; -Problem::Problem(std::shared_ptr<MshData> _msh, double aoa, double aos, double sref, double cref, - double xref, double yref, double zref) : msh(_msh), alpha(aoa), beta(aos), +Problem::Problem(std::shared_ptr<MshData> _smsh, double aoa, double aos, double sref, double cref, + double xref, double yref, double zref) : smsh(_smsh), alpha(aoa), beta(aos), sR(sref), cR(cref) { xR(0) = xref; @@ -39,13 +38,6 @@ void Problem::add(std::shared_ptr<Body> b) { bodies.push_back(b); } -/** - * @brief Add a lifting body - */ -void Problem::add(std::shared_ptr<Lifting> l) -{ - liftings.push_back(l); -} /** * @brief Update the elements memory (Jacobian) @@ -56,9 +48,6 @@ void Problem::updateMem() for (auto s : bodies) for (auto e : s->tag->elems) e->getVMem().update(false); - for (auto s : liftings) - for (auto e : s->tag->elems) - e->getVMem().update(false); } /** @@ -67,7 +56,7 @@ void Problem::updateMem() void Problem::check() const { // Sanity checks - if (liftings.empty()) + if (bodies.empty()) throw std::runtime_error("No lifting bodies provided!\n"); // Three-dimension problem @@ -81,15 +70,6 @@ void Problem::check() const << ELTYPE::QUAD4 << " (" << e->type() << " was given)!\n"; throw std::runtime_error(err.str()); } - for (auto l : liftings) - for (auto e : l->tag->elems) - if (e->type() != ELTYPE::QUAD4) - { - std::stringstream err; - err << "FPM solver is only implemented for surface elements of type " - << ELTYPE::QUAD4 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } } void Problem::write(std::ostream &out) const @@ -104,6 +84,4 @@ void Problem::write(std::ostream &out) const out << "with"; for (auto b : bodies) out << "\t" << *b; - for (auto l : liftings) - out << "\t" << *l; } diff --git a/fpm/src/fProblem.h b/fpm/src/fProblem.h index d34d255155813a8ae5b828accae17dfe8836011e..54cf0159924a8e100ad81a1ca01fc77b90669efb 100644 --- a/fpm/src/fProblem.h +++ b/fpm/src/fProblem.h @@ -32,10 +32,9 @@ namespace fpm class FPM_API Problem : public fwk::wSharedObject { public: - std::shared_ptr<tbox::MshData> msh; ///< Mesh data structure + std::shared_ptr<tbox::MshData> smsh; ///< surface mesh data structure #ifndef SWIG - std::vector<std::shared_ptr<Body>> bodies; ///< Non-lifting bodies - std::vector<std::shared_ptr<Lifting>> liftings; ///< Lifting bodies + std::vector<std::shared_ptr<Body>> bodies; ///< bodies in fluid #endif // Reference values double alpha; ///< Angle of attack @@ -44,11 +43,10 @@ public: double cR; ///< Reference chord Eigen::Vector3d xR; ///< Reference center point (for moment computation) - Problem(std::shared_ptr<tbox::MshData> _msh, double aoa, double aos, double sref, double cref, double xref, double yref, double zref); + Problem(std::shared_ptr<tbox::MshData> _smsh, double aoa, double aos, double sref, double cref, double xref, double yref, double zref); ~Problem() { std::cout << "~Problem()\n"; } void add(std::shared_ptr<Body> b); - void add(std::shared_ptr<Lifting> l); #ifndef SWIG void check() const; diff --git a/fpm/src/fpm.h b/fpm/src/fpm.h index 0d681a8504d5405b1564c9775b485d8080aa1f6e..a56c56666b8cef734fd365b5fdff0158dab358e1 100644 --- a/fpm/src/fpm.h +++ b/fpm/src/fpm.h @@ -41,7 +41,6 @@ class Timers; // problem definition class Problem; class Body; -class Lifting; class Wake; // misc diff --git a/fpm/tests/basic.py b/fpm/tests/basic.py index 232d38fa7344ebbd066f3c532f0c3ffebfe76ab2..af8a994832dc1d3edcabf841750934bbd74664c3 100644 --- a/fpm/tests/basic.py +++ b/fpm/tests/basic.py @@ -34,9 +34,7 @@ def main(): msh = gmsh.MeshLoader('../models/n0012.geo', __file__).execute(**pars) # problem pbl = fpm.Problem(msh, 0, 0, 5., 1., 0., 0., 0.) - fuselage = fpm.Body(msh, 'wing') - pbl.add(fuselage) - wing = fpm.Lifting(msh, ['wing', 'te'], 5) + wing = fpm.Body(msh, 'wing', ['te'], 5) pbl.add(wing) print(pbl) # end timer