Select Git revision
flexible_acquisition.cpp
flexible_acquisition.cpp 17.06 KiB
//Standard Library
#include <numeric>
#include <array>
//GmshFEM Library
#include "GmshFem.h"
#include "Exception.h"
#include "Message.h"
#include "Domain.h"
#include "Function.h"
#include "CSVio.h"
//Gmsh Library
#include "gmsh.h"
//GmshFWI Library
#include "../../common/model/macro.h"
#include "../../common/data/element.h"
#include "../wave/correlation.h"
#include "flexible_acquisition.h"
#include "yaml_interface.h"
namespace gmodel = gmsh::model;
namespace factory = gmsh::model::geo;
using namespace gmshfem;
using namespace gmshfem::common;
using namespace gmshfem::domain;
using namespace gmshfem::function;
static const std::complex< double > im = std::complex< double >(0., 1.);
namespace flexible_acquisition
{
/*
* class Configuration
*/
Configuration::Configuration(std::string name, const ParametrizationInterface* const parametrization, const GmshFem& gmshFem) : ConfigurationInterface(name, parametrization, gmshFem)
{
msg::print << "Initialize flexible configuration" << msg::endl;
/*
* MESH
*/
if(
!(
gmshFem.userDefinedParameter(_H, "H") &&
gmshFem.userDefinedParameter(_L, "L") &&
gmshFem.userDefinedParameter(_Hsub, "Hsub") &&
gmshFem.userDefinedParameter(_h, "h")
)
)
{
throw common::Exception("A geometric parameter could not be found.");
}
// SETUP FROM YAML
std::string shotsPath;
if (!gmshFem.userDefinedParameter(shotsPath, "shots_config"))
{
throw common::Exception("Path to a shots_config is needed in flexible_acquisition.");
}
ShotsConfigurationYAML shotsConfig(shotsPath);
_ns = shotsConfig.numShots();
// Configure points
for (const auto &coords : shotsConfig.points())
{
_er_positions.push_back(coords);
}
_np = _er_positions.size();
mesh();
// Configure shots
for (unsigned s = 0; s < shotsConfig.numShots(); ++s)
{
_emitter.push_back(shotsConfig.emitters(s));
_receiver.push_back(shotsConfig.receivers(s));
}
for (unsigned p = 0; p < _er_positions.size(); ++p) {
_point.push_back("emitter_receiver_"+std::to_string(p));
_points |= _point[p];
}
/*
* DOMAIN
*/
// TODO: actual data mesh!
_data_omega = Domain("supersurface") | Domain("subsurface");
_subsurface[Support::BLK] = Domain("subsurface");
_subsurface[Support::BND] = Domain("subsurface_bnd");
_supersurface[Support::BLK] = Domain("supersurface");
_supersurface[Support::BND] = Domain("supersurface_bnd");
std::string unknownRegion = "subsurface";
gmshFem.userDefinedParameter(unknownRegion, "unknown");
if (unknownRegion == "subsurface")
{
_model_known[Support::BLK] = _supersurface[Support::BLK];
_model_known[Support::BND] = _supersurface[Support::BND];
_model_unknown[Support::BLK] = _subsurface[Support::BLK];
_model_unknown[Support::BND] = _subsurface[Support::BND];
}
else if (unknownRegion == "none")
{
_model_known[Support::BLK] = _supersurface[Support::BLK] | _subsurface[Support::BLK];
_model_known[Support::BND] = _supersurface[Support::BND] | _subsurface[Support::BND];
}
else if (unknownRegion == "all")
{
_model_unknown[Support::BLK] = _supersurface[Support::BLK] | _subsurface[Support::BLK];
_model_unknown[Support::BND] = _supersurface[Support::BND] | _subsurface[Support::BND];
}
else {
throw Exception("Invalid unknown region type: " + unknownRegion);
}
_wave_omega[Support::BLK] = _model_known[Support::BLK] | _model_unknown[Support::BLK];
_wave_omega[Support::BND] = _model_known[Support::BND] | _model_unknown[Support::BND];
// Once Dirichlet BCs are added
//_named_domains() ...
_named_domains["top_bnd"] = Domain("top_bnd");
/*
* Reference model function
*/
// TODO: remove debugging stuff
setupInitialModel(parametrization, gmshFem);
gmshfem::post::save(_m0[0], _model_known[Support::BLK], "model_known");
gmshfem::post::save(_m0[0], _model_unknown[Support::BLK], "model_unknown");
}
void Configuration::wave_mesh() const
{
int p0 = factory::addPoint(0., -_H, 0., _h);
int p1 = factory::addPoint(_L, -_H, 0., _h);
int p2 = factory::addPoint(_L, -_Hsub, 0., _h);
int p3 = factory::addPoint(0., -_Hsub, 0., _h);
int p4 = factory::addPoint(_L, 0., 0., _h);
int p5 = factory::addPoint(0., 0., 0., _h);
// All horizontal lines defined left to right, vertical bottom to top
int lineBottom = factory::addLine(p0, p1);
int lineSub = factory::addLine(p3, p2);
int lineTop = factory::addLine(p5, p4);
int lineLeftSub = factory::addLine(p0, p3);
int lineLeftSuper = factory::addLine(p3, p5);
int lineRightSub = factory::addLine(p1, p2);
int lineRightSuper = factory::addLine(p2, p4);
int clSub = factory::addCurveLoop({lineBottom, lineRightSub, -lineSub, -lineLeftSub});
int clSuper = factory::addCurveLoop({lineSub, lineRightSuper, -lineTop, -lineLeftSuper});
int sSub = factory::addPlaneSurface({clSub});
int sSuper = factory::addPlaneSurface({clSuper});
std::vector<int> p_er;
// Emitters and receivers
for (auto pos: _er_positions) {
p_er.push_back(factory::addPoint(pos.first, pos.second, 0.0, _h));
}
factory::synchronize();
// Embed the e/r. Check if they're in the subsurface or supersurface
for (unsigned i = 0; i < p_er.size(); ++i) {
bool isSub = _er_positions[i].second < (-_Hsub);
gmodel::mesh::embed(0, {p_er[i]}, 2, isSub ? sSub : sSuper);
}
gmodel::addPhysicalGroup(2, {sSub}, 21);
gmodel::setPhysicalName(2, 21, "subsurface");
gmodel::addPhysicalGroup(2, {sSuper}, 22);
gmodel::setPhysicalName(2, 22, "supersurface");
gmodel::addPhysicalGroup(1, {lineLeftSub, lineBottom, lineRightSub}, 11);
gmodel::setPhysicalName(1, 11, "subsurface_bnd");
gmodel::addPhysicalGroup(1, {lineLeftSuper, lineTop, lineRightSuper}, 12);
gmodel::setPhysicalName(1, 12, "supersurface_bnd");
gmodel::addPhysicalGroup(1, {lineTop}, 13);
gmodel::setPhysicalName(1, 13, "top_bnd");
for (unsigned p = 0; p < p_er.size(); ++p) {
gmodel::addPhysicalGroup(0, {p_er[p]}, 1000+p);
gmodel::setPhysicalName(0, 1000+p, "emitter_receiver_"+std::to_string(p));
}
}
void Configuration::data_mesh() const
{
// TODO
/*
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
double Le0 = DAngle * _emitter_offset * _rer;
double Lr0 = DAngle * _receiver_offset * _rer;
double Le = (_ne-1) * Ds_e;
double Lr = (_nr-1) * Ds_r;
int p0 = factory::addPoint(Le0, Lr0, 1.);
int p1 = factory::addPoint(Le0+Le, Lr0, 1.);
int p2 = factory::addPoint(Le0+Le, Lr0+Lr, 1.);
int p3 = factory::addPoint(Le0, Lr0+Lr, 1.);
int l0 = factory::addLine(p0, p1);
int l1 = factory::addLine(p1, p2);
int l2 = factory::addLine(p2, p3);
int l3 = factory::addLine(p3, p0);
int cl = factory::addCurveLoop({l0,l1,l2,l3});
int s1 = factory::addPlaneSurface({cl});
factory::mesh::setTransfiniteCurve(l0,_ne);
factory::mesh::setTransfiniteCurve(l1,_nr);
factory::mesh::setTransfiniteCurve(l2,_ne);
factory::mesh::setTransfiniteCurve(l3,_nr);
factory::mesh::setTransfiniteSurface(s1,"Left",{p0,p1,p2,p3});
factory::mesh::setRecombine(2,s1);
gmodel::addPhysicalGroup(2, {s1}, 1);
gmodel::setPhysicalName(2, 1, "data_omega");
*/
}
void Configuration::setupInitialModel(const ParametrizationInterface* const parametrization, const GmshFem& gmshFem) {
/*
* Reference model function
*/
_m_super.resize(model_size());
_m_sub.resize(model_size());
for (unsigned int c = 0; c < model_size(); c++)
{
ScalarPiecewiseFunction<std::complex<double>> m0;
std::string suffix = "c" + std::to_string(c);
double Rem_super, Imm_super, Rem_sub, Imm_sub;
if (!(
gmshFem.userDefinedParameter(Rem_super, "Re(m_super" + suffix + ")") && gmshFem.userDefinedParameter(Imm_super, "Im(m_super" + suffix + ")") &&
gmshFem.userDefinedParameter(Rem_sub, "Re(m_sub" + suffix + ")") && gmshFem.userDefinedParameter(Imm_sub, "Im(m_sub" + suffix + ")")))
{
throw common::Exception("A model component " + suffix + " could not be found.");
}
_m_super[c] = Rem_super + im * Imm_super;
_m_sub[c] = Rem_sub + im * Imm_sub;
_mc[c] = _m_sub[c];
m0.addFunction(_m_super[c], _supersurface[Support::BLK] | _supersurface[Support::BND] | _points);
std::string m0_type;
if (!gmshFem.userDefinedParameter(m0_type, "m0_type" + suffix))
{
throw Exception("Reference model type could not be found.");
}
if (m0_type == "file")
{
std::string path = "";
if (!gmshFem.userDefinedParameter(path, "m0_path" + suffix))
{
throw common::Exception("Path to subsurface data could not be found.");
}
m0.addFunction(bilinearInterpolation(path), _subsurface[Support::BLK] | _subsurface[Support::BND]);
}
else if (m0_type == "file.pos")
{
std::string path = "";
if (!gmshFem.userDefinedParameter(path, "m0_path" + suffix))
{
throw common::Exception("Path to subsurface data could not be found.");
}
gmsh::merge(path + suffix + ".pos");
// Fix for weird tags when loading .pos files.
std::vector<int> tags;
gmsh::view::getTags(tags);
auto view = tags.back();
ScalarFunction<std::complex<double>> mpos = probeScalarView<std::complex<double>>(view);
m0.addFunction(mpos, _subsurface[Support::BLK] | _subsurface[Support::BND]);
}
/*
else if (m0_type == "inverse_linear_squared")
{
double Rea_0, Ima_0;
if (!(
gmshFem.userDefinedParameter(Rea_0, "Re(a0" + suffix + ")") && gmshFem.userDefinedParameter(Ima_0, "Im(a0" + suffix + ")")))
{
throw common::Exception("Initial model parameter (a0) could not be found.");
}
double Rea_H, Ima_H;
if (!(
gmshFem.userDefinedParameter(Rea_H, "Re(aH" + suffix + ")") && gmshFem.userDefinedParameter(Ima_H, "Im(aH" + suffix + ")")))
{
throw common::Exception("Initial model parameter (aH) could not be found.");
}
ScalarFunction<std::complex<double>> num = (Rea_0 + im * Ima_0) - ((Rea_H + im * Ima_H) - (Rea_0 + im * Ima_0)) / H() * y<std::complex<double>>();
m0.addFunction(1. / pow(num, 2), _subsurface[Support::BLK] | _subsurface[Support::BND]);
}
else if (m0_type == "linear")
{
double Rea_0, Ima_0;
if (!(
gmshFem.userDefinedParameter(Rea_0, "Re(a0" + suffix + ")") && gmshFem.userDefinedParameter(Ima_0, "Im(a0" + suffix + ")")))
{
throw common::Exception("Initial model parameter (a0) could not be found.");
}
double Rea_H, Ima_H;
if (!(
gmshFem.userDefinedParameter(Rea_H, "Re(aH" + suffix + ")") && gmshFem.userDefinedParameter(Ima_H, "Im(aH" + suffix + ")")))
{
throw common::Exception("Initial model parameter (aH) could not be found.");
}
ScalarFunction<std::complex<double>> lin = (Rea_0 + im * Ima_0) - ((Rea_H + im * Ima_H) - (Rea_0 + im * Ima_0)) / H() * (y<std::complex<double>>() + _ymin);
m0.addFunction(lin, _subsurface[Support::BLK] | _subsurface[Support::BND]);
}*/
else if (m0_type == "constant")
{
m0.addFunction(_m_sub[c], _subsurface[Support::BLK] | _subsurface[Support::BND]);
}
else
{
throw common::Exception("Initial model type (" + suffix + ") " + m0_type + " is unknown.");
}
_m0.push_back(m0);
}
}
std::array<unsigned int,2> Configuration::data_coordinate_to_index(double xs, double xr) const
{
throw Exception("Unimplemented Configuration::data_coordinate_to_index");
/*
if( (!_receiver_on_emitter) )
{
throw Exception("Data space when an emitter is not also a receiver is not implemented yet");
}
std::array<unsigned int,2> index;
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
double Le0 = DAngle * _emitter_offset * _rer;
double Lr0 = DAngle * _receiver_offset * _rer;
index[0] = std::round( (xs-Le0) / Ds_e );
index[1] = std::round( (xr-Lr0) / Ds_r );
return index;
*/
}
std::array<double,2> Configuration::index_to_data_coordinate(unsigned int s, unsigned int r) const
{
throw Exception("Unimplemented Configuration::index_to_data_coordinate");
/*
if( (!_receiver_on_emitter) )
{
throw Exception("Data space when an emitter is not also a receiver is not implemented yet");
}
std::array<double,2> index;
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
double Le0 = DAngle * _emitter_offset * _rer;
double Lr0 = DAngle * _receiver_offset * _rer;
index[0] = Le0 + ((double)s) * Ds_e;
index[1] = Lr0 + ((double)r) * Ds_r;
return index;*/
}
double Configuration::data_area() const
{
throw Exception("Unimplemented Configuration::data_area");
/*
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
double Le = (_ne-1) * Ds_e;
double Lr = (_nr-1) * Ds_r;
return Le * Lr;
*/
};
double Configuration::datapoint_area() const
{
throw Exception("Unimplemented Configuration::datapoint_area");
/*
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
return Ds_e * Ds_r;*/
};
bool Configuration::data_coordinate_isValid(double xs,double xr) const
{
throw Exception("Unimplemented Configuration::data_coordinate_isValid");
/*
double DAngle = 2. * M_PI /((double) _np);
double Ds_e = DAngle * _emitter_skip * _rer;
double Ds_r = DAngle * _receiver_skip * _rer;
double Le0 = DAngle * _emitter_offset * _rer;
double Lr0 = DAngle * _receiver_offset * _rer;
double Le = (_ne-1) * Ds_e;
double Lr = (_nr-1) * Ds_r;
double eps = 1e-8;
gmsh::option::getNumber("Geometry.MatchMeshTolerance",eps);
if( (Le0-eps <= xs) && (xs <= Le0+Le+eps) && (Lr0-eps <= xr) && (xr <= Lr0+Lr+eps) )
{
return true;
}
else
{
return false;
}
*/
}
template<Physic T_Physic>
ModelMonoFunction green0_preconditioner(const Data<T_Physic>& dd, const WaveMultiField<T_Physic>& g, const Configuration* const config)
{
return autocorrelate<T_Physic>(g,config->emitter_idx())*autocorrelate<T_Physic>(g,config->receiver_idx());
}
template ModelMonoFunction green0_preconditioner<Physic::acoustic>(const Data<Physic::acoustic>&, const WaveMultiField<Physic::acoustic>&, const Configuration* const);
template ModelMonoFunction green0_preconditioner<Physic::electromagnetic>(const Data<Physic::electromagnetic>&, const WaveMultiField<Physic::electromagnetic>&, const Configuration* const);
template ModelMonoFunction green0_preconditioner<Physic::elastodynamic>(const Data<Physic::elastodynamic>&, const WaveMultiField<Physic::elastodynamic>&, const Configuration* const);
} // namespace circular_acquisition