1 // Copyright (c) 2015-2016, Massachusetts Institute of Technology
2 // Copyright (c) 2016-2017 Sandia Corporation
3 // Copyright (c) 2017 NTESS, LLC.
4 
5 // This file is part of the Compressed Continuous Computation (C3) Library
6 // Author: Alex A. Gorodetsky
7 // Contact: alex@alexgorodetsky.com
8 
9 // All rights reserved.
10 
11 // Redistribution and use in source and binary forms, with or without modification,
12 // are permitted provided that the following conditions are met:
13 
14 // 1. Redistributions of source code must retain the above copyright notice,
15 //    this list of conditions and the following disclaimer.
16 
17 // 2. Redistributions in binary form must reproduce the above copyright notice,
18 //    this list of conditions and the following disclaimer in the documentation
19 //    and/or other materials provided with the distribution.
20 
21 // 3. Neither the name of the copyright holder nor the names of its contributors
22 //    may be used to endorse or promote products derived from this software
23 //    without specific prior written permission.
24 
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 
36 //Code
37 
38 
39 /** \file linelm.c
40  * Provides routines for manipulating linear elements
41 */
42 
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <math.h>
46 #include <complex.h>
47 #include <string.h>
48 #include <float.h>
49 #include <assert.h>
50 
51 #include "stringmanip.h"
52 #include "array.h"
53 #include "linalg.h"
54 #include "futil.h"
55 #include "linelm.h"
56 
57 /** \struct LinElemExpAopts
58  * \brief Approximation options of LinElemExp
59  * \var LinElemExpAopts::num_nodes
60  * number of basis functions or nodes
61  * \var LinElemExpAopts::node_alloc
62  * indicator whether nodes were self allocated
63  * \var LinElemExpAopts::nodes
64  * nodes
65  * \var LinElemExpAopts::adapt
66  * whether or not to adapt (0 or 1)
67  * \var LinElemExpAopts::lb
68  * lower bound
69  * \var LinElemExpAopts::ub
70  * upper bound
71  * \var LinElemExpAopts::delta
72  * adaptation function value tolerance
73  * \var LinElemExpAopts::hmin
74  * adaptation node spacing tolerance
75  */
76 struct LinElemExpAopts{
77 
78     size_t num_nodes;
79     int node_alloc;
80     double * nodes;
81     int adapt;
82 
83     double lb;
84     double ub;
85     double delta;
86     double hmin;
87 
88     // for periodic boundary conditions
89     double * Lp;
90     double * p;
91 };
92 
93 /********************************************************//**
94     Allocate approximation arguments (by reference)
95 
96     \param[in] N - number of nodes
97     \param[in] x - nodes
98 
99     \return approximation arguments
100 *************************************************************/
lin_elem_exp_aopts_alloc(size_t N,double * x)101 struct LinElemExpAopts * lin_elem_exp_aopts_alloc(size_t N, double * x)
102 {
103     assert (x != NULL);
104     struct LinElemExpAopts * aopts = NULL;
105     aopts = malloc(sizeof(struct LinElemExpAopts));
106     if (aopts == NULL){
107         fprintf(stderr,"Memory error allocate LinElemExpAopts\n");
108         exit(1);
109     }
110     aopts->num_nodes = N;
111     aopts->node_alloc = 0;
112     aopts->nodes = x;
113     aopts->lb = x[0];
114     aopts->ub = x[N-1];
115 
116     /* printf("in allocation: lin_elem_exp_aopts nodes = "); dprint(N,x); */
117     aopts->adapt = 0;
118     aopts->delta = DBL_MAX;
119     aopts->hmin = DBL_MAX;
120 
121     return aopts;
122 }
123 
124 /********************************************************//**
125     Allocate approximation arguments for adaptation
126 
127     \param[in] N     - number of nodes
128     \param[in] x     - starting nodes reference
129     \param[in] lb    - lower bound lb==x[0] if x! NULL
130     \param[in] ub    - upper bound ub==x[0] if x! NULL
131     \param[in] delta - size of deviation from linear
132     \param[in] hmin  - minimum spacing
133 
134     \return approximation arguments
135 *************************************************************/
136 struct LinElemExpAopts *
lin_elem_exp_aopts_alloc_adapt(size_t N,double * x,double lb,double ub,double delta,double hmin)137 lin_elem_exp_aopts_alloc_adapt(size_t N, double * x,
138                                double lb, double ub,
139                                double delta, double hmin)
140 {
141     struct LinElemExpAopts * aopts = NULL;
142     aopts = malloc(sizeof(struct LinElemExpAopts));
143     if (aopts == NULL){
144         fprintf(stderr,"Memory error allocate LinElemExpAopts\n");
145         exit(1);
146     }
147     aopts->num_nodes= N;
148     aopts->node_alloc = 0;
149     aopts->lb = lb;
150     aopts->ub = ub;
151     if (N > 0){
152         aopts->nodes = x;
153     }
154     else{
155         aopts->nodes = NULL;
156     }
157     aopts->adapt = 1;
158     aopts->delta = delta;
159     aopts->hmin = hmin;
160 
161     return aopts;
162 }
163 
164 /********************************************************//**
165     Free memory allocated to approximation arguments
166 
167     \param[in,out] aopts - approximation arguments
168 *************************************************************/
lin_elem_exp_aopts_free(struct LinElemExpAopts * aopts)169 void lin_elem_exp_aopts_free(struct LinElemExpAopts * aopts)
170 {
171     if (aopts != NULL){
172         if (aopts->node_alloc == 1){
173             free(aopts->nodes); aopts->nodes = NULL;
174         }
175         free(aopts); aopts = NULL;
176     }
177 }
178 
179 /********************************************************//**
180     (deep)Free memory allocated to approximation arguments
181 
182     \param[in,out] aopts - approximation arguments
183 *************************************************************/
lin_elem_exp_aopts_free_deep(struct LinElemExpAopts ** aopts)184 void lin_elem_exp_aopts_free_deep(struct LinElemExpAopts ** aopts)
185 {
186     if (*aopts != NULL){
187         if ((*aopts)->node_alloc == 1){
188             free((*aopts)->nodes); (*aopts)->nodes = NULL;
189         }
190         free(*aopts); *aopts = NULL;
191     }
192 }
193 
194 /********************************************************//**
195     Get number of nodes
196 *************************************************************/
lin_elem_exp_aopts_get_num_nodes(const struct LinElemExpAopts * aopts)197 size_t lin_elem_exp_aopts_get_num_nodes(const struct LinElemExpAopts * aopts)
198 {
199     assert (aopts != NULL);
200     return aopts->num_nodes;
201 }
202 
203 /********************************************************//**
204     Get the lower bound
205 *************************************************************/
lin_elem_exp_aopts_get_lb(const struct LinElemExpAopts * aopts)206 double lin_elem_exp_aopts_get_lb(const struct LinElemExpAopts * aopts)
207 {
208     assert (aopts != NULL);
209     return aopts->lb;
210 }
211 
212 /********************************************************//**
213     Get the upper bound
214 *************************************************************/
lin_elem_exp_aopts_get_ub(const struct LinElemExpAopts * aopts)215 double lin_elem_exp_aopts_get_ub(const struct LinElemExpAopts * aopts)
216 {
217     assert (aopts != NULL);
218     return aopts->ub;
219 }
220 
221 /********************************************************//**
222     Sets new nodes (by reference) for approximation options.
223     frees old ones if
224     previously allocated
225 
226     \param[in,out] aopts - approximation arguments
227     \param[in]     N     - number of nodes
228     \param[in]     nodes - nodes
229 *************************************************************/
lin_elem_exp_aopts_set_nodes(struct LinElemExpAopts * aopts,size_t N,double * nodes)230 void lin_elem_exp_aopts_set_nodes(struct LinElemExpAopts * aopts,
231                                   size_t N, double * nodes)
232 {
233 
234     if (aopts == NULL){
235         fprintf(stderr,"Must allocate LinElemExpAopts before setting nodes\n");
236         exit(1);
237     }
238     if (aopts->node_alloc == 1){
239         free(aopts->nodes); aopts->nodes = NULL;
240     }
241     aopts->num_nodes= N;
242     aopts->node_alloc = 0;
243     if (N > 0){
244         aopts->nodes = nodes;
245     }
246 }
247 
248 /********************************************************//**
249     Sets new nodes for approximation options.
250     frees old ones if
251     previously allocated
252 
253     \param[in,out] aopts - approximation arguments
254     \param[in]     N     - number of nodes
255     \param[in]     nodes - nodes
256 *************************************************************/
lin_elem_exp_aopts_set_nodes_copy(struct LinElemExpAopts * aopts,size_t N,const double * nodes)257 void lin_elem_exp_aopts_set_nodes_copy(struct LinElemExpAopts * aopts,
258 				       size_t N, const double * nodes)
259 {
260 
261     if (aopts == NULL){
262         fprintf(stderr,"Must allocate LinElemExpAopts before setting nodes\n");
263         exit(1);
264     }
265     if (aopts->node_alloc == 1){
266         free(aopts->nodes); aopts->nodes = NULL;
267     }
268     aopts->num_nodes = N;
269     aopts->node_alloc = 1;
270     aopts->nodes = calloc_double(N);
271     memmove(aopts->nodes,nodes,N*sizeof(double));
272 
273 }
274 
275 /********************************************************//**
276     Set adaptation
277 
278     \param[in,out] aopts - approximation arguments
279     \param[in]     delta - maximum deviation from linear
280     \param[in]     hmin  - minimum distance between nodes
281 *************************************************************/
lin_elem_exp_aopts_set_adapt(struct LinElemExpAopts * aopts,double delta,double hmin)282 void lin_elem_exp_aopts_set_adapt(struct LinElemExpAopts * aopts,
283                                   double delta, double hmin)
284 {
285     if (aopts == NULL){
286         fprintf(stderr,"Must allocate LinElemExpAopts before turning on adapting\n");
287         exit(1);
288     }
289     aopts->adapt = 1;
290     aopts->delta = delta;
291     aopts->hmin = hmin;
292 }
293 /********************************************************//**
294     Setting delta for adaptation
295 
296     \param[in,out] aopts - approximation arguments
297     \param[in]     delta - maximum deviation from linear
298 *************************************************************/
lin_elem_exp_aopts_set_delta(struct LinElemExpAopts * aopts,double delta)299 void lin_elem_exp_aopts_set_delta(struct LinElemExpAopts * aopts, double delta)
300 {
301     if (aopts == NULL){
302         fprintf(stderr,"Must allocate LinElemExpAopts before setting delta\n");
303         exit(1);
304     }
305     aopts->delta = delta;
306 }
307 
308 /********************************************************//**
309     Setting hmin for adaptation
310 
311     \param[in,out] aopts - approximation arguments
312     \param[in]     hmin  - minimum distance between nodes
313 *************************************************************/
lin_elem_exp_aopts_set_hmin(struct LinElemExpAopts * aopts,double hmin)314 void lin_elem_exp_aopts_set_hmin(struct LinElemExpAopts * aopts, double hmin)
315 {
316     if (aopts == NULL){
317         fprintf(stderr,"Must allocate LinElemExpAopts before setting hmin\n");
318         exit(1);
319     }
320     aopts->hmin = hmin;
321 }
322 
323 
324 ///////////////////////////////////////////////
325 
326 
327 /********************************************************//**
328 *   Get number of free parameters
329 *
330 *   \note Can change this later to include knot locations
331 *************************************************************/
lin_elem_exp_aopts_get_nparams(const struct LinElemExpAopts * lexp)332 size_t lin_elem_exp_aopts_get_nparams(const struct LinElemExpAopts* lexp)
333 {
334     assert (lexp != NULL);
335     return lexp->num_nodes;
336 }
337 
338 /********************************************************//**
339 *   Set number of free parameters
340 *
341 *   \note Can change this later to include knot locations
342 *************************************************************/
lin_elem_exp_aopts_set_nparams(struct LinElemExpAopts * lexp,size_t num)343 void lin_elem_exp_aopts_set_nparams(struct LinElemExpAopts* lexp, size_t num)
344 {
345     assert (lexp != NULL);
346     lexp->num_nodes = num;
347     fprintf(stderr,"Warning: setting new nparams in linelem aopts. Do I need to adjust the node locations?\n");
348 }
349 
350 
351 /********************************************************//**
352 *   Allocate a Linear Element Expansion
353 *
354 *  \return  Allocated Expansion
355 *************************************************************/
lin_elem_exp_alloc()356 struct LinElemExp * lin_elem_exp_alloc()
357 {
358 
359     struct LinElemExp * p = NULL;
360     if ( NULL == (p = malloc(sizeof(struct LinElemExp)))){
361         fprintf(stderr, "failed to allocate memory for LinElemExp.\n");
362         exit(1);
363     }
364     p->num_nodes = 0;
365     p->nodes = NULL;
366     p->coeff = NULL;
367     p->diff = NULL;
368     p->inner = NULL;
369 
370     p->Lp = NULL;
371     return p;
372 }
373 
374 /********************************************************//**
375     Make a copy of a linear element expansion
376 
377     \param[in] lexp - linear element expansion to copy
378 
379     \return linear element expansion
380 *************************************************************/
lin_elem_exp_copy(struct LinElemExp * lexp)381 struct LinElemExp * lin_elem_exp_copy(struct LinElemExp * lexp)
382 {
383 
384     struct LinElemExp * p = NULL;
385     if (lexp != NULL){
386         p = lin_elem_exp_alloc();
387         p->num_nodes = lexp->num_nodes;
388         if (lexp->nodes != NULL){
389             p->nodes = calloc_double(p->num_nodes);
390             memmove(p->nodes,lexp->nodes,p->num_nodes*sizeof(double));
391         }
392         if (lexp->coeff != NULL){
393             p->coeff = calloc_double(p->num_nodes);
394             memmove(p->coeff,lexp->coeff,p->num_nodes*sizeof(double));
395         }
396 
397         if (lexp->Lp != NULL){
398             p->Lp = calloc_double(p->num_nodes*p->num_nodes);
399             memmove(p->Lp, lexp->Lp, p->num_nodes*p->num_nodes * sizeof(double));
400         }
401     }
402     return p;
403 }
404 
405 /********************************************************//**
406 *  Free a Linear Element Expansion
407 *
408 *  \param[in,out] exp - expansion to free
409 *************************************************************/
lin_elem_exp_free(struct LinElemExp * exp)410 void lin_elem_exp_free(struct LinElemExp * exp)
411 {
412     if (exp != NULL){
413         free(exp->nodes); exp->nodes = NULL;
414         free(exp->coeff); exp->coeff = NULL;
415         free(exp->diff); exp->diff = NULL;
416         free(exp->Lp);   exp->Lp = NULL;
417         free(exp); exp = NULL;
418     }
419 }
420 
421 /* static void compute_inner_helper(struct LinElemExp * exp) */
422 /* { */
423 /*     if (exp != NULL){ */
424 /*         if (exp->coeff != NULL){ */
425 /*             if (exp->diff != NULL){ */
426 /*                 free(exp->diff); exp->diff = NULL; */
427 /*             } */
428 
429 /*             //left  */
430 /*             exp->diff = calloc_double(exp->num_nodes); */
431 /*             for (size_t ii = 0; ii < exp->num_nodes-1; ii++){ */
432 /*                 exp->diff[ii] = exp->coeff[ii+1]-exp->coeff[ii]; */
433 /*             } */
434 /*         } */
435 /*     } */
436 /* } */
437 
438 /********************************************************//**
439     Initialize a linear element expansion
440 
441     \param[in] num_nodes - number of nodes/basis functions
442     \param[in] nodes     - nodes
443     \param[in] coeff     - weights on nodes
444 
445     \return linear element expansion
446 
447     \note
448     makes a copy of nodes and coefficients
449 *************************************************************/
lin_elem_exp_init(size_t num_nodes,double * nodes,double * coeff)450 struct LinElemExp * lin_elem_exp_init(size_t num_nodes, double * nodes,
451                                       double * coeff)
452 {
453     struct LinElemExp * lexp = lin_elem_exp_alloc();
454     assert (num_nodes > 1);
455     lexp->num_nodes = num_nodes;
456     lexp->nodes = calloc_double(num_nodes);
457     lexp->coeff = calloc_double(num_nodes);
458     memmove(lexp->nodes,nodes,num_nodes*sizeof(double));
459     memmove(lexp->coeff,coeff,num_nodes*sizeof(double));
460     /* compute_diff(lexp); */
461     return lexp;
462 }
463 
464 /********************************************************//**
465     Initialize a linear element expansion with particular parameters
466 
467     \param[in] opts  - options
468     \param[in] dim   - number of parameters
469     \param[in] param - parameters
470 
471     \return linear element expansion
472 
473     \note
474     makes a copy of nodes and coefficients
475 *************************************************************/
476 struct LinElemExp *
lin_elem_exp_create_with_params(struct LinElemExpAopts * opts,size_t dim,const double * param)477 lin_elem_exp_create_with_params(struct LinElemExpAopts * opts,
478                                size_t dim, const double * param)
479 {
480     assert (opts != NULL);
481     assert (opts->num_nodes == dim);
482     assert (opts->nodes != NULL);
483     struct LinElemExp * lexp = lin_elem_exp_alloc();
484 
485     lexp->num_nodes = dim;;
486     lexp->nodes = calloc_double(dim);
487     lexp->coeff = calloc_double(dim);
488 
489     memmove(lexp->nodes,opts->nodes,dim*sizeof(double));
490     memmove(lexp->coeff,param,dim*sizeof(double));
491 
492     return lexp;
493 }
494 
495 /********************************************************//**
496     Get number of nodes
497 *************************************************************/
lin_elem_exp_get_num_nodes(const struct LinElemExp * lexp)498 size_t lin_elem_exp_get_num_nodes(const struct LinElemExp * lexp)
499 {
500     assert (lexp != NULL);
501     return lexp->num_nodes;
502 }
503 
504 /********************************************************//**
505     Get number of params
506 *************************************************************/
lin_elem_exp_get_num_params(const struct LinElemExp * lexp)507 size_t lin_elem_exp_get_num_params(const struct LinElemExp * lexp)
508 {
509     assert (lexp != NULL);
510     return lexp->num_nodes;
511 }
512 
513 /********************************************************//**
514     Get the parameters of a linear element expansion
515 
516     \param[in] lexp  - expansion
517     \param[in] param - parameters
518 
519     \returns number of parameters
520 *************************************************************/
lin_elem_exp_get_params(const struct LinElemExp * lexp,double * param)521 size_t lin_elem_exp_get_params(const struct LinElemExp * lexp, double * param)
522 {
523     assert (lexp != NULL);
524     memmove(param,lexp->coeff,lexp->num_nodes*sizeof(double));
525     return lexp->num_nodes;
526 }
527 
528 /********************************************************//**
529     Get a reference to parameters of a linear element expansion
530 
531     \param[in]     lexp   - expansion
532     \param[in,out] nparam - parameters
533 
534     \returns reference to parameters
535 *************************************************************/
lin_elem_exp_get_params_ref(const struct LinElemExp * lexp,size_t * nparam)536 double * lin_elem_exp_get_params_ref(const struct LinElemExp * lexp, size_t * nparam)
537 {
538     assert (lexp != NULL);
539     *nparam = lexp->num_nodes;
540     return lexp->coeff;
541 }
542 
543 /********************************************************//**
544     Update the parameters (coefficients) for a linear element expansion
545 
546     \param[in] lexp  - expansion
547     \param[in] dim   - number of parameters
548     \param[in] param - parameters
549 
550     \returns 0 if succesfull
551 *************************************************************/
552 int
lin_elem_exp_update_params(struct LinElemExp * lexp,size_t dim,const double * param)553 lin_elem_exp_update_params(struct LinElemExp * lexp,
554                            size_t dim, const double * param)
555 {
556     assert (lexp != NULL);
557     assert (lexp->num_nodes == dim);
558     for (size_t ii = 0; ii < dim; ii++){
559         lexp->coeff[ii] = param[ii];
560     }
561 
562     return 0;
563 }
564 
565 /********************************************************//**
566 *   Serialize a LinElemExp
567 *
568 *   \param[in]     ser       - location at which to serialize
569 *   \param[in]     f         - function to serialize
570 *   \param[in,out] totSizeIn - if not NULL then return size of struct
571 *                              if NULL then serialiaze
572 *
573 *   \return pointer to the end of the serialization
574 *************************************************************/
575 unsigned char *
serialize_lin_elem_exp(unsigned char * ser,struct LinElemExp * f,size_t * totSizeIn)576 serialize_lin_elem_exp(unsigned char * ser, struct LinElemExp * f,
577                        size_t * totSizeIn)
578 {
579 
580     // 3 * sizeof(size_t)-- 1 for num_nodes, 2 for sizes of nodes and coeffs
581     size_t totsize = 3*sizeof(size_t) + 2 * f->num_nodes*sizeof(double);
582 
583     if (totSizeIn != NULL){
584         *totSizeIn = totsize;
585         return ser;
586     }
587 
588     unsigned char * ptr = serialize_size_t(ser, f->num_nodes);
589     //serializing a pointer also serializes its size
590     ptr = serialize_doublep(ptr, f->nodes, f->num_nodes);
591     ptr = serialize_doublep(ptr, f->coeff, f->num_nodes);
592     return ptr;
593 
594 }
595 
596 /********************************************************//**
597 *   Deserialize a linear element expansion
598 *
599 *   \param[in]     ser - serialized structure
600 *   \param[in,out] f - function
601 *
602 *   \return ptr - ser + number of bytes of poly expansion
603 *************************************************************/
deserialize_lin_elem_exp(unsigned char * ser,struct LinElemExp ** f)604 unsigned char * deserialize_lin_elem_exp(unsigned char * ser,
605                                          struct LinElemExp ** f)
606 {
607 
608     *f = lin_elem_exp_alloc();
609 
610     unsigned char * ptr = ser;
611     ptr = deserialize_size_t(ptr,&((*f)->num_nodes));
612     ptr = deserialize_doublep(ptr, &((*f)->nodes), &((*f)->num_nodes));
613     ptr = deserialize_doublep(ptr, &((*f)->coeff), &((*f)->num_nodes));
614 
615     return ptr;
616 }
617 
618 /********************************************************//**
619 *   Get index of the node immediately to the left of x
620 *************************************************************/
lin_elem_exp_find_interval(const struct LinElemExp * f,double x)621 size_t lin_elem_exp_find_interval(const struct LinElemExp * f, double x)
622 {
623 
624     size_t indmin = 0;
625     size_t indmax = f->num_nodes-1;
626     size_t indmid = indmin + (indmax - indmin)/2;
627 
628     while (indmid != indmin){
629         if (fabs(x - f->nodes[indmid]) <= 1e-15){
630             /* printf("eventually here!\n"); */
631             return indmid;
632         }
633         else if (x < f->nodes[indmid]){
634             indmax = indmid;
635         }
636         else { // x > f->nodes[indmid]
637             indmin = indmid;
638         }
639         indmid = indmin + (indmax-indmin)/2;
640         //  printf("indmid = %zu, indmin=%zu,indmax=%zu\n",indmid,indmin,indmax);
641     }
642 
643     return indmin;
644 }
645 
646 
647 /********************************************************//**
648 *   Evaluate the lin elem expansion
649 *
650 *   \param[in] f - function
651 *   \param[in] x - location
652 *
653 *   \return value
654 *************************************************************/
lin_elem_exp_eval(const struct LinElemExp * f,double x)655 double lin_elem_exp_eval(const struct LinElemExp * f, double x)
656 {
657     if ((x < f->nodes[0]) || (x > f->nodes[f->num_nodes-1])){
658         return 0.0;
659     }
660 
661     size_t indmin = lin_elem_exp_find_interval(f,x);
662     /* printf("indmin = %zu\n",indmin); */
663     /* printf("x = %G\n",x); */
664 
665     if (fabs(x - f->nodes[indmin]) <= 1e-15){
666         return f->coeff[indmin];
667     }
668 
669     double den = f->nodes[indmin+1]-f->nodes[indmin];
670     double t = (f->nodes[indmin+1]-x)/den;
671     double value = f->coeff[indmin] * t + f->coeff[indmin+1]*(1.0-t);
672     return value;
673 }
674 
675 /********************************************************//**
676 *   Evaluate the derivative of a linear  lin elem expansion
677 *
678 *   \param[in] f - function
679 *   \param[in] x - location
680 *
681 *   \return value
682 *************************************************************/
lin_elem_exp_deriv_eval(const struct LinElemExp * f,double x)683 double lin_elem_exp_deriv_eval(const struct LinElemExp * f, double x)
684 {
685     if ((x < f->nodes[0]) || (x > f->nodes[f->num_nodes-1])){
686         return 0.0;
687     }
688 
689     size_t indmin = lin_elem_exp_find_interval(f,x);
690     /* printf("indmin = %zu\n",indmin); */
691     /* printf("x = %G\n",x); */
692 
693     if (fabs(x - f->nodes[indmin]) <= 1e-15){
694         if (indmin == 0){
695             double plus = f->coeff[indmin+1];
696             double curr = f->coeff[indmin];
697             return (plus-curr)/(f->nodes[indmin+1]-f->nodes[indmin]);
698         }
699         else if (indmin < f->num_nodes-1){
700             double plus = f->coeff[indmin+1];
701             double minus = f->coeff[indmin-1];
702             return (plus-minus)/(f->nodes[indmin+1]-f->nodes[indmin-1]);
703         }
704         else{
705             double curr = f->coeff[indmin];
706             double minus = f->coeff[indmin-1];
707             return (curr-minus)/(f->nodes[indmin]-f->nodes[indmin-1]);
708         }
709     }
710 
711     double den = f->nodes[indmin+1]-f->nodes[indmin];
712     double dtdx = -1.0/den;
713 
714     double value = (f->coeff[indmin]- f->coeff[indmin+1])*dtdx;
715     return value;
716 }
717 
718 /********************************************************//**
719 *   Evaluate the lin elem expansion
720 *
721 *   \param[in]     poly - function
722 *   \param[in]     N    - number of evaluations
723 *   \param[in]     x    - location at which to evaluate
724 *   \param[in]     incx - increment of x
725 *   \param[in,out] y    - allocated space for evaluations
726 *   \param[in]     incy - increment of y
727 ************************************************************/
lin_elem_exp_evalN(const struct LinElemExp * poly,size_t N,const double * x,size_t incx,double * y,size_t incy)728 void lin_elem_exp_evalN(const struct LinElemExp * poly, size_t N,
729                         const double * x, size_t incx, double * y, size_t incy)
730 {
731     for (size_t ii = 0; ii < N; ii++){
732         y[ii*incy] = lin_elem_exp_eval(poly,x[ii*incx]);
733     }
734 }
735 
736 
737 
738 /********************************************************//**
739 *   Get the value of the expansion at a particular node
740 *
741 *   \param[in] f - function
742 *   \param[in] node - location
743 *
744 *   \return value
745 *************************************************************/
lin_elem_exp_get_nodal_val(const struct LinElemExp * f,size_t node)746 double lin_elem_exp_get_nodal_val(const struct LinElemExp * f, size_t node)
747 {
748     assert (f != NULL);
749     assert (node < f->num_nodes);
750     return f->coeff[node];
751 }
752 
753 
754 
755 /********************************************************//**
756 *   Take a derivative same nodes,
757 *
758 *   \param[in] f - function
759 *
760 *   \return derivative
761 *************************************************************/
lin_elem_exp_deriv(const struct LinElemExp * f)762 struct LinElemExp * lin_elem_exp_deriv(const struct LinElemExp * f)
763 {
764     struct LinElemExp * le = lin_elem_exp_init(f->num_nodes,
765                                                f->nodes,f->coeff);
766 
767     assert(f->num_nodes > 1);
768     if (f->num_nodes <= 5){
769         //first order for first part
770         le->coeff[0] = (f->coeff[1]-f->coeff[0])/
771             (f->nodes[1]-f->nodes[0]);
772         // second order centeral
773         for (size_t ii = 1; ii < le->num_nodes-1; ii++){
774             le->coeff[ii] = (f->coeff[ii+1]-f->coeff[ii-1])/
775                 (f->nodes[ii+1]-f->nodes[ii-1]);
776         }
777         // first order last
778         le->coeff[le->num_nodes-1] =
779             (f->coeff[le->num_nodes-1] - f->coeff[le->num_nodes-2]) /
780             (f->nodes[f->num_nodes-1] - f->nodes[f->num_nodes-2]);
781     }
782     else{ // mostly fourth order
783 
784         //first order for first part
785         le->coeff[0] = (f->coeff[1]-f->coeff[0])/
786                        (f->nodes[1]-f->nodes[0]);
787         // second order
788         le->coeff[1] = (f->coeff[2]-f->coeff[0]) / (f->nodes[2]-f->nodes[0]);
789 
790         // fourth order central
791         for (size_t ii = 2; ii < le->num_nodes-2; ii++){
792             double sum_all = f->nodes[ii+2]-f->nodes[ii-2];
793             double sum_mid = f->nodes[ii+1]-f->nodes[ii-1];
794             double r_num = pow(f->nodes[ii+2]-f->nodes[ii],3) +
795                 pow(f->nodes[ii] - f->nodes[ii-2],3);
796             double r_den = pow(f->nodes[ii+1]-f->nodes[ii],3) +
797                 pow(f->nodes[ii]-f->nodes[ii-1],3);
798 
799             double r = r_num/r_den;
800 
801             double den = r*sum_mid - sum_all;
802             double num = r*(f->coeff[ii+1]-f->coeff[ii-1]) -
803                            f->coeff[ii+2] + f->coeff[ii-2];
804             le->coeff[ii] = num/den;
805         }
806 
807         // second order
808         le->coeff[f->num_nodes-2] = (f->coeff[f->num_nodes-1] -
809                                      f->coeff[f->num_nodes-3]) /
810                                     (f->nodes[f->num_nodes-1] -
811                                      f->nodes[f->num_nodes-3]);
812 
813         // first order last
814         le->coeff[le->num_nodes-1] =
815             (f->coeff[le->num_nodes-1] - f->coeff[le->num_nodes-2]) /
816             (f->nodes[f->num_nodes-1] - f->nodes[f->num_nodes-2]);
817     }
818 
819     return le;
820 }
821 
822 /********************************************************//**
823 *   Take a second derivative same nodes,
824 *
825 *   \param[in] f - function
826 *************************************************************/
lin_elem_exp_dderiv(const struct LinElemExp * f)827 struct LinElemExp * lin_elem_exp_dderiv(const struct LinElemExp * f)
828 {
829 
830     struct LinElemExp * temp = lin_elem_exp_deriv(f);
831     struct LinElemExp * out = lin_elem_exp_deriv(temp);
832     lin_elem_exp_free(temp); temp = NULL;
833     return out;
834 }
835 
lin_elem_exp_dderiv_initialize_fourier(struct LinElemExp * f)836 void lin_elem_exp_dderiv_initialize_fourier(struct LinElemExp * f)
837 {
838     double dx = f->nodes[1] - f->nodes[0];    // assumes constant dx for now.
839     for (size_t ii = 1; ii < f->num_nodes-1; ii++){
840         double dx2 = f->nodes[ii+1] - f->nodes[ii];
841         if (fabs(dx2-dx) > 1e-15){
842             fprintf(stderr, "lin_elem_exp_dderiv_periodic only defined for uniform spacing\n");
843             fprintf(stderr, "%3.15G %3.15G\n", dx, dx2);
844             exit(1);
845         }
846 
847     }
848 
849     if (f->Lp != NULL){
850         free(f->Lp); f->Lp = NULL;
851     }
852 
853 
854     size_t nx = f->num_nodes;
855     double ub = f->nodes[nx-1] + dx; // because periodic!
856     double lb = f->nodes[0];
857     /* double ub = -lb; */
858 
859     double * x = f->nodes;
860 
861     /* printf("nodes = "); dprint(nx, x); */
862 
863     /* double dp = 2.0 * M_PI / (ub - lb); */
864     double dp = 2.0 * M_PI / (ub - lb);
865     double * p = calloc_double(nx);
866     f->Lp = calloc_double(nx * nx);
867     for (size_t ii = 0; ii < nx; ii++){
868         for (size_t jj = 0; jj < nx; jj++){
869             f->Lp[ii*nx + jj] = 0.0;
870         }
871     }
872 
873     for (size_t ii = 0; ii < nx; ii++){
874         p[ii] = dp * ii - dp * nx / 2.0;
875     }
876 
877     for (size_t ll=0; ll<nx; ll++){
878         for (size_t jj=0; jj<nx; jj++){
879             for (size_t kk=0; kk<nx; kk++){
880                 double update =  creal(cexp((_Complex double)I*(x[jj]-x[ll])*p[kk])*pow(p[kk],2)*dx*dp/(2*M_PI));
881                 f->Lp[ll * nx + jj] = f->Lp[ll*nx + jj] - update;
882             }
883         }
884     }
885     free(p); p = NULL;
886 }
887 
888 /********************************************************//**
889 *   Take a second derivative same nodes,
890 *
891 *   \param[in] f - function
892 *************************************************************/
893 struct LinElemExp *
lin_elem_exp_dderiv_periodic(struct LinElemExp * f)894 lin_elem_exp_dderiv_periodic(struct LinElemExp * f)
895 {
896 
897     assert (f != NULL);
898 
899     if (f->Lp == NULL){
900         lin_elem_exp_dderiv_initialize_fourier(f);
901     }
902 
903     // assumes constant dx for now.
904     size_t nx = f->num_nodes;
905     double dx = f->nodes[1] - f->nodes[0];
906     for (size_t ii = 1; ii < f->num_nodes-1; ii++){
907         double dx2 = f->nodes[ii+1] - f->nodes[ii];
908         if (fabs(dx2-dx) > 1e-15){
909             fprintf(stderr, "lin_elem_exp_dderiv_periodic only defined for uniform spacing\n");
910             fprintf(stderr, "%3.15G %3.15G\n", dx, dx2);
911             exit(1);
912         }
913 
914     }
915 
916     /* printf("Lp = \n"); */
917     /* for (size_t ii = 0; ii < nx; ii++){ */
918     /*     for (size_t jj = 0; jj < nx; jj++){ */
919     /*         printf("%3.5G ", Lp[ii * nx + jj]); */
920     /*     } */
921     /*     printf("\n"); */
922     /* } */
923     /* printf("\n"); */
924 
925     /* for (size_t ii = 0; ii < ) */
926     double * new_vals = calloc_double(nx);
927     for (size_t jj = 0; jj < nx; jj++){
928         new_vals[jj] = 0.0;
929         for (size_t kk = 0; kk < nx; kk++){
930             new_vals[jj] += f->Lp[kk*nx + jj] * f->coeff[kk];
931         }
932     }
933     struct LinElemExp * out = lin_elem_exp_init(nx, f->nodes, new_vals);
934 
935     free(new_vals); new_vals = NULL;
936 
937     return out;
938 }
939 
940 
941 
942 /********************************************************//*
943 *   Evaluate the gradient of a linear element expansion
944 *   with respect to the coefficients of each basis
945 *
946 *   \param[in]     f    - polynomial expansion
947 *   \param[in]     nx   - number of x points
948 *   \param[in]     x    - location at which to evaluate
949 *   \param[in,out] grad - gradient values (N,nx)
950 *
951 *   \return out - value
952 *************************************************************/
lin_elem_exp_param_grad_eval(struct LinElemExp * f,size_t nx,const double * x,double * grad)953 int lin_elem_exp_param_grad_eval(
954     struct LinElemExp * f, size_t nx, const double * x, double * grad)
955 {
956 
957     size_t nparam = f->num_nodes;
958     /* assert (nparam == lexp->nnodes); */
959     for (size_t ii = 0; ii < nx; ii++){
960         size_t indmin = lin_elem_exp_find_interval(f,x[ii]);
961 
962         /* printf("x = %G, indmin = %zu\n",x[ii],indmin); */
963         for (size_t jj = 0; jj < indmin; jj++)
964         {
965             grad[ii*nparam+jj] = 0.0;
966         }
967 
968         for (size_t jj = indmin+2; jj < nparam; jj++)
969         {
970             grad[ii*nparam+jj] = 0.0;
971         }
972 
973         double den = f->nodes[indmin+1]-f->nodes[indmin];
974         double t = (f->nodes[indmin+1]-x[ii])/den;
975 
976         grad[ii*nparam+indmin] = t;
977         grad[ii*nparam+indmin+1] = 1.0-t;
978 
979         /* double value = f->coeff[indmin] * t + f->coeff[indmin+1]*(1.0-t); */
980         /* fprintf(stderr,"Lin_elem_exp_param_grad_eval IS NOT YET IMPLEMENTED\n"); */
981         /* exit(1); */
982     }
983 
984     if (grad != NULL){
985         /* dprint(nparam*nx,grad); */
986         /* exit(1); */
987     }
988     return 0;
989 }
990 
991 /********************************************************//*
992 *   Evaluate the gradient of an linear element expansion
993 *   with respect to the coefficients of each basis
994 *
995 *   \param[in]     f    - polynomial expansion
996 *   \param[in]     x    - location at which to evaluate
997 *   \param[in,out] grad - gradient values (N)
998 *
999 *   \return out - value
1000 *************************************************************/
lin_elem_exp_param_grad_eval2(struct LinElemExp * f,double x,double * grad)1001 double lin_elem_exp_param_grad_eval2(
1002     struct LinElemExp * f, double x, double * grad)
1003 {
1004     assert (grad != NULL);
1005 
1006     size_t nparam = lin_elem_exp_get_num_params(f);
1007     size_t indmin = lin_elem_exp_find_interval(f,x);
1008     for (size_t jj = 0; jj < indmin; jj++)
1009     {
1010         grad[jj] = 0.0;
1011     }
1012 
1013     for (size_t jj = indmin+2; jj < nparam; jj++)
1014     {
1015         grad[jj] = 0.0;
1016     }
1017 
1018     double den = f->nodes[indmin+1]-f->nodes[indmin];
1019     double t = (f->nodes[indmin+1]-x)/den;
1020 
1021     grad[indmin] = t;
1022     grad[indmin+1] = 1.0-t;
1023 
1024     double value = f->coeff[indmin] * t + f->coeff[indmin+1]*(1.0-t);
1025 
1026     return value;
1027 }
1028 
1029 /********************************************************//**
1030     Take a gradient of the squared norm
1031     with respect to its parameters, and add a scaled version
1032     of this gradient to *grad*
1033 
1034     \param[in]     f     - linear element expansion
1035     \param[in]     scale - scaling for additional gradient
1036     \param[in,out] grad  - gradient, on output adds scale * new_grad
1037 
1038     \return  0 - success, 1 -failure
1039 
1040 ************************************************************/
1041 int
lin_elem_exp_squared_norm_param_grad(const struct LinElemExp * f,double scale,double * grad)1042 lin_elem_exp_squared_norm_param_grad(const struct LinElemExp * f,
1043                                      double scale, double * grad)
1044 {
1045     if (grad == NULL){
1046         return 0;
1047     }
1048 
1049     double dx = f->nodes[1]-f->nodes[0];
1050     double term1 = ((f->coeff[0]-1.0)/3.0 + f->coeff[1]/2.0) * dx;
1051     grad[0] += 2.0 * scale * term1;
1052     double dx2,df;
1053     for (size_t ii = 1; ii < f->num_nodes-1; ii++){
1054         // left side of ii
1055         df = f->coeff[ii] - f->coeff[ii-1];
1056         grad[ii] += 2.0 * scale * (0.5 * f->coeff[ii] * dx + 1.0/3.0 * df * dx);
1057 
1058         // right side
1059         dx2 = dx * dx;
1060         term1 = ((f->coeff[ii]-1.0)/3.0 + f->coeff[ii+1]/2.0) * dx;
1061         grad[ii] += 2.0 * scale * term1;
1062 
1063         dx = dx2;
1064     }
1065 
1066     // left side of last node node
1067     size_t ii = f->num_nodes-1;
1068     df = f->coeff[ii] - f->coeff[ii-1];
1069     grad[ii] += 2.0 * scale * (0.5 * f->coeff[ii] * dx + 1.0/3.0 * df * dx);
1070 
1071     return 0;
1072 }
1073 
1074 /********************************************************//**
1075 *   Integrate the Linear Element Approximation
1076 *
1077 *   \param[in] f - function
1078 *
1079 *   \return integral
1080 *************************************************************/
lin_elem_exp_integrate(const struct LinElemExp * f)1081 double lin_elem_exp_integrate(const struct LinElemExp * f)
1082 {
1083 
1084     assert (f->num_nodes>1 );
1085     double dx = f->nodes[1]-f->nodes[0];
1086     double integral = f->coeff[0] * dx * 0.5;
1087     /* printf("0: integrand(%3.15g) = %3.15G\n", f->nodes[0], integral); */
1088     for (size_t ii = 1; ii < f->num_nodes-1;ii++){
1089         dx = f->nodes[ii+1]-f->nodes[ii-1];
1090         integral += f->coeff[ii] * dx * 0.5;
1091         /* double newval = f->coeff[ii]*dx*0.5; */
1092         /* printf("%zu: integrand(%3.15g) = %3.15G\n", ii, f->nodes[ii], newval); */
1093     }
1094     dx = f->nodes[f->num_nodes-1]-f->nodes[f->num_nodes-2];
1095     integral += f->coeff[f->num_nodes-1] * dx * 0.5;
1096     return integral;
1097 }
1098 
lin_elem_exp_integrate_weighted(const struct LinElemExp * f)1099 double lin_elem_exp_integrate_weighted(const struct LinElemExp * f)
1100 {
1101     (void)(f);
1102     NOT_IMPLEMENTED_MSG("lin_elem_exp_integrate_weighted")
1103     return 0.0;
1104 }
1105 
1106 
1107 /********************************************************//**
1108 *   Determine if two functions have the same discretization
1109 *
1110 *   \param[in] f - function
1111 *   \param[in] g - function
1112 *
1113 *   \return 1 - yes
1114 *           0 - no
1115 *************************************************************/
lin_elem_sdiscp(const struct LinElemExp * f,const struct LinElemExp * g)1116 static int lin_elem_sdiscp(const struct LinElemExp * f,
1117                            const struct LinElemExp * g)
1118 {
1119     if (f->num_nodes != g->num_nodes){
1120         return 0;
1121     }
1122     for (size_t ii = 0; ii < f->num_nodes;ii++){
1123         if (fabs(f->nodes[ii] - g->nodes[ii]) > 1e-15){
1124             return 0;
1125         }
1126     }
1127     return 1;
1128 }
1129 
1130 /********************************************************//**
1131 *   Compute Integrals necessary for inner products for an element
1132 *   \f[
1133 *    left = \int_{x_1}^{x_2} (x_2-x)^2 dx
1134 *   \f]
1135 *   \f[
1136 *    mixed = \int_{x_1}^{x_2} (x_2-x)(x-x_1) dx
1137 *   \f]
1138 *   \f[
1139 *    right = \int_{x_1}^{x_2} (x-x_1)^2 dx
1140 *   \f]
1141 *
1142 *   \param[in]     x1 - left boundary of element
1143 *   \param[in]     x2 - right boundary of element
1144 *   \param[in,out] left - first integral
1145 *   \param[in,out] mixed - second integral
1146 *   \param[in,out] right - third integral
1147 *************************************************************/
1148 /* static void lin_elem_exp_inner_element( */
1149 /*     double x1, double x2, double * left, double * mixed,  */
1150 /*     double * right) */
1151 /* { */
1152 /*     double dx = (x2-x1); */
1153 /*     double x2sq = x2*x2; */
1154 /*     double x1sq = x1*x1; */
1155 /*     double x2cu = x2sq * x2; */
1156 /*     double x1cu = x1sq * x1; */
1157 /*     double dx2 = x2sq - x1sq; //pow(x2,2)-pow(x1,2); */
1158 /*     double dx3 = (x2cu - x1cu)/3.0; //(pow(x2,3)-pow(x1,3))/3.0; */
1159 
1160 /*     *left = x2sq*dx - x2*dx2 + dx3; // pow(x2,2)*dx - x2*dx2 + dx3; */
1161 /*     *mixed = (x2+x1) * dx2/2.0 - x1*x2*dx - dx3; */
1162 /*     *right = dx3 - x1*dx2 + x1sq * dx; //pow(x1,2)*dx; */
1163 /* } */
1164 
1165 /********************************************************//**
1166 *   Interpolate two linear element expansions onto the same grid
1167 *   keeping only those nodes needed for inner product
1168 *
1169 *   \param[in]     f - function
1170 *   \param[in]     g - function
1171 *   \param[in,out] x - interpolated nodes
1172 *   \param[in,out] fvals - values of f
1173 *   \param[in,out] gvals - values of g
1174 
1175 *   \return number of nodes
1176 
1177 *   \note
1178     x,fvals,gvals must all be previously allocaed with enough space
1179     at least f->num_nodes + g->num_nodes is enough for a
1180     conservative allocation
1181 *************************************************************/
lin_elem_exp_inner_same_grid(const struct LinElemExp * f,const struct LinElemExp * g,double * x,double * fvals,double * gvals)1182 static size_t lin_elem_exp_inner_same_grid(
1183     const struct LinElemExp * f, const struct LinElemExp * g, double * x,
1184     double * fvals, double * gvals)
1185 {
1186     size_t nnodes = 0;
1187     size_t inodef = 0;
1188     size_t inodeg = 0;
1189 
1190     if (f->nodes[0] > g->nodes[g->num_nodes-1]){
1191         return 0;
1192     }
1193     if (g->nodes[0] > f->nodes[f->num_nodes-1])
1194     {
1195         return 0;
1196     }
1197     while(f->nodes[inodef+1] < g->nodes[0]){
1198         inodef++;
1199     }
1200     while (g->nodes[inodeg+1] < f->nodes[0]){
1201         inodeg++;
1202     }
1203 
1204     while ((inodef < f->num_nodes) && (inodeg < g->num_nodes)){
1205         if (fabs(f->nodes[inodef] - g->nodes[inodeg]) < 1e-15){
1206             x[nnodes] = f->nodes[inodef];
1207             fvals[nnodes] = f->coeff[inodef];
1208             gvals[nnodes] = g->coeff[inodeg];
1209             inodef++;
1210             inodeg++;
1211             nnodes++;
1212         }
1213         else if (f->nodes[inodef] < g->nodes[inodeg]){
1214             x[nnodes] = f->nodes[inodef];
1215             fvals[nnodes] = f->coeff[inodef];
1216             gvals[nnodes] = lin_elem_exp_eval(g,x[nnodes]);
1217             inodef++;
1218             nnodes++;
1219         }
1220         else if (g->nodes[inodeg] < f->nodes[inodef]){
1221             x[nnodes] = g->nodes[inodeg];
1222             fvals[nnodes] = lin_elem_exp_eval(f, x[nnodes]);
1223             gvals[nnodes] = g->coeff[inodeg];
1224             inodeg++;
1225             nnodes++;
1226         }
1227     }
1228     //printf("nodes are "); dprint(nnodes,x);
1229 //    printf("fvalues are "); dprint(nnodes,fvals);
1230 //    printf("gvalues are "); dprint(nnodes, gvals);
1231     return nnodes;
1232 }
1233 
1234 /********************************************************//**
1235 *   Inner product between two functions with the same discretizations
1236 *
1237 *   \param[in] N - number of nodes
1238 *   \param[in] x - nodes
1239 *   \param[in] f - coefficients of first function
1240 *   \param[in] g - coefficients of second function
1241 *
1242 *   \return inner product
1243 *************************************************************/
lin_elem_exp_inner_same(size_t N,double * x,double * f,double * g)1244 static double lin_elem_exp_inner_same(size_t N, double * x,
1245                                       double * f, double * g)
1246 {
1247 
1248     // This first part is a high accuracy scheme, but assumes higher
1249     // order structure than piecewise linear
1250     /* double value = 0.0; */
1251     /* double left,mixed,right,dx2; */
1252     /* for (size_t ii = 0; ii < N-1; ii++){ */
1253     /*     dx2 = (x[ii+1]-x[ii])*(x[ii+1] - x[ii]); */
1254     /*     lin_elem_exp_inner_element(x[ii],x[ii+1],&left,&mixed,&right); */
1255     /*     /\* double new_val = (f[ii] * g[ii]) / dx2 * left + *\/ */
1256     /*     /\*     (f[ii] * g[ii+1]) / dx2 * mixed + *\/ */
1257     /*     /\*     (g[ii] * f[ii+1]) / dx2 * mixed + *\/ */
1258     /*     /\*     (f[ii+1] * g[ii+1]) / dx2 * right; *\/ */
1259     /*     /\* printf("%zu: integrand(%3.15g) = %3.15G\n", ii, x[ii], new_val); *\/ */
1260     /*     /\* value += new_val; *\/ */
1261     /*     value += (f[ii] * g[ii]) / dx2 * left + */
1262     /*              (f[ii] * g[ii+1]) / dx2 * mixed + */
1263     /*              (g[ii] * f[ii+1]) / dx2 * mixed + */
1264     /*              (f[ii+1] * g[ii+1]) / dx2 * right; */
1265     /* } */
1266 
1267     /* printf("nodes are "); */
1268     /* dprint(N, x); */
1269     // assuming quadratic not accurate when spacing is too large
1270     /* double value1 = 0.0; */
1271     /* for (size_t ii = 0; ii < N-1; ii++){ */
1272     /*     double m1 = (f[ii+1] - f[ii]) / (x[ii+1] - x[ii]); */
1273     /*     double m2 = (g[ii+1] - g[ii]) / (x[ii+1] - x[ii]); */
1274     /*     double d1 = (f[ii+1] - m1 * x[ii+1]); */
1275     /*     double d2 = (g[ii+1] - m2 * x[ii+1]); */
1276 
1277     /*     double t1 = d1*d2 * (x[ii+1] - x[ii]); */
1278     /*     double t2 = 0.5 * (d1 * m2 + m1 * d2) * (x[ii+1] * x[ii+1] - x[ii] * x[ii]); */
1279     /*     double t3 = m1 * m2 / 3.0 * (x[ii+1] * x[ii+1] * x[ii+1] - x[ii] * x[ii] * x[ii]); */
1280     /*     value1 += (t1 + t2 + t3); */
1281     /*     /\* printf("%zu: integrand(%3.15g) = %3.15G\n", ii, x[ii], value1); *\/ */
1282     /* } */
1283 
1284     /* printf("\n\n"); */
1285     double dx = x[1]-x[0];
1286     double value = f[0]*g[0]*dx * 0.5;
1287     /* printf("0: integrand(%3.15g) = %3.15G\n", x[0], value); */
1288     for (size_t ii = 1; ii < N-1; ii++){
1289         dx = x[ii+1]-x[ii-1];
1290         /* dx = x[ii+1]-x[ii]; */
1291         /* double new_val = f[ii]*g[ii]*0.5*dx; */
1292         value += f[ii]*g[ii]*0.5*dx;
1293         /* printf("%zu: integrand(%3.15g) = %3.15G\n", ii, x[ii], value); */
1294     }
1295     dx = x[N-1] - x[N-2];
1296     value += f[N-1]*g[N-1]*dx*0.5;
1297 
1298     /* printf("diff values is  = %3.15G\n", value1 - value); */
1299     return value;
1300 }
1301 
1302 /********************************************************//**
1303 *   Inner product between two functions
1304 *
1305 *   \param[in] f - function
1306 *   \param[in] g - function
1307 *
1308 *   \return inner product
1309 *************************************************************/
lin_elem_exp_inner(const struct LinElemExp * f,const struct LinElemExp * g)1310 double lin_elem_exp_inner(const struct LinElemExp * f,
1311                           const struct LinElemExp * g)
1312 {
1313 
1314     double value = 0.0;
1315     int samedisc = lin_elem_sdiscp(f,g);
1316     if (samedisc == 1){
1317 //        printf("here?!\n");
1318         /* if (f->diff == NULL){ */
1319         /*     compute_diff(f); */
1320         /* } */
1321         /* if (g->diff == NULL){ */
1322         /*     compute_diff(g); */
1323         /* } */
1324         value = lin_elem_exp_inner_same(f->num_nodes,f->nodes,
1325                                         f->coeff, g->coeff);
1326     }
1327     else{
1328 
1329         double xnew[10000];
1330         double fnew[10000];
1331         double gnew[10000];
1332         double * xuse,*fuse,*guse;
1333         double * xx = NULL;
1334         double * ff = NULL;
1335         double * gg = NULL;
1336         size_t n_new = f->num_nodes + g->num_nodes;
1337         if (n_new >= 10000){
1338             xx = calloc_double(n_new);
1339             ff = calloc_double(n_new);
1340             gg = calloc_double(n_new);
1341             xuse = xx;
1342             fuse = ff;
1343             guse = gg;
1344         }
1345         else{
1346             xuse = xnew;
1347             fuse = fnew;
1348             guse = gnew;
1349         }
1350 
1351         size_t nnodes = lin_elem_exp_inner_same_grid(f,g, xuse,fuse,guse);
1352         if (nnodes > 2){
1353             value = lin_elem_exp_inner_same(nnodes,xuse,fuse,guse);
1354         }
1355         else{
1356             printf("weird =\n");
1357             printf("f = \n");
1358             print_lin_elem_exp(f,3,NULL,stdout);
1359             printf("g = \n");
1360             print_lin_elem_exp(g,3,NULL,stdout);
1361             assert(1 == 0);
1362         }
1363 
1364         if ( xx != NULL){
1365             free(xx); xx = NULL;
1366             free(ff); ff = NULL;
1367             free(gg); gg = NULL;
1368         }
1369         //       printf("there\n");
1370     }
1371     return value;
1372 }
1373 
1374 /********************************************************//**
1375    Add two functions with same discretization levels
1376 
1377    \param[in] a - scaled value
1378    \param[in] f - function
1379    \param[in,out] g - function
1380 
1381    \returns 0 successful
1382             1 error
1383 
1384    \note
1385    Could be sped up by keeping track of evaluations
1386 *************************************************************/
lin_elem_exp_axpy_same(double a,const struct LinElemExp * f,struct LinElemExp * g)1387 static int lin_elem_exp_axpy_same(double a, const struct LinElemExp * f,
1388                                   struct LinElemExp * g)
1389 {
1390 
1391     cblas_daxpy(g->num_nodes,a,f->coeff,1,g->coeff,1);
1392     return 0;
1393 }
1394 
1395 
1396 /********************************************************//**
1397 *   Interpolate two linear element expansions onto the same grid
1398 *
1399 *   \param[in]     f - function
1400 *   \param[in]     g - function
1401 *   \param[in,out] x - interpolated nodes
1402 
1403 *   \return number of nodes
1404 
1405 *   \note
1406     x must be previously allocaed with enough space
1407     at least f->num_nodes + g->num_nodes is enough for a
1408     conservative allocation
1409 *************************************************************/
lin_elem_exp_interp_same_grid(const struct LinElemExp * f,const struct LinElemExp * g,double * x)1410 static size_t lin_elem_exp_interp_same_grid(
1411     const struct LinElemExp * f,
1412     const struct LinElemExp * g, double * x)
1413 {
1414     size_t nnodes = 0;
1415     size_t inodef = 0;
1416     size_t inodeg = 0;
1417 
1418     while ((inodef < f->num_nodes) || (inodeg < g->num_nodes)){
1419         if (inodef == f->num_nodes){
1420             x[nnodes] = g->nodes[inodeg];
1421             inodeg++;
1422             nnodes++;
1423         }
1424         else if (inodeg == g->num_nodes){
1425             x[nnodes] = f->nodes[inodef];
1426             inodef++;
1427             nnodes++;
1428         }
1429         else if (fabs(f->nodes[inodef] - g->nodes[inodeg]) < 1e-15){
1430             x[nnodes] = f->nodes[inodef];
1431             inodef++;
1432             inodeg++;
1433             nnodes++;
1434         }
1435         else if (f->nodes[inodef] < g->nodes[inodeg]){
1436             x[nnodes] = f->nodes[inodef];
1437             inodef++;
1438             nnodes++;
1439         }
1440         else if (g->nodes[inodeg] < f->nodes[inodef]){
1441             x[nnodes] = g->nodes[inodeg];
1442             inodeg++;
1443             nnodes++;
1444         }
1445     }
1446 
1447     return nnodes;
1448 }
1449 
1450 
1451 /********************************************************//**
1452    Add two functions
1453 
1454    \param[in] a - scaled value
1455    \param[in] f - function
1456    \param[in,out] g - function
1457 
1458    \returns 0 successful
1459             1 error
1460 
1461    \note
1462    Could be sped up by keeping track of evaluations
1463 *************************************************************/
lin_elem_exp_axpy(double a,const struct LinElemExp * f,struct LinElemExp * g)1464 int lin_elem_exp_axpy(double a,
1465                       const struct LinElemExp * f,
1466                       struct LinElemExp * g)
1467 {
1468 
1469     int res = 0;
1470     int samedisc = lin_elem_sdiscp(f,g);
1471     if (samedisc == 1){
1472         res = lin_elem_exp_axpy_same(a,f, g);
1473     }
1474     else{
1475         double * x = calloc_double(f->num_nodes+g->num_nodes);
1476         double * coeff = calloc_double(f->num_nodes+g->num_nodes);
1477         size_t num = lin_elem_exp_interp_same_grid(f,g,x);
1478 //        printf("interpolated!\n");
1479         for (size_t ii = 0; ii < num; ii++){
1480             coeff[ii] = a*lin_elem_exp_eval(f,x[ii]) +
1481                         lin_elem_exp_eval(g,x[ii]);
1482         }
1483 //        printf("good\n");
1484         g->num_nodes = num;
1485         free(g->nodes); g->nodes = x;
1486 //        printf("bad!\n");
1487         free(g->coeff); g->coeff = coeff;
1488 //        printf("word\n");
1489     }
1490     return res;
1491 }
1492 
1493 struct lefg
1494 {
1495     const struct LinElemExp * f;
1496     const struct LinElemExp * g;
1497 };
1498 
leprod(size_t N,const double * x,double * out,void * arg)1499 static int leprod(size_t N, const double * x,double * out, void * arg)
1500 {
1501     struct lefg * fg = arg;
1502     for (size_t ii = 0; ii < N; ii++){
1503         out[ii] = lin_elem_exp_eval(fg->f,x[ii]);
1504         out[ii] *= lin_elem_exp_eval(fg->g,x[ii]);
1505     }
1506     return 0;
1507 }
1508 
1509 /********************************************************//**
1510    Multiply two functions
1511 
1512    \param[in] f   - first function
1513    \param[in] g   - second function
1514 
1515    \returns product
1516 
1517    \note
1518 *************************************************************/
lin_elem_exp_prod(const struct LinElemExp * f,const struct LinElemExp * g)1519 struct LinElemExp * lin_elem_exp_prod(const struct LinElemExp * f,
1520                                       const struct LinElemExp * g)
1521 {
1522 
1523     double lb = f->nodes[0] < g->nodes[0] ? g->nodes[0] : f->nodes[0];
1524     double ub = f->nodes[f->num_nodes-1] > g->nodes[g->num_nodes-1] ? g->nodes[g->num_nodes-1] : f->nodes[f->num_nodes-1];
1525 
1526     struct lefg fg;
1527     fg.f = f;
1528     fg.g = g;
1529     struct LinElemExpAopts * opts = NULL;
1530     double hmin = 1e-3;
1531     double delta = 1e-4;
1532     int samedisc = lin_elem_sdiscp(f,g);
1533     if (samedisc == 1){
1534         opts = lin_elem_exp_aopts_alloc(f->num_nodes, f->nodes);
1535     }
1536     else{
1537         opts = lin_elem_exp_aopts_alloc_adapt(0,NULL,lb,ub,delta,hmin);
1538     }
1539 
1540 
1541     struct Fwrap * fw = fwrap_create(1,"general-vec");
1542     fwrap_set_fvec(fw,leprod,&fg);
1543 
1544     struct LinElemExp * prod = NULL;
1545     prod = lin_elem_exp_approx(opts,fw);
1546     fwrap_destroy(fw);
1547 
1548     lin_elem_exp_aopts_free(opts);
1549     return prod;
1550 }
1551 
1552 /********************************************************//**
1553     Compute the norm of a function
1554 
1555     \param[in] f - function
1556 
1557     \return norm
1558 *************************************************************/
lin_elem_exp_norm(const struct LinElemExp * f)1559 double lin_elem_exp_norm(const struct LinElemExp * f)
1560 {
1561     double norm = lin_elem_exp_inner(f,f);
1562     return sqrt(norm);
1563 }
1564 
1565 /********************************************************//**
1566     Compute the maximum of the function
1567 
1568     \param[in]     f - function
1569     \param[in,out] x - location of maximum
1570 
1571     \return value of maximum
1572 *************************************************************/
lin_elem_exp_max(const struct LinElemExp * f,double * x)1573 double lin_elem_exp_max(const struct LinElemExp * f, double * x)
1574 {
1575     double mval = f->coeff[0];
1576     *x = f->nodes[0];
1577     for (size_t ii = 1; ii < f->num_nodes;ii++){
1578         if (f->coeff[ii] > mval){
1579             mval = f->coeff[ii];
1580             *x = f->nodes[ii];
1581         }
1582     }
1583     return mval;
1584 }
1585 
1586 /********************************************************//**
1587     Compute the minimum of the function
1588 
1589     \param[in]     f - function
1590     \param[in,out] x - location of minimum
1591 
1592     \return value of minimum
1593 *************************************************************/
lin_elem_exp_min(const struct LinElemExp * f,double * x)1594 double lin_elem_exp_min(const struct LinElemExp * f, double * x)
1595 {
1596     double mval = f->coeff[0];
1597     *x = f->nodes[0];
1598     for (size_t ii = 1; ii < f->num_nodes;ii++){
1599         if (f->coeff[ii] < mval){
1600             mval = f->coeff[ii];
1601             *x = f->nodes[ii];
1602         }
1603     }
1604     return mval;
1605 }
1606 
1607 /********************************************************//**
1608     Compute the maximum of the absolute value function
1609 
1610     \param[in]     f       - function
1611     \param[in,out] x       - location of absolute value max
1612     \param[in]     size    - size of x variable (sizeof(double) or sizeof(size_t))
1613     \param[in]     optargs - optimization arguments
1614 
1615     \return value
1616 *************************************************************/
lin_elem_exp_absmax(const struct LinElemExp * f,void * x,size_t size,void * optargs)1617 double lin_elem_exp_absmax(const struct LinElemExp * f, void * x,
1618                            size_t size,
1619                            void * optargs)
1620 {
1621     if (optargs == NULL){
1622         size_t dsize = sizeof(double);
1623         double mval = fabs(f->coeff[0]);
1624         if (size == dsize){
1625             *(double *)(x) = f->nodes[0];
1626         }
1627         else{
1628             *(size_t *)(x) = 0;
1629         }
1630         for (size_t ii = 1; ii < f->num_nodes;ii++){
1631             if (fabs(f->coeff[ii]) > mval){
1632                 mval = fabs(f->coeff[ii]);
1633                 if (size == dsize){
1634                     *(double *)(x) = f->nodes[ii];
1635                 }
1636                 else{
1637                     *(size_t *)(x) = ii;
1638                 }
1639             }
1640         }
1641         return mval;
1642     }
1643     else{
1644         assert (size == sizeof(double));
1645         struct c3Vector * optnodes = optargs;
1646         double mval = fabs(lin_elem_exp_eval(f,optnodes->elem[0]));
1647         *(double *)(x) = optnodes->elem[0];
1648         for (size_t ii = 0; ii < optnodes->size; ii++){
1649             double val = fabs(lin_elem_exp_eval(f,optnodes->elem[ii]));
1650             if (val > mval){
1651                 mval = val;
1652                 *(double *)(x) = optnodes->elem[ii];
1653             }
1654         }
1655         return mval;
1656     }
1657 }
1658 
1659 /********************************************************//**
1660     Compute an error estimate
1661 
1662     \param[in]     f    - function
1663     \param[in,out] errs - errors for each element
1664     \param[in]     dir  - direction (1 for forward, -1 for backward)
1665     \param[in]     type - 0 for Linf, 2 for L2
1666 
1667     \return maximum error
1668 
1669     \note
1670     The error estimate consists of finite difference approximations
1671     to the second derivative of the function
1672     Left boundary always uses forward difference and
1673     right boundary always uses backward
1674 *************************************************************/
lin_elem_exp_err_est(struct LinElemExp * f,double * errs,short dir,short type)1675 double lin_elem_exp_err_est(struct LinElemExp * f, double * errs, short dir, short type)
1676 {
1677     assert (f->num_nodes > 2);
1678     double value = 0.0;
1679 
1680     double dx = (f->nodes[1]-f->nodes[0]);
1681     double dx2 = (f->nodes[2]-f->nodes[1]);
1682     double m1 = (f->coeff[1]-f->coeff[0])/dx;
1683     double mid1 = (f->nodes[1] + f->nodes[0])/2.0;
1684     double m2 = (f->coeff[2]-f->coeff[1])/dx2;
1685     double mid2 = (f->nodes[2] + f->nodes[1])/2.0;
1686     double err = (m2-m1)/(mid2-mid1);
1687     if (type == 0){
1688         errs[0] = pow(dx,2)*fabs(err)/8.0;
1689         value = errs[0];
1690     }
1691     else if (type == 2){
1692         errs[0] = pow(dx,2)*sqrt(pow(err,2)*dx)/8.0;
1693         value += errs[0];
1694     }
1695     dx = dx2;
1696     double m3,mid3;
1697     for (size_t ii = 2; ii < f->num_nodes-1; ii++){
1698         dx2 = (f->nodes[ii+1]-f->nodes[ii]);
1699         m3 = (f->coeff[ii+1]-f->coeff[ii]);
1700         mid3 = (f->nodes[ii+1] + f->nodes[ii])/2.0;
1701         if (dir == 1){
1702             err = (m3-m2)/(mid3-mid2);
1703         }
1704         else{
1705             err = (m2-m1)/(mid2-mid1);
1706         }
1707         if (type == 0){
1708             errs[ii-1] = pow(dx,2)*fabs(err)/8.0;
1709             if (errs[ii-1] > value){
1710                 value = errs[ii-1];
1711             }
1712         }
1713         else if (type == 2){
1714             errs[ii-1] = pow(dx,2)*sqrt(pow(err,2)*dx)/8.0;
1715             value += errs[ii-1];
1716         }
1717 
1718         m1 = m2;
1719         mid1 = mid2;
1720         m2 = m3;
1721         mid2 = mid3;
1722         dx = dx2;
1723     }
1724     err = (m2-m1)/(mid2-mid1);
1725     size_t ii = f->num_nodes-1;
1726     if (type == 0){
1727         errs[ii-1] = pow(dx,2)*fabs(err)/8.0;
1728         if (errs[ii-1] > value){
1729             value = errs[ii-1];
1730         }
1731     }
1732     else if (type == 2){
1733         errs[ii-1] = pow(dx,2)*sqrt(pow(err,2)*dx)/8.0;
1734         value += errs[ii-1];
1735     }
1736 
1737     return value;
1738 }
1739 
1740 /// @private
1741 struct LinElemXY
1742 {
1743     double x;
1744     double y;
1745     struct LinElemXY * next;
1746 };
1747 
1748 /// @private
xy_init(double x,double y)1749 struct LinElemXY * xy_init(double x, double y)
1750 {
1751     struct LinElemXY * xy = malloc(sizeof(struct LinElemXY));
1752     if (xy == NULL){
1753         fprintf(stderr,"Cannot allocate LinElemXY struct for lin element adapting\n");
1754         exit(1);
1755     }
1756 
1757     xy->x = x;
1758     xy->y = y;
1759     xy->next = NULL;
1760     return xy;
1761 }
1762 
1763 /// @private
xy_append(struct LinElemXY ** xy,double x,double y)1764 void xy_append(struct LinElemXY ** xy, double x, double y)
1765 {
1766 
1767     if (*xy == NULL){
1768         /* printf("xy is null so initialize\n"); */
1769         *xy = xy_init(x,y);
1770         /* printf("got it\n"); */
1771     }
1772     else{
1773         /* printf("xy == NULL = %d\n",xy==NULL); */
1774         /* printf("xy is not null!\n"); */
1775         struct LinElemXY * temp = *xy;
1776         /* printf("iterate\n"); */
1777         while (temp->next != NULL){
1778             /* printf("iterate\n"); */
1779             temp = temp->next;
1780         }
1781         /* printf("done iterating\n"); */
1782         temp->next = xy_init(x,y);
1783 
1784         /* if ((*xy)->next == NULL){ */
1785         /*     printf("next is null!\n"); */
1786         /*     (*xy)->next = xy_init(x,y); */
1787         /* } */
1788         /* else{ */
1789         /*     printf("next is not null!\n"); */
1790         /*     xy_append(&((*xy)->next),x,y); */
1791         /*     printf("appended next!\n"); */
1792         /* } */
1793         /* printf("got it2\n"); */
1794     }
1795 }
1796 
1797 /// @private
xy_concat(struct LinElemXY ** xy,struct LinElemXY * r)1798 void xy_concat(struct LinElemXY ** xy,struct LinElemXY * r)
1799 {
1800 
1801     if (*xy == NULL){
1802         *xy = r;
1803     }
1804     else{
1805         xy_concat(&((*xy)->next),r);
1806     }
1807 }
1808 
1809 /// @private
xy_last(struct LinElemXY * xy)1810 struct LinElemXY * xy_last(struct LinElemXY * xy)
1811 {
1812     if (xy == NULL){
1813         return NULL;
1814     }
1815     struct LinElemXY * temp = xy;
1816     while (temp->next != NULL){
1817         temp = temp->next;
1818     }
1819     return temp;
1820 }
1821 
1822 /// @private
lin_elem_xy_get_x(struct LinElemXY * xy)1823 double lin_elem_xy_get_x(struct LinElemXY * xy)
1824 {
1825     return xy->x;
1826 }
1827 
1828 /// @private
lin_elem_xy_get_y(struct LinElemXY * xy)1829 double lin_elem_xy_get_y(struct LinElemXY * xy)
1830 {
1831     return xy->y;
1832 }
1833 
1834 /// @private
lin_elem_xy_next(struct LinElemXY * xy)1835 struct LinElemXY * lin_elem_xy_next(struct LinElemXY * xy)
1836 {
1837     return xy->next;
1838 }
1839 
1840 /// @private
lin_elem_xy_length(struct LinElemXY * xy)1841 size_t lin_elem_xy_length(struct LinElemXY * xy)
1842 {
1843     size_t count = 0;
1844     struct LinElemXY * temp = xy;
1845     if (temp == NULL){
1846         return count;
1847     }
1848     while (temp!= NULL){
1849         count ++;
1850         temp = temp->next;
1851     }
1852     return count;
1853 }
1854 
1855 /// @private
lin_elem_xy_free(struct LinElemXY * xy)1856 void lin_elem_xy_free(struct LinElemXY * xy)
1857 {
1858     if (xy != NULL){
1859         lin_elem_xy_free(xy->next); xy->next = NULL;
1860         free(xy); xy = NULL;
1861     }
1862 }
1863 
1864 /********************************************************//**
1865     Recursively partition
1866 
1867     \param[in] f     - function
1868     \param[in] xl    - left bound
1869     \param[in] fl    - left evaluation
1870     \param[in] xr    - right bound
1871     \param[in] fr    - right evaluation
1872     \param[in] delta - value tolerance
1873     \param[in] hmin  - input tolerance
1874     \param[in] xy    - xypairs
1875 *************************************************************/
lin_elem_adapt(struct Fwrap * f,double xl,double fl,double xr,double fr,double delta,double hmin,struct LinElemXY ** xy)1876 void lin_elem_adapt(struct Fwrap * f,
1877                     double xl, double fl,double xr, double fr,
1878                     double delta, double hmin,struct LinElemXY ** xy)
1879 {
1880     //xy_append(xy,xl,fl);
1881     if ((xr - xl) <= hmin){
1882         /* printf("adapt is within bounds!\n"); */
1883         /* printf("adding left (xl,fl)=(%G,%G)\n",xl,fl); */
1884         xy_append(xy,xl,fl);
1885         /* printf("added left (xl,fl)=(%G,%G)\n",xl,fl); */
1886 
1887         xy_append(xy,xr,fr);
1888         /* printf("done!\n"); */
1889     }
1890     else{
1891         double mid = (xl+xr)/2.0;
1892         double fmid;
1893         fwrap_eval(1,&mid,&fmid,f);
1894         /* printf("xl = %3.15G, xr = %3.15G, fl = %3.15G, fr = %3.15G, fmid = %3.15G\n", xl, xr, fl, fr, fmid); */
1895         /* printf("adapt! diff=%3.15G, delta=%3.15G\n", (fl+fr)/2.0-fmid, delta); */
1896         if (fabs( (fl+fr)/2.0 - fmid  )/fabs(fmid) < delta){
1897         /* if (fabs( (fl+fr)/2.0 - fmid  ) < delta){ */
1898             // maybe should add the midpoint since evaluated
1899             /* printf("finish again! xy==null?=%d\n\n",xy==NULL); */
1900             /* printf("adding the left %G,%G\n",xl,fl); */
1901             xy_append(xy,xl,fl);
1902             xy_append(xy,mid,fmid);
1903             /* printf("added the left %G,%G\n",xl,fl); */
1904             /* printf("adding the right %G,%G\n",xr,fr); */
1905             xy_append(xy,xr,fr);
1906             /* printf("added the right %G,%G\n",xr,fr); */
1907         }
1908         else{
1909             /* printf("adapt further\n"); */
1910             lin_elem_adapt(f,xl,fl,mid,fmid,delta,hmin,xy);
1911             struct LinElemXY * last = NULL;//xy_last(*xy);
1912             lin_elem_adapt(f,mid,fmid,xr,fr,delta,hmin,&last);
1913             if (last != NULL){
1914                 xy_concat(xy,last->next);
1915                 free(last);
1916             }
1917         }
1918     }
1919 }
1920 
1921 
1922 /********************************************************//**
1923     Approximate a function
1924 
1925     \param[in] opts - approximation options
1926     \param[in] f    - function
1927 
1928     \return Approximated function
1929 *************************************************************/
1930 struct LinElemExp *
lin_elem_exp_approx(struct LinElemExpAopts * opts,struct Fwrap * f)1931 lin_elem_exp_approx(struct LinElemExpAopts * opts, struct Fwrap * f)
1932 {
1933 
1934     assert(opts != NULL);
1935     struct LinElemExp * lexp = lin_elem_exp_alloc();
1936     if (opts->adapt == 0){
1937         assert (opts->nodes != NULL);
1938 
1939         // allocate nodes and coefficients
1940         size_t N = opts->num_nodes;
1941         lexp->num_nodes = N;
1942         lexp->nodes = calloc_double(N);
1943         lexp->coeff = calloc_double(N);
1944 
1945 	/* printf("in approx: lin_elem_exp_aopts nodes = "); dprint(N,opts->nodes); */
1946         // copy nodes from options
1947         memmove(lexp->nodes,opts->nodes,N*sizeof(double));
1948 
1949         // evaluate the function
1950         /* printf("evaluate points\n"); */
1951         /* dprint(N,lexp->nodes); */
1952         fwrap_eval(N,lexp->nodes,lexp->coeff,f);
1953 
1954         if (fabs(lexp->nodes[0] - opts->nodes[0]) > 1e-15){
1955             fprintf(stderr, "In lin_elem_exp_approx\n");
1956             fprintf(stderr,"N nodes %zu\n",N);
1957             fprintf(stderr,"First approx_opt_node is %G\n",opts->nodes[0]);
1958             fprintf(stderr,"First expansion opt_node is %G\n",lexp->nodes[0]);
1959             exit(1);
1960         }
1961         /* printf("cannot evaluate them"); */
1962     }
1963     else{
1964         /* printf("adapting!\n"); */
1965         /* printf("not here!\n"); */
1966         // adapt
1967         struct LinElemXY * xy = NULL;
1968         if (opts->nodes == NULL){ // no nodes yet specified
1969             double xl = opts->lb;
1970             double xr = opts->ub;
1971             double fl,fr;
1972             fwrap_eval(1,&xl,&fl,f);
1973             fwrap_eval(1,&xr,&fr,f);
1974 
1975             lin_elem_adapt(f,xl,fl,xr,fr,opts->delta,opts->hmin,&xy);
1976             lexp->num_nodes = lin_elem_xy_length(xy);
1977             lexp->nodes = calloc_double(lexp->num_nodes);
1978             lexp->coeff = calloc_double(lexp->num_nodes);
1979             struct LinElemXY * temp = xy;
1980             for (size_t ii = 0; ii < lexp->num_nodes; ii++){
1981                 lexp->nodes[ii] = temp->x;
1982                 lexp->coeff[ii] = temp->y;
1983                 temp = temp->next;
1984             }
1985             lin_elem_xy_free(xy); xy = NULL;
1986         }
1987         else{
1988             // starting nodes specified
1989             assert (opts->num_nodes > 1);
1990             double xl = opts->nodes[0];
1991             double xr = opts->nodes[1];
1992 
1993             double fl,fr;
1994             fwrap_eval(1,&xl,&fl,f);
1995             fwrap_eval(1,&xr,&fr,f);
1996 
1997             lin_elem_adapt(f,xl,fl,xr,fr,opts->delta,opts->hmin,&xy);
1998             for (size_t ii = 2; ii < opts->num_nodes; ii++){
1999                 /* printf("on node = %zu\n",ii); */
2000                 xl = xr;
2001                 fl = fr;
2002 
2003                 xr = opts->nodes[ii];
2004                 fwrap_eval(1,&xr,&fr,f);
2005 
2006                 /* printf("(xl,fl,xr,fr)=(%G,%G,%G,%G)\n",xl,fl,xr,fr); */
2007                 struct LinElemXY * temp = NULL;
2008                 lin_elem_adapt(f,xl,fl,xr,fr,opts->delta,opts->hmin,&temp);
2009                 /* printf("adapted\n"); */
2010                 if (temp != NULL){
2011                     xy_concat(&xy,temp->next);
2012                     free(temp);
2013                 }
2014             }
2015             /* printf("finished here\n"); */
2016             lexp->num_nodes = lin_elem_xy_length(xy);
2017             lexp->nodes = calloc_double(lexp->num_nodes);
2018             lexp->coeff = calloc_double(lexp->num_nodes);
2019             struct LinElemXY * temp = xy;
2020             for (size_t ii = 0; ii < lexp->num_nodes; ii++){
2021                 lexp->nodes[ii] = temp->x;
2022                 lexp->coeff[ii] = temp->y;
2023                 temp = temp->next;
2024             }
2025             lin_elem_xy_free(xy); xy = NULL;
2026         }
2027 
2028     }
2029 
2030     assert (lexp->num_nodes != 0);
2031     return lexp;
2032 }
2033 
2034 /********************************************************//**
2035     Return a zero function
2036 
2037     \param[in] opts        - extra arguments depending on function_class, sub_type, etc.
2038     \param[in] force_param - if == 1 then approximation will have the number of parameters
2039                                      defined by *get_nparams, for each approximation type
2040                              if == 0 then it may be more compressed
2041 
2042     \return p - zero function
2043 ************************************************************/
2044 struct LinElemExp *
lin_elem_exp_zero(const struct LinElemExpAopts * opts,int force_param)2045 lin_elem_exp_zero(const struct LinElemExpAopts * opts, int force_param)
2046 {
2047 
2048     struct LinElemExp * lexp = NULL;
2049     if (force_param == 0){
2050         lexp = lin_elem_exp_constant(0.0,opts);
2051     }
2052     else{
2053         lexp = lin_elem_exp_alloc();
2054         if (opts->num_nodes == 0){
2055             lexp->num_nodes = 2;
2056             lexp->nodes = linspace(opts->lb,opts->ub,2);
2057         }
2058         else{
2059             lexp->num_nodes = opts->num_nodes;
2060             lexp->nodes = calloc_double(opts->num_nodes);
2061             memmove(lexp->nodes,opts->nodes,opts->num_nodes*sizeof(double));
2062         }
2063         lexp->coeff = calloc_double(lexp->num_nodes);
2064         for (size_t ii = 0; ii < lexp->num_nodes; ii++){
2065             lexp->coeff[ii] = 0.0;
2066         }
2067     }
2068     return lexp;
2069 }
2070 
2071 
2072 /********************************************************//**
2073     Create a constant function
2074 
2075     \param[in] a  - function value
2076     \param[in] opts  - options
2077 
2078     \return function
2079 *************************************************************/
2080 struct LinElemExp *
lin_elem_exp_constant(double a,const struct LinElemExpAopts * opts)2081 lin_elem_exp_constant(double a,
2082                       const struct LinElemExpAopts * opts)
2083 {
2084 
2085     struct LinElemExp * lexp = lin_elem_exp_alloc();
2086     if (opts->num_nodes == 0){
2087         lexp->num_nodes = 2;
2088         lexp->nodes = linspace(opts->lb,opts->ub,2);
2089     }
2090     else{
2091         lexp->num_nodes = opts->num_nodes;
2092         lexp->nodes = calloc_double(opts->num_nodes);
2093         memmove(lexp->nodes,opts->nodes,opts->num_nodes*sizeof(double));
2094     }
2095     lexp->coeff = calloc_double(lexp->num_nodes);
2096     for (size_t ii = 0; ii < lexp->num_nodes; ii++){
2097         lexp->coeff[ii] = a;
2098     }
2099     assert (lexp->num_nodes != 0);
2100     return lexp;
2101 }
2102 
2103 /********************************************************//**
2104     Create a linear function
2105     \f[
2106         y = ax + b
2107     \f]
2108 
2109     \param[in] a    - function value
2110     \param[in] b    - y intercept
2111     \param[in] opts - options
2112 
2113     \return function
2114 *************************************************************/
2115 struct LinElemExp *
lin_elem_exp_linear(double a,double b,const struct LinElemExpAopts * opts)2116 lin_elem_exp_linear(double a, double b,
2117                     const struct LinElemExpAopts * opts)
2118 {
2119 
2120     struct LinElemExp * lexp = lin_elem_exp_alloc();
2121     if (opts->num_nodes == 0){
2122         lexp->num_nodes = 2;
2123         lexp->nodes = linspace(opts->lb,opts->ub,2);
2124     }
2125     else{
2126         lexp->num_nodes = opts->num_nodes;
2127         lexp->nodes = calloc_double(opts->num_nodes);
2128         memmove(lexp->nodes,opts->nodes,opts->num_nodes*sizeof(double));
2129     }
2130     lexp->coeff = calloc_double(lexp->num_nodes);
2131     for (size_t ii = 0; ii < lexp->num_nodes; ii++){
2132         lexp->coeff[ii] = a * lexp->nodes[ii] + b;
2133     }
2134     assert (lexp->num_nodes != 0);
2135     return lexp;
2136 }
2137 
2138 /*******************************************************//**
2139     Update a linear function
2140 
2141     \param[in] f      - existing linear function
2142     \param[in] a      - slope of the function
2143     \param[in] offset - offset of the function
2144 
2145     \returns 0 if successfull, 1 otherwise
2146 ***********************************************************/
2147 int
lin_elem_exp_linear_update(struct LinElemExp * f,double a,double offset)2148 lin_elem_exp_linear_update(struct LinElemExp * f,
2149                            double a, double offset)
2150 {
2151     (void) f;
2152     (void) a;
2153     (void) offset;
2154     NOT_IMPLEMENTED_MSG("lin_elem_exp_linear_update");
2155     return 1;
2156 }
2157 
2158 
2159 /********************************************************//**
2160     Return a quadratic function a * (x - offset)^2 = a (x^2 - 2offset x + offset^2)
2161 
2162     \param[in] a      - quadratic coefficients
2163     \param[in] offset - shift of the function
2164     \param[in] opts  - extra arguments depending on function_class, sub_type,  etc.
2165 
2166     \return quadratic
2167 *************************************************************/
2168 struct LinElemExp *
lin_elem_exp_quadratic(double a,double offset,const struct LinElemExpAopts * opts)2169 lin_elem_exp_quadratic(double a, double offset,
2170                        const struct LinElemExpAopts * opts)
2171 {
2172     (void)(a);
2173     (void)(offset);
2174     (void)(opts);
2175     NOT_IMPLEMENTED_MSG("lin_elem_exp_quadratic");
2176     return NULL;
2177 }
2178 
2179 /********************************************************//**
2180     Multiply by -1
2181 
2182     \param[in,out] f - function
2183 *************************************************************/
lin_elem_exp_flip_sign(struct LinElemExp * f)2184 void lin_elem_exp_flip_sign(struct LinElemExp * f)
2185 {
2186     for (size_t ii = 0; ii < f->num_nodes; ii++){
2187         f->coeff[ii] *= -1.0;
2188     }
2189     assert (f->num_nodes != 0);
2190 }
2191 
2192 /********************************************************//**
2193     Generate an orthonormal basis
2194 
2195     \param[in]     n    - number of basis function
2196     \param[in,out] f    - linear element expansions with allocated nodes
2197                           and coefficients set to zero
2198     \param[in]     opts - approximation options
2199 
2200     \note
2201     Uses modified gram schmidt to determine function coefficients
2202     Each function f[ii] must have the same nodes
2203 *************************************************************/
lin_elem_exp_orth_basis(size_t n,struct LinElemExp ** f,struct LinElemExpAopts * opts)2204 void lin_elem_exp_orth_basis(size_t n, struct LinElemExp ** f, struct LinElemExpAopts * opts)
2205 {
2206     assert (opts != NULL);
2207 
2208     if (opts->adapt == 0){
2209         assert (opts->nodes != NULL);
2210         /* assert (n <= opts->num_nodes); */
2211         double * zeros = calloc_double(opts->num_nodes);
2212         /* double * zeros = calloc_double(n); */
2213         /* double * nodes = linspace(opts->lb, opts->ub, n); */
2214         for (size_t ii = 0; ii < n; ii++){
2215             f[ii] = lin_elem_exp_init(opts->num_nodes,opts->nodes,zeros);
2216             /* f[ii] = lin_elem_exp_init(n,opts->nodes,zeros); */
2217             if (ii < opts->num_nodes){
2218                 f[ii]->coeff[ii] = 1.0;
2219             }
2220         }
2221         /* free(nodes); nodes = NULL; */
2222         double norm, proj;
2223         for (size_t ii = 0; ii < n; ii++){
2224             norm = lin_elem_exp_norm(f[ii]);
2225             if (norm > 1e-200){
2226                 lin_elem_exp_scale(1/norm,f[ii]);
2227                 assert (f[ii]->num_nodes != 0);
2228                 for (size_t jj = ii+1; jj < n; jj++){
2229                     proj = lin_elem_exp_inner(f[ii],f[jj]);
2230                     lin_elem_exp_axpy(-proj,f[ii],f[jj]);
2231                 }
2232             }
2233         }
2234 
2235 
2236         /* for (size_t ii = n) */
2237         free(zeros); zeros = NULL;
2238     }
2239     else{
2240         // not on a grid I can do whatever I want
2241         assert (n > 1);
2242         double * nodes = linspace(opts->lb,opts->ub,n);
2243         double * zeros = calloc_double(n);
2244         for (size_t ii = 0; ii < n; ii++){
2245             f[ii] = lin_elem_exp_init(n,nodes,zeros);
2246             f[ii]->coeff[ii] = 1.0;
2247         }
2248         double norm, proj;
2249         for (size_t ii = 0; ii < n; ii++){
2250             norm = lin_elem_exp_norm(f[ii]);
2251             lin_elem_exp_scale(1/norm,f[ii]);
2252             assert (f[ii]->num_nodes != 0);
2253             for (size_t jj = ii+1; jj < n; jj++){
2254                 proj = lin_elem_exp_inner(f[ii],f[jj]);
2255                 lin_elem_exp_axpy(-proj,f[ii],f[jj]);
2256             }
2257 
2258         }
2259         free(zeros); zeros = NULL;
2260         free(nodes); nodes = NULL;
2261     }
2262 
2263 
2264     /* double norm, proj; */
2265     /* for (size_t ii = 0; ii < n; ii++){ */
2266     /*     assert (f[ii]->num_nodes >= n); */
2267     /*     f[ii]->coeff[ii] = 1.0;         */
2268     /* } */
2269     /* for (size_t ii = 0; ii < n; ii++){ */
2270     /*     norm = lin_elem_exp_norm(f[ii]); */
2271     /*     lin_elem_exp_scale(1/norm,f[ii]); */
2272     /*     for (size_t jj = ii+1; jj < n; jj++){ */
2273     /*         proj = lin_elem_exp_inner(f[ii],f[jj]); */
2274     /*         lin_elem_exp_axpy(-proj,f[ii],f[jj]); */
2275     /*     } */
2276     /* } */
2277 }
2278 
2279 /********************************************************//**
2280    Scale a function
2281 
2282    \param[in]     a - value
2283    \param[in,out] f - function
2284 *************************************************************/
lin_elem_exp_scale(double a,struct LinElemExp * f)2285 void lin_elem_exp_scale(double a, struct LinElemExp * f)
2286 {
2287     for (size_t ii = 0; ii < f->num_nodes; ii++){
2288         f->coeff[ii] *= a;
2289     }
2290 }
2291 
2292 /********************************************************//**
2293     Get lower bound
2294 
2295     \param[in] f - function
2296 
2297     \return lower bound
2298 *************************************************************/
lin_elem_exp_get_lb(struct LinElemExp * f)2299 double lin_elem_exp_get_lb(struct LinElemExp * f)
2300 {
2301     return f->nodes[0];
2302 }
2303 
2304 /********************************************************//**
2305     Get upper bound
2306 
2307     \param[in] f - function
2308 
2309     \return upper bound
2310 *************************************************************/
lin_elem_exp_get_ub(struct LinElemExp * f)2311 double lin_elem_exp_get_ub(struct LinElemExp * f)
2312 {
2313     return f->nodes[f->num_nodes-1];
2314 }
2315 
2316 
compare_le(const void * a,const void * b)2317 static int compare_le (const void * a, const void * b)
2318 {
2319     const double * aa = a;
2320     const double * bb = b;
2321     if (*aa > *bb){
2322         return 1;
2323     }
2324     else{
2325         return 0;
2326     }
2327 }
2328 
2329 /********************************************************//**
2330     Create a linear element function with zeros at particular
2331     locations and 1 everyhwhere else.
2332 
2333     \param[in] nzeros    - number of zeros
2334     \param[in] zero_locs - locations of zeros
2335     \param[in] opts      - linear expansion options
2336 
2337     \return upper bound
2338 *************************************************************/
2339 struct LinElemExp *
lin_elem_exp_onezero(size_t nzeros,double * zero_locs,struct LinElemExpAopts * opts)2340 lin_elem_exp_onezero(size_t nzeros, double * zero_locs,
2341                      struct LinElemExpAopts * opts)
2342 {
2343     assert (opts != NULL);
2344     if (opts->adapt == 1){
2345         // can do whatever I want
2346         if (nzeros == 0){
2347             double * nodes = calloc_double(2);
2348             double * coeff = calloc_double(2);
2349             struct LinElemExp * le = lin_elem_exp_init(2,nodes,coeff);
2350             le->coeff[0] = 1.0;
2351             free(nodes); nodes = NULL;
2352             free(coeff); coeff = NULL;
2353             /* print_lin_elem_exp(le,3,NULL,stdout); */
2354             return le;
2355         }
2356         else{
2357             struct LinElemExp * le = NULL;
2358             double * sorted_arr = calloc_double(nzeros);
2359             memmove(sorted_arr,zero_locs,nzeros*sizeof(double));
2360             qsort (sorted_arr, nzeros, sizeof(double), compare_le);
2361 
2362             int onlb = 0;
2363             int onub = 0;
2364             double difflb = fabs(sorted_arr[0]-opts->lb);
2365             if (difflb < 1e-14){
2366                 onlb = 1;
2367             }
2368             double diffub = fabs(zero_locs[nzeros-1]-opts->ub);
2369             if (diffub < 1e-14){
2370                 onub = 1;
2371             }
2372             if ((onlb == 0) && (onub == 0)){
2373                 double * nodes = calloc_double(nzeros+2);
2374                 double * coeff = calloc_double(nzeros+2);
2375                 nodes[0] = opts->lb;
2376                 coeff[0] = 0.0;
2377                 for (size_t jj = 1; jj < nzeros+1; jj++){
2378                     nodes[jj] = sorted_arr[jj-1];
2379                     coeff[jj] = 0.0;
2380                 }
2381                 nodes[nzeros+1] = opts->ub;
2382                 coeff[nzeros+1] = 1.0;
2383                 le = lin_elem_exp_init(nzeros+2,nodes,coeff);
2384                 free(nodes); nodes = NULL;
2385                 free(coeff); coeff = NULL;
2386             }
2387             else if ((onlb == 1) && (onub == 1)){
2388                 double * nodes = calloc_double(nzeros+1);
2389                 double * coeff = calloc_double(nzeros+1);
2390                 nodes[0] = opts->lb;
2391                 coeff[0] = 0.0;
2392                 nodes[1] = (opts->lb + sorted_arr[1])/2.0;
2393                 coeff[1] = 1.0;
2394                 for (size_t jj = 2; jj< nzeros+1; jj++){
2395                     nodes[jj] = sorted_arr[jj-1];
2396                     coeff[jj] = 0.0;
2397                 }
2398                 le = lin_elem_exp_init(nzeros+1,nodes,coeff);
2399                 free(nodes); nodes = NULL;
2400                 free(coeff); coeff = NULL;
2401             }
2402             else if ((onlb == 1) && (onub == 0)){
2403                 double * nodes = calloc_double(nzeros+1);
2404                 double * coeff = calloc_double(nzeros+1);
2405                 nodes[0] = opts->lb;
2406                 coeff[0] = 0.0;
2407                 for (size_t jj = 1; jj < nzeros; jj++){
2408                     nodes[jj] = sorted_arr[jj-1];
2409                     coeff[jj] = 0.0;
2410                 }
2411                 nodes[nzeros] = opts->ub;
2412                 coeff[nzeros] = 1.0;
2413                 le = lin_elem_exp_init(nzeros+1,nodes,coeff);
2414                 free(nodes); nodes = NULL;
2415                 free(coeff); coeff = NULL;
2416             }
2417             else if ((onlb == 0) && (onub == 1)){
2418                 double * nodes = calloc_double(nzeros+1);
2419                 double * coeff = calloc_double(nzeros+1);
2420                 nodes[0] = opts->lb;
2421                 coeff[0] = 1.0;
2422                 for (size_t jj = 1; jj< nzeros+1; jj++){
2423                     nodes[jj] = sorted_arr[jj-1];
2424                     coeff[jj] = 0.0;
2425                 }
2426                 le = lin_elem_exp_init(nzeros+1,nodes,coeff);
2427                 free(nodes); nodes = NULL;
2428                 free(coeff); coeff = NULL;
2429             }
2430             else{
2431                 assert (1 == 0);
2432             }
2433             /* print_lin_elem_exp(le,3,NULL,stdout); */
2434             return le;
2435         }
2436     }
2437     else{
2438         assert(opts->nodes != NULL);
2439         assert(opts->num_nodes > nzeros);
2440         double * coeff = calloc_double(opts->num_nodes);
2441         struct LinElemExp * le = lin_elem_exp_init(opts->num_nodes, opts->nodes, coeff);
2442         for (size_t ii = 0; ii < opts->num_nodes; ii++){
2443             int nonzero = 1;
2444             for (size_t jj = 0; jj < nzeros; jj++){
2445                 if (fabs(le->nodes[ii] - zero_locs[jj]) < 1e-14){
2446                     nonzero = 0;
2447                     break;
2448                 }
2449             }
2450             if (nonzero == 1){
2451                 le->coeff[ii] = 1.0;
2452             }
2453         }
2454         free(coeff);
2455         return le;
2456     }
2457 }
2458 
2459 /********************************************************//**
2460     Print a linear element function
2461 
2462     \param[in] f      - linear element function
2463     \param[in] args   - extra arguments (not used I think)
2464     \param[in] prec   - precision with which to save it
2465     \param[in] stream - stream to print to
2466 ************************************************************/
print_lin_elem_exp(const struct LinElemExp * f,size_t prec,void * args,FILE * stream)2467 void print_lin_elem_exp(const struct LinElemExp * f, size_t prec,
2468                         void * args, FILE * stream)
2469 {
2470     if (f == NULL){
2471         fprintf(stream, "Lin Elem Expansion is NULL\n");
2472     }
2473     else{
2474         assert (args == NULL);
2475         fprintf(stream, "Lin Elem Expansion: num_nodes=%zu\n",f->num_nodes);
2476         for (size_t ii = 0; ii < f->num_nodes; ii++){
2477             if (prec < 100){
2478                 fprintf(stream, "(%3.*G,%3.*G)  ",(int)prec,f->nodes[ii],
2479                         (int)prec,f->coeff[ii]);
2480             }
2481         }
2482         fprintf(stream,"\n");
2483     }
2484 }
2485 
2486 /********************************************************//**
2487     Save a linear element expansion in text format
2488 
2489     \param[in] f      - function to save
2490     \param[in] stream - stream to save it to
2491     \param[in] prec   - precision with which to save it
2492 ************************************************************/
lin_elem_exp_savetxt(const struct LinElemExp * f,FILE * stream,size_t prec)2493 void lin_elem_exp_savetxt(const struct LinElemExp * f,
2494                           FILE * stream, size_t prec)
2495 {
2496     assert (f != NULL);
2497     fprintf(stream,"%zu ",f->num_nodes);
2498     for (size_t ii = 0; ii < f->num_nodes; ii++){
2499         if (prec < 100){
2500             fprintf(stream, "%3.*G ",(int)prec,f->nodes[ii]);
2501             fprintf(stream, "%3.*G ",(int)prec,f->coeff[ii]);
2502         }
2503     }
2504 }
2505 
2506 /********************************************************//**
2507     Load a linear element expansion in text format
2508 
2509     \param[in] stream - stream to save it to
2510 
2511     \return Linear Element Expansion
2512 ************************************************************/
lin_elem_exp_loadtxt(FILE * stream)2513 struct LinElemExp * lin_elem_exp_loadtxt(FILE * stream)//, size_t prec)
2514 {
2515     size_t num_nodes;
2516 
2517     int num = fscanf(stream,"%zu ",&num_nodes);
2518     assert (num == 1);
2519     /* printf("number of nodes read = %zu\n",num_nodes); */
2520     double * nodes = calloc_double(num_nodes);
2521     double * coeff = calloc_double(num_nodes);
2522     for (size_t ii = 0; ii < num_nodes; ii++){
2523         num = fscanf(stream,"%lG",nodes+ii);
2524         assert (num == 1);
2525         num = fscanf(stream,"%lG",coeff+ii);
2526         assert (num == 1);
2527     };
2528     struct LinElemExp * lexp = lin_elem_exp_init(num_nodes,nodes,coeff);
2529     free(nodes); nodes = NULL;
2530     free(coeff); coeff = NULL;
2531     return lexp;
2532 }
2533 
2534