MFEM  v4.6.0
Finite element discretization library
nurbs_curveint.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 //
12 // ------------------------------------------------------------
13 // NURBS CurveInt Miniapp: Interpolate a Curve in a NURBS Patch
14 // ------------------------------------------------------------
15 //
16 // Compile with: make nurbs_curveint
17 //
18 // Sample runs: ./nurbs_curveint -uw -n 9
19 // ./nurbs_curveint -nw -n 9
20 //
21 // Description: This example code demonstrates the use of MFEM to interpolate a
22 // curve in a NURBS patch. We first define a square shaped NURBS
23 // patch. We then interpolate a sine function on the bottom
24 // edge. The results can be viewed in VisIt.
25 //
26 // We use curve interpolation for curves with all weights being 1,
27 // B-splines, and curves with not all weights being 1, NURBS. The
28 // spacing in both cases is chosen differently.
29 
30 #include "mfem.hpp"
31 #include <fstream>
32 #include <iostream>
33 
34 using namespace std;
35 using namespace mfem;
36 
37 KnotVector *UniformKnotVector(int order, int ncp)
38 {
39  if (order>=ncp)
40  {
41  mfem_error("UniformKnotVector: ncp should be at least order + 1");
42  }
43  KnotVector *kv = new KnotVector(order, ncp);
44 
45  for (int i = 0; i < order+1; i++)
46  {
47  (*kv)[i] = 0.0;
48  }
49  for (int i = order+1; i < ncp; i++)
50  {
51  (*kv)[i] = (i-order)/double(ncp-order);
52  }
53  for (int i = ncp ; i < ncp + order + 1; i++)
54  {
55  (*kv)[i] = 1.0;
56  }
57  return kv;
58 }
59 
60 int main(int argc, char *argv[])
61 {
62  // Parse command-line options.
63  OptionsParser args(argc, argv);
64 
65  double l = 1.0;
66  double a = 0.1;
67  int ncp = 9;
68  int order = 2;
69  bool ifbspline = true;
70  bool visualization = true;
71  bool visit = true;
72 
73  args.AddOption(&l, "-l", "--box-side-length",
74  "Height and width of the box");
75  args.AddOption(&a, "-a", "--sine-ampl",
76  "Amplitude of the fitted sine function.");
77  args.AddOption(&ncp, "-n", "--ncp",
78  "Number of control points used over four box sides.");
79  args.AddOption(&order, "-o", "--order",
80  "Order of the NURBSPatch");
81  args.AddOption(&ifbspline, "-uw", "--unit-weight", "-nw",
82  "--non-unit-weight",
83  "Use a unit-weight for B-splines (default) or not: for general NURBS");
84  args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
85  "--no-visualization",
86  "Enable or disable GLVis visualization. This is a dummy option to enable testing.");
87  args.AddOption(&visit, "-visit", "--visit", "-no-visit", "--no-visit",
88  "Enable or disable VisIt visualization.");
89 
90  // Parse and print command line options
91  args.Parse();
92  if (!args.Good())
93  {
94  args.PrintUsage(cout);
95  return 1;
96  }
97  args.PrintOptions(cout);
98 
99  if (order < 2 && ifbspline == false)
100  {
101  mfem_error("For a non unity weight, the order should be at least 2.");
102  }
103 
104  KnotVector *kv_o1 = UniformKnotVector(1, 2);
105  KnotVector *kv = UniformKnotVector(order, ncp);
106 
107  // 1. Create a box shaped NURBS patch
108  NURBSPatch patch(kv_o1, kv_o1, 3);
109 
110  // Set weights
111  for (int j = 0; j < 2; j++)
112  for (int i = 0; i < 2; i++)
113  {
114  patch(i,j,2) = 1.0;
115  }
116 
117  // Define patch corners which are box corners
118  patch(0,0,0) = -0.5*l;
119  patch(0,0,1) = -0.5*l;
120 
121  patch(1,0,0) = 0.5*l;
122  patch(1,0,1) = -0.5*l;
123 
124  patch(0,1,0) = -0.5*l;
125  patch(0,1,1) = 0.5*l;
126 
127  patch(1,1,0) = 0.5*l;
128  patch(1,1,1) = 0.5*l;
129 
130  // 2. Interpolation process
131  Array<Vector*> xy(2);
132  xy[0] = new Vector();
133  xy[1] = new Vector();
134  Vector xi_args, u_args;
135  Array<int> i_args;
136  xy[0]->SetSize(ncp); xy[1]->SetSize(ncp);
137 
138  // Refine direction which has fitting
139  if (!ifbspline)
140  {
141  // We alter the weight for demonstration purposes to a random value. This
142  // is not necessary for general curve fitting.
143  patch.DegreeElevate(0, 1);
144  patch(1,0,2) = sqrt(2)/2;
145  patch.DegreeElevate(0, order-kv_o1->GetOrder()-1);
146  }
147  else
148  {
149  patch.DegreeElevate(0, order-kv_o1->GetOrder());
150  }
151  patch.KnotInsert(0, *kv);
152 
153  // We locate the control points at the location of the maxima of the
154  // knot vectors. This works very well for patches with unit weights.
155  kv->FindMaxima(i_args,xi_args, u_args);
156 
157  for (int i = 0; i < ncp; i++)
158  {
159  (*xy[0])[i] = u_args[i]*l;
160  (*xy[1])[i] = a * sin((*xy[0])[i]/l*2*M_PI)-0.5*l;
161  (*xy[0])[i] -= 0.5*l;
162  }
163 
164  kv->FindInterpolant(xy);
165 
166  // Apply interpolation to patch
167  for (int i = 0; i < ncp; i++)
168  {
169  patch(i,0,0) = (*xy[0])[i];
170  patch(i,0,1) = (*xy[1])[i];
171  }
172 
173  if (!ifbspline)
174  {
175  // Convert to homogeneous coordinates. FindInterpolant returns
176  // Cartesian coordinates.
177  for (int i = 0; i < ncp; i++)
178  {
179  patch(i,0,0) *= patch(i,0,2);
180  patch(i,0,1) *= patch(i,0,2);
181  }
182  }
183 
184  // Refinement in curve interpolation direction
185  patch.DegreeElevate(1, order-kv_o1->GetOrder());
186  patch.KnotInsert(1, *kv);
187 
188  // 3. Open and write mesh output file
189  string mesh_file("sin-fit.mesh");
190  ofstream output(mesh_file.c_str());
191 
192  output<<"MFEM NURBS mesh v1.0"<<endl;
193  output<< endl << "# Square nurbs mesh with a sine fitted at its bottom edge" <<
194  endl << endl;
195  output<< "dimension"<<endl;
196  output<< 2 <<endl;
197  output<< endl;
198 
199  output<<"elements"<<endl;
200  output<<"1"<<endl;
201  output<<"1 3 0 1 2 3"<<endl;
202  output<<endl;
203 
204  output<<"boundary"<<endl;
205  output<<"0"<<endl;
206  output<<endl;
207 
208  output << "edges" <<endl;
209  output << "4" <<endl;
210  output << "0 0 1"<<endl;
211  output << "0 3 2"<<endl;
212  output << "1 0 3"<<endl;
213  output << "1 1 2"<<endl;
214  output<<endl;
215 
216  output << "vertices" << endl;
217  output << 4 << endl;
218 
219  output<<"patches"<<endl;
220  output<<endl;
221 
222  output << "# Patch 1 " << endl;
223  patch.Print(output);
224  output.close();
225 
226  // Print mesh info to screen
227  cout << "=========================================================="<< endl;
228  cout << " Attempting to read mesh: " <<mesh_file.c_str()<< endl ;
229  cout << "=========================================================="<< endl;
230  Mesh *mesh = new Mesh(mesh_file.c_str(), 1, 1);
231  mesh->PrintInfo();
232 
233  if (visit)
234  {
235  // Print mesh to file for visualization
236  VisItDataCollection dc = VisItDataCollection("mesh", mesh);
237  dc.SetPrefixPath("CurveInt");
238  dc.SetCycle(0);
239  dc.SetTime(0.0);
240  dc.Save();
241  }
242 
243  delete mesh;
244  delete kv_o1;
245  delete kv;
246  delete xy[0];
247  delete xy[1];
248 
249  return 0;
250 }
void DegreeElevate(int dir, int t)
Definition: nurbs.cpp:966
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void PrintOptions(std::ostream &out) const
Print the options.
Definition: optparser.cpp:331
virtual void PrintInfo(std::ostream &os=mfem::out)
In serial, this method calls PrintCharacteristics(). In parallel, additional information about the pa...
Definition: mesh.hpp:2088
void KnotInsert(int dir, const KnotVector &knot)
Definition: nurbs.cpp:817
void PrintUsage(std::ostream &out) const
Print the usage message.
Definition: optparser.cpp:462
int GetOrder() const
Definition: nurbs.hpp:52
bool Good() const
Return true if the command line options were parsed successfully.
Definition: optparser.hpp:159
STL namespace.
KnotVector * UniformKnotVector(int order, int ncp)
void FindMaxima(Array< int > &ks, Vector &xi, Vector &u)
Definition: nurbs.cpp:346
int main(int argc, char *argv[])
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
Definition: optparser.cpp:151
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
Data collection with VisIt I/O routines.
void FindInterpolant(Array< Vector *> &x)
Definition: nurbs.cpp:409
void SetTime(double t)
Set physical time (for time-dependent simulations)
virtual void Save() override
Save the collection and a VisIt root file.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set &#39;var&#39; to receive the value. Enable/disable tags are used to set the bool...
Definition: optparser.hpp:82
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:687
double a
Definition: lissajous.cpp:41
Vector data type.
Definition: vector.hpp:58
void Print(std::ostream &out) const
Definition: nurbs.cpp:700
void SetPrefixPath(const std::string &prefix)
Set the path where the DataCollection will be saved.