Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add math function from file #692 #701

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/io/io_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class IOMesh {
virtual std::vector<std::tuple<mpm::Index, unsigned, double>> read_forces(
const std::string& forces_file) = 0;

//! Read math function file
//! \param[in] math function file name with values of x and fx
virtual std::vector<std::tuple<double, double>> read_math_function(
const std::string& math_function_file) = 0;

}; // IOMesh class
} // namespace mpm

Expand Down
5 changes: 5 additions & 0 deletions include/io/io_mesh_ascii.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ class IOMeshAscii : public IOMesh<Tdim> {
std::vector<std::tuple<mpm::Index, unsigned, double>> read_forces(
const std::string& forces_file) override;

//! Read math function file
//! \param[in] math function file name with values of x and fx
std::vector<std::tuple<double, double>> read_math_function(
const std::string& math_function_file) override;

private:
//! Logger
std::shared_ptr<spdlog::logger> console_;
Expand Down
104 changes: 74 additions & 30 deletions include/io/io_mesh_ascii.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ std::map<mpm::Index, Eigen::Matrix<double, Tdim, 1>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID and read stream
mpm::Index id;
// Angles and ream stream
Eigen::Matrix<double, Tdim, 1> angles;
while (istream.good()) {
// ID and read stream
mpm::Index id;
istream >> id;
// Angles and ream stream
Eigen::Matrix<double, Tdim, 1> angles;
for (unsigned i = 0; i < Tdim; ++i) istream >> angles[i];
euler_angles.emplace(std::make_pair(id, angles));
}
Expand Down Expand Up @@ -314,11 +314,11 @@ std::vector<std::tuple<mpm::Index, double>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID
mpm::Index id;
// Volume
double volume;
while (istream.good()) {
// ID
mpm::Index id;
// Volume
double volume;
// Read stream
istream >> id >> volume;
volumes.emplace_back(std::make_tuple(id, volume));
Expand Down Expand Up @@ -358,9 +358,9 @@ std::vector<std::array<mpm::Index, 2>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID
mpm::Index pid, cid;
while (istream.good()) {
// ID
mpm::Index pid, cid;
// Read stream
istream >> pid >> cid;
particles_cells.emplace_back(std::array<mpm::Index, 2>({pid, cid}));
Expand Down Expand Up @@ -416,13 +416,13 @@ std::vector<std::tuple<mpm::Index, unsigned, double>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Velocity
double velocity;
while (istream.good()) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Velocity
double velocity;
// Read stream
istream >> id >> dir >> velocity;
constraints.emplace_back(std::make_tuple(id, dir, velocity));
Expand Down Expand Up @@ -462,15 +462,15 @@ std::vector<std::tuple<mpm::Index, unsigned, int, double>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Sign
int sign;
// Friction
double friction;
while (istream.good()) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Sign
int sign;
// Friction
double friction;
// Read stream
istream >> id >> dir >> sign >> friction;
constraints.emplace_back(std::make_tuple(id, dir, sign, friction));
Expand Down Expand Up @@ -509,13 +509,13 @@ std::vector<std::tuple<mpm::Index, unsigned, double>>
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Force
double force;
while (istream.good()) {
// ID
mpm::Index id;
// Direction
unsigned dir;
// Force
double force;
// Read stream
istream >> id >> dir >> force;
forces.emplace_back(std::make_tuple(id, dir, force));
Expand All @@ -530,3 +530,47 @@ std::vector<std::tuple<mpm::Index, unsigned, double>>
}
return forces;
}

//! Return math function
template <unsigned Tdim>
std::vector<std::tuple<double, double>>
mpm::IOMeshAscii<Tdim>::read_math_function(
const std::string& math_function_file) {

// initialize math function
std::vector<std::tuple<double, double>> math_function;
math_function.clear();

// input file stream
std::fstream file;
file.open(math_function_file.c_str(), std::ios::in);

try {
if (file.is_open() && file.good()) {
// Line
std::string line;
while (std::getline(file, line)) {
boost::algorithm::trim(line);
std::istringstream istream(line);
// ignore comment lines (# or !) or blank lines
if ((line.find('#') == std::string::npos) &&
(line.find('!') == std::string::npos) && (line != "")) {
// x value
double x_value;
// fx value
double fx_value;
while (istream.good()) {
// Read stream
istream >> x_value >> fx_value;
math_function.emplace_back(std::make_tuple(x_value, fx_value));
}
}
}
}
file.close();
} catch (std::exception& exception) {
console_->error("Read math function : {}", exception.what());
file.close();
}
return math_function;
}
31 changes: 29 additions & 2 deletions include/solvers/mpm_base.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -762,16 +762,43 @@ bool mpm::MPMBase<Tdim>::initialise_math_functions(const Json& math_functions) {
const std::string function_type =
function_props["type"].template get<std::string>();

// Initiate another function_prop to be passed
auto function_props_update = function_props;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?


// Create a file reader
const std::string io_type =
io_->json_object("mesh")["io_type"].template get<std::string>();
auto reader = Factory<mpm::IOMesh<Tdim>>::instance()->create(io_type);

// Math function is specified in a file, replace function_props_update
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read files in io class not in mpm_base. Create a separate class in io or use the read_mesh_ascii to read these files. I'd prefer for now if you use read_mesh_ascii to read the input file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I have tried to use in the beginning, and you requested CSV. Can we agree on which one to use now before I make more changes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not asking you to revert back, this is an io operation and reading the CSV should be in the io class as an additional function and not in the mpm_base

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so still CSV but within read_mesh_ascii. But doesn't it refer to ascii not csv?

if (function_props.find("file") != function_props.end()) {
std::string math_file =
function_props.at("file").template get<std::string>();
auto math_function_values =
reader->read_math_function(io_->file_name(math_file));

// Make separate arrays
std::vector<double> xvalues;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having separate vectors makes it decoupled between x and y values, use a vector of arrays instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

std::vector<double> fxvalues;
for (const auto& math_function_value : math_function_values) {
xvalues.emplace_back(std::get<0>(math_function_value));
fxvalues.emplace_back(std::get<1>(math_function_value));
}

function_props_update["xvalues"] = xvalues;
function_props_update["fxvalues"] = fxvalues;
}

// Create a new function from JSON object
auto function =
Factory<mpm::FunctionBase, unsigned, const Json&>::instance()->create(
function_type, std::move(function_id), function_props);

// Add material to list
// Add math function to list
auto insert_status =
math_functions_.insert(std::make_pair(function->id(), function));

// If insert material failed
// If insert math function failed
if (!insert_status.second) {
status = false;
throw std::runtime_error(
Expand Down
53 changes: 52 additions & 1 deletion tests/io/io_mesh_ascii_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ TEST_CASE("IOMeshAscii is checked for 2D", "[IOMesh][IOMeshAscii][2D]") {
// Create a read_mesh object
auto read_mesh = std::make_unique<mpm::IOMeshAscii<dim>>();

// Try to read constrtaints from a non-existant file
// Try to read forces from a non-existant file
auto forces = read_mesh->read_forces("forces-missing.txt");
// Check number of forces
REQUIRE(forces.size() == 0);
Expand Down Expand Up @@ -482,6 +482,57 @@ TEST_CASE("IOMeshAscii is checked for 2D", "[IOMesh][IOMeshAscii][2D]") {
}
}
}

SECTION("Check math function file") {
// Vector of math function
std::vector<std::tuple<double, double>> math_function_values;

// Constraint
math_function_values.emplace_back(std::make_tuple(0.0, 1.75));
math_function_values.emplace_back(std::make_tuple(0.2, -1.25));
math_function_values.emplace_back(std::make_tuple(0.4, -3.99));
math_function_values.emplace_back(std::make_tuple(0.6, 4.55));

// Dump constraints as an input file to be read
std::ofstream file;
file.open("math-functions.txt");
// Write particle coordinates
for (const auto& math_function_value : math_function_values) {
file << std::get<0>(math_function_value) << "\t";
file << std::get<1>(math_function_value) << "\t";

file << "\n";
}

file.close();

// Check read math function
SECTION("Check math functions") {
// Create a read_mesh object
auto read_mesh = std::make_unique<mpm::IOMeshAscii<dim>>();

// Try to read function from a non-existant file
auto math_functions =
read_mesh->read_math_function("math-functions-missing.txt");
// Check number of function
REQUIRE(math_functions.size() == 0);

// Check math function
math_functions = read_mesh->read_math_function("math-functions.txt");
// Check number of values
REQUIRE(math_functions.size() == math_function_values.size());

// Check math function
for (unsigned i = 0; i < math_function_values.size(); ++i) {
REQUIRE(
std::get<0>(math_functions.at(i)) ==
Approx(std::get<0>(math_function_values.at(i))).epsilon(Tolerance));
REQUIRE(
std::get<1>(math_functions.at(i)) ==
Approx(std::get<1>(math_function_values.at(i))).epsilon(Tolerance));
}
}
}
}

// Check IOMeshAscii
Expand Down