diff --git a/sdpm/api/om.py b/sdpm/api/om.py index 4e75025d5620f735bb256089324ef9a9e3247dfe..9fe3a5c58ec5b1e719514408492f8b2f3ad6e952 100644 --- a/sdpm/api/om.py +++ b/sdpm/api/om.py @@ -66,6 +66,8 @@ class SdpmSolver(om.ExplicitComponent): # self.declare_partials(of=['Q_re', 'Q_im'], wrt=['x_aero', 'q_aero'], method='exact') def compute(self, inputs, outputs): + # Update coordinates + self.bdy.setNodes(inputs['x_aero0'].reshape((len(self.bdy.getNodes()), 3))) # Update modes for i in range(self.nm): x_modes = np.zeros((len(self.bdy.getNodes()), 3)) # 3 DOF per mode and node diff --git a/sdpm/src/sdpmBody.cpp b/sdpm/src/sdpmBody.cpp index 494eea5f0d4db7777e41ccc1608cd37e4affeb6f..d4de4561278cefbd3c57ba299fd8c1137a17135e 100644 --- a/sdpm/src/sdpmBody.cpp +++ b/sdpm/src/sdpmBody.cpp @@ -43,14 +43,13 @@ Body::Body(Mesh &msh, std::string const &name, std::string const &teName, std::string wkName = _tag->getName() + "Wake"; // get TE nodes and sort them according to their y-coordinate (ascending) Group te(_msh, teName); - std::vector<Node *> teNodes; for (auto e : te.getElements()) for (auto n : e->getNodes()) - teNodes.push_back(n); - std::sort(teNodes.begin(), teNodes.end(), [](Node *a, Node *b) -> bool + _teNodes.push_back(n); + std::sort(_teNodes.begin(), _teNodes.end(), [](Node *a, Node *b) -> bool { return a->getCoords()(1) < b->getCoords()(1); }); - teNodes.erase(std::unique(teNodes.begin(), teNodes.end()), teNodes.end()); - _nTe = teNodes.size() - 1; + _teNodes.erase(std::unique(_teNodes.begin(), _teNodes.end()), _teNodes.end()); + size_t nTe = _teNodes.size() - 1; // create wake geometry if it does not already exist std::map<std::string, Tag *> tags = _msh.getTags(); auto it = tags.find(wkName); @@ -63,38 +62,38 @@ Body::Body(Mesh &msh, std::string const &name, std::string const &teName, err << "sdpm::Body: zero or negative characteristic chord length given for " << *_tag << "!\n"; throw std::runtime_error(err.str()); } + // duplicate TE nodes + std::map<Node *, Node *> teMap; + for (auto n : _teNodes) + { + Node *nN = new Node(_msh.getNodes().back()->getId() + 1, n->getCoords()); + _msh.addNode(nN); + teMap[n] = nN; + } // create tag and add it to the mesh Tag *tagp = new Tag(tags.size() + 1, wkName, 2); _msh.addTag(wkName, tagp); // create wake nodes and elements - std::vector<Node *> wkNodes = teNodes; + std::vector<Node *> wkNodes = _teNodes; for (size_t i = 0; i < 10 * nShedDiv; ++i) { // translate TE nodes along x-coordinate sdpmVector3d delta((i + 1) * shedLgth / nShedDiv, 0., 0.); - for (auto n : teNodes) + for (auto n : _teNodes) { Node *nN = new Node(_msh.getNodes().back()->getId() + 1, n->getCoords() + delta); wkNodes.push_back(nN); _msh.addNode(nN); } // create elements - for (size_t j = 0; j < _nTe; ++j) + for (size_t j = 0; j < nTe; ++j) { - std::vector<Node *> qnodes = {wkNodes[i * teNodes.size() + j], wkNodes[(i + 1) * teNodes.size() + j], wkNodes[(i + 1) * teNodes.size() + j + 1], wkNodes[i * teNodes.size() + j + 1]}; + std::vector<Node *> qnodes = {wkNodes[i * (nTe + 1) + j], wkNodes[(i + 1) * (nTe + 1) + j], wkNodes[(i + 1) * (nTe + 1) + j + 1], wkNodes[i * (nTe + 1) + j + 1]}; _msh.addElement(new Quad4(_msh.getElements().back()->getId() + 1, tagp, qnodes)); } } - // duplicate TE nodes - std::map<Node *, Node *> teMap; - for (auto n : teNodes) - { - Node *nN = new Node(_msh.getNodes().back()->getId() + 1, n->getCoords()); - _msh.addNode(nN); - teMap[n] = nN; - } // create wake - _wake = new Wake(_msh, wkName, _tag, _nTe); + _wake = new Wake(_msh, wkName, _tag, nTe); // swap nodes std::unordered_set<Element *> lwEl; // get set of unique wing TE elements on the pressure side for (auto p : _wake->getElMap()) @@ -127,7 +126,7 @@ Body::Body(Mesh &msh, std::string const &name, std::string const &teName, getUniqueNodes(); // map the lower TE nodes to their upper nodes std::map<Node *, Node *> iTeMap; - for (auto ten : teNodes) + for (auto ten : _teNodes) for (auto wn : _nodes) if (ten->getCoords() == wn->getCoords() && ten->getId() != wn->getId()) { @@ -135,11 +134,11 @@ Body::Body(Mesh &msh, std::string const &name, std::string const &teName, break; } // create wake and print - _wake = new Wake(_msh, wkName, _tag, _nTe, iTeMap); + _wake = new Wake(_msh, wkName, _tag, nTe, iTeMap); std::cout << *_wake << "already existing, nothing done." << std::endl; // check if parameters match existing wake geometry - std::vector<Element *> wEls = _wake->getElements(); - if (std::abs(wEls[0]->getNodes()[1]->getCoords()(0) - wEls[0]->getNodes()[0]->getCoords()(0) - shedLgth / nShedDiv) > 1e-12 || wEls.size() != 10 * nShedDiv * (_nTe)) + std::vector<Node *> wNods = _wake->getNodes(); + if (std::abs(wNods[nTe + 1]->getCoords()(0) - wNods[0]->getCoords()(0) - shedLgth / nShedDiv) > 1e-12 || _wake->getElements().size() != 10 * nShedDiv * nTe) { std::stringstream err; err << "sdpm::Body: parameters \'shedLgth\' and \'nShedDiv\' do not match existing wake geometry!\n"; @@ -170,6 +169,26 @@ Body::~Body() std::cout << "~sdpm::Body()\n"; } +/** + * @brief Set new coordinates for all nodes + */ +void Body::setNodes(std::vector<std::vector<double>> const &coords) +{ + // Check size + if (coords.size() != _nodes.size()) + throw std::runtime_error("sdpm::Problem: size of coordinates vector must be equal to the number of nodes!\n"); + // Set nodes coordinates + for (size_t i = 0; i < _nodes.size(); ++i) + _nodes[i]->setCoords(sdpmVector3d(coords[i].data())); + // Update wake + double dx = _wake->getLagMap().at(_wake->getElements()[0]); // dx = dt of first cell + size_t nTe = _teNodes.size(); + std::vector<Node *> wkNodes = _wake->getNodes(); + for (size_t i = 1; i < wkNodes.size() / nTe; ++i) + for (size_t j = 0; j < nTe; ++j) + wkNodes[i * nTe + j]->setCoords(_teNodes[j]->getCoords() + sdpmVector3d(i * dx, 0., 0.)); +} + /** * @brief Add motion */ @@ -213,8 +232,9 @@ std::pair<std::vector<Element *>, std::vector<Element *>> Body::getTrailingEdgeE { std::vector<Element *> we = _wake->getElements(); std::map<Element *, std::pair<Element *, Element *>> wwMap = _wake->getElMap(); - std::vector<Element *> up(_nTe), lw(_nTe); - for (size_t i = 0; i < _nTe; ++i) + size_t nTe = _teNodes.size() - 1; + std::vector<Element *> up(nTe), lw(nTe); + for (size_t i = 0; i < nTe; ++i) { std::pair<Element *, Element *> p = wwMap.at(we[i]); up[i] = p.first; diff --git a/sdpm/src/sdpmBody.h b/sdpm/src/sdpmBody.h index de338a54217f04d7f54cde48c5c5e65377162042..2754d2cb260de2044cac6e40b18e22b834db8d68 100644 --- a/sdpm/src/sdpmBody.h +++ b/sdpm/src/sdpmBody.h @@ -33,9 +33,9 @@ namespace sdpm class SDPM_API Body : public Group { // Geometry - size_t _nTe; ///< number of trailing edge elements std::vector<Node *> _nodes; ///< nodes of the surface - std::map<Node *, std::vector<Element *>> _neMap; ///< map between nodes and adjacent elements + std::vector<Node *> _teNodes; ///< nodes of the (upper) trailing edge + std::map<Node *, std::vector<Element *>> _neMap; ///< map between surface nodes and adjacent elements Wake *_wake; ///< wake attached to the lifting body // Motion std::vector<Motion *> _motions; ///< body motions @@ -85,6 +85,7 @@ public: sdpmDouble getUnsteadySideforceCoeffImag(size_t imd, size_t ifq) const { return _cs1Im[imd][ifq]; } sdpmDouble getUnsteadyMomentCoeffReal(size_t imd, size_t ifq) const { return _cm1Re[imd][ifq]; } sdpmDouble getUnsteadyMomentCoeffImag(size_t imd, size_t ifq) const { return _cm1Im[imd][ifq]; } + void setNodes(std::vector<std::vector<double>> const &coords); void addMotion(); void setRigidMotion(size_t m, double aAmp, double hAmp, double xRef, double zRef); void setFlexibleMotion(size_t m, double mAmp, std::vector<std::vector<double>> const &xMod); diff --git a/sdpm/src/sdpmNode.h b/sdpm/src/sdpmNode.h index 811875abc8ec13b7c29d16e8281c9cbd9c535f17..45bb6112c89ad23688d546e2b585e9bb9f16a036 100644 --- a/sdpm/src/sdpmNode.h +++ b/sdpm/src/sdpmNode.h @@ -40,6 +40,7 @@ public: size_t getId() { return _id; } size_t const &getIdRef() { return _id; } sdpmVector3d getCoords() { return _coord; } + void setCoords(sdpmVector3d const &c) { _coord = c; } #ifndef SWIG virtual void write(std::ostream &out) const override; diff --git a/sdpm/src/sdpmWake.cpp b/sdpm/src/sdpmWake.cpp index 642b53e159e9928afa02a044dafc5d112f998185..8e2f8ae120dbc51dfa3a958e987d5b4f598122bb 100644 --- a/sdpm/src/sdpmWake.cpp +++ b/sdpm/src/sdpmWake.cpp @@ -16,6 +16,7 @@ #include "sdpmWake.h" #include "sdpmEdge.h" +#include "sdpmMesh.h" #include "sdpmNode.h" #include "sdpmElement.h" #include <vector> @@ -35,6 +36,19 @@ Wake::Wake(Mesh &msh, std::string const &name, Tag *const &wingTag, size_t nTe, teEdges.insert(ed); } + // Save nodes + std::vector<Node *> mshNodes = msh.getNodes(); + size_t endNodW = mshNodes.size(); + size_t nNodWake = ((elems.size() / nTe) + 1) * (nTe + 1); + _nodes.resize(nNodWake); + // first nTe+1 nodes are trailing edge nodes + for (size_t i = 0; i <= nTe; ++i) + _nodes[i] = elems[i]->getNodes()[0]; + _nodes[nTe] = elems[nTe - 1]->getNodes()[3]; + // other nodes are last added nodes in the mesh (other than duplicated trailing edge nodes) + for (size_t i = 1; i <= nNodWake - nTe - 1; ++i) + _nodes[nNodWake - i] = mshNodes[endNodW - i]; + // Find wing elements having an edge on the TE... // ... the elements on the pressure side still have their original (suction side) trailing edge nodes if (iTeMap.empty()) diff --git a/sdpm/src/sdpmWake.h b/sdpm/src/sdpmWake.h index 37968e7c425e5a8524d9f36bf5a1e74330b3e7fe..3b062e4defe406921f5c63b8de5384258d0017f0 100644 --- a/sdpm/src/sdpmWake.h +++ b/sdpm/src/sdpmWake.h @@ -31,6 +31,7 @@ namespace sdpm */ class SDPM_API Wake : public Group { + std::vector<Node *> _nodes; ///< nodes of the wake std::map<Element *, std::pair<Element *, Element *>> _wwMap; ///< wing-wake map std::map<Element *, sdpmDouble> _lagMap; ///< time lag map @@ -39,10 +40,8 @@ public: ~Wake() {} #ifndef SWIG - std::map<Element *, std::pair<Element *, Element *>> const &getElMap() const - { - return _wwMap; - } + std::vector<Node *> const &getNodes() const { return _nodes; } + std::map<Element *, std::pair<Element *, Element *>> const &getElMap() const { return _wwMap; } std::map<Element *, sdpmDouble> const &getLagMap() const { return _lagMap; } virtual void write(std::ostream &out) const override; #endif