13 #include "GmshConfig.h"
19 #if defined(HAVE_KBIPACK)
22 {
GMSH_FULLRC,
"ApplyBoundaryOperatorToResults",
nullptr, 0}};
25 {
GMSH_FULLRC,
"TransformationMatrix",
nullptr,
"1, 0; 0, 1"},
26 {
GMSH_FULLRC,
"PhysicalGroupsOfOperatedChains",
nullptr,
"1, 2"},
27 {
GMSH_FULLRC,
"PhysicalGroupsOfOperatedChains2",
nullptr,
""},
28 {
GMSH_FULLRC,
"PhysicalGroupsToTraceResults",
nullptr,
""},
29 {
GMSH_FULLRC,
"PhysicalGroupsToProjectResults",
nullptr,
""},
34 GMSH_Plugin *GMSH_RegisterHomologyPostProcessingPlugin()
36 return new GMSH_HomologyPostProcessingPlugin();
40 std::string GMSH_HomologyPostProcessingPlugin::getHelp()
const
42 return "Plugin(HomologyPostProcessing) operates on representative "
43 "basis chains of homology and cohomology spaces. Functionality:\n\n"
45 "1. (co)homology basis transformation:\n "
46 "'TransformationMatrix': Integer matrix of the transformation.\n "
47 "'PhysicalGroupsOfOperatedChains': (Co)chains of a (co)homology space "
48 "basis to be transformed.\n "
49 "Results a new (co)chain basis that is an integer combination of the "
52 "2. Make basis representations of a homology space and a cohomology "
54 "'PhysicalGroupsOfOperatedChains': Chains of a homology space basis.\n"
55 "'PhysicalGroupsOfOperatedChains2': Cochains of a cohomology space "
57 "Results a new basis for the homology space such that the incidence "
58 "matrix of the new basis and the basis of the cohomology space is the "
59 "identity matrix.\n\n"
62 "'PhysicalGroupsToTraceResults': Trace the resulting (co)chains to "
63 "the given physical groups.\n"
64 "'PhysicalGroupsToProjectResults': Project the resulting (co)chains "
65 "to the complement of the given physical groups.\n"
66 "'NameForResultChains': Post-processing view name prefix for the "
68 "'ApplyBoundaryOperatorToResults': Apply boundary operator to the "
69 "resulting chains.\n";
72 int GMSH_HomologyPostProcessingPlugin::getNbOptions()
const
74 return sizeof(HomologyPostProcessingOptions_Number) /
sizeof(
StringXNumber);
77 StringXNumber *GMSH_HomologyPostProcessingPlugin::getOption(
int iopt)
79 return &HomologyPostProcessingOptions_Number[iopt];
82 int GMSH_HomologyPostProcessingPlugin::getNbOptionsStr()
const
84 return sizeof(HomologyPostProcessingOptions_String) /
sizeof(
StringXString);
87 StringXString *GMSH_HomologyPostProcessingPlugin::getOptionStr(
int iopt)
89 return &HomologyPostProcessingOptions_String[iopt];
92 bool GMSH_HomologyPostProcessingPlugin::parseStringOpt(
93 int stringOpt, std::vector<int> &intList)
95 std::string list = HomologyPostProcessingOptions_String[stringOpt].
def;
100 std::istringstream ss(list);
102 intList.push_back(n);
105 Msg::Error(
"Unexpected character \'%c\' while parsing \'%s\'", a,
106 HomologyPostProcessingOptions_String[stringOpt].str);
114 int GMSH_HomologyPostProcessingPlugin::detIntegerMatrix(
115 std::vector<int> &matrix)
117 int n = sqrt((
double)matrix.size());
119 for(
int i = 0; i < n; i++)
120 for(
int j = 0; j < n; j++) m(i, j) = matrix.at(i * n + j);
122 return m.determinant();
125 bool GMSH_HomologyPostProcessingPlugin::invertIntegerMatrix(
126 std::vector<int> &matrix)
128 int n = sqrt((
double)matrix.size());
130 for(
int i = 0; i < n; i++)
131 for(
int j = 0; j < n; j++) m(i, j) = matrix.at(i * n + j);
133 if(!m.invertInPlace()) {
138 for(
int i = 0; i < n; i++)
139 for(
int j = 0; j < n; j++) matrix.at(i * n + j) = m(i, j);
143 PView *GMSH_HomologyPostProcessingPlugin::execute(
PView *v)
145 std::string matrixString = HomologyPostProcessingOptions_String[0].
def;
146 std::string opString1 = HomologyPostProcessingOptions_String[1].
def;
147 std::string opString2 = HomologyPostProcessingOptions_String[2].
def;
148 std::string cname = HomologyPostProcessingOptions_String[5].
def;
149 std::string traceString = HomologyPostProcessingOptions_String[3].
def;
150 std::string projectString = HomologyPostProcessingOptions_String[4].
def;
151 int bd = (int)HomologyPostProcessingOptions_Number[0].def;
159 std::vector<int> matrix;
160 if(matrixString !=
"I") {
161 std::istringstream ss(matrixString);
166 if(a !=
',' && a !=
';') {
167 Msg::Error(
"Unexpected character \'%c\' while parsing \'%s\'", a,
168 HomologyPostProcessingOptions_String[0].str);
172 if(cols != 0 && cols != col) {
173 Msg::Error(
"Number of columns must match (%d != %d)", cols, col);
181 if(cols != 0 && cols != col && col != 0) {
182 Msg::Error(
"Number of columns must match (%d != %d)", cols, col);
185 if(cols == 0) cols = col;
189 if(!matrix.empty()) {
190 rows = matrix.size() / cols;
191 if((
int)matrix.size() % cols != 0) {
193 "Number of matrix rows and columns aren't compatible (residual: %d)",
194 (
int)matrix.size() % cols);
199 std::vector<int> basisPhysicals;
200 if(!parseStringOpt(1, basisPhysicals))
return nullptr;
201 std::vector<int> basisPhysicals2;
202 if(!parseStringOpt(2, basisPhysicals2))
return nullptr;
204 if(matrixString !=
"I" && (
int)basisPhysicals.size() != cols &&
205 basisPhysicals2.empty()) {
207 "Number of matrix columns and operated chains must match (%d != %d)",
208 cols, basisPhysicals.size());
211 else if(matrixString ==
"I") {
212 cols = basisPhysicals.size();
214 matrix = std::vector<int>(cols * cols, 0);
215 for(
int i = 0; i < cols; i++) matrix.at(i * cols + i) = 1;
218 if(!basisPhysicals2.empty() &&
219 basisPhysicals.size() != basisPhysicals2.size()) {
220 Msg::Error(
"Number of operated chains must match (%d != %d)",
221 basisPhysicals.size(), basisPhysicals2.size());
225 std::vector<int> tracePhysicals;
226 if(!parseStringOpt(3, tracePhysicals))
return nullptr;
227 std::vector<int> projectPhysicals;
228 if(!parseStringOpt(4, projectPhysicals))
return nullptr;
230 std::vector<Chain<int> > curBasis;
231 for(std::size_t i = 0; i < basisPhysicals.size(); i++) {
232 curBasis.push_back(Chain<int>(m, basisPhysicals.at(i)));
234 if(curBasis.empty()) {
238 int dim = curBasis.at(0).getDim();
240 std::vector<Chain<int> > curBasis2;
241 for(std::size_t i = 0; i < basisPhysicals2.size(); i++) {
242 curBasis2.push_back(Chain<int>(m, basisPhysicals2.at(i)));
245 if(!curBasis2.empty()) {
246 rows = curBasis2.size();
247 cols = curBasis.size();
248 matrix = std::vector<int>(rows * cols, 0);
249 for(
int i = 0; i < rows; i++)
250 for(
int j = 0; j < cols; j++)
251 matrix.at(i * cols + j) = incidence(curBasis2.at(i), curBasis.at(j));
254 if(!curBasis2.empty())
258 for(
int i = 0; i < rows; i++)
259 for(
int j = 0; j < cols; j++)
260 Msg::Debug(
"(%d, %d) = %d", i, j, matrix.at(i * cols + j));
262 std::vector<Chain<int> > newBasis(rows, Chain<int>());
263 if(!curBasis2.empty()) {
264 Msg::Info(
"Computing new basis %d-chains such that the incidence matrix of "
265 "%d-chain bases %s and %s is the indentity matrix",
266 dim, dim, opString1.c_str(), opString2.c_str());
267 int det = detIntegerMatrix(matrix);
268 if(det != 1 && det != -1)
269 Msg::Warning(
"Incidence matrix is not unimodular (det = %d)", det);
270 if(!invertIntegerMatrix(matrix))
return nullptr;
271 for(
int i = 0; i < rows; i++)
272 for(
int j = 0; j < cols; j++)
273 newBasis.at(i) += matrix.at(i * cols + j) * curBasis2.at(j);
276 Msg::Info(
"Applying transformation matrix [%s] to %d-chains %s",
277 matrixString.c_str(), dim, opString1.c_str());
279 int det = detIntegerMatrix(matrix);
280 if(det != 1 && det != -1)
281 Msg::Warning(
"Transformation matrix is not unimodular (det = %d)", det);
283 for(
int i = 0; i < rows; i++)
284 for(
int j = 0; j < cols; j++)
285 newBasis.at(i) += matrix.at(i * cols + j) * curBasis.at(j);
289 Msg::Info(
"Applying boundary operator to the result %d-chains", dim);
290 for(std::size_t i = 0; i < newBasis.size(); i++)
291 newBasis.at(i) = newBasis.at(i).getBoundary();
294 if(!tracePhysicals.empty()) {
295 Msg::Info(
"Taking trace of result %d-chains to domain %s", dim,
296 traceString.c_str());
297 for(std::size_t i = 0; i < newBasis.size(); i++)
298 newBasis.at(i) = newBasis.at(i).getTrace(m, tracePhysicals);
300 if(!projectPhysicals.empty()) {
301 Msg::Info(
"Taking projection of result %d-chains to the complement of the "
303 dim, projectString.c_str());
304 for(std::size_t i = 0; i < newBasis.size(); i++)
305 newBasis.at(i) = newBasis.at(i).getProject(m, projectPhysicals);
307 if(!tracePhysicals.empty() || !projectPhysicals.empty())
308 ElemChain::clearVertexCache();
310 for(std::size_t i = 0; i < newBasis.size(); i++) {
311 std::string dims = convertInt(newBasis.at(i).getDim());
312 std::string nums = convertInt(i + 1);
313 newBasis.at(i).setName(
"C" + dims +
" " + cname + nums);
314 newBasis.at(i).addToModel(m);