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