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

Merge branch 'adri' into 'master'

Version 0.1.0 (setup)

See merge request !1
parents f5d6754a 98d9624b
No related branches found
No related tags found
1 merge request!1Version 0.1.0 (setup)
Pipeline #2354 passed
Showing with 1658 additions and 0 deletions
# 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.
# CMake input file of fpm.so
FILE(GLOB SRCS *.h *.cpp *.inl *.hpp)
ADD_LIBRARY(fpm SHARED ${SRCS})
MACRO_DebugPostfix(fpm)
TARGET_INCLUDE_DIRECTORIES(fpm PUBLIC ${PROJECT_SOURCE_DIR}/fpm/src)
# -- Eigen
FIND_PACKAGE(EIGEN 3.3.4 REQUIRED)
TARGET_INCLUDE_DIRECTORIES(fpm PUBLIC ${EIGEN_INCLUDE_DIRS})
TARGET_COMPILE_DEFINITIONS(fpm PUBLIC EIGEN_DONT_PARALLELIZE)
# -- WAVES (if no path is provided, assume that it is located next to fpm)
IF(NOT DEFINED CMAKE_PREFIX_PATH)
SET(CMAKE_PREFIX_PATH "${PROJECT_SOURCE_DIR}/../waves/build")
ENDIF()
FIND_PACKAGE(WAVES REQUIRED)
TARGET_INCLUDE_DIRECTORIES(fpm PUBLIC ${WAVES_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(fpm ${WAVES_LIBRARIES})
SOURCE_GROUP(base REGULAR_EXPRESSION ".*\\.(cpp|inl|hpp|h)")
/*
* 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 "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 &id,
std::vector<std::string> const &teIds, double xF) : Group(_msh, id), Cl(0), Cd(0), Cs(0), Cm(0)
{
// Get nodes
for (auto e : tag->elems)
for (auto n : e->nodes)
nodes.push_back(n);
std::sort(nodes.begin(), nodes.end());
nodes.erase(std::unique(nodes.begin(), nodes.end()), nodes.end());
// Associate each node to its adjacent elements
for (auto e : tag->elems)
for (auto n : e->nodes)
neMap[n].push_back(e);
// 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(nodes.size());
cLoadY.resize(nodes.size());
cLoadZ.resize(nodes.size());
}
/**
* @brief Save global quantities to file
*/
void Body::save(std::string const &name)
{
// Write to file
std::cout << "writing file: " << name + ".dat"
<< "... " << std::flush;
std::ofstream outfile;
outfile.open(name + ".dat");
// Header
outfile << "$Body - " << tag->name << std::endl;
// Element count
outfile << "$Elements" << std::endl;
outfile << tag->elems.size();
// Aerodynamic coefficients
outfile << "$Aerodynamic coefficients" << std::endl;
outfile << "#" << std::fixed
<< std::setw(14) << "Cl"
<< std::setw(15) << "Cd"
<< std::setw(15) << "Cs"
<< std::setw(15) << "Cm"
<< std::endl;
outfile << std::fixed
<< std::setw(15) << Cl
<< std::setw(15) << Cd
<< std::setw(15) << Cs
<< std::setw(15) << Cm
<< std::endl;
// Footer
outfile << std::endl;
// Close file
outfile.close();
std::cout << "done!" << std::endl;
}
void Body::write(std::ostream &out) const
{
out << "fpm::Body " << *tag << std::endl;
out << "with";
for (auto w : wakes)
out << "\t" << *w;
}
/*
* 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 FBODY_H
#define FBODY_H
#include "fpm.h"
#include "wGroup.h"
#include <vector>
#include <map>
namespace fpm
{
/**
* @brief Manage a body immersed in the fluid (lifting surface)
* @authors Adrien Crovato
*/
class FPM_API Body : public tbox::Group
{
public:
double Cl; ///< lift coefficient
double Cd; ///< drag coefficient
double Cs; ///< sideforce coefficient
double Cm; ///< pitch moment coefficient (positive nose-up)
std::vector<double> cLoadX; ///< x-component of aerodynamic load normalized by dynamic pressure
std::vector<double> cLoadY; ///< y-component of aerodynamic load normalized by dynamic pressure
std::vector<double> cLoadZ; ///< z-component of aerodynamic load normalized by dynamic pressure
std::vector<tbox::Node *> nodes; ///< nodes of the surface
std::map<tbox::Node *, std::vector<tbox::Element *>> neMap; ///< map between nodes and adjacent elements
std::vector<Wake *> wakes; ///< wake(s) attached to the lifting surface
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);
#ifndef SWIG
virtual void write(std::ostream &out) const override;
#endif
};
} // namespace fpm
#endif //FBODY_H
/*
* 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 "fBuilder.h"
#include "fProblem.h"
#include "fField.h"
#include "fBody.h"
#include "fWake.h"
#include "wTag.h"
#include "wElement.h"
#include "wMem.h"
#define PI 3.14159
using namespace tbox;
using namespace fpm;
/**
* @brief Initialize the solver and perform sanity checks
* @authors Adrien Crovato
*/
Builder::Builder(std::shared_ptr<Problem> _pbl) : pbl(_pbl), valid(false)
{
// Check the problem and update element memory
pbl->check();
pbl->updateMem();
// Setup AIC matrices
pbl->field ? nF = pbl->field->tag->elems.size() : nF = 0;
nP = 0;
for (auto body : pbl->bodies)
nP += body->tag->elems.size();
A = Eigen::MatrixXd::Zero(nP, nP);
B = Eigen::MatrixXd::Zero(nP, nP);
C = Eigen::MatrixXd::Zero(nP, nF);
Cx = Eigen::MatrixXd::Zero(nP, nF);
Cy = Eigen::MatrixXd::Zero(nP, nF);
Cz = Eigen::MatrixXd::Zero(nP, nF);
}
/**
* @brief Fill AIC matrices
*/
void Builder::run()
{
// global->local id
std::map<Element *, int> rows;
int i = 0;
for (auto body : pbl->bodies)
for (auto e : body->tag->elems)
{
rows[e] = i;
i++;
}
// body to body
for (auto ibody : pbl->bodies)
for (auto ei : ibody->tag->elems)
{
// body panels
for (auto jbody : pbl->bodies)
for (auto ej : jbody->tag->elems)
{
A(rows.at(ei), rows.at(ej)) = mu(ei, ej);
B(rows.at(ei), rows.at(ej)) = tau(ei, ej);
}
// wake panels
for (auto jbody : pbl->bodies)
for (auto wake : jbody->wakes)
for (auto ew : wake->tag->elems)
{
double wmu = mu(ei, ew);
A(rows.at(ei), rows.at(wake->wkMap.at(ew).first)) += wmu;
A(rows.at(ei), rows.at(wake->wkMap.at(ew).second)) -= wmu;
}
}
// field to body
if (pbl->field)
for (auto body : pbl->bodies)
for (auto e : body->tag->elems)
for (size_t j = 0; j < pbl->field->tag->elems.size(); ++j)
{
C(rows.at(e), j) = sigma(e, pbl->field->tag->elems[j]);
Cx(rows.at(e), j) = sigmaX(e, pbl->field->tag->elems[j]);
Cy(rows.at(e), j) = sigmaY(e, pbl->field->tag->elems[j]);
Cz(rows.at(e), j) = sigmaY(e, pbl->field->tag->elems[j]);
}
valid = true;
}
/**
* @brief Compute doublet AIC from body panel ej to body panel ei
*/
double Builder::mu(Element *ei, Element *ej)
{
if (ei == ej)
return 0.5;
else
return 0;
}
/**
* @brief Compute source AIC from body panel ej to body panel ei
*/
double Builder::tau(Element *ei, Element *ej)
{
if (ei == ej)
return 0;
else
return 0;
}
/**
* @brief Compute source AIC from field panel ej to body panel ei
*/
double Builder::sigma(Element *ei, Element *ej)
{
return 0;
}
/**
* @brief Compute source x-velocity AIC from field panel ej to body panel ei
*/
double Builder::sigmaX(Element *ei, Element *ej)
{
return 0;
}
/**
* @brief Compute source y-velocity AIC from field panel ej to body panel ei
*/
double Builder::sigmaY(Element *ei, Element *ej)
{
return 0;
}
/**
* @brief Compute source z-velocity AIC from field panel ej to body panel ei
*/
double Builder::sigmaZ(Element *ei, Element *ej)
{
return 0;
}
void Builder::write(std::ostream &out) const
{
out << "fpm::Builder with AIC matrices:"
<< "\n\tA(" << A.rows() << "," << A.cols() << "), B(" << B.rows() << "," << B.cols() << ")"
<< "\n\tC(" << C.rows() << "," << C.cols() << ")"
<< "\n\tCx(" << Cx.rows() << "," << Cx.cols() << "), Cy(" << Cy.rows() << "," << Cy.cols() << "), Cz(" << Cz.rows() << "," << Cz.cols() << ")"
<< "\nwith\t" << *pbl;
}
/*
* 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 FBUILDER_H
#define FBUILDER_H
#include "fpm.h"
#include "wObject.h"
#include <iostream>
#include <vector>
#include <memory>
#include <Eigen/Dense>
namespace fpm
{
/**
* @brief Aerodynamic Influence Coefficients builder
* @authors Adrien Crovato
* @todo add symmetry support
* @todo implement AIC computation
*/
class FPM_API Builder : public fwk::wSharedObject
{
public:
std::shared_ptr<Problem> pbl; ///< problem definition
bool valid; ///< matrices are up-to-date
int nP; ///< number of body panels
int nF; ///< number of field panels
Eigen::MatrixXd A; ///< body-body doublet matrix
Eigen::MatrixXd B; ///< body-body source matrix
Eigen::MatrixXd C; ///< field-body source matrix
Eigen::MatrixXd Cx; ///< field-body x-velocity source matrix
Eigen::MatrixXd Cy; ///< field-body y-velocity source matrix
Eigen::MatrixXd Cz; ///< field-body z-velocity source matrix
Builder(std::shared_ptr<Problem> _pbl);
~Builder() { std::cout << "~Builder()\n"; }
void run();
#ifndef SWIG
virtual void write(std::ostream &out) const override;
#endif
private:
double mu(tbox::Element *ei, tbox::Element *ej);
double tau(tbox::Element *ei, tbox::Element *ej);
double sigma(tbox::Element *ei, tbox::Element *ej);
double sigmaX(tbox::Element *ei, tbox::Element *ej);
double sigmaY(tbox::Element *ei, tbox::Element *ej);
double sigmaZ(tbox::Element *ei, tbox::Element *ej);
};
} // namespace fpm
#endif //FBUILDER_H
/*
* 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 FEDGE_H
#define FEDGE_H
#include "fpm.h"
#include "wNode.h"
#ifndef SWIG
namespace fpm
{
/**
* @brief Common edge of three elements
* @authors Adrien Crovato
* @todo copy-pasted from waves/flow/wFace.h
*/
class FPM_API Edge
{
public:
std::vector<tbox::Node *> nods;
tbox::Element *el0;
tbox::Element *el1;
tbox::Element *el2;
Edge(std::vector<tbox::Node *> const &_nods) : nods(_nods), el0(NULL), el1(NULL), el2(NULL) {}
};
/**
* @brief Edge comparator
* @authors Adrien Crovato, Romain Boman
* @todo copy-pasted from waves/flow/wFace.h
*/
class FPM_API EquEdge
{
public:
// Default parameters
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
// Function returning a unique size_t per Edge
size_t operator()(Edge *const f) const
{
size_t sum = 0;
for (auto n : f->nods)
sum += static_cast<size_t>(n->no);
return sum; // sum of nodes id
}
// Function allowing to univoquely identify a Edge
bool operator()(Edge *const f0, Edge *const f1) const
{
bool flag = false;
size_t cnt = 0;
// compare nodes of f0 to nodes of f1
for (auto n0 : f0->nods)
{
for (auto n1 : f1->nods)
{
if (n0 == n1)
{
cnt++;
break;
}
}
if (cnt == 0)
break;
}
// check the number of shared nodes
if (cnt == f0->nods.size())
flag = true;
return flag; // true if f0 = f1 (ie, f0 and f1 share the same nodes)
}
};
} // namespace fpm
#endif
#endif //FEDGE_H
/*
* 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 "fField.h"
#include "wTag.h"
using namespace tbox;
using namespace fpm;
void Field::write(std::ostream &out) const
{
out << "fpm::Field " << *tag << 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 FFIELD_H
#define FFIELD_H
#include "fpm.h"
#include "wGroup.h"
namespace fpm
{
/**
* @brief Manage the fluid field
* @authors Adrien Crovato
*/
class FPM_API Field : public tbox::Group
{
public:
Field(std::shared_ptr<tbox::MshData> _msh, std::string const &name) : Group(_msh, name) {}
~Field() { std::cout << "~Field()\n"; }
#ifndef SWIG
virtual void write(std::ostream &out) const override;
#endif
};
} // namespace fpm
#endif //FFIELD_H
This diff is collapsed.
/*
* 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 FPROBLEM_H
#define FPROBLEM_H
#include "fpm.h"
#include "wObject.h"
#include <memory>
#include <vector>
#include <Eigen/Dense>
namespace fpm
{
/**
* @brief Manage the problem
* @authors Adrien Crovato
* @todo check and implement velocity computation
*/
class FPM_API Problem : public fwk::wSharedObject
{
public:
std::shared_ptr<tbox::MshData> msh; ///< mesh data structure
#ifndef SWIG
std::shared_ptr<Field> field; ///< fluid field
std::vector<std::shared_ptr<Body>> bodies; ///< bodies in fluid
#endif
// Reference values
double alpha; ///< Angle of attack
double beta; ///< Angle of sideslip
double mach; ///< Mach number
double sR; ///< Reference surface
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 mch, double sref, double cref, double xref, double yref, double zref);
~Problem() { std::cout << "~Problem()\n"; }
void set(std::shared_ptr<Field> f);
void add(std::shared_ptr<Body> b);
// Functions
inline double PhiI(Eigen::Vector3d const &pos);
inline Eigen::Vector3d Ui();
Eigen::Vector3d U(tbox::Element &e, std::vector<double> const &phi);
double Rho(tbox::Element &e, std::vector<double> const &phi);
double Mach(tbox::Element &e, std::vector<double> const &phi);
double Cp(tbox::Element &e, std::vector<double> const &phi);
#ifndef SWIG
void check() const;
void updateMem();
virtual void write(std::ostream &out) const override;
#endif
};
#include "fProblem.inl"
} // namespace fpm
#endif //FPROBLEM_H
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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