Skip to content
Snippets Groups Projects
Commit f020b9fd authored by Adrien Crovato's avatar Adrien Crovato
Browse files

Remove Lifting (all bodies are lifting). Add multiwake support.

parent d5e7156a
No related branches found
No related tags found
1 merge request!1Version 0.1.0 (setup)
......@@ -15,7 +15,6 @@
*/
#include "fBody.h"
#include "fLifting.h"
#include "fProblem.h"
#include "fTimers.h"
#include "fWake.h"
......@@ -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"
......
......@@ -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;
}
......@@ -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);
......
/*
* 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;
}
/*
* 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
......@@ -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;
}
......@@ -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;
......
......@@ -41,7 +41,6 @@ class Timers;
// problem definition
class Problem;
class Body;
class Lifting;
class Wake;
// misc
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment