Nektar++
NodeOptiCAD.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NodeOpti.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Calculate jacobians of elements.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include "NodeOptiCAD.h"
36 #include "Evaluator.hxx"
37 
38 using namespace std;
39 using namespace Nektar::NekMeshUtils;
40 
41 namespace Nektar
42 {
43 namespace Utilities
44 {
45 
46 std::mutex mtx;
47 
48 int NodeOpti1D3D::m_type = GetNodeOptiFactory().RegisterCreatorFunction(
49  13, NodeOpti1D3D::create, "1D3D");
50 
51 void NodeOpti1D3D::Optimise()
52 {
53  NekDouble minJacNew;
54  NekDouble currentW = GetFunctional<3>(minJacNew);
55  NekDouble newVal = currentW;
56 
57  if (m_grad[0] * m_grad[0] + m_grad[1] * m_grad[1] + m_grad[2] * m_grad[2] >
58  gradTol())
59  {
60  // modify the gradient to be on the cad system
61  ProcessGradient();
62 
63  // needs to optimise
64  NekDouble tc = m_node->GetCADCurveInfo(curve->GetId());
65  NekDouble xc = m_node->m_x;
66  NekDouble yc = m_node->m_y;
67  NekDouble zc = m_node->m_z;
68  NekDouble nt;
69 
70  vector<NekDouble> sk(1);
71 
72  if (m_grad[1] < 1e-6)
73  {
74  m_grad[1] = 1e-6 - m_grad[1];
75  }
76 
77  sk[0] = m_grad[0] / m_grad[1] * -1.0;
78 
79  vector<NekDouble> bd(2);
80  curve->GetBounds(bd[0], bd[1]);
81 
82  bool found = false;
83 
84  NekDouble pg = m_grad[0] * sk[0];
85 
86  // normal gradient line Search
87  NekDouble alpha = 1.0;
88 
89  while (alpha > alphaTol())
90  {
91  // Update node
92  nt = tc + alpha * sk[0];
93  if (nt < bd[0] || nt > bd[1])
94  {
95  alpha /= 2.0;
96  continue;
97  }
98 
99  curve->P(nt, m_node->m_x, m_node->m_y, m_node->m_z);
100 
101  newVal = GetFunctional<3>(minJacNew, false);
102 
103  // Wolfe conditions
104  if (newVal <= currentW + c1() * alpha * pg)
105  {
106  found = true;
107  break;
108  }
109 
110  alpha /= 2.0;
111  }
112 
113  if (!found)
114  {
115  // reset the node
116  nt = tc;
117  curve->P(nt, m_node->m_x, m_node->m_y, m_node->m_z);
118 
119  mtx.lock();
120  m_res->nReset[0]++;
121  mtx.unlock();
122  }
123  else
124  {
125  m_minJac = minJacNew;
126  m_node->Move(m_node->m_x, m_node->m_y, m_node->m_z, curve->GetId(),
127  nt);
128  }
129  mtx.lock();
130  m_res->val = max(sqrt((m_node->m_x - xc) * (m_node->m_x - xc) +
131  (m_node->m_y - yc) * (m_node->m_y - yc) +
132  (m_node->m_z - zc) * (m_node->m_z - zc)),
133  m_res->val);
134  mtx.unlock();
135  }
136 
137  mtx.lock();
138  m_res->func += newVal;
139  mtx.unlock();
140 }
141 
142 int NodeOpti2D3D::m_type = GetNodeOptiFactory().RegisterCreatorFunction(
143  23, NodeOpti2D3D::create, "2D3D");
144 
145 void NodeOpti2D3D::Optimise()
146 {
147  NekDouble minJacNew;
148  NekDouble currentW = GetFunctional<3>(minJacNew);
149  NekDouble newVal = currentW;
150 
151  if (m_grad[0] * m_grad[0] + m_grad[1] * m_grad[1] + m_grad[2] * m_grad[2] >
152  gradTol())
153  {
154  // modify the gradient to be on the cad system
155  ProcessGradient();
156 
157  // needs to optimise
158  Array<OneD, NekDouble> uvc = m_node->GetCADSurfInfo(surf->GetId());
159  NekDouble xc = m_node->m_x;
160  NekDouble yc = m_node->m_y;
161  NekDouble zc = m_node->m_z;
162  Array<OneD, NekDouble> uvt(2);
163  vector<NekDouble> bd(4);
164  surf->GetBounds(bd[0], bd[1], bd[2], bd[3]);
165 
166  vector<NekDouble> sk(2);
167  NekDouble val;
168 
169  // Calculate minimum eigenvalue
170  MinEigen<2>(val);
171 
172  if (val < 1e-6)
173  {
174  // Add constant identity to Hessian matrix.
175  m_grad[2] += 1e-6 - val;
176  m_grad[4] += 1e-6 - val;
177  }
178 
179  sk[0] = -1.0 / (m_grad[2] * m_grad[4] - m_grad[3] * m_grad[3]) *
180  (m_grad[4] * m_grad[0] - m_grad[3] * m_grad[1]);
181  sk[1] = -1.0 / (m_grad[2] * m_grad[4] - m_grad[3] * m_grad[3]) *
182  (m_grad[2] * m_grad[1] - m_grad[3] * m_grad[0]);
183 
184  bool found = false;
185  NekDouble pg = (m_grad[0] * sk[0] + m_grad[1] * sk[1]);
186 
187  // normal gradient line Search
188  NekDouble alpha = 1.0;
189  while (alpha > alphaTol())
190  {
191  uvt[0] = uvc[0] + alpha * sk[0];
192  uvt[1] = uvc[1] + alpha * sk[1];
193 
194  if (uvt[0] < bd[0] || uvt[0] > bd[1] || uvt[1] < bd[2] ||
195  uvt[1] > bd[3])
196  {
197  alpha /= 2.0;
198  continue;
199  }
200 
201  surf->P(uvt, m_node->m_x, m_node->m_y, m_node->m_z);
202 
203  newVal = GetFunctional<3>(minJacNew, false);
204 
205  // Wolfe conditions
206  if (newVal <= currentW + c1() * (alpha * pg))
207  {
208  found = true;
209  break;
210  }
211 
212  alpha /= 2.0;
213  }
214 
215  if (!found)
216  {
217  // reset the node
218  surf->P(uvc, m_node->m_x, m_node->m_y, m_node->m_z);
219 
220  mtx.lock();
221  m_res->nReset[1]++;
222  mtx.unlock();
223  }
224  else
225  {
226  m_minJac = minJacNew;
227  m_node->Move(m_node->m_x, m_node->m_y, m_node->m_z, surf->GetId(),
228  uvt);
229  }
230 
231  mtx.lock();
232  m_res->val = max(sqrt((m_node->m_x - xc) * (m_node->m_x - xc) +
233  (m_node->m_y - yc) * (m_node->m_y - yc) +
234  (m_node->m_z - zc) * (m_node->m_z - zc)),
235  m_res->val);
236  mtx.unlock();
237 
238  Array<OneD, NekDouble> uva = m_node->GetCADSurfInfo(surf->GetId());
239  if (uva[0] < bd[0] || uva[0] > bd[1] || uva[1] < bd[2] ||
240  uva[1] > bd[3])
241  {
242  ASSERTL0(false, "something when very wrong and the node finished "
243  "out of its parameter plane");
244  }
245  }
246 
247  mtx.lock();
248  m_res->func += newVal;
249  mtx.unlock();
250 }
251 
252 void NodeOpti1D3D::ProcessGradient()
253 {
254  NekDouble tc = m_node->GetCADCurveInfo(curve->GetId());
255  vector<NekDouble> grad = m_grad;
256  m_grad = vector<NekDouble>(2, 0.0);
257 
258  // Grab first and second order CAD derivatives
259  Array<OneD, NekDouble> d2 = curve->D2(tc);
260 
261  // Multiply gradient by derivative of CAD
262  m_grad[0] = grad[0] * d2[3] + grad[1] * d2[4] + grad[2] * d2[5];
263 
264  // Second order: product rule of above, so multiply gradient by second
265  // order CAD derivatives and Hessian by gradient of CAD
266  m_grad[1] = grad[0] * d2[6] + grad[1] * d2[7] + grad[2] * d2[8] +
267  d2[3] * (grad[3] * d2[3] + grad[4] * d2[4] + grad[5] * d2[5]) +
268  d2[4] * (grad[4] * d2[3] + grad[6] * d2[4] + grad[7] * d2[5]) +
269  d2[5] * (grad[5] * d2[3] + grad[7] * d2[4] + grad[8] * d2[5]);
270 }
271 
272 void NodeOpti2D3D::ProcessGradient()
273 {
274  Array<OneD, NekDouble> uvc = m_node->GetCADSurfInfo(surf->GetId());
275 
276  vector<NekDouble> grad = m_grad;
277  m_grad = vector<NekDouble>(5, 0.0);
278 
279  Array<OneD, NekDouble> d2 = surf->D2(uvc);
280  // r[0] x
281  // r[1] y
282  // r[2] z
283  // r[3] dx/du a
284  // r[4] dy/du b
285  // r[5] dz/du c
286  // r[6] dx/dv d
287  // r[7] dy/dv e
288  // r[8] dz/dv f
289  // r[9] d2x/du2
290  // r[10] d2y/du2
291  // r[11] d2z/du2
292  // r[12] d2x/dv2
293  // r[13] d2y/dv2
294  // r[14] d2z/dv2
295  // r[15] d2x/dudv
296  // r[16] d2y/dudv
297  // r[17] d2z/dudv
298  //
299  // grad[0] d/dx
300  // grad[1] d/dy
301  // grad[2] d/dz
302  // grad[3] d2/dx2
303  // grad[4] d2/dxdy
304  // grad[5] d2/dxdz
305  // grad[6] d2/dy2
306  // grad[7] d2/dydz
307  // grad[8] d2/dz2
308 
309  // Gradients
310  m_grad[0] = d2[3] * grad[0] + d2[4] * grad[1] + d2[5] * grad[2];
311  m_grad[1] = d2[6] * grad[0] + d2[7] * grad[1] + d2[8] * grad[2];
312 
313  m_grad[2] = grad[0] * d2[9] + grad[1] * d2[10] + grad[2] * d2[11] +
314  grad[3] * d2[3] * d2[3] + grad[6] * d2[4] * d2[4] +
315  grad[8] * d2[5] * d2[5] + 2.0 * grad[4] * d2[3] * d2[4] +
316  2.0 * grad[5] * d2[3] * d2[5] + 2.0 * grad[7] * d2[4] * d2[5];
317 
318  m_grad[4] = grad[0] * d2[12] + grad[1] * d2[13] + grad[2] * d2[14] +
319  grad[3] * d2[6] * d2[6] + grad[6] * d2[7] * d2[7] +
320  grad[8] * d2[8] * d2[8] + 2.0 * grad[4] * d2[6] * d2[7] +
321  2.0 * grad[5] * d2[6] * d2[8] + 2.0 * grad[7] * d2[7] * d2[8];
322 
323  m_grad[3] = grad[0] * d2[15] + grad[1] * d2[16] + grad[2] * d2[17] +
324  grad[3] * d2[3] * d2[6] + grad[6] * d2[4] * d2[7] +
325  grad[8] * d2[5] * d2[8] +
326  grad[4] * (d2[3] * d2[7] + d2[4] * d2[6]) +
327  grad[5] * (d2[3] * d2[8] + d2[5] * d2[6]) +
328  grad[7] * (d2[4] * d2[8] + d2[5] * d2[7]);
329 }
330 }
331 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
NodeOptiFactory & GetNodeOptiFactory()
Definition: NodeOpti.cpp:51
STL namespace.
double NekDouble
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199