1 // GetDP - Copyright (C) 1997-2021 P. Dular and C. Geuzaine, University of Liege
2 //
3 // See the LICENSE.txt file for license information. Please report all
4 // issues on https://gitlab.onelab.info/getdp/getdp/issues.
5 //
6 // Contributed by Erin Kuci
7
8 #include <map>
9 #include <string>
10 #include <vector>
11 #include "ProData.h"
12 #include "ProParser.h"
13 #include "Cal_Quantity.h"
14 #include "Message.h"
15 #include "GetDPConfig.h"
16
17 #if defined(HAVE_MMA) && defined(HAVE_PETSC)
18
19 #include "mma_mat.h"
20 #include "mma_primaldual.h"
21
22 // utility functions
CreateVector(Vec & Vector,PetscInt nn)23 static void CreateVector(Vec& Vector, PetscInt nn)
24 {
25 VecCreate(PETSC_COMM_WORLD, &Vector);
26 VecSetSizes(Vector,PETSC_DECIDE,nn);
27 VecSetFromOptions(Vector);
28 }
29
UpdateVector(const PetscReal value,const PetscInt row,Vec & vector)30 static void UpdateVector(const PetscReal value, const PetscInt row, Vec& vector)
31 {
32 VecSetValue(vector,row,value,INSERT_VALUES);
33 }
34
GetValueVector(double & value,const PetscInt id,const Vec & vector)35 static void GetValueVector(double &value, const PetscInt id, const Vec& vector)
36 {
37 PetscScalar val;
38 VecGetValues(vector, 1, &id, &val);
39 value = PetscRealPart(val);
40 }
41
AssembleVector(const Vec & vector)42 static void AssembleVector(const Vec& vector)
43 {
44 VecAssemblyBegin(vector);
45 VecAssemblyEnd(vector);
46 }
47
CreateMatrix(Mat & Matrix,PetscInt nbrows,PetscInt nbcols)48 static void CreateMatrix(Mat& Matrix, PetscInt nbrows, PetscInt nbcols)
49 {
50 // full matrix... but in AIJ format for subsequent operations in mma
51 PetscInt prealloc = nbcols;
52 MatCreateAIJ(MPI_COMM_WORLD, PETSC_DECIDE, PETSC_DECIDE, nbrows, nbcols,
53 prealloc, PETSC_NULL, prealloc, PETSC_NULL, &Matrix);
54
55 // Preallocation routines automatically set now MAT_NEW_NONZERO_ALLOCATION_ERR,
56 // what causes a problem when the mask of the matrix changes (e.g. moving band)
57 // We must disable the error generation and allow new allocation (if needed)
58 MatSetOption(Matrix,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);
59
60 // override the default options with the ones from the option database (if
61 // any)
62 MatSetFromOptions(Matrix);
63 }
64
UpdateMatrixRowFromVector(double * myvecvals,int vecsize,PetscInt row,Mat & Matrix)65 static void UpdateMatrixRowFromVector(double* myvecvals, int vecsize,
66 PetscInt row, Mat& Matrix)
67 {
68 // Count the number of nonzero elements in the vector:
69 //int numnonzero = 0;
70 //for (int i = 0; i < vecsize; i++){if (myvecvals[i] != 0){numnonzero++;}}
71
72 // Get the adresses and values of the nonzeros:
73 //int nonzeroadresses[numnonzero];
74 //double nonzerovalues[numnonzero];
75 //int index = 0;
76 //for (int i = 0; i < vecsize; i++){
77 // if (myvecvals[i] != 0){
78 // nonzeroadresses[index] = i;
79 // nonzerovalues[index] = myvecvals[i];
80 // index++;
81 // }
82 //}
83 int nonzeroadresses[vecsize];
84 PetscScalar nonzerovalues[vecsize];
85 for (int i = 0; i < vecsize; i++){
86 nonzeroadresses[i] = i;
87 nonzerovalues[i] = (PetscScalar)myvecvals[i];
88 }
89
90 // fill the matrix
91 PetscInt row_vec[1] = {row};
92 MatSetValues(Matrix,1,row_vec,vecsize,nonzeroadresses,nonzerovalues,
93 INSERT_VALUES);
94
95 // MatSetValues(Matrix,1,row_vec,numnonzero,nonzeroadresses,nonzerovalues,
96 // INSERT_VALUES);
97 }
98
AssembleMatrix(const Mat & Matrix)99 static void AssembleMatrix(const Mat& Matrix)
100 {
101 MatAssemblyBegin(Matrix, MAT_FINAL_ASSEMBLY);
102 MatAssemblyEnd(Matrix, MAT_FINAL_ASSEMBLY);
103 }
104
105 class optimizerContext
106 {
107 public:
108 // name of getdp variables used for I/O with the parser
109 std::string algorithm;
110 std::string currentPoint;
111 std::string objective, objectiveSensitivity;
112 std::vector<std::string> constraints, constraintsSensitivity;
113 // internal petsc data
114 PetscInt nvar, mcon;
115 Vec xval_pt, LowerBounds, UpperBounds, GradOfObjective, Constraints;
116 Mat GradOfConstraints;
117 // subproblem
118 MMA_MAT *subProblem;
119 // subproblem solver
120 MMA_PRIMALDUAL_INTERIORPOINT *subProblemSolver;
121
122 public:
optimizerContext(char * nameAlgorithm,char * nameCurrentPoint,char * nameObjective,char * nameObjectiveSensitivity,List_T * nameConstraints,List_T * nameConstraintsSensitivity,List_T * currentPointLowerBounds,List_T * currentPointUpperBounds)123 optimizerContext(char *nameAlgorithm, char *nameCurrentPoint,
124 char *nameObjective, char *nameObjectiveSensitivity,
125 List_T *nameConstraints, List_T *nameConstraintsSensitivity,
126 List_T *currentPointLowerBounds, List_T *currentPointUpperBounds)
127 : algorithm(nameAlgorithm), currentPoint(nameCurrentPoint),
128 objective(nameObjective), objectiveSensitivity(nameObjectiveSensitivity)
129 {
130 // names of GetDP exchange variables
131 for(int i = 0; i < List_Nbr(nameConstraints); i++){
132 char *c; List_Read(nameConstraints, i, &c);
133 constraints.push_back(c);
134 }
135 for(int i = 0; i < List_Nbr(nameConstraintsSensitivity); i++){
136 char *c; List_Read(nameConstraintsSensitivity, i, &c);
137 constraintsSensitivity.push_back(c);
138 }
139 std::map<std::string, std::map<int, std::vector<double> > >::iterator itv =
140 GetDPNumbersMap.find(currentPoint);
141 nvar = itv->second.size();
142
143 // FIXME: get actual number of constraints
144 mcon = constraints.size();
145
146 // Lower bounds of the current point
147 CreateVector(LowerBounds, nvar);
148 if(List_Nbr(currentPointLowerBounds) == 1){
149 double v; List_Read(currentPointLowerBounds, 0, &v);
150 VecSet(LowerBounds, v);
151 }
152 else{
153 Message::Warning("Multiple lower bounds not implemented yet");
154 }
155 AssembleVector(LowerBounds);
156
157 // Upper bounds of the current point
158 CreateVector(UpperBounds, nvar);
159 if(List_Nbr(currentPointUpperBounds) == 1){
160 double v; List_Read(currentPointUpperBounds, 0, &v);
161 VecSet(UpperBounds, v);
162 }
163 else{
164 Message::Warning("Multiple lower bounds not implemented yet");
165 }
166 AssembleVector(UpperBounds);
167
168 // Create all the useful vectors/matrices
169 CreateVector(xval_pt, nvar);
170 CreateVector(GradOfObjective, nvar);
171 CreateVector(Constraints, mcon);
172 CreateMatrix(GradOfConstraints, mcon, nvar);
173
174 // Create the subproblem
175 subProblem = new MMA_MAT(mcon, nvar, LowerBounds, UpperBounds);
176 subProblem->verbosity = 0;
177
178 // Create the solver of the subproblem
179 subProblemSolver = new MMA_PRIMALDUAL_INTERIORPOINT(subProblem);
180 subProblemSolver->verbosity = 0;
181
182 printInfo();
183 }
printInfo()184 void printInfo()
185 {
186 Message::Info("Optimizer algorithm: %s", algorithm.c_str());
187 Message::Info("Optimizer Number of design variables: %i", nvar);
188 Message::Info("Optimizer Number of constraints %i", mcon);
189 //VecView(LowerBounds, PETSC_VIEWER_STDOUT_WORLD);
190 //VecView(UpperBounds, PETSC_VIEWER_STDOUT_WORLD);
191 }
192 };
193
194 static optimizerContext *context = 0;
195
UpdateCurrentPointList(const std::string & name,const Vec & data)196 static void UpdateCurrentPointList(const std::string &name, const Vec &data)
197 {
198 double datav;
199 std::map<std::string, std::map<int, std::vector<double> > >::iterator itv =
200 GetDPNumbersMap.find(name);
201 if(itv != GetDPNumbersMap.end()){
202 printf(" - table Current Point \n");
203 int ii = 0;
204 for(std::map<int, std::vector<double> >::iterator it = itv->second.begin();
205 it != itv->second.end(); it++){
206 GetValueVector(datav, ii, data);
207 for(unsigned int i = 0; i < it->second.size(); i++){
208 it->second[i] = datav;
209 //printf("%g ", it->second[i]);
210 }
211 ii++;
212 }
213 }
214 else{
215 std::map<std::string, std::vector<double> >::iterator its =
216 GetDPNumbers.find(name);
217 if(its != GetDPNumbers.end()){
218 printf(" - scalar Current Point \n");
219 for(unsigned int i = 0; i < its->second.size(); i++){
220 GetValueVector(datav, i, data);
221 its->second[i] = datav;
222 //printf("%g ", its->second[i]);
223 }
224 }
225 else{
226 Message::Warning("Unknown %s", name.c_str());
227 }
228 }
229 }
230
UpdateVecFromInput(const std::string & type,const std::string & name,Vec & vv,int idGlobal=0)231 static void UpdateVecFromInput(const std::string &type, const std::string &name,
232 Vec &vv, int idGlobal=0)
233 {
234 std::map<std::string, std::map<int, std::vector<double> > >::iterator itv =
235 GetDPNumbersMap.find(name);
236 if(itv != GetDPNumbersMap.end()){
237 printf(" - table %s:\n", type.c_str());
238 int ii = 0;
239 for(std::map<int, std::vector<double> >::iterator it = itv->second.begin();
240 it != itv->second.end(); it++){
241 UpdateVector(it->second[0], idGlobal+ii, vv);
242 //printf(" ele %d: ", it->first);
243 //for(unsigned int i = 0; i < it->second.size(); i++){
244 //printf("%g ", it->second[i]);
245 //}
246 //printf("\n");
247 ii++;
248 }
249 }
250 else{
251 std::map<std::string, std::vector<double> >::iterator its =
252 GetDPNumbers.find(name);
253 if(its != GetDPNumbers.end()){
254 printf(" - scalar variable %s: \n", type.c_str());
255 for(unsigned int i = 0; i < its->second.size(); i++){
256 UpdateVector(its->second[i], idGlobal+i, vv);
257 }
258 }
259 else{
260 Message::Warning("Unknown %s: %s", type.c_str(), name.c_str());
261 }
262 }
263 }
264
UpdateMatFromInput(const std::string & type,const std::string & name,Mat & vv,int idGlobal=0)265 static void UpdateMatFromInput(const std::string &type, const std::string &name,
266 Mat &vv, int idGlobal=0)
267 {
268 std::map<std::string, std::map<int, std::vector<double> > >::iterator itv =
269 GetDPNumbersMap.find(name);
270 if(itv != GetDPNumbersMap.end()){
271 printf(" - table %s:\n", type.c_str());
272 double myvecvals[itv->second.size()];
273 int ii = 0;
274 for(std::map<int, std::vector<double> >::iterator it = itv->second.begin();
275 it != itv->second.end(); it++){
276 //UpdateVector(it->second[0], idGlobal+ii, vv);
277 myvecvals[ii] = it->second[0];
278 //printf(" ele %d: ", it->first);
279 //for(unsigned int i = 0; i < it->second.size(); i++){
280 // printf("%g ", it->second[i]);
281 //}
282 //printf("\n");
283 ii++;
284 }
285 UpdateMatrixRowFromVector(myvecvals, itv->second.size(), idGlobal, vv);
286 }
287 else{
288 std::map<std::string, std::vector<double> >::iterator its =
289 GetDPNumbers.find(name);
290 if(its != GetDPNumbers.end()){
291 double myvecvals[its->second.size()];
292 printf(" - scalar variable %s \n", type.c_str());
293 for(unsigned int i = 0; i < its->second.size(); i++){
294 myvecvals[i] = its->second[i];
295 //printf("%g ", its->second[i]);
296 }
297 //printf("\n");
298 UpdateMatrixRowFromVector(myvecvals, its->second.size(), idGlobal, vv);
299 }
300 else{
301 Message::Warning("Unknown %s: %s", type.c_str(), name.c_str());
302 }
303 }
304 }
305
Operation_OptimizerInitialize(struct Operation * Operation_P)306 void Operation_OptimizerInitialize(struct Operation *Operation_P)
307 {
308 context = new optimizerContext
309 (Operation_P->Case.OptimizerInitialize.algorithm,
310 Operation_P->Case.OptimizerInitialize.currentPoint,
311 Operation_P->Case.OptimizerInitialize.objective,
312 Operation_P->Case.OptimizerInitialize.objectiveSensitivity,
313 Operation_P->Case.OptimizerInitialize.constraints,
314 Operation_P->Case.OptimizerInitialize.constraintsSensitivity,
315 Operation_P->Case.OptimizerInitialize.currentPointLowerBounds,
316 Operation_P->Case.OptimizerInitialize.currentPointUpperBounds);
317 }
318
Operation_OptimizerUpdate(struct Operation * Operation_P)319 void Operation_OptimizerUpdate(struct Operation *Operation_P)
320 {
321 //subProblem->nvar
322 printf("Opti update:\n");
323
324 // Update the vectors
325
326 UpdateVecFromInput("currentPoint", context->currentPoint, context->xval_pt);
327 AssembleVector(context->xval_pt);
328 //VecView(context->xval_pt, PETSC_VIEWER_STDOUT_WORLD);
329
330 UpdateVecFromInput("objectiveSensitivity", context->objectiveSensitivity,
331 context->GradOfObjective);
332 AssembleVector(context->GradOfObjective);
333 //VecView(context->GradOfObjective, PETSC_VIEWER_STDOUT_WORLD);
334
335 // FIXME: constraints are not in the same order as they have been declared
336 // => Maybe their sensitivity are in a different order => mix
337 for(unsigned int i = 0; i < context->constraints.size(); i++){
338 UpdateVecFromInput("constraints", context->constraints[i],
339 context->Constraints, i);
340 }
341 AssembleVector(context->Constraints);
342 //VecView(context->Constraints, PETSC_VIEWER_STDOUT_WORLD);
343
344 for(unsigned int i = 0; i < context->constraintsSensitivity.size(); i++){
345 UpdateMatFromInput("constraint sensitivity", context->constraintsSensitivity[i],
346 context->GradOfConstraints, i);
347 }
348 AssembleMatrix(context->GradOfConstraints);
349 //MatView(context->GradOfConstraints, PETSC_VIEWER_STDOUT_WORLD);
350
351 // Call the optimizer to update the current point
352 context->subProblemSolver->UpdateCurrentPoint(context->xval_pt,
353 context->GradOfObjective,
354 context->Constraints,
355 context->GradOfConstraints);
356 //VecView(context->xval_pt, PETSC_VIEWER_STDOUT_WORLD);
357
358 Value v;
359 v.Type = SCALAR;
360 context->subProblem->DesignChange(context->xval_pt, v.Val[0]);
361 Cal_StoreInVariable(&v, Operation_P->Case.OptimizerUpdate.residual);
362
363 // Update the list of design variables
364 UpdateCurrentPointList(context->currentPoint, context->xval_pt);
365
366 }
367
Operation_OptimizerFinalize(struct Operation * Operation_P)368 void Operation_OptimizerFinalize(struct Operation *Operation_P)
369 {
370 VecDestroy(&context->xval_pt);
371 VecDestroy(&context->LowerBounds);
372 VecDestroy(&context->UpperBounds);
373 VecDestroy(&context->GradOfObjective);
374 VecDestroy(&context->Constraints);
375 MatDestroy(&context->GradOfConstraints);
376 }
377
378 #else
379
Operation_OptimizerInitialize(struct Operation * Operation_P)380 void Operation_OptimizerInitialize(struct Operation *Operation_P)
381 {
382 Message::Error("This version of GetDP is not compiled with MMA support");
383 }
384
Operation_OptimizerUpdate(struct Operation * Operation_P)385 void Operation_OptimizerUpdate(struct Operation *Operation_P)
386 {
387 Message::Error("This version of GetDP is not compiled with MMA support");
388 }
389
Operation_OptimizerFinalize(struct Operation * Operation_P)390 void Operation_OptimizerFinalize(struct Operation *Operation_P)
391 {
392 Message::Error("This version of GetDP is not compiled with MMA support");
393 }
394
395
396 #endif
397