heat_transfer_and_melt_elements.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 // Header file for elements that are used to solar/Stefan Boltzmann radiation
27 // and melting processes
28 
29 #ifndef OOMPH_HEAT_TRANSFER_AND_MELT_ELEMENTS_HEADER
30 #define OOMPH_HEAT_TRANSFER_AND_MELT_ELEMENTS_HEADER
31 
32 // Config header generated by autoconfig
33 #ifdef HAVE_CONFIG_H
34  #include <oomph-lib-config.h>
35 #endif
36 
37 //Standard libray headers
38 #include <cmath>
39 
40 // oomph-lib includes
41 #include "generic.h" // ../generic/Qelements.h"
42 
43 
44 namespace oomph
45 {
46 
47 // hierher
48 
49 /* //=======start_namespace========================================== */
50 /* /// Namespace for intersection checker */
51 /* //================================================================ */
52 /* namespace IntersectionChecker */
53 /* { */
54 
55 /* /// Check if finite-length line segments specified by end points */
56 /* /// intersect (true) or not (false). From */
57 /* /// http://paulbourke.net/geometry/lineline2d/ */
58 /* /// C++ contribution by Damian Coventry. */
59 /* bool intersects(const Vector<Vector<double> >& first_segment_vertex, */
60 /* const Vector<Vector<double> >& second_segment_vertex, */
61 /* const double& epsilon_parallel=1.0e-15) */
62 /* { */
63 
64 /* double denom = ((first_segment_vertex[1][1] - first_segment_vertex[0][1])* */
65 /* (second_segment_vertex[1][0] - second_segment_vertex[0][0])) - */
66 /* ((first_segment_vertex[1][0] - first_segment_vertex[0][0])* */
67 /* (second_segment_vertex[1][1] - second_segment_vertex[0][1])); */
68 
69 /* double nume_a = ((first_segment_vertex[1][0] - first_segment_vertex[0][0])* */
70 /* (second_segment_vertex[0][1] - first_segment_vertex[0][1])) - */
71 /* ((first_segment_vertex[1][1] - first_segment_vertex[0][1])* */
72 /* (second_segment_vertex[0][0] - first_segment_vertex[0][0])); */
73 
74 /* double nume_b = ((second_segment_vertex[1][0] - second_segment_vertex[0][0])* */
75 /* (second_segment_vertex[0][1] - first_segment_vertex[0][1])) - */
76 /* ((second_segment_vertex[1][1] - second_segment_vertex[0][1])* */
77 /* (second_segment_vertex[0][0] - first_segment_vertex[0][0])); */
78 
79 /* if(std::fabs(denom) < epsilon_parallel) */
80 /* { */
81 /* if( (std::fabs(nume_a) < epsilon_parallel) && */
82 /* (std::fabs(nume_b) < epsilon_parallel) ) */
83 /* { */
84 /* return false; //COINCIDENT; */
85 /* } */
86 /* return false; //PARALLEL; */
87 /* } */
88 
89 /* double ua = nume_a / denom; */
90 /* double ub = nume_b / denom; */
91 
92 /* if( (ua >= 0.0) && (ua <= 1.0) && (ub >= 0.0) && (ub <= 1.0) ) */
93 /* { */
94 /* /\* // Get the intersection point. *\/ */
95 /* /\* intersection[0] = second_segment_vertex[0][0] + *\/ */
96 /* /\* ua*(second_segment_vertex[1][0] - second_segment_vertex[0][0]); *\/ */
97 /* /\* intersection[1] = second_segment_vertex[0][1] + *\/ */
98 /* /\* ua*(second_segment_vertex[1][1] - second_segment_vertex[0][1]); *\/ */
99 
100 /* return true; //INTERESECTING; */
101 /* } */
102 
103 /* return false; //NOT_INTERESECTING; */
104 /* } */
105 
106 /* } */
107 
108 //end hierher
109 
113 
114 
115 
116 
117 //======================================================================
121 //======================================================================
123  {
124 
125  public:
126 
127 
132  typedef void (*UnsteadyHeatPrescribedFluxFctPt)(const double& time,
133  const Vector<double>& x,
134  const Vector<double>& n,
135  const double& u,
136  double& flux);
137 
140  Dim(0), Flux_fct_pt(0)
141  {}
142 
145 
148 
149  protected:
150 
159  virtual void get_flux(const unsigned& ipt,
160  const double& time,
161  const Vector<double>& x,
162  const Vector<double>& n,
163  const double& u,
164  double& flux)
165  {
166  //If the function pointer is zero return zero
167  if(Flux_fct_pt == 0)
168  {
169  flux=0.0;
170  }
171  //Otherwise call the function
172  else
173  {
174  (*Flux_fct_pt)(time,x,n,u,flux);
175  }
176  }
177 
180 
182  unsigned Dim;
183 
186 
187 };
188 
189 
190 
194 
195 // hierher
196 
197 /* //======================================================================= */
198 /* /// Namespace containing default function that provides zero */
199 /* /// atmospheric radiation */
200 /* //======================================================================= */
201 /* namespace SolarRadiationHelper */
202 /* { */
203 
204 /* //======================================================================= */
205 /* /// Default analytical radiation function in terms of time, position on */
206 /* /// melting surface and its outer unit normal; returns zero. */
207 /* //======================================================================= */
208 /* void Zero_analytical_radiation_fct(const double& time, */
209 /* const Vector<double> &x, */
210 /* const Vector<double>& N, */
211 /* double& radiation) */
212 /* { */
213 /* radiation=0.0; */
214 /* } */
215 
216 
217 /* //======================================================================= */
218 /* /// Default atmospheric radiation function in terms of time */
219 /* //======================================================================= */
220 /* void Zero_atmospheric_radiation_fct(const double& time, */
221 /* double& solar_flux_magnitude, */
222 /* Vector<double> &solar_flux_unit_vector, */
223 /* double& total_diffuse_radiation) */
224 /* { */
225 /* solar_flux_magnitude=0.0; */
226 /* solar_flux_unit_vector[0]= 0.0; */
227 /* solar_flux_unit_vector[1]=-1.0; */
228 /* total_diffuse_radiation=0.0; */
229 /* } */
230 
231 /* } */
232 
233 // end hierher
234 
238 
239 
240 // hierher
241 
242 /* //====================================================================== */
243 /* /// Base class for elements that are illuminated by solar radiation */
244 /* //====================================================================== */
245 /* class SolarRadiationBase : public virtual FiniteElement, */
246 /* public virtual FaceElement */
247 /* { */
248 
249 /* public: */
250 
251 /* /// Constructor */
252 /* SolarRadiationBase() */
253 /* { */
254 /* // Assign default zero analytical radiation fct... */
255 /* Analytical_radiation_fct_pt= */
256 /* &SolarRadiationHelper::Zero_analytical_radiation_fct; */
257 
258 /* // ...but don't use it */
259 /* Use_analytical_radiation_fct=false; */
260 
261 /* // Don't use tanh profile to smooth solar shadows */
262 /* Smoothed_sun_shadow=false; */
263 
264 /* // Factor for tanh profile to smooth solar shadows */
265 /* Alpha_tanh_smooth_sun_shadow=100.0; */
266 
267 /* // Assign default zero atmospheric radiation fct... */
268 /* Atmospheric_radiation_fct_pt= */
269 /* &SolarRadiationHelper::Zero_atmospheric_radiation_fct; */
270 
271 /* // Make space for limiting angles for diffuse radiation */
272 /* unsigned n_intpt = integral_pt()->nweight(); */
273 /* Diffuse_limit_angles.resize(n_intpt); */
274 /* for (unsigned i=0;i<n_intpt;i++) */
275 /* { */
276 /* Diffuse_limit_angles[i].first=0.0; */
277 /* Diffuse_limit_angles[i].second=MathematicalConstants::Pi; */
278 /* } */
279 /* } */
280 
281 
282 /* /// Enable smoothing of shadow; optional argument provides */
283 /* /// value for tanh smoothing factor (defaults to 100) */
284 /* void enable_smoothed_sun_shadow(const double& alpha_tanh_smooth_sun_shadow= */
285 /* 100.0) */
286 /* { */
287 /* Smoothed_sun_shadow=true; */
288 /* Alpha_tanh_smooth_sun_shadow=alpha_tanh_smooth_sun_shadow; */
289 /* } */
290 
291 /* /// Disable smoothing of shadow */
292 /* void disable_smoothed_sun_shadow() */
293 /* { */
294 /* Smoothed_sun_shadow=false; */
295 /* } */
296 
297 /* /// Disable smoothing of shadow */
298 /* bool smoothed_sun_shadow_is_enabled() */
299 /* { */
300 /* return Smoothed_sun_shadow; */
301 /* } */
302 
303 
304 /* /// Value for tanh smoothing factor (read only -- set with enable... fct; */
305 /* /// only used if enabled!) */
306 /* double alpha_tanh_smooth_sun_shadow() */
307 /* { */
308 /* return Alpha_tanh_smooth_sun_shadow; */
309 /* } */
310 
311 
312 /* /// Reference to the analytical radiation function pointer */
313 /* void (* &analytical_radiation_fct_pt())(const double& time, */
314 /* const Vector<double>& x, */
315 /* const Vector<double>& n, */
316 /* double& radiation) */
317 /* {return Analytical_radiation_fct_pt;} */
318 
319 
320 /* /// Reference to the atmospheric radiation function pointer */
321 /* void (* &atmospheric_radiation_fct_pt())(const double& time, */
322 /* double &solar_flux_magnitude, */
323 /* Vector<double>& */
324 /* solar_flux_unit_vector, */
325 /* double& total_diffuse_radiation) */
326 /* {return Atmospheric_radiation_fct_pt;} */
327 
328 
329 /* /// Enable use of analytical radiation function */
330 /* void enable_analytical_radiation_fct_pt() */
331 /* { */
332 /* Use_analytical_radiation_fct=true; */
333 /* } */
334 
335 /* /// Disable use of analytical radiation function */
336 /* void disable_analytical_radiation_fct_pt() */
337 /* { */
338 /* Use_analytical_radiation_fct=false; */
339 /* } */
340 
341 /* /// Update limiting angles for diffuse radiation, given the */
342 /* /// pointers to nodes that make up the "upper boundary" */
343 /* /// that can potentially shield the integration points from diffuse */
344 /* /// radiation */
345 /* void update_limiting_angles(const Vector<Node*>& */
346 /* shielding_node_pt); */
347 
348 
349 /* /// Get the atmospheric radiation as fct of integration point */
350 /* /// index, time, Eulerian coordinate and outer unit normal. Virtual */
351 /* /// so it can be overloaded in multiphysics problems */
352 /* virtual double atmospheric_radiation(const unsigned& intpt, */
353 /* const double& time, */
354 /* const Vector<double>& x, */
355 /* const Vector<double>& n); */
356 
357 
358 
359 /* /// Output cone of diffuse radiation for all integration points */
360 /* void output_diffuse_radiation_cone(std::ostream &outfile, */
361 /* const double& radius); */
362 
363 
364 /* /// Output illumination angles for all integration points */
365 /* void output_limiting_angles(std::ostream &outfile); */
366 
367 
368 /* /// Output diffuse and direct radiation */
369 /* void output_atmospheric_radiation(std::ostream &outfile); */
370 
371 /* protected: */
372 
373 /* /// Use tanh profile to smooth solar shadows */
374 /* bool Smoothed_sun_shadow; */
375 
376 /* /// Factor for tanh profile to smooth solar shadows */
377 /* double Alpha_tanh_smooth_sun_shadow; */
378 
379 
380 /* /// Boolean to indicate the analytically prescribed radiation */
381 /* /// fct (radiation flux as fct of x,n,t) should be used */
382 /* /// rather than radiative flux based on direct and diffuse solar */
383 /* /// flux. */
384 /* bool Use_analytical_radiation_fct; */
385 
386 /* /// Vector of pairs storing max. and minimum angle for exposure */
387 /* /// to diffuse atmospheric radiation for each integration point. */
388 /* /// Initialised to 0 and pi (full radiation from semicircle above */
389 /* /// integration point) */
390 /* Vector<std::pair<double,double> > Diffuse_limit_angles; */
391 
392 /* /// Pointer to function that specifies atmospheric */
393 /* /// radiation in terms of directional solar flux (unit vector and magnitude) */
394 /* /// and total diffusive radiation (which is later weighted by diffuse limiting */
395 /* /// angles). Input argument: time. */
396 /* void (*Atmospheric_radiation_fct_pt)(const double& time, */
397 /* double& solar_flux_magnitude, */
398 /* Vector<double> &solar_flux_unit_vector, */
399 /* double& total_diffuse_radiation); */
400 
401 /* /// Pointer to analytical radiation function. Arguments: */
402 /* /// Time, Eulerian coordinate and outer unit normal. Returns */
403 /* /// heat flux. Only used for validation */
404 /* void (*Analytical_radiation_fct_pt)(const double& time, */
405 /* const Vector<double> &x, */
406 /* const Vector<double> &n, */
407 /* double& radiation); */
408 
409 
410 /* private: */
411 
412 /* /// Private helper function to check if the straight line */
413 /* /// connecting (x_prev,y_prev) and (x_next,y_next) jumps */
414 /* /// quadrants (in which case crossing_quadrants is returned as true) */
415 /* /// and what increment to the winding number this results in. */
416 /* /// Error (indicated by no_problem being false) occurs if */
417 /* /// the line crosses the origin exactly in which case we're */
418 /* /// stuffed. Diagnostics are returned in error string. */
419 /* void check_quadrant_jump(const double& x_prev, */
420 /* const double& y_prev, */
421 /* const double& x_next, */
422 /* const double& y_next, */
423 /* bool& crossing_quadrants, */
424 /* int& n_winding_increment, */
425 /* std::string& error_string, */
426 /* bool& no_problem); */
427 
428 /* }; */
429 
430 
431 
432 
433 /* //===================================================================== */
434 /* /// Get the atmospheric radiation as fct of integration point */
435 /* /// index, time, Eulerian coordinate and outer unit normal. Virtual */
436 /* /// so it can be overloaded in multiphysics problems */
437 /* //===================================================================== */
438 /* double SolarRadiationBase::atmospheric_radiation(const unsigned& intpt, */
439 /* const double& time, */
440 /* const Vector<double>& x, */
441 /* const Vector<double>& n) */
442 /* { */
443 /* double radiation=0.0; */
444 /* if (Use_analytical_radiation_fct) */
445 /* { */
446 /* Analytical_radiation_fct_pt(time,x,n,radiation); */
447 /* } */
448 /* else */
449 /* { */
450 /* unsigned n_dim = this->nodal_dimension(); */
451 /* double solar_flux_magnitude=0.0; */
452 /* Vector<double> solar_flux_unit_vector(n_dim); */
453 /* double total_diffuse_radiation=0.0; */
454 /* Atmospheric_radiation_fct_pt(time,solar_flux_magnitude, */
455 /* solar_flux_unit_vector, */
456 /* total_diffuse_radiation); */
457 
458 /* // Diffuse radiation from opening angle */
459 /* //------------------------------------- */
460 /* double phi_exposed=Diffuse_limit_angles[intpt].second- */
461 /* Diffuse_limit_angles[intpt].first; */
462 /* if (phi_exposed>0.0) */
463 /* { */
464 /* radiation+=total_diffuse_radiation*phi_exposed/ */
465 /* MathematicalConstants::Pi; */
466 /* } */
467 
468 /* //#ifdef PARANOID // hierher paranoidify */
469 /* if (phi_exposed>MathematicalConstants::Pi) */
470 /* { */
471 /* std::stringstream error_message; */
472 /* error_message << "Exposure angle " << phi_exposed */
473 /* << " greater than 180^o at ( " */
474 /* << x[0] << " , " << x[1] << " )"; */
475 /* throw OomphLibError(error_message.str(), */
476 /* "SolarRadiationBase::atmospheric_radiation()", */
477 /* OOMPH_EXCEPTION_LOCATION); */
478 /* } */
479 /* //#endif */
480 
481 /* // Direct radiation (with directional cosine and ignore */
482 /* //----------------------------------------------------- */
483 /* // shielded bits) */
484 /* //--------------- */
485 
486 
487 /* // Cos of angle between outer unit normal and direct solar flux */
488 /* double cos_angle=-(n[0]*solar_flux_unit_vector[0]+ */
489 /* n[1]*solar_flux_unit_vector[1]); */
490 
491 /* // No further contributions if we're pointing away from the sun */
492 /* if (cos_angle>0.0) */
493 /* { */
494 /* // Angle that the incoming solar radiation makes */
495 /* // with the horizontal */
496 /* double theta=atan2(solar_flux_unit_vector[0],-solar_flux_unit_vector[1]); */
497 /* double phi=0.5*MathematicalConstants::Pi+theta; */
498 
499 
500 /* // Bounding angles of visibility */
501 /* double phi_min=Diffuse_limit_angles[intpt].first; */
502 /* double phi_max=Diffuse_limit_angles[intpt].second; */
503 
504 /* // Is the sun visible? */
505 /* if (Smoothed_sun_shadow) */
506 /* { */
507 /* // Smooth shadow */
508 /* double tanh_factor= */
509 /* 0.5*(-tanh(Alpha_tanh_smooth_sun_shadow*(phi-phi_max)) */
510 /* -tanh(Alpha_tanh_smooth_sun_shadow*(phi_min-phi))); */
511 /* radiation+=cos_angle*solar_flux_magnitude*tanh_factor; */
512 /* } */
513 /* else */
514 /* { */
515 /* // Hard shadow */
516 /* if (phi>phi_min) */
517 /* { */
518 /* if (phi<phi_max) */
519 /* { */
520 /* radiation+=cos_angle*solar_flux_magnitude; */
521 /* } */
522 /* } */
523 /* } */
524 /* } */
525 /* } */
526 
527 /* return radiation; */
528 /* } */
529 
530 
531 /* //==================================================================== */
532 /* /// Private helper function to check if the straight line */
533 /* /// connecting (x_prev,y_prev) and (x_next,y_next) jumps */
534 /* /// quadrants (in which case crossing_quadrants is returned as true) */
535 /* /// and what increment to the winding number this results in. */
536 /* /// Error (indicated by no_problem being false) occurs if */
537 /* /// the line crosses the origin exactly in which case we're */
538 /* /// stuffed. Diagnostics are returned in error string. */
539 /* //==================================================================== */
540 /* void SolarRadiationBase::check_quadrant_jump(const double& x_prev, */
541 /* const double& y_prev, */
542 /* const double& x_next, */
543 /* const double& y_next, */
544 /* bool& crossing_quadrants, */
545 /* int& n_winding_increment, */
546 /* std::string& error_string, */
547 /* bool& no_problem) */
548 /* { */
549 /* // Sanity check: We have to keep track of winding numbers */
550 /* // but we're stuffed if we our discrete increments in coordinates */
551 /* // jump diagonally across quadrants... */
552 /* std::stringstream error_message; */
553 /* no_problem=true; */
554 /* crossing_quadrants=false; */
555 
556 /* // y coordinate of intersection with x axis */
557 /* double y_intersect=0.0; */
558 /* double denom=x_next-x_prev; */
559 
560 /* // If denominator is zero then we're intersection exactly */
561 /* // at the sample point and we're absolutely screwed. This */
562 /* // really shouldn't happen. */
563 /* if (denom!=0.0) */
564 /* { */
565 /* y_intersect=y_prev-(y_next-y_prev)*x_prev/denom; */
566 /* } */
567 /* if ((x_prev>0.0)&&(y_prev>0.0)&&(x_next<0.0)&&(y_next<0.0)) */
568 /* { */
569 /* crossing_quadrants=true; */
570 /* error_message << "Jumped from upper right quadrant to lower left one\n"; */
571 /* oomph_info << "Jumped from upper right quadrant to lower left one\n"; */
572 /* if (y_intersect==0.0) */
573 /* { */
574 /* error_message << "..and cannot be repaired!\n"; */
575 /* no_problem=false; */
576 /* } */
577 /* // Path crosses the positive x axis: No winding */
578 /* else if (y_intersect<0.0) */
579 /* { */
580 /* n_winding_increment=0; */
581 /* } */
582 /* // Path crosses the negative x axis from above: increase winding number */
583 /* else if (y_intersect>0.0) */
584 /* { */
585 /* n_winding_increment=1; */
586 /* } */
587 /* } */
588 /* else if ((x_prev<0.0)&&(y_prev<0.0)&&(x_next>0.0)&&(y_next>0.0)) */
589 /* { */
590 /* crossing_quadrants=true; */
591 /* error_message << "Jumped from lower left quadrant to upper right one\n"; */
592 /* oomph_info << "Jumped from lower left quadrant to upper right one\n"; */
593 /* if (y_intersect==0.0) */
594 /* { */
595 /* error_message << "..and cannot be repaired!\n"; */
596 /* no_problem=false; */
597 /* } */
598 /* // Path crosses the positive x axis: No winding */
599 /* else if (y_intersect<0.0) */
600 /* { */
601 /* n_winding_increment=0; */
602 /* } */
603 /* // Path crosses the negative x axis from below: reduce winding number */
604 /* else if (y_intersect>0.0) */
605 /* { */
606 /* n_winding_increment=-1; */
607 /* } */
608 /* } */
609 /* else if ((x_prev<0.0)&&(y_prev>0.0)&&(x_next>0.0)&&(y_next<0.0)) */
610 /* { */
611 /* crossing_quadrants=true; */
612 /* error_message << "Jumped from upper left quadrant to lower right one\n"; */
613 /* oomph_info << "Jumped from upper left quadrant to lower right one\n"; */
614 /* if (y_intersect==0.0) */
615 /* { */
616 /* error_message << "..and cannot be repaired!\n"; */
617 /* no_problem=false; */
618 /* } */
619 /* // Path crosses the positive x axis: No winding */
620 /* else if (y_intersect<0.0) */
621 /* { */
622 /* n_winding_increment=0; */
623 /* } */
624 /* // Path crosses the negative x axis from above: increase winding number */
625 /* else if (y_intersect>0.0) */
626 /* { */
627 /* n_winding_increment=1; */
628 /* } */
629 /* } */
630 /* else if ((x_prev>0.0)&&(y_prev<0.0)&&(x_next<0.0)&&(y_next>0.0)) */
631 /* { */
632 /* crossing_quadrants=true; */
633 /* error_message << "Jumped from lower right quadrant to upper left one\n"; */
634 /* oomph_info << "Jumped from lower right quadrant to upper left one\n"; */
635 /* if (y_intersect==0.0) */
636 /* { */
637 /* error_message << "..and cannot be repaired!\n"; */
638 /* no_problem=false; */
639 /* } */
640 /* // Path crosses the positive x axis: No winding */
641 /* else if (y_intersect>0.0) */
642 /* { */
643 /* n_winding_increment=0; */
644 /* } */
645 /* // Path crosses the negative x axis from below: decrease winding number */
646 /* else if (y_intersect<0.0) */
647 /* { */
648 /* n_winding_increment=-1; */
649 /* } */
650 /* } */
651 /* } */
652 
653 /* //===================================================================== */
654 /* /// Update limiting angles for diffuse radiation, given the */
655 /* /// Vector of pointers to nodes that make up the "upper boundary" */
656 /* /// that can potentially shield the integration points from diffuse */
657 /* /// radiation */
658 /* //===================================================================== */
659 /* void SolarRadiationBase::update_limiting_angles(const Vector<Node*>& */
660 /* shielding_node_pt) */
661 /* { */
662 
663 /* // Search through all shielding nodes and find the */
664 /* // bounding ones for this element */
665 /* Node* first_vertex_node_pt=node_pt(0); */
666 /* unsigned nnod_el=nnode(); */
667 /* Node* second_vertex_node_pt=node_pt(nnod_el-1); */
668 
669 /* // Find left and rightmost node of element in shielding_node_pt vector: */
670 /* unsigned j_left=0; */
671 /* bool found=false; */
672 /* unsigned nnod=shielding_node_pt.size(); */
673 /* for (unsigned j=0;j<nnod;j++) */
674 /* { */
675 /* // We come from the left so we're definitely meeting the leftmost */
676 /* // node */
677 /* if ((shielding_node_pt[j]==first_vertex_node_pt)|| */
678 /* (shielding_node_pt[j]==second_vertex_node_pt)) */
679 /* { */
680 /* j_left=j; */
681 /* found=true; */
682 /* break; */
683 /* } */
684 /* } */
685 /* unsigned j_right=j_left+1; */
686 
687 /* // Did we succeed? */
688 /* if (!found) */
689 /* { */
690 /* throw OomphLibError("Failed to find leftmost node in shielding_node_pt", */
691 /* "SolarRadiationBase::update_limiting_angles", */
692 /* OOMPH_EXCEPTION_LOCATION); */
693 /* } */
694 
695 /* //Set the value of n_intpt */
696 /* unsigned n_intpt = integral_pt()->nweight(); */
697 
698 /* // Spatial dimension of the nodes */
699 /* unsigned n_dim = this->nodal_dimension(); */
700 /* Vector<double> x(n_dim); */
701 /* Vector<double> s(n_dim-1); */
702 
703 /* //Loop over the integration points */
704 /* for(unsigned ipt=0;ipt<n_intpt;ipt++) */
705 /* { */
706 
707 /* // Local coordinate of integration point */
708 /* for (unsigned i=0;i<n_dim-1;i++) */
709 /* { */
710 /* s[i]=integral_pt()->knot(ipt,i); */
711 /* } */
712 
713 /* // No recycling of shape fcts -- may as well call interpolated_x */
714 /* // directly */
715 /* this->interpolated_x(s,x); */
716 
717 /* // Loop over all potential shielding nodes to the left to find */
718 /* // minimum angle */
719 /* int n_winding=0; */
720 
721 /* // Initial point */
722 /* Node* nod_pt=shielding_node_pt[0]; */
723 
724 /* // Coordinate relative to sampling point */
725 /* double x_prev=nod_pt->x(0)-x[0]; */
726 /* double y_prev=nod_pt->x(1)-x[1]; */
727 
728 /* // Angle against x-axis relative to sampling point */
729 /* double phi_prev=atan2(y_prev,x_prev); */
730 
731 /* // Current best guess for minimum angle to the left */
732 /* double phi_left=phi_prev; */
733 
734 /* // Loop over all other nodes */
735 /* for (unsigned j=1;j<=j_left;j++) */
736 /* { */
737 /* Node* nod_pt=shielding_node_pt[j]; */
738 /* double x_next=nod_pt->x(0)-x[0]; */
739 /* double y_next=nod_pt->x(1)-x[1]; */
740 /* double phi_next=atan2(y_next,x_next); */
741 
742 
743 /* // Sanity check: We have to keep track of winding numbers */
744 /* // but we're stuffed if we our discrete increments in coordinates */
745 /* // jump diagonally across quadrants... */
746 /* std::string error_string; */
747 /* bool no_problem=true; */
748 /* bool crossing_quadrants=false; */
749 /* int n_winding_increment=0; */
750 
751 /* // Check if we've crossed quadrants */
752 /* check_quadrant_jump(x_prev, */
753 /* y_prev, */
754 /* x_next, */
755 /* y_prev, */
756 /* crossing_quadrants, */
757 /* n_winding_increment, */
758 /* error_string, */
759 /* no_problem); */
760 
761 /* // Success? */
762 /* if (no_problem) */
763 /* { */
764 /* n_winding+=n_winding_increment; */
765 /* } */
766 /* // Complain bitterly */
767 /* else */
768 /* { */
769 /* std::stringstream error_message; */
770 /* error_message << error_string; */
771 /* error_message << "\n x/y_prev, x/y_next:" */
772 /* << x_prev << " " */
773 /* << y_prev << " " */
774 /* << x_next << " " */
775 /* << y_next << " "<< std::endl; */
776 /* error_message << "for point at " */
777 /* << x[0] << " " << x[1] << std::endl; */
778 /* error_message << "chain of shielding nodes on left:\n"; */
779 /* for (unsigned jj=1;jj<=j_left;jj++) */
780 /* { */
781 /* Node* nnod_pt=shielding_node_pt[jj]; */
782 /* error_message << nnod_pt->x(0) << " " */
783 /* << nnod_pt->x(1) << "\n"; */
784 /* } */
785 /* throw OomphLibError( */
786 /* error_message.str(), */
787 /* "SolarRadiationBase::update_limiting_angles()", */
788 /* OOMPH_EXCEPTION_LOCATION); */
789 /* } */
790 
791 /* // If we're crossing the x axis to the left of the origin */
792 /* // without jumping across quadrants we */
793 /* // have to adjust the winding number */
794 /* if (!crossing_quadrants) */
795 /* { */
796 /* if ((x_prev<0.0)&&(x_next<0.0)) */
797 /* { */
798 /* if ((y_prev>=0.0)&&(y_next<0.0)) */
799 /* { */
800 /* n_winding+=1; */
801 /* } */
802 /* else if ((y_prev<0.0)&&(y_next>=0.0)) */
803 /* { */
804 /* n_winding-=1; */
805 /* } */
806 /* } */
807 /* } */
808 
809 /* // Correct angle by winding */
810 /* phi_next+=double(n_winding)*2.0*MathematicalConstants::Pi; */
811 
812 /* // Is it smaller? */
813 /* if (phi_next<phi_left) */
814 /* { */
815 /* phi_left=phi_next; */
816 /* } */
817 
818 /* // Bump up */
819 /* x_prev=x_next; */
820 /* y_prev=y_next; */
821 /* phi_prev=phi_next; */
822 /* } */
823 
824 
825 /* // Loop over all potential shielding nodes to the right to find */
826 /* // maximum angle */
827 /* n_winding=0; */
828 
829 /* // Initial point */
830 /* nod_pt=shielding_node_pt[j_right]; */
831 
832 /* // Coordinate relative to sampling point */
833 /* x_prev=nod_pt->x(0)-x[0]; */
834 /* y_prev=nod_pt->x(1)-x[1]; */
835 
836 /* // Angle against x-axis relative to sampling point */
837 /* phi_prev=atan2(y_prev,x_prev); */
838 
839 /* // Current best guess for maximum angle to the right */
840 /* double phi_right=phi_prev; */
841 
842 /* // Loop over all other nodes */
843 /* for (unsigned j=j_right+1;j<nnod;j++) */
844 /* { */
845 /* Node* nod_pt=shielding_node_pt[j]; */
846 /* double x_next=nod_pt->x(0)-x[0]; */
847 /* double y_next=nod_pt->x(1)-x[1]; */
848 /* double phi_next=atan2(y_next,x_next); */
849 
850 /* // Sanity check: We have to keep track of winding numbers */
851 /* // but we're stuffed if we our discrete increments in coordinates */
852 /* // jump diagonally across quadrants... */
853 /* std::string error_string; */
854 /* bool no_problem=true; */
855 /* bool crossing_quadrants=false; */
856 /* int n_winding_increment=0; */
857 
858 /* // Check if we've crossed quadrants */
859 /* check_quadrant_jump(x_prev, */
860 /* y_prev, */
861 /* x_next, */
862 /* y_prev, */
863 /* crossing_quadrants, */
864 /* n_winding_increment, */
865 /* error_string, */
866 /* no_problem); */
867 
868 /* // Success? */
869 /* if (no_problem) */
870 /* { */
871 /* n_winding+=n_winding_increment; */
872 /* } */
873 /* // Complain bitterly */
874 /* else */
875 /* { */
876 /* std::stringstream error_message; */
877 /* error_message << error_string; */
878 /* error_message << "\n x/y_prev, x/y_next:" */
879 /* << x_prev << " " */
880 /* << y_prev << " " */
881 /* << x_next << " " */
882 /* << y_next << " "<< std::endl; */
883 /* error_message << "for point at " */
884 /* << x[0] << " " << x[1] << std::endl; */
885 /* error_message << "chain of shielding nodes on right:\n"; */
886 /* for (unsigned jj=j_right;jj<nnod;jj++) */
887 /* { */
888 /* Node* nnod_pt=shielding_node_pt[jj]; */
889 /* error_message << nnod_pt->x(0) << " " */
890 /* << nnod_pt->x(1) << "\n"; */
891 /* } */
892 /* throw OomphLibError( */
893 /* error_message.str(), */
894 /* "SolarRadiationBase::update_limiting_angles()", */
895 /* OOMPH_EXCEPTION_LOCATION); */
896 /* } */
897 
898 
899 /* // If we're crossing the x axis to the left of the origin */
900 /* // without jumping across quadrants we */
901 /* // have to adjust the winding number */
902 /* if (!crossing_quadrants) */
903 /* { */
904 /* if ((x_prev<0.0)&&(x_next<0.0)) */
905 /* { */
906 /* if ((y_prev>=0.0)&&(y_next<0.0)) */
907 /* { */
908 /* n_winding+=1; */
909 /* } */
910 /* else if ((y_prev<0.0)&&(y_next>=0.0)) */
911 /* { */
912 /* n_winding-=1; */
913 /* } */
914 /* } */
915 /* } */
916 
917 /* // Correct angle by winding */
918 /* phi_next+=double(n_winding)*2.0*MathematicalConstants::Pi; */
919 
920 /* // Is it bigger? */
921 /* if (phi_next>phi_right) */
922 /* { */
923 /* phi_right=phi_next; */
924 /* } */
925 
926 /* // Bump up */
927 /* x_prev=x_next; */
928 /* y_prev=y_next; */
929 /* phi_prev=phi_next; */
930 /* } */
931 
932 /* Diffuse_limit_angles[ipt].first=phi_right; */
933 /* Diffuse_limit_angles[ipt].second=phi_left; */
934 /* } */
935 /* } */
936 
937 
938 
939 /* //===================================================================== */
940 /* /// Output cone of diffuse radiation for all integration points */
941 /* //===================================================================== */
942 /* void SolarRadiationBase::output_diffuse_radiation_cone( */
943 /* std::ostream &outfile, const double& radius) */
944 /* { */
945 /* //Set the value of n_intpt */
946 /* unsigned n_intpt = integral_pt()->nweight(); */
947 
948 /* // Spatial dimension of the nodes */
949 /* unsigned n_dim = this->nodal_dimension(); */
950 /* Vector<double> x(n_dim); */
951 /* Vector<double> s(n_dim-1); */
952 
953 /* //Loop over the integration points */
954 /* for(unsigned ipt=0;ipt<n_intpt;ipt++) */
955 /* { */
956 /* outfile << "ZONE\n"; */
957 
958 /* // Local coordinate of integration point */
959 /* for (unsigned i=0;i<n_dim-1;i++) */
960 /* { */
961 /* s[i]=integral_pt()->knot(ipt,i); */
962 /* } */
963 
964 /* // No recycling of shape fcts -- may as well call interpolated_x */
965 /* // directly */
966 /* this->interpolated_x(s,x); */
967 
968 /* double phi_min=Diffuse_limit_angles[ipt].first; */
969 /* double phi_max=Diffuse_limit_angles[ipt].second; */
970 
971 /* outfile << x[0]+radius*cos(phi_min) << " " */
972 /* << x[1]+radius*sin(phi_min) << "\n" */
973 /* << x[0] << " " */
974 /* << x[1] << "\n" */
975 /* << x[0]+radius*cos(phi_max) << " " */
976 /* << x[1]+radius*sin(phi_max) << "\n"; */
977 /* } */
978 /* } */
979 
980 
981 
982 /* //===================================================================== */
983 /* /// Output illumination angles for all integration points */
984 /* //===================================================================== */
985 /* void SolarRadiationBase::output_limiting_angles(std::ostream &outfile) */
986 /* { */
987 /* //Set the value of n_intpt */
988 /* unsigned n_intpt = integral_pt()->nweight(); */
989 
990 /* // Spatial dimension of the nodes */
991 /* unsigned n_dim = this->nodal_dimension(); */
992 /* Vector<double> x(n_dim); */
993 /* Vector<double> s(n_dim-1); */
994 /* Vector<double> normal(n_dim); */
995 
996 /* //Loop over the integration points */
997 /* for(unsigned ipt=0;ipt<n_intpt;ipt++) */
998 /* { */
999 /* outfile << "ZONE\n"; */
1000 
1001 /* // Local coordinate of integration point */
1002 /* for (unsigned i=0;i<n_dim-1;i++) */
1003 /* { */
1004 /* s[i]=integral_pt()->knot(ipt,i); */
1005 /* } */
1006 
1007 /* // No recycling of shape fcts -- may as well call interpolated_x */
1008 /* // directly */
1009 /* this->interpolated_x(s,x); */
1010 
1011 /* // Get outer unit normal */
1012 /* this->outer_unit_normal(s,normal); */
1013 
1014 /* double phi_min=Diffuse_limit_angles[ipt].first; */
1015 /* double phi_max=Diffuse_limit_angles[ipt].second; */
1016 
1017 /* outfile << x[0] << " " */
1018 /* << x[1] << " " */
1019 /* << normal[0] << " " */
1020 /* << normal[1] << " " */
1021 /* << phi_min << " " */
1022 /* << phi_max << "\n"; */
1023 
1024 /* } */
1025 /* } */
1026 
1027 
1028 
1029 
1030 /* //===================================================================== */
1031 /* /// Output illumination angles for all integration points */
1032 /* //===================================================================== */
1033 /* void SolarRadiationBase::output_atmospheric_radiation(std::ostream &outfile) */
1034 /* { */
1035 
1036 /* // Get time from first node */
1037 /* double time=node_pt(0)->time_stepper_pt()->time_pt()->time(); */
1038 
1039 /* //Set the value of n_intpt */
1040 /* unsigned n_intpt = integral_pt()->nweight(); */
1041 
1042 /* // Spatial dimension of the nodes */
1043 /* unsigned n_dim = this->nodal_dimension(); */
1044 /* Vector<double> x(n_dim); */
1045 /* Vector<double> s(n_dim-1); */
1046 /* Vector<double> normal(n_dim); */
1047 
1048 /* //Loop over the integration points */
1049 /* for(unsigned ipt=0;ipt<n_intpt;ipt++) */
1050 /* { */
1051 /* outfile << "ZONE\n"; */
1052 
1053 /* // Local coordinate of integration point */
1054 /* for (unsigned i=0;i<n_dim-1;i++) */
1055 /* { */
1056 /* s[i]=integral_pt()->knot(ipt,i); */
1057 /* } */
1058 
1059 /* // No recycling of shape fcts -- may as well call interpolated_x */
1060 /* // directly */
1061 /* this->interpolated_x(s,x); */
1062 
1063 /* // Get outer unit normal */
1064 /* this->outer_unit_normal(s,normal); */
1065 
1066 /* // Get radiation */
1067 /* double radiation=atmospheric_radiation(ipt, */
1068 /* time, */
1069 /* x, */
1070 /* normal); */
1071 
1072 /* // output */
1073 /* outfile << x[0] << " " */
1074 /* << x[1] << " " */
1075 /* << radiation << " " */
1076 /* << normal[0] << " " */
1077 /* << normal[1] << "\n"; */
1078 
1079 /* } */
1080 /* } */
1081 
1082 
1083 
1084 
1085 /* ///////////////////////////////////////////////////////////////////// */
1086 /* ///////////////////////////////////////////////////////////////////// */
1087 /* ///////////////////////////////////////////////////////////////////// */
1088 
1089 
1090 
1091 /* //====================================================================== */
1092 /* /// Base class for elements that are illuminated by (and illuminate) */
1093 /* /// other Stefan Boltzmann elements */
1094 /* //====================================================================== */
1095 /* class StefanBoltzmannRadiationBase : */
1096 /* public virtual FiniteElement, */
1097 /* public virtual FaceElement, */
1098 /* public virtual TemplateFreeUnsteadyHeatBaseFaceElement */
1099 /* { */
1100 
1101 /* public: */
1102 
1103 /* /// Constructor */
1104 /* StefanBoltzmannRadiationBase() */
1105 /* { */
1106 /* // Pointer to non-dim Stefan Boltzmann constant */
1107 /* Sigma_pt=0; */
1108 
1109 /* // Pointer to non-dim zero centrigrade offset in Stefan Boltzmann law */
1110 /* Theta_0_pt=0; */
1111 
1112 /* // Make space for Stefan Boltzmann illumination info */
1113 /* unsigned n_intpt = integral_pt()->nweight(); */
1114 /* Stefan_boltzmann_illumination_info.resize(n_intpt); */
1115 /* } */
1116 
1117 /* /// Pointer to non-dim Stefan Boltzmann constant */
1118 /* double*& sigma_pt(){return Sigma_pt;} */
1119 
1120 /* /// Pointer to non-dim zero centrigrade offset in Stefan Boltzmann law */
1121 /* double*& theta_0_pt(){return Theta_0_pt;} */
1122 
1123 /* /// Non-dim Stefan Boltzmann constant (switched off by default) */
1124 /* double sigma() */
1125 /* { */
1126 /* if (Sigma_pt==0) */
1127 /* { */
1128 /* return 0.0; */
1129 /* } */
1130 /* else */
1131 /* { */
1132 /* return *Sigma_pt; */
1133 /* } */
1134 /* } */
1135 
1136 /* /// Non-dim zero centrigrade offset in Stefan Boltzmann law */
1137 /* /// (must be set if effect is enabled i.e. if non-default */
1138 /* /// non-dim Stefan Boltzmann constant has been set) */
1139 /* double theta_0() */
1140 /* { */
1141 /* if (Sigma_pt==0) */
1142 /* { */
1143 /* return 0.0; */
1144 /* } */
1145 /* else */
1146 /* { */
1147 /* if (Theta_0_pt==0) */
1148 /* { */
1149 /* throw OomphLibError("Non-dim zero-centrigrade offset not set", */
1150 /* "StefanBoltzmannRadiationBase", */
1151 /* OOMPH_EXCEPTION_LOCATION); */
1152 /* } */
1153 /* else */
1154 /* { */
1155 /* return *Theta_0_pt; */
1156 /* } */
1157 /* } */
1158 /* } */
1159 
1160 
1161 /* /// Compute the incoming Stefan Boltzmann radiation */
1162 /* /// onto integration point ipt -- input externally pre-computed */
1163 /* /// Eulerian coordinate of illuminated integration point, r_illuminated, */
1164 /* /// and outer unit normal to that point, n_illuminated. */
1165 /* double incoming_stefan_boltzmann_radiation(const unsigned& ipt, */
1166 /* const Vector<double>& r_illuminated, */
1167 /* const Vector<double>& n_illuminated) */
1168 /* { */
1169 /* // Initialise flux */
1170 /* double flux=0.0; */
1171 
1172 /* /// Number of contributing elements */
1173 /* unsigned n_contrib=Stefan_boltzmann_illumination_info[ipt].size(); */
1174 /* for (unsigned e=0;e<n_contrib;e++) */
1175 /* { */
1176 /* // Pointer to contributing element */
1177 /* StefanBoltzmannRadiationBase* el_pt= */
1178 /* Stefan_boltzmann_illumination_info[ipt][e].first; */
1179 
1180 /* // Indices of integration points that contribute */
1181 /* Vector<unsigned> visible_integration_points= */
1182 /* Stefan_boltzmann_illumination_info[ipt][e].second; */
1183 
1184 /* // Add contribution */
1185 /* flux+=el_pt->contribution_to_stefan_boltzmann_radiation */
1186 /* (r_illuminated,n_illuminated,visible_integration_points); */
1187 /* } */
1188 
1189 /* return flux; */
1190 /* } */
1191 
1192 
1193 /* /// Compute the element's contribution to Stefan Boltzmann */
1194 /* /// radiation onto point at r_illuminated with local outer unit */
1195 /* /// normal n_illuminated, */
1196 /* /// using the integration points (in current element) contained */
1197 /* /// in visible_intpts_in_current_element. */
1198 /* double contribution_to_stefan_boltzmann_radiation( */
1199 /* const Vector<double>& r_illuminated, */
1200 /* const Vector<double>& n_illuminated, */
1201 /* const Vector<unsigned>& visible_intpts_in_current_element) */
1202 /* { */
1203 /* // Dummy file */
1204 /* std::ofstream outfile; */
1205 /* return contribution_to_stefan_boltzmann_radiation( */
1206 /* r_illuminated, */
1207 /* n_illuminated, */
1208 /* visible_intpts_in_current_element, */
1209 /* outfile); */
1210 /* } */
1211 
1212 /* /// Compute the element's contribution to Stefan Boltzmann */
1213 /* /// radiation onto point at r_illuminated with local outer unit */
1214 /* /// normal n_illuminated, */
1215 /* /// using the integration points (in current element) contained */
1216 /* /// in visible_intpts_in_current_element; output in outfile */
1217 /* double contribution_to_stefan_boltzmann_radiation( */
1218 /* const Vector<double>& r_illuminated, */
1219 /* const Vector<double>& n_illuminated, */
1220 /* const Vector<unsigned>& visible_intpts_in_current_element, */
1221 /* std::ofstream& outfile); */
1222 
1223 /* /// Wipe illumination info */
1224 /* void wipe_stefan_boltzmann_illumination_info() */
1225 /* { */
1226 /* unsigned nint= Stefan_boltzmann_illumination_info.size(); */
1227 /* for (unsigned ipt=0;ipt<nint;ipt++) */
1228 /* { */
1229 /* Stefan_boltzmann_illumination_info[ipt].clear(); */
1230 /* } */
1231 /* } */
1232 
1233 /* /// Set illumination info: For integration point, ipt, */
1234 /* /// we store all pairs identifying illuminating elements */
1235 /* /// (via pointer to element and indices of illuminating */
1236 /* /// integration points): */
1237 /* /// Stefan_boltzmann_illumination_info[ipt].size() = number of illuminating */
1238 /* /// elements */
1239 /* /// Stefan_boltzmann_illumination_info[ipt][e].first = pointer to e-th */
1240 /* /// illuminating element */
1241 /* /// Stefan_boltzmann_illumination_info[ipt][e].second = vector containing */
1242 /* /// indices of integration points in e-th illuminating element */
1243 /* /// that are visible from current element's ipt'th integration point. */
1244 /* void add_stefan_boltzmann_illumination_info( */
1245 /* const unsigned& ipt, */
1246 /* StefanBoltzmannRadiationBase* illuminating_el_pt, */
1247 /* Vector<unsigned>& illuminating_integration_point_index) */
1248 /* { */
1249 /* #ifdef PARANOID */
1250 /* unsigned n=Stefan_boltzmann_illumination_info[ipt].size(); */
1251 /* for (unsigned e=0;e<n;e++) */
1252 /* { */
1253 /* if (Stefan_boltzmann_illumination_info[ipt][e].first==illuminating_el_pt) */
1254 /* { */
1255 /* throw OomphLibError( */
1256 /* "Element has already been added!", */
1257 /* "StefanBoltzmannRadiationBase::add_stefan_boltzmann_illumination_info()", */
1258 /* OOMPH_EXCEPTION_LOCATION); */
1259 /* } */
1260 /* } */
1261 /* #endif */
1262 
1263 /* Stefan_boltzmann_illumination_info[ipt].push_back( */
1264 /* std::make_pair(illuminating_el_pt,illuminating_integration_point_index)); */
1265 
1266 /* // Add other elements as external data */
1267 /* unsigned nnod=illuminating_el_pt->nnode(); */
1268 /* for (unsigned j=0;j<nnod;j++) */
1269 /* { */
1270 /* Node* ext_node_pt=illuminating_el_pt->node_pt(j); */
1271 /* bool own=false; */
1272 /* for (unsigned jj=0;jj<nnod;jj++) */
1273 /* { */
1274 /* if (node_pt(jj)==ext_node_pt) */
1275 /* { */
1276 /* own=true; */
1277 /* break; */
1278 /* } */
1279 /* } */
1280 /* if (!own) */
1281 /* { */
1282 /* // hierher positional data? */
1283 /* add_external_data(illuminating_el_pt->node_pt(j)); */
1284 /* } */
1285 /* } */
1286 
1287 /* } */
1288 
1289 /* /// Output Stefan Boltzmann radiation: x,y,in,out,n_x,n_y */
1290 /* void output_stefan_boltzmann_radiation(std::ostream &outfile); */
1291 
1292 /* /// Output Stefan Boltzmann radiation: Plots rays from illuminated */
1293 /* /// integration point to illuminating ones (and back). */
1294 /* void output_stefan_boltzmann_radiation_rays(std::ostream &outfile); */
1295 
1296 /* protected: */
1297 
1298 /* /// Pointer to non-dim Stefan Boltzmann constant */
1299 /* double* Sigma_pt; */
1300 
1301 /* /// Pointer to non-dim zero centrigrade offset in Stefan Boltzmann law */
1302 /* double* Theta_0_pt; */
1303 
1304 /* /// Illumination info: For each integration point, ipt, */
1305 /* /// we store all pairs identifying illuminating elements */
1306 /* /// (via pointer to element and illumnating integration points): */
1307 /* /// */
1308 /* /// Stefan_boltzmann_illumination_info[ipt].size() = number of illuminating */
1309 /* /// elements */
1310 /* /// Stefan_boltzmann_illumination_info[ipt][e].first = pointer to e-th */
1311 /* /// illuminating element */
1312 /* /// Stefan_boltzmann_illumination_info[ipt][e].second = vector containing */
1313 /* /// index of integration points in e-th illuminating element that are */
1314 /* /// visible from current element's ipt'th integration point. */
1315 /* Vector<Vector<std::pair<StefanBoltzmannRadiationBase*,Vector<unsigned> > > > */
1316 /* Stefan_boltzmann_illumination_info; */
1317 
1318 
1319 /* }; */
1320 
1321 
1322 
1323 /* //===================================================================== */
1324 /* /// Compute the element's contribution to Stefan Boltzmann radiation */
1325 /* /// onto point at r_illuminated with local outer unit normal n_illuminated, */
1326 /* /// using the integration points (in current element) contained */
1327 /* /// in visible_intpts_in_current_element. */
1328 /* //===================================================================== */
1329 /* double StefanBoltzmannRadiationBase::contribution_to_stefan_boltzmann_radiation( */
1330 /* const Vector<double>& r_illuminated, */
1331 /* const Vector<double>& n_illuminated, */
1332 /* const Vector<unsigned>& visible_intpts_in_current_element, */
1333 /* std::ofstream &outfile) */
1334 /* { */
1335 
1336 /* if (outfile.is_open()) */
1337 /* { */
1338 /* outfile << "ZONE\n"; */
1339 /* outfile << r_illuminated[0] << " " */
1340 /* << r_illuminated[1] << " 0 0\n"; */
1341 /* } */
1342 
1343 /* // Initialise */
1344 /* double contribution=0.0; */
1345 
1346 /* //Find out how many nodes there are */
1347 /* unsigned n_node = nnode(); */
1348 
1349 /* //Set up memory for the shape functions */
1350 /* Shape psi(n_node); */
1351 /* DShape dpsids(n_node,1); */
1352 
1353 /* // Local coordinate */
1354 /* Vector<double> s(1); */
1355 
1356 /* // Loop over contributing integration points */
1357 /* unsigned nint=visible_intpts_in_current_element.size(); */
1358 /* for (unsigned ii=0;ii<nint;ii++) */
1359 /* { */
1360 /* // Get integration point */
1361 /* unsigned ipt=visible_intpts_in_current_element[ii]; */
1362 
1363 /* //Only need to call the local derivatives */
1364 /* dshape_local_at_knot(ipt,psi,dpsids); */
1365 
1366 /* //Get the integral weight */
1367 /* double w = integral_pt()->weight(ipt); */
1368 
1369 /* //Calculate the coords and tangent vector */
1370 /* Vector<double> r_illuminating(2,0.0); */
1371 /* Vector<double> interpolated_dxds(2,0.0); */
1372 /* double interpolated_u=0; */
1373 
1374 /* //Loop over nodes */
1375 /* for(unsigned l=0;l<n_node;l++) */
1376 /* { */
1377 /* // Add to temperature */
1378 /* interpolated_u+= */
1379 /* node_pt(l)->value(U_index_ust_heat)*psi[l]; */
1380 
1381 /* //Loop over directions */
1382 /* for(unsigned i=0;i<2;i++) */
1383 /* { */
1384 /* r_illuminating[i] += nodal_position(l,i)*psi(l); */
1385 /* interpolated_dxds[i] += nodal_position(l,i)*dpsids(l,0); */
1386 /* } */
1387 /* } */
1388 
1389 /* // Vector from illuminated to illuminated point */
1390 /* Vector<double> ray(2); */
1391 /* ray[0]=r_illuminating[0]-r_illuminated[0]; */
1392 /* ray[1]=r_illuminating[1]-r_illuminated[1]; */
1393 
1394 /* // Get inverse length */
1395 /* double inv_length=1.0/sqrt(ray[0]*ray[0]+ray[1]*ray[1]); */
1396 
1397 /* // e_phi (phi measured in mathematically negative sense */
1398 /* // from vertically above illuminated point -- 'cos that's */
1399 /* // what it is in my sketch.. */
1400 /* Vector<double> e_phi(2); */
1401 /* e_phi[0]= inv_length*ray[1]; */
1402 /* e_phi[1]=-inv_length*ray[0]; */
1403 
1404 /* // Angles */
1405 /* double cos_phi=inv_length*(n_illuminated[0]*ray[0]+ */
1406 /* n_illuminated[1]*ray[1]); */
1407 
1408 /* // INTEGRAL IS: */
1409 /* // \int sigma T^4 1/2 \cos \varphi d \varphi = */
1410 /* // where */
1411 /* // d\varphi=1/|{\bf R}| \partial {\bf R}/\partial s \cdot {\bf e}_\varphi ds */
1412 
1413 /* double integrand= */
1414 /* this->sigma()*pow((interpolated_u+this->theta_0()),4)* */
1415 /* 0.5*cos_phi*std::fabs(inv_length*(interpolated_dxds[0]*e_phi[0]+ */
1416 /* interpolated_dxds[1]*e_phi[1])); */
1417 
1418 /* // Add it in... */
1419 /* contribution+=integrand*w; */
1420 
1421 /* if (outfile.is_open()) */
1422 /* { */
1423 /* outfile << r_illuminating[0] << " " */
1424 /* << r_illuminating[1] << " " */
1425 /* << cos_phi << " " */
1426 /* << integrand << " " */
1427 /* << "\n"; */
1428 /* } */
1429 /* } */
1430 
1431 /* return contribution; */
1432 /* } */
1433 
1434 
1435 
1436 
1437 /* //===================================================================== */
1438 /* /// Output Stefan Boltzmann radiation. Plots rays from illuminated */
1439 /* /// integration point to illuminating ones (and back). */
1440 /* //===================================================================== */
1441 /* void StefanBoltzmannRadiationBase::output_stefan_boltzmann_radiation_rays( */
1442 /* std::ostream &outfile) */
1443 /* { */
1444 
1445 /* // Vector to illuminated/ing Gauss points */
1446 /* Vector<double> r_illuminated(2); */
1447 /* Vector<double> s_illuminated(1); */
1448 /* Vector<double> unit_normal_illuminated(2); */
1449 /* Vector<double> r_illuminating(2); */
1450 /* Vector<double> s_illuminating(1); */
1451 /* Vector<double> unit_normal_illuminating(2); */
1452 
1453 /* // Loop over integration points */
1454 /* unsigned nint=this->integral_pt()->nweight(); */
1455 /* for (unsigned ipt=0;ipt<nint;ipt++) */
1456 /* { */
1457 /* // Local coordinate of integration point */
1458 /* s_illuminated[0]=this->integral_pt()->knot(ipt,0); */
1459 
1460 /* // Get coordinate of illuminated integration point */
1461 /* this->interpolated_x(s_illuminated,r_illuminated); */
1462 
1463 /* // Plot illuminted point */
1464 /* outfile << "ZONE\n"; */
1465 /* outfile << r_illuminated[0] << " " << r_illuminated[1] << "\n"; */
1466 
1467 /* // Process illuminating Gauss points; their indices are stored in */
1468 
1469 /* // Number of illuminating elements */
1470 /* unsigned n_illuminating=Stefan_boltzmann_illumination_info[ipt].size(); */
1471 /* for (unsigned i2=0;i2<n_illuminating;i2++) */
1472 /* { */
1473 /* // Get pointer to illuminating element */
1474 /* FiniteElement* el_pt= */
1475 /* (//dynamic_cast<FiniteElement*>( */
1476 /* Stefan_boltzmann_illumination_info[ipt][i2].first); */
1477 
1478 /* // Illuminating Gauss points in illuminating element */
1479 /* unsigned n_pts=(Stefan_boltzmann_illumination_info[ipt][i2].second).size(); */
1480 /* for (unsigned ipt2=0;ipt2<n_pts;ipt2++) */
1481 /* { */
1482 
1483 /* // Illuminating integration point */
1484 /* unsigned ipt_illum= */
1485 /* (Stefan_boltzmann_illumination_info[ipt][i2].second)[ipt2]; */
1486 
1487 /* // Get local coordinate of that integration point */
1488 /* s_illuminating[0]=el_pt->integral_pt()->knot(ipt_illum,0); */
1489 
1490 /* // Get coordinate of illuminating integration point */
1491 /* el_pt->interpolated_x(s_illuminating,r_illuminating); */
1492 
1493 /* // Plot ray to illuminting point and back */
1494 /* outfile << r_illuminating[0] << " " << r_illuminating[1] << "\n"; */
1495 /* outfile << r_illuminated[0] << " " << r_illuminated[1] << "\n"; */
1496 /* } */
1497 /* } */
1498 /* } */
1499 /* } */
1500 
1501 
1502 // end hierher
1503 
1507 
1508 
1509 
1510 //======================================================================
1517 //======================================================================
1518 template <class ELEMENT>
1519  class UnsteadyHeatBaseFaceElement : public virtual FaceGeometry<ELEMENT>,
1520  public virtual FaceElement,
1522  {
1523  public:
1524 
1527  const int &face_index)
1528  {
1529 
1530 #ifdef PARANOID
1531  {
1532  //Check that the element is not a refineable 3d element
1533  if(bulk_el_pt->dim()==3)
1534  {
1535  //Is it refineable
1536  if(dynamic_cast<RefineableElement*>(bulk_el_pt))
1537  {
1538  //Issue a warning
1539  std::string error_string=
1540  "This face element will not work correctly if nodes are hanging.\n";
1541  error_string+="Use the refineable version instead. ";
1542  OomphLibWarning(error_string,
1545  }
1546  }
1547  }
1548 #endif
1549 
1550  //Attach the geometrical information to the element. N.B. This function
1551  //also assigns nbulk_value from the required_nvalue of the bulk element
1552  bulk_el_pt->build_face_element(face_index,this);
1553 
1554 
1555  // Extract the dimension of the problem from the dimension of
1556  // the first node
1557  Dim = this->node_pt(0)->ndim();
1558 
1559  //Cast to the appropriate UnsteadyHeatEquation so that we can
1560  //find the index at which the variable is stored
1561  //We assume that the dimension of the full problem is the same
1562  //as the dimension of the node, if this is not the case you will have
1563  //to write custom elements, sorry
1564  switch(Dim)
1565  {
1566  //One dimensional problem
1567  case 1:
1568  {
1569  UnsteadyHeatEquations<1>* eqn_pt =
1570  dynamic_cast<UnsteadyHeatEquations<1>*>(bulk_el_pt);
1571  //If the cast has failed die
1572  if(eqn_pt==0)
1573  {
1574  std::string error_string =
1575  "Bulk element must inherit from UnsteadyHeatEquations.";
1576  error_string +=
1577  "Nodes are one dimensional, but cannot cast the bulk element to\n";
1578  error_string += "UnsteadyHeatEquations<1>\n.";
1579  error_string +=
1580  "If you desire this functionality, you must implement it yourself\n";
1581 
1582  throw OomphLibError(error_string,
1585  }
1586  //Otherwise read out the value
1587  else
1588  {
1589  //Read the index from the (cast) bulk element
1590  U_index_ust_heat = eqn_pt->u_index_ust_heat();
1591  }
1592  }
1593  break;
1594 
1595  //Two dimensional problem
1596  case 2:
1597  {
1598  UnsteadyHeatEquations<2>* eqn_pt =
1599  dynamic_cast<UnsteadyHeatEquations<2>*>(bulk_el_pt);
1600  //If the cast has failed die
1601  if(eqn_pt==0)
1602  {
1603  std::string error_string =
1604  "Bulk element must inherit from UnsteadyHeatEquations.";
1605  error_string +=
1606  "Nodes are two dimensional, but cannot cast the bulk element to\n";
1607  error_string += "UnsteadyHeatEquations<2>\n.";
1608  error_string +=
1609  "If you desire this functionality, you must implement it yourself\n";
1610 
1611  throw OomphLibError(error_string,
1614  }
1615  else
1616  {
1617  //Read the index from the (cast) bulk element.
1618  U_index_ust_heat = eqn_pt->u_index_ust_heat();
1619  }
1620  }
1621  break;
1622 
1623  //Three dimensional problem
1624  case 3:
1625  {
1626  UnsteadyHeatEquations<3>* eqn_pt =
1627  dynamic_cast<UnsteadyHeatEquations<3>*>(bulk_el_pt);
1628  //If the cast has failed die
1629  if(eqn_pt==0)
1630  {
1631  std::string error_string =
1632  "Bulk element must inherit from UnsteadyHeatEquations.";
1633  error_string +=
1634  "Nodes are three dimensional, but cannot cast the bulk element to\n";
1635  error_string += "UnsteadyHeatEquations<3>\n.";
1636  error_string +=
1637  "If you desire this functionality, you must implement it yourself\n";
1638 
1639  throw OomphLibError(error_string,
1642  }
1643  else
1644  {
1645  //Read the index from the (cast) bulk element.
1646  U_index_ust_heat = eqn_pt->u_index_ust_heat();
1647  }
1648  }
1649  break;
1650 
1651  //Any other case is an error
1652  default:
1653  std::ostringstream error_stream;
1654  error_stream << "Dimension of node is " << Dim
1655  << ". It should be 1,2, or 3!" << std::endl;
1656 
1657  throw OomphLibError(error_stream.str(),
1660  break;
1661  }
1662 
1663  }
1664 
1667 
1669  void interpolated_u(const Vector<double>& s, double& u)
1670  {
1671  u=0.0;
1672 
1673  //Find out how many nodes there are
1674  const unsigned n_node = nnode();
1675 
1676  //Set up memory for the shape functions
1677  Shape psif(n_node);
1678 
1679  // Get shape fct
1680  shape(s,psif);
1681 
1682  //Calculate temp
1683  for(unsigned l=0;l<n_node;l++)
1684  {
1685  //Calculate the value at the nodes
1686  double u_value = raw_nodal_value(l,U_index_ust_heat);
1687  u += u_value*psif[l];
1688  }
1689  }
1690 
1691 
1697  double zeta_nodal(const unsigned &n, const unsigned &k,
1698  const unsigned &i) const
1699  {return FaceElement::zeta_nodal(n,k,i);}
1700 
1701 
1704  {
1705  //Call the generic residuals function
1707  }
1708 
1709 
1710  // No Jacobian because of potential of nonlinear dependence of
1711  // flux on temperature
1712  /* /// Compute the element's residual vector and its Jacobian matrix */
1713  /* inline void fill_in_contribution_to_jacobian(Vector<double> &residuals, */
1714  /* DenseMatrix<double> &jacobian) */
1715  /* { */
1716  /* //Call the generic routine with the flag set to 1 */
1717  /* fill_in_generic_residual_contribution_ust_heat_flux(residuals,jacobian,1); */
1718  /* } */
1719 
1720 
1722  void output(std::ostream &outfile)
1723  {
1724  unsigned nplot=5;
1725  output(outfile,nplot);
1726  }
1727 
1731  void output(std::ostream &outfile, const unsigned &n_plot)
1732  {
1733  unsigned n_dim = this->nodal_dimension();
1734  Vector<double> x(n_dim);
1735  Vector<double> s(n_dim-1);
1736  Vector<double> unit_normal(n_dim);
1737 
1738  // Get continuous time from timestepper of first node
1739  double time=node_pt(0)->time_stepper_pt()->time_pt()->time();
1740 
1741  // Number of integration points
1742  unsigned n_intpt = integral_pt()->nweight();
1743 
1744  outfile << "ZONE\n";
1745 
1746  //Loop over the integration points
1747  for(unsigned ipt=0;ipt<n_intpt;ipt++)
1748  {
1749  // Local coordinate of integration point
1750  for (unsigned i=0;i<n_dim-1;i++)
1751  {
1752  s[i]=integral_pt()->knot(ipt,i);
1753  }
1754 
1755  // Get Eulerian coordinates
1756  this->interpolated_x(s,x);
1757 
1758  // Get temperature
1759  double interpolated_u=0;
1760  this->interpolated_u(s,interpolated_u);
1761 
1762  // Outer unit normal
1763  outer_unit_normal(s,unit_normal);
1764 
1765  //Get the incoming flux
1766  double flux=0.0;
1767  get_flux(ipt,time,x,unit_normal,interpolated_u,flux);
1768 
1769  //Output the x,y,..
1770  for(unsigned i=0;i<n_dim;i++)
1771  {
1772  outfile << x[i] << " ";
1773  }
1774 
1775  // Temperature
1776  outfile << interpolated_u << " ";
1777 
1778  // Incoming flux
1779  outfile << flux << " ";
1780 
1781  // Outer unit normal
1782  for(unsigned i=0;i<n_dim;i++)
1783  {
1784  outfile << unit_normal[i] << " ";
1785  }
1786 
1787  outfile << std::endl;
1788  }
1789  }
1790 
1792  void output(FILE* file_pt)
1793  {FiniteElement::output(file_pt);}
1794 
1796  void output(FILE* file_pt, const unsigned &n_plot)
1797  {FiniteElement::output(file_pt,n_plot);}
1798 
1799 
1800  protected:
1801 
1805  inline double shape_and_test(const Vector<double> &s, Shape &psi, Shape &test)
1806  const
1807  {
1808  //Find number of nodes
1809  unsigned n_node = nnode();
1810 
1811  //Get the shape functions
1812  shape(s,psi);
1813 
1814  //Set the test functions to be the same as the shape functions
1815  for(unsigned i=0;i<n_node;i++) {test[i] = psi[i];}
1816 
1817  //Return the value of the jacobian
1818  return J_eulerian(s);
1819  }
1820 
1821  private:
1822 
1825  residuals);
1826 
1827  };
1828 
1829 
1830 
1831 //===========================================================================
1835 //===========================================================================
1836 template<class ELEMENT>
1839 {
1840  //Find out how many nodes there are
1841  const unsigned n_node = nnode();
1842 
1843  // Get continuous time from timestepper of first node
1844  double time=node_pt(0)->time_stepper_pt()->time_pt()->time();
1845 
1846  //Set up memory for the shape and test functions
1847  Shape psif(n_node), testf(n_node);
1848 
1849  //Set the value of n_intpt
1850  const unsigned n_intpt = integral_pt()->nweight();
1851 
1852  //Set the Vector to hold local coordinates
1853  Vector<double> s(Dim-1);
1854 
1855  //Integer to store the local equation and unknowns
1856  int local_eqn=0;
1857 
1858  // Locally cache the index at which the variable is stored
1859  const unsigned u_index_ust_heat = U_index_ust_heat;
1860 
1861  //Loop over the integration points
1862  //--------------------------------
1863  for(unsigned ipt=0;ipt<n_intpt;ipt++)
1864  {
1865 
1866  //Assign values of s
1867  for(unsigned i=0;i<(Dim-1);i++)
1868  {
1869  s[i] = integral_pt()->knot(ipt,i);
1870  }
1871 
1872  //Get the integral weight
1873  double w = integral_pt()->weight(ipt);
1874 
1875  //Find the shape and test functions and return the Jacobian
1876  //of the mapping
1877  double J = shape_and_test(s,psif,testf);
1878 
1879  //Premultiply the weights and the Jacobian
1880  double W = w*J;
1881 
1882  //Need to find position to feed into flux function
1883  Vector<double> interpolated_x(Dim);
1884 
1885  //Initialise to zero
1886  double interpolated_u=0.0;
1887  for(unsigned i=0;i<Dim;i++)
1888  {
1889  interpolated_x[i] = 0.0;
1890  }
1891 
1892  // hierher replace in second sweep (once inline computation of
1893  // n has been validated somewhere)
1894 
1895  //Get the outer unit normal
1896  Vector<double> interpolated_n(Dim);
1897  this->outer_unit_normal(ipt,interpolated_n);
1898 
1899  //Calculate coordinate and temperature
1900  for(unsigned l=0;l<n_node;l++)
1901  {
1902  double u_value = raw_nodal_value(l,u_index_ust_heat);
1903  interpolated_u += u_value*psif[l];
1904 
1905  //Loop over directions
1906  for(unsigned i=0;i<Dim;i++)
1907  {
1908  interpolated_x[i] += nodal_position(l,i)*psif[l];
1909  }
1910  }
1911 
1912  //Get the imposed flux
1913  double flux=0.0;
1914  get_flux(ipt,time,interpolated_x,interpolated_n,interpolated_u,flux);
1915 
1916  //Now add to the appropriate equations
1917 
1918  //Loop over the test functions
1919  for(unsigned l=0;l<n_node;l++)
1920  {
1921  local_eqn = nodal_local_eqn(l,u_index_ust_heat);
1922  /*IF it's not a boundary condition*/
1923  if(local_eqn >= 0)
1924  {
1925  //Add the prescribed flux terms
1926  residuals[local_eqn] -= flux*testf[l]*W;
1927  }
1928  }
1929  }
1930 }
1931 
1932 
1933 
1934 
1935 
1939 
1940 
1941 /* // hierher */
1942 
1943 
1944 /* //====================================================================== */
1945 /* /// A class for elements that allow the imposition of solar/ */
1946 /* /// atmospheric heat flux on the boundaries of UnsteadyHeat elements. */
1947 /* /// The element geometry is obtained from the FaceGeometry<ELEMENT> */
1948 /* /// policy class. */
1949 /* //====================================================================== */
1950 /* template <class ELEMENT> */
1951 /* class SolarUnsteadyHeatFluxElement : */
1952 /* public virtual FaceGeometry<ELEMENT>, */
1953 /* public virtual FaceElement, */
1954 /* public virtual StefanBoltzmannRadiationBase, */
1955 /* public virtual SolarRadiationBase, */
1956 /* public virtual UnsteadyHeatBaseFaceElement<ELEMENT> */
1957 /* { */
1958 
1959 /* public: */
1960 
1961 /* /// Constructor, takes the pointer to the "bulk" element and the */
1962 /* /// index of the face to be created */
1963 /* SolarUnsteadyHeatFluxElement(FiniteElement* const &bulk_el_pt, */
1964 /* const int &face_index); */
1965 
1966 /* /// Broken copy constructor */
1967 /* SolarUnsteadyHeatFluxElement(const SolarUnsteadyHeatFluxElement& dummy) */
1968 /* { */
1969 /* BrokenCopy::broken_copy("SolarUnsteadyHeatFluxElement"); */
1970 /* } */
1971 
1972 /* /// Broken assignment operator */
1973 /* void operator=(const SolarUnsteadyHeatFluxElement&) */
1974 /* { */
1975 /* BrokenCopy::broken_assign("SolarUnsteadyHeatFluxElement"); */
1976 /* } */
1977 
1978 /* /// Compute the element residual vector */
1979 /* inline void fill_in_contribution_to_residuals(Vector<double> &residuals) */
1980 /* { */
1981 /* //Call the generic residuals function with flag set to 0 */
1982 /* //using a dummy matrix argument */
1983 /* fill_in_generic_residual_contribution_solar_ust_heat_flux( */
1984 /* residuals,GeneralisedElement::Dummy_matrix,0); */
1985 /* } */
1986 
1987 
1988 /* // // FD-ed now that we've made it nonlinear with Stefan Boltzmann */
1989 /* // // radiation */
1990 /* // /// Compute the element's residual vector and its Jacobian matrix */
1991 /* // inline void fill_in_contribution_to_jacobian(Vector<double> &residuals, */
1992 /* // DenseMatrix<double> &jacobian) */
1993 /* // { */
1994 /* // //Call the generic routine with the flag set to 1 */
1995 /* // fill_in_generic_residual_contribution_solar_ust_heat_flux(residuals,jacobian,1); */
1996 /* // } */
1997 
1998 /* /// Change integration scheme (overloads underlying version and */
1999 /* /// and resizes lookup schemes introduced in this class. */
2000 /* void set_integration_scheme(Integral* const &integral_pt) */
2001 /* { */
2002 /* FiniteElement::set_integration_scheme(integral_pt); */
2003 /* unsigned n_intpt = integral_pt->nweight(); */
2004 /* Stefan_boltzmann_illumination_info.resize(n_intpt); */
2005 /* Diffuse_limit_angles.resize(n_intpt); */
2006 /* for (unsigned i=0;i<n_intpt;i++) */
2007 /* { */
2008 /* Diffuse_limit_angles[i].first=0.0; */
2009 /* Diffuse_limit_angles[i].second=MathematicalConstants::Pi; */
2010 /* } */
2011 /* } */
2012 
2013 
2014 /* // hierher needed? */
2015 
2016 /* /// Specify the value of nodal zeta from the face geometry: */
2017 /* /// The "global" intrinsic coordinate of the element when */
2018 /* /// viewed as part of a geometric object should be given by */
2019 /* /// the FaceElement representation, by default (needed to break */
2020 /* /// indeterminacy if bulk element is SolidElement) */
2021 /* double zeta_nodal(const unsigned &n, const unsigned &k, */
2022 /* const unsigned &i) const */
2023 /* {return FaceElement::zeta_nodal(n,k,i);} */
2024 
2025 
2026 /* protected: */
2027 
2028 /* /// Function to compute the shape and test functions and to return */
2029 /* /// the Jacobian of mapping between local and global (Eulerian) */
2030 /* /// coordinates */
2031 /* inline double shape_and_test(const Vector<double> &s, Shape &psi, Shape &test) */
2032 /* const */
2033 /* { */
2034 /* //Find number of nodes */
2035 /* unsigned n_node = nnode(); */
2036 
2037 /* //Get the shape functions */
2038 /* shape(s,psi); */
2039 
2040 /* //Set the test functions to be the same as the shape functions */
2041 /* for(unsigned i=0;i<n_node;i++) {test[i] = psi[i];} */
2042 
2043 /* //Return the value of the jacobian */
2044 /* return J_eulerian(s); */
2045 /* } */
2046 
2047 
2048 
2049 /* private: */
2050 
2051 /* /// Compute the element residual vector. */
2052 /* /// flag=1(or 0): do (or don't) compute the Jacobian as well. */
2053 /* void fill_in_generic_residual_contribution_solar_ust_heat_flux( */
2054 /* Vector<double> &residuals, DenseMatrix<double> &jacobian, */
2055 /* unsigned flag); */
2056 
2057 /* }; */
2058 
2059 /* //////////////////////////////////////////////////////////////////////// */
2060 /* //////////////////////////////////////////////////////////////////////// */
2061 /* //////////////////////////////////////////////////////////////////////// */
2062 
2063 /* //=========================================================================== */
2064 /* /// Constructor, takes the pointer to the "bulk" element and the */
2065 /* /// index of the face to be created. */
2066 /* //=========================================================================== */
2067 /* template<class ELEMENT> */
2068 /* SolarUnsteadyHeatFluxElement<ELEMENT>:: */
2069 /* SolarUnsteadyHeatFluxElement(FiniteElement* const &bulk_el_pt, */
2070 /* const int &face_index) : */
2071 /* FaceGeometry<ELEMENT>(), FaceElement() */
2072 /* { */
2073 
2074 /* #ifdef PARANOID */
2075 /* { */
2076 /* //Check that the element is not a refineable 3d element */
2077 /* ELEMENT* elem_pt = new ELEMENT; */
2078 /* //If it's three-d */
2079 /* if(elem_pt->dim()==3) */
2080 /* { */
2081 /* //Is it refineable */
2082 /* if(dynamic_cast<RefineableElement*>(elem_pt)) */
2083 /* { */
2084 /* //Issue a warning */
2085 /* OomphLibWarning( */
2086 /* "This flux element will not work correctly if nodes are hanging\n", */
2087 /* "MyUnsteadyHeatFluxElement::Constructor", */
2088 /* OOMPH_EXCEPTION_LOCATION); */
2089 /* } */
2090 /* } */
2091 /* } */
2092 /* #endif */
2093 
2094 /* // Let the bulk element build the FaceElement, i.e. setup the pointers */
2095 /* // to its nodes (by referring to the appropriate nodes in the bulk */
2096 /* // element), etc. */
2097 /* bulk_el_pt->build_face_element(face_index,this); */
2098 
2099 /* // Extract index of nodal value that stores temperature from */
2100 /* // bulk elements */
2101 /* this->extract_temperature_index_from_bulk_element(bulk_el_pt); */
2102 
2103 /* } */
2104 
2105 
2106 
2107 /* //=========================================================================== */
2108 /* /// Compute the element's residual vector and the (zero) Jacobian matrix. */
2109 /* //=========================================================================== */
2110 /* template<class ELEMENT> */
2111 /* void SolarUnsteadyHeatFluxElement<ELEMENT>:: */
2112 /* fill_in_generic_residual_contribution_solar_ust_heat_flux( */
2113 /* Vector<double> &residuals, DenseMatrix<double> &jacobian, */
2114 /* unsigned flag) */
2115 /* { */
2116 /* //Find out how many nodes there are */
2117 /* const unsigned n_node = nnode(); */
2118 
2119 /* //Set up memory for the shape and test functions */
2120 /* Shape psif(n_node), testf(n_node); */
2121 
2122 /* //Set the value of n_intpt */
2123 /* const unsigned n_intpt = integral_pt()->nweight(); */
2124 
2125 /* //Set the Vector to hold local coordinates */
2126 /* Vector<double> s(Dim-1); */
2127 
2128 /* //Integer to store the local equation numbers */
2129 /* int local_eqn=0; */
2130 
2131 /* // Locally cache the index at which the variable is stored */
2132 /* const unsigned u_index_ust_heat = U_index_ust_heat; */
2133 
2134 /* // Interpolated u */
2135 /* double interpolated_u=0; */
2136 
2137 /* //Loop over the integration points */
2138 /* //-------------------------------- */
2139 /* for(unsigned ipt=0;ipt<n_intpt;ipt++) */
2140 /* { */
2141 
2142 /* //Assign values of s */
2143 /* for(unsigned i=0;i<(Dim-1);i++) */
2144 /* { */
2145 /* s[i] = integral_pt()->knot(ipt,i); */
2146 /* } */
2147 
2148 /* //Get the integral weight */
2149 /* double w = integral_pt()->weight(ipt); */
2150 
2151 /* //Find the shape and test functions and return the Jacobian */
2152 /* //of the mapping */
2153 /* double J = shape_and_test(s,psif,testf); */
2154 
2155 /* //Premultiply the weights and the Jacobian */
2156 /* double W = w*J; */
2157 
2158 /* // Get outer unit normal */
2159 /* Vector<double> n(Dim); */
2160 /* outer_unit_normal(s,n); */
2161 
2162 /* //Need to find position to feed into flux function */
2163 /* Vector<double> interpolated_x(Dim); */
2164 
2165 /* //Initialise to zero */
2166 /* for(unsigned i=0;i<Dim;i++) */
2167 /* { */
2168 /* interpolated_x[i] = 0.0; */
2169 /* } */
2170 
2171 /* //Calculate temperature position */
2172 /* interpolated_u=0.0; */
2173 /* for(unsigned l=0;l<n_node;l++) */
2174 /* { */
2175 /* //Calculate the value at the nodes */
2176 /* double u_value = raw_nodal_value(l,u_index_ust_heat); */
2177 /* interpolated_u += u_value*psif[l]; */
2178 
2179 /* //Loop over directions */
2180 /* for(unsigned i=0;i<Dim;i++) */
2181 /* { */
2182 /* interpolated_x[i] += nodal_position(l,i)*psif[l]; */
2183 /* } */
2184 /* } */
2185 
2186 /* //Get the solar flux */
2187 /* double solar_flux=atmospheric_radiation(ipt,time(),interpolated_x,n); */
2188 
2189 /* // Outgoing Stefan Boltzmann radiation */
2190 /* double outgoing_sb_radiation= */
2191 /* this->sigma()*pow((interpolated_u+this->theta_0()),4); */
2192 
2193 /* // Incoming Stefan Boltzmann radiation */
2194 /* double incoming_sb_radiation=incoming_stefan_boltzmann_radiation */
2195 /* (ipt,interpolated_x,n); */
2196 
2197 /* // Add 'em */
2198 /* double flux=solar_flux+incoming_sb_radiation-outgoing_sb_radiation; */
2199 
2200 /* //Loop over the test functions */
2201 /* for(unsigned l=0;l<n_node;l++) */
2202 /* { */
2203 /* local_eqn = nodal_local_eqn(l,u_index_ust_heat); */
2204 /* /\*IF it's not a boundary condition*\/ */
2205 /* if(local_eqn >= 0) */
2206 /* { */
2207 /* // Add the prescribed flux terms NOTE THAT THERE'S NO BETA */
2208 /* // IN HERE THE ABOVE BALANCES THE BETA * DU/DN THAT APPEARS */
2209 /* // IN THE WEAK FORM OF THE EQUATIONS! */
2210 /* residuals[local_eqn] -= flux*testf[l]*W; */
2211 
2212 /* // No Jacobian -- computed by FD anyway! */
2213 /* if (flag==1) */
2214 /* { */
2215 /* assert(false); */
2216 /* } */
2217 
2218 /* } */
2219 /* } */
2220 /* } */
2221 /* } */
2222 
2223 
2224 
2225 // end hierher
2226 
2230 
2231 
2232 
2233 
2234 
2235 //======================================================================
2242 //======================================================================
2243 template <class ELEMENT>
2245 public virtual FaceGeometry<ELEMENT>,
2246  public virtual SolidFaceElement,
2247  public virtual UnsteadyHeatBaseFaceElement<ELEMENT>
2248 
2249  {
2250 
2251  public:
2252 
2255  SurfaceMeltElement(FiniteElement* const &bulk_el_pt,
2256  const int &face_index,
2257  const unsigned &id=0,
2258  const bool& called_from_refineable_constructor=false) :
2259  UnsteadyHeatBaseFaceElement<ELEMENT>(bulk_el_pt,face_index)
2260  {
2261 
2262 #ifdef PARANOID
2263  {
2264  //Check that the element is not a refineable 3d element
2265  if (!called_from_refineable_constructor)
2266  {
2267  if(bulk_el_pt->dim()==3)
2268  {
2269  //Is it refineable
2270  if(dynamic_cast<RefineableElement*>(bulk_el_pt))
2271  {
2272  //Issue a warning
2273  std::string error_string=
2274  "This face element will not work correctly if nodes are hanging.\n";
2275  error_string+="Use the refineable version instead. ";
2276  OomphLibWarning(error_string,
2279  }
2280  }
2281  }
2282  }
2283 #endif
2284 
2285  // Use default melt temperature
2287 
2288  // Store the ID of the FaceElement -- this is used to distinguish
2289  // it from any others
2290  Melt_id=id;
2291 
2292  // We need two additional value for each FaceElement node:
2293  // (1) the normal traction (Lagrange multiplier) to be
2294  // exerted onto the pseudo-solid and (2) the melt rate
2295  unsigned n_nod=nnode();
2296  Vector<unsigned> n_additional_values(n_nod,2);
2297 
2298  // Now add storage for Lagrange multipliers and set the map containing
2299  // the position of the first entry of this face element's
2300  // additional values.
2301  add_additional_values(n_additional_values,id);
2302 
2303 #ifdef PARANOID
2304  // Check spatial dimension
2305  if (this->Dim!=2)
2306  {
2307  //Issue a warning
2308  throw OomphLibError(
2309  "This element will almost certainly not work in non-2D problems, though it should be easy enough to upgrade... Volunteers?\n",
2312  }
2313 #endif
2314 
2315 
2316  /* // hierher */
2317  /* // Add positions of bulk nodes as external data */
2318  /* unsigned nnod_bulk=bulk_el_pt->nnode(); */
2319  /* unsigned count=0; */
2320  /* for (unsigned j=0;j<nnod_bulk;j++) */
2321  /* { */
2322  /* SolidNode* bulk_nod_pt=dynamic_cast<SolidNode*>(bulk_el_pt->node_pt(j)); */
2323  /* unsigned do_it=true; */
2324  /* for (unsigned k=0;k<n_nod;k++) */
2325  /* { */
2326  /* SolidNode* nod_pt=dynamic_cast<SolidNode*>(node_pt(k)); */
2327  /* if (nod_pt==bulk_nod_pt) */
2328  /* { */
2329  /* do_it=false; */
2330  /* break; */
2331  /* } */
2332  /* } */
2333  /* if (do_it) */
2334  /* { */
2335  /* count++; */
2336  /* add_external_data(bulk_nod_pt->variable_position_pt()); */
2337  /* add_external_data(bulk_nod_pt); */
2338  /* } */
2339  /* } */
2340  /* oomph_info << "Added " << count << " position data from bulk\n"; */
2341 
2342  }
2343 
2344 
2348  {
2349  // Initialise pressure
2350  double p=0;
2351 
2352  //Find out how many nodes there are
2353  unsigned n_node = nnode();
2354 
2355  //Set up memory for the shape functions
2356  Shape psi(n_node);
2357 
2358  // Evaluate shape function
2359  shape(s,psi);
2360 
2361  // Build up Lagrange multiplier (pressure)
2362  for (unsigned j=0;j<n_node;j++)
2363  {
2364  // Cast to a boundary node
2365  BoundaryNodeBase *bnod_pt =
2366  dynamic_cast<BoundaryNodeBase*>(node_pt(j));
2367 
2368  // Get the index of the first nodal value associated with
2369  // this FaceElement
2370  unsigned first_index=
2372 
2373  // Pressure (Lagrange multiplier) is the first of two additional
2374  // values created by this face element
2375  p+=node_pt(j)->value(first_index)*psi[j];
2376  }
2377  return p;
2378  }
2379 
2380 
2383  {
2385  }
2386 
2387 
2390  {
2391  if (Melt_temperature_pt==0)
2392  {
2393  return 0.0;
2394  }
2395  else
2396  {
2397  return *Melt_temperature_pt;
2398  }
2399  }
2400 
2403  {
2404  return Melt_temperature_pt;
2405  }
2406 
2409  {
2410  unsigned n_node=nnode();
2411  for(unsigned l=0;l<n_node;l++)
2412  {
2413  // get the node pt
2414  Node* nod_pt = node_pt(l);
2415 
2416  // Cast to a boundary node
2417  BoundaryNodeBase *bnod_pt =
2418  dynamic_cast<BoundaryNodeBase*>(nod_pt);
2419 
2420  // Get the index of the first nodal value associated with
2421  // this FaceElement
2422  unsigned first_index=
2424 
2425  // Pin melt rate (second additional value created by this face element)
2426  nod_pt->pin(first_index+1);
2427  }
2428  }
2429 
2430 
2434  {
2435  unsigned n_node=nnode();
2436  for(unsigned l=0;l<n_node;l++)
2437  {
2438  // get the node pt
2439  Node* nod_pt = node_pt(l);
2440 
2441  // Cast to a boundary node
2442  BoundaryNodeBase *bnod_pt =
2443  dynamic_cast<BoundaryNodeBase*>(nod_pt);
2444 
2445  // Get the index of the first nodal value associated with
2446  // this FaceElement
2447  unsigned first_index=
2449 
2450  // Lagrange multiplier is first additional value created by this
2451  // face element)
2452  nod_pt->set_value(first_index,0.0);
2453  }
2454  }
2455 
2456 
2462  double zeta_nodal(const unsigned &n, const unsigned &k,
2463  const unsigned &i) const
2464  {return FaceElement::zeta_nodal(n,k,i);}
2465 
2466 
2467  // /// Fill in contribution from Jacobian
2468  // void fill_in_contribution_to_jacobian(Vector<double> &residuals,
2469  // DenseMatrix<double> &jacobian);
2470 
2471 
2472 
2475  {
2476  // Iinitialise
2477  melt_flux=0.0;
2478 
2479  //Find out how many nodes there are
2480  const unsigned n_node = nnode();
2481 
2482  //Set up memory for the shape functions
2483  Shape psi(n_node);
2484 
2485  // Get shape fct
2486  shape(s,psi);
2487 
2488  //Calculate stuff
2489  for(unsigned l=0;l<n_node;l++)
2490  {
2491  // get the node pt
2492  Node* nod_pt = node_pt(l);
2493 
2494  // Cast to a boundary node
2495  BoundaryNodeBase *bnod_pt = dynamic_cast<BoundaryNodeBase*>(nod_pt);
2496 
2497  // Get the index of the first nodal value associated with
2498  // this FaceElement
2499  unsigned first_index=
2501 
2502  // Melt rate
2503  melt_flux+=nod_pt->value(first_index+1)*psi[l];
2504  }
2505  }
2506 
2509  void output_melt(std::ostream &outfile)
2510  {
2511  unsigned n_dim = this->nodal_dimension();
2512  Vector<double> x(n_dim);
2513  Vector<double> s(n_dim-1);
2514  Vector<double> unit_normal(n_dim);
2515 
2516  // Get continuous time from timestepper of first node
2517  double time=node_pt(0)->time_stepper_pt()->time_pt()->time();
2518 
2519  // Number of integration points
2520  unsigned n_intpt = integral_pt()->nweight();
2521 
2522  outfile << "ZONE\n";
2523 
2524  //Loop over the integration points
2525  for(unsigned ipt=0;ipt<n_intpt;ipt++)
2526  {
2527  // Local coordinate of integration point
2528  for (unsigned i=0;i<n_dim-1;i++)
2529  {
2530  s[i]=integral_pt()->knot(ipt,i);
2531  }
2532 
2533  // Get Eulerian coordinates
2534  this->interpolated_x(s,x);
2535 
2536  // Get temperature
2537  double interpolated_u=0;
2538  this->interpolated_u(s,interpolated_u);
2539 
2540  // Outer unit normal
2541  outer_unit_normal(s,unit_normal);
2542 
2543  // Get melt rate
2544  double interpolated_m=0.0;
2545  this->interpolated_melt_rate(s,interpolated_m);
2546 
2547  // Get "lagrange multiplier" pressure
2548  double lagrange_p=get_interpolated_lagrange_p(s);
2549 
2550  //Get the incoming flux
2551  double flux=0.0;
2552  this->get_flux(ipt,time,x,unit_normal,interpolated_u,flux);
2553 
2554  //Output the x,y,..
2555  for(unsigned i=0;i<n_dim;i++)
2556  {
2557  outfile << x[i] << " ";
2558  }
2559 
2560  // Temperature
2561  outfile << interpolated_u << " ";
2562 
2563  // Incoming flux
2564  outfile << flux << " ";
2565 
2566  // Melt rate
2567  outfile << interpolated_m << " ";
2568 
2569  // Lagrange multiplier-like pressure
2570  outfile << lagrange_p << " ";
2571 
2572  // Outer unit normal
2573  for(unsigned i=0;i<n_dim;i++)
2574  {
2575  outfile << unit_normal[i] << " ";
2576  }
2577  outfile << std::endl;
2578  }
2579  }
2580 
2581  protected:
2582 
2585  Vector<double> &residuals);
2586 
2588  unsigned Melt_id;
2589 
2592 
2593  };
2594 
2598 
2599 // hierher kill
2600 
2601 /* //===================================================================== */
2602 /* /// Output melt rate etc. */
2603 /* //===================================================================== */
2604 /* template<class ELEMENT> */
2605 /* void SurfaceMeltElement<ELEMENT>::output_melt_rate(std::ostream &outfile, */
2606 /* const unsigned &n_plot) */
2607 /* { */
2608 
2609 /* // Locally cache the index at which the variable is stored */
2610 /* const unsigned u_index_ust_heat = this->U_index_ust_heat; */
2611 
2612 /* // Get continuous time from timestepper of first node */
2613 /* double time=node_pt(0)->time_stepper_pt()->time_pt()->time(); */
2614 
2615 /* //Find out how many nodes there are */
2616 /* const unsigned n_node = nnode(); */
2617 
2618 /* //Set up memory for the shape functions */
2619 /* Shape psi(n_node); */
2620 
2621 /* // Local and global coordinates */
2622 /* Vector<double> s(this->Dim-1); */
2623 /* Vector<double> interpolated_x(this->Dim); */
2624 
2625 /* // Tecplot header info */
2626 /* outfile << this->tecplot_zone_string(n_plot); */
2627 
2628 /* // Loop over plot points */
2629 /* unsigned num_plot_points=this->nplot_points(n_plot); */
2630 /* for (unsigned iplot=0;iplot<num_plot_points;iplot++) */
2631 /* { */
2632 /* // Get local coordinates of plot point */
2633 /* this->get_s_plot(iplot,n_plot,s); */
2634 
2635 /* // Outer unit normal */
2636 /* Vector<double> unit_normal(this->Dim); */
2637 /* outer_unit_normal(s,unit_normal); */
2638 
2639 /* //Find the shape functions */
2640 /* shape(s,psi); */
2641 
2642 /* // Melt flux */
2643 /* double melt_flux=0.0; */
2644 
2645 /* // Temperature */
2646 /* double u=0.0; */
2647 
2648 /* //Initialise to zero */
2649 /* for(unsigned i=0;i<this->Dim;i++) */
2650 /* { */
2651 /* interpolated_x[i] = 0.0; */
2652 /* } */
2653 
2654 /* //Calculate stuff */
2655 /* for(unsigned l=0;l<n_node;l++) */
2656 /* { */
2657 /* // get the node pt */
2658 /* Node* nod_pt = node_pt(l); */
2659 
2660 /* // Cast to a boundary node */
2661 /* BoundaryNodeBase *bnod_pt = */
2662 /* dynamic_cast<BoundaryNodeBase*>(nod_pt); */
2663 
2664 /* // Get the index of the first nodal value associated with */
2665 /* // this FaceElement */
2666 /* unsigned first_index= */
2667 /* bnod_pt->index_of_first_value_assigned_by_face_element(Melt_id); */
2668 
2669 /* // Melt rate */
2670 /* melt_flux+=nod_pt->value(first_index+1)*psi[l]; */
2671 
2672 /* // Temperature */
2673 /* u+=nod_pt->value(u_index_ust_heat)*psi[l]; */
2674 
2675 /* //Loop over directions */
2676 /* for(unsigned i=0;i<this->Dim;i++) */
2677 /* { */
2678 /* interpolated_x[i] += nodal_position(l,i)*psi[l]; */
2679 /* } */
2680 /* } */
2681 
2682 /* //Get the imposed flux */
2683 /* double flux=0.0; */
2684 /* this->get_flux(time,interpolated_x,flux,u); */
2685 
2686 /* //Output the x,y,.. */
2687 /* for(unsigned i=0;i<this->Dim;i++) */
2688 /* { */
2689 /* outfile << interpolated_x[i] << " "; */
2690 /* } */
2691 
2692 /* // Output imposed flux and melt flux */
2693 /* outfile << flux << " "; */
2694 /* outfile << melt_flux << " "; */
2695 
2696 /* // Output normal */
2697 /* for(unsigned i=0;i<this->Dim;i++) */
2698 /* { */
2699 /* outfile << unit_normal[i] << " "; */
2700 /* } */
2701 /* outfile << std::endl; */
2702 /* } */
2703 
2704 /* } */
2705 // hierher end kill
2706 
2707 //=====================================================================
2709 //=====================================================================
2710 template<class ELEMENT>
2713  {
2714 
2715  // hierher kill oomph_info << "hierher: Number of dofs: " << ndof() << std::endl;
2716 
2717  // Get continuous time from timestepper of first node
2718  double time=node_pt(0)->time_stepper_pt()->time_pt()->time();
2719 
2720  //Find out how many nodes there are
2721  unsigned n_node = nnode();
2722 
2723  //Find out how many positional dofs there are
2724  unsigned n_position_type = this->nnodal_position_type();
2725 
2726  //Find out the dimension of the node
2727  unsigned n_dim = this->nodal_dimension();
2728 
2729  //Integer to hold the local equation number
2730  int local_eqn=0;
2731 
2732  /* // hierher kill */
2733  /* { */
2734  /* for (unsigned j=0;j<n_node;j++) */
2735  /* { */
2736  /* SolidNode* nod_pt=dynamic_cast<SolidNode*>(node_pt(j)); */
2737  /* unsigned nval=nod_pt->nvalue(); */
2738  /* for (unsigned i=0;i<nval;i++) */
2739  /* { */
2740  /* oomph_info << "i_val, eqn_number: " << i << " " */
2741  /* << nod_pt->eqn_number(i) << " " */
2742  /* << std::endl; */
2743  /* } */
2744  /* Data* data_pt=dynamic_cast<SolidNode*>(node_pt(j)) */
2745  /* ->variable_position_pt(); */
2746  /* nval=data_pt->nvalue(); */
2747  /* for (unsigned i=0;i<nval;i++) */
2748  /* { */
2749  /* oomph_info << "i_pos, eqn_number: " << i << " " */
2750  /* << data_pt->eqn_number(i) << " " */
2751  /* << std::endl; */
2752  /* } */
2753  /* } */
2754  /* } */
2755 
2756  //Set up memory for the shape functions
2757  //Note that in this case, the number of lagrangian coordinates is always
2758  //equal to the dimension of the nodes
2759  Shape psi(n_node,n_position_type);
2760  DShape dpsids(n_node,n_position_type,n_dim-1);
2761 
2762  //Set the value of n_intpt
2763  unsigned n_intpt = integral_pt()->nweight();
2764 
2765  //Loop over the integration points
2766  for(unsigned ipt=0;ipt<n_intpt;ipt++)
2767  {
2768  //Get the integral weight
2769  double w = integral_pt()->weight(ipt);
2770 
2771  //Only need to call the local derivatives
2772  dshape_local_at_knot(ipt,psi,dpsids);
2773 
2774  //Calculate the Eulerian and Lagrangian coordinates
2775  Vector<double> interpolated_x(n_dim,0.0);
2776  Vector<double> interpolated_dxdt(n_dim,0.0);
2777  Vector<double> interpolated_xi(n_dim,0.0);
2778 
2779  // Interpolated Lagrange multiplier (pressure acting on solid
2780  // to enforce melting)
2781  double interpolated_lambda_p=0.0;
2782 
2783  // Get temperature
2784  double u=0;
2785 
2786  // Melt rate
2787  double melt_rate=0.0;
2788 
2789  //Also calculate the surface Vectors (derivatives wrt local coordinates)
2790  DenseMatrix<double> interpolated_A(n_dim-1,n_dim,0.0);
2791 
2792  //Calculate stuff
2793  for(unsigned l=0;l<n_node;l++)
2794  {
2795  // Cast to a boundary node
2796  BoundaryNodeBase *bnod_pt =
2797  dynamic_cast<BoundaryNodeBase*>(node_pt(l));
2798 
2799  // Get the index of the first nodal value associated with
2800  // this FaceElement
2801  unsigned first_index=
2803 
2804  // Add to Lagrange multiplier (acting as pressure on solid
2805  // to enforce melting motion)
2806  interpolated_lambda_p+=node_pt(l)->value(first_index)*psi[l];
2807 
2808  // Add to melt rate
2809  melt_rate+=node_pt(l)->value(first_index+1)*psi[l];
2810 
2811  // Add to temperature
2812  u+=node_pt(l)->value(this->U_index_ust_heat)*psi[l];
2813 
2814  //Loop over positional dofs
2815  for(unsigned k=0;k<n_position_type;k++)
2816  {
2817  //Loop over spatial dimension
2818  for(unsigned i=0;i<n_dim;i++)
2819  {
2820  //Calculate the Eulerian and Lagrangian positions
2821  interpolated_x[i] +=
2822  nodal_position_gen(l,bulk_position_type(k),i)*psi(l,k);
2823 
2824  interpolated_dxdt[i] +=
2825  this->dnodal_position_gen_dt(l,bulk_position_type(k),i)*psi(l,k);
2826 
2827  interpolated_xi[i] +=
2828  this->lagrangian_position_gen(l,bulk_position_type(k),i)*psi(l,k);
2829 
2830  //Loop over LOCAL derivative directions, to calculate the tangent(s)
2831  for(unsigned j=0;j<n_dim-1;j++)
2832  {
2833  interpolated_A(j,i) +=
2834  nodal_position_gen(l,bulk_position_type(k),i)*dpsids(l,k,j);
2835  }
2836  }
2837  }
2838  }
2839 
2840  //Now find the local deformed metric tensor from the tangent Vectors
2841  DenseMatrix<double> A(n_dim-1);
2842  for(unsigned i=0;i<n_dim-1;i++)
2843  {
2844  for(unsigned j=0;j<n_dim-1;j++)
2845  {
2846  //Initialise surface metric tensor to zero
2847  A(i,j) = 0.0;
2848  //Take the dot product
2849  for(unsigned k=0;k<n_dim;k++)
2850  {
2851  A(i,j) += interpolated_A(i,k)*interpolated_A(j,k);
2852  }
2853  }
2854  }
2855 
2856  // hierher replaced this in first sweep!
2857 
2858  //Get the outer unit normal
2859  Vector<double> interpolated_normal(n_dim);
2860  outer_unit_normal(ipt,interpolated_normal);
2861 
2862  // Local coordinate of integration point
2863  unsigned n_dim = this->nodal_dimension();
2864  Vector<double> s(n_dim-1);
2865  for (unsigned i=0;i<n_dim-1;i++)
2866  {
2867  s[i]=integral_pt()->knot(ipt,i);
2868  }
2869 
2870  /* // Outgoing Stefan Boltzmann radiative flux */
2871  /* //========================================= */
2872  /* double outgoing_stefan_boltzmann_flux=sigma()*pow((u+theta_0()),4); */
2873 
2874  /* // Incoming Stefan Boltzmann radiation */
2875  /* //==================================== */
2876  /* double incoming_sb_radiation=incoming_stefan_boltzmann_radiation */
2877  /* (ipt,interpolated_x,interpolated_normal); */
2878 
2879  /* // Get the incoming atmospheric radiation */
2880  /* //======================================== */
2881  /* double incoming_atmospheric_radiation= */
2882  /* atmospheric_radiation(ipt,time(),interpolated_x, */
2883  /* interpolated_normal); */
2884 
2885  /* // Get net heat flux */
2886  /* //================== */
2887  /* double net_heat_flux=incoming_atmospheric_radiation+ */
2888  /* incoming_sb_radiation-outgoing_stefan_boltzmann_flux; */
2889 
2890  //Get the imposed flux
2891  double flux=0.0;
2892  this->get_flux(ipt,time,interpolated_x,interpolated_normal,u,flux);
2893 
2894 
2895  // Calculate the "load" -- Lagrange multiplier acts as traction to
2896  //================================================================
2897  // to enforce required surface displacement
2898  //=========================================
2899  Vector<double> traction(n_dim);
2900  for (unsigned i=0;i<n_dim;i++)
2901  {
2902  traction[i]=-interpolated_lambda_p*interpolated_normal[i];
2903  }
2904 
2905 
2906  // Get normal velocity
2907  double normal_veloc=0.0;
2908  for (unsigned i=0;i<n_dim;i++)
2909  {
2910  normal_veloc+=interpolated_dxdt[i]*interpolated_normal[i];
2911  }
2912 
2913 
2914  //Find the determinant of the metric tensor
2915  double Adet =0.0;
2916  switch(n_dim)
2917  {
2918  case 2:
2919  Adet = A(0,0);
2920  break;
2921  case 3:
2922  Adet = A(0,0)*A(1,1) - A(0,1)*A(1,0);
2923  break;
2924  default:
2925  throw
2926  OomphLibError("Wrong dimension in SurfaceMeltElement",
2929  }
2930 
2931 
2932  //Premultiply the weights and the square-root of the determinant of
2933  //the metric tensor
2934  double W = w*sqrt(Adet);
2935 
2936  //Loop over the test functions, nodes of the element
2937  for(unsigned l=0;l<n_node;l++)
2938  {
2939 
2940  // Contributions to bulk solid equations
2941  //--------------------------------------
2942  //Loop of types of dofs
2943  for(unsigned k=0;k<n_position_type;k++)
2944  {
2945  //Loop over the displacement components
2946  for(unsigned i=0;i<n_dim;i++)
2947  {
2948  local_eqn = this->position_local_eqn(l,bulk_position_type(k),i);
2949  if(local_eqn >= 0)
2950  {
2951  //Add the loading terms to the residuals
2952  residuals[local_eqn] -= traction[i]*psi(l,k)*W;
2953  }
2954  }
2955  } //End of if not boundary condition
2956 
2957 
2958  // Contributions to equation that determines the Lagrange multiplier
2959  //------------------------------------------------------------------
2960  // (pressure) from kinematic condition
2961  //------------------------------------
2962 
2963  // Cast to a boundary node
2964  BoundaryNodeBase *bnod_pt =
2965  dynamic_cast<BoundaryNodeBase*>(node_pt(l));
2966 
2967  // Get the index of the first nodal value associated with
2968  // this FaceElement
2969  unsigned first_index=
2971  local_eqn=this->nodal_local_eqn(l,first_index);
2972  if (local_eqn>=0)
2973  {
2974  residuals[local_eqn]+=(normal_veloc+melt_rate)*psi[l]*W;
2975  }
2976 
2977  // Contribution to flux into bulk
2978  //-------------------------------
2979  local_eqn = nodal_local_eqn(l,this->U_index_ust_heat);
2980  if(local_eqn >= 0)
2981  {
2982  //Add the prescribed flux terms
2983  residuals[local_eqn] -= (flux-melt_rate)*psi[l]*W;
2984  }
2985 
2986  } //End of loop over shape functions
2987  } //End of loop over integration points
2988 
2989 
2990  // Collocation for melt rate:
2991  //---------------------------
2992 
2993  //Loop over the nodes
2994  for(unsigned l=0;l<n_node;l++)
2995  {
2996  // get the node pt
2997  Node* nod_pt = node_pt(l);
2998 
2999  // Cast to a boundary node
3000  BoundaryNodeBase *bnod_pt =
3001  dynamic_cast<BoundaryNodeBase*>(nod_pt);
3002 
3003  // Get the index of the first nodal value associated with
3004  // this FaceElement
3005  unsigned first_index=
3007 
3008  // Melt rate equation is second added one
3009  local_eqn = nodal_local_eqn(l,first_index+1);
3010 
3011  /*IF it's not a boundary condition*/
3012  if(local_eqn >= 0)
3013  {
3014  double u=nod_pt->value(this->U_index_ust_heat);
3015  double melt_rate=nod_pt->value(first_index+1);
3016 
3017  // Piecewise linear variation
3018  if ((melt_temperature()-u)>melt_rate)
3019  {
3020  residuals[local_eqn]+=melt_rate;
3021  }
3022  else
3023  {
3024  residuals[local_eqn]+=(melt_temperature()-u);
3025  }
3026 
3027  }
3028  }
3029 
3030  }
3031 
3035 
3036 }
3037 
3038 #endif
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
JacobiRotation< float > J
Definition: Jacobi_makeJacobi.cpp:3
RowVector3d w
Definition: Matrix_resize_int.cpp:3
float * p
Definition: Tutorial_Map_using.cpp:9
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Definition: nodes.h:1996
unsigned index_of_first_value_assigned_by_face_element(const unsigned &face_id=0) const
Definition: nodes.h:2061
Definition: shape.h:278
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:385
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
void set_value(const unsigned &i, const double &value_)
Definition: nodes.h:271
Definition: elements.h:4338
int & face_index()
Definition: elements.h:4626
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
Definition: elements.cc:6006
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: elements.h:4497
void add_additional_values(const Vector< unsigned > &nadditional_values, const unsigned &id)
Definition: elements.h:4428
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Definition: elements.h:4528
double J_eulerian(const Vector< double > &s) const
Definition: elements.cc:5242
Definition: elements.h:4998
Definition: elements.h:1313
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
virtual void output(std::ostream &outfile)
Definition: elements.h:3050
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Definition: elements.cc:5132
virtual void shape(const Vector< double > &s, Shape &psi) const =0
unsigned dim() const
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1963
unsigned nodal_dimension() const
Return the required Eulerian dimension of the nodes in this element.
Definition: elements.h:2484
double raw_nodal_value(const unsigned &n, const unsigned &i) const
Definition: elements.h:2576
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
Definition: nodes.h:906
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
double value(const unsigned &i) const
Definition: nodes.cc:2408
Definition: oomph_definitions.h:222
Definition: oomph_definitions.h:267
Definition: refineable_elements.h:97
Definition: shape.h:76
Definition: elements.h:4914
Definition: heat_transfer_and_melt_elements.h:2249
void interpolated_melt_rate(const Vector< double > &s, double &melt_flux)
Melt rate at local coordinate s.
Definition: heat_transfer_and_melt_elements.h:2474
double melt_temperature()
Melt temperature.
Definition: heat_transfer_and_melt_elements.h:2389
double * Melt_temperature_pt
Pointer to non-default melt temperature.
Definition: heat_transfer_and_melt_elements.h:2591
void set_lagrange_multiplier_pressure_to_zero()
Definition: heat_transfer_and_melt_elements.h:2433
void output_melt(std::ostream &outfile)
Definition: heat_transfer_and_melt_elements.h:2509
void fill_in_contribution_to_residuals_surface_melt(Vector< double > &residuals)
Helper function that actually calculates the residuals.
Definition: heat_transfer_and_melt_elements.h:2712
double get_interpolated_lagrange_p(const Vector< double > &s)
Definition: heat_transfer_and_melt_elements.h:2347
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: heat_transfer_and_melt_elements.h:2462
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Return the residuals.
Definition: heat_transfer_and_melt_elements.h:2382
void disable_melting()
Switch off melting by pinning melt-rate dofs.
Definition: heat_transfer_and_melt_elements.h:2408
double *& melt_temperature_pt()
Pointer to (non-default) melt temperature.
Definition: heat_transfer_and_melt_elements.h:2402
unsigned Melt_id
Id of additional unknowns (Lagrange multiplier ("pressure") and melt rate)
Definition: heat_transfer_and_melt_elements.h:2588
SurfaceMeltElement(FiniteElement *const &bulk_el_pt, const int &face_index, const unsigned &id=0, const bool &called_from_refineable_constructor=false)
Definition: heat_transfer_and_melt_elements.h:2255
Definition: heat_transfer_and_melt_elements.h:123
UnsteadyHeatPrescribedFluxFctPt & flux_fct_pt()
Access function for the prescribed-flux function pointer.
Definition: heat_transfer_and_melt_elements.h:147
UnsteadyHeatPrescribedFluxFctPt Flux_fct_pt
Function pointer to the (global) prescribed-flux function.
Definition: heat_transfer_and_melt_elements.h:185
void(* UnsteadyHeatPrescribedFluxFctPt)(const double &time, const Vector< double > &x, const Vector< double > &n, const double &u, double &flux)
Definition: heat_transfer_and_melt_elements.h:132
unsigned U_index_ust_heat
Index at which temperature is stored.
Definition: heat_transfer_and_melt_elements.h:179
TemplateFreeUnsteadyHeatBaseFaceElement()
Constructor.
Definition: heat_transfer_and_melt_elements.h:139
virtual void get_flux(const unsigned &ipt, const double &time, const Vector< double > &x, const Vector< double > &n, const double &u, double &flux)
Definition: heat_transfer_and_melt_elements.h:159
unsigned Dim
The spatial dimension of the problem.
Definition: heat_transfer_and_melt_elements.h:182
virtual ~TemplateFreeUnsteadyHeatBaseFaceElement()
Destrutor.
Definition: heat_transfer_and_melt_elements.h:144
Time *const & time_pt() const
Access function for the pointer to time (const version)
Definition: timesteppers.h:572
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:123
Definition: heat_transfer_and_melt_elements.h:1522
void output(std::ostream &outfile, const unsigned &n_plot)
Definition: heat_transfer_and_melt_elements.h:1731
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Compute the element residual vector.
Definition: heat_transfer_and_melt_elements.h:1703
double shape_and_test(const Vector< double > &s, Shape &psi, Shape &test) const
Definition: heat_transfer_and_melt_elements.h:1805
void output(std::ostream &outfile)
Output function.
Definition: heat_transfer_and_melt_elements.h:1722
virtual ~UnsteadyHeatBaseFaceElement()
Destructor.
Definition: heat_transfer_and_melt_elements.h:1666
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: heat_transfer_and_melt_elements.h:1697
void output(FILE *file_pt)
C_style output function.
Definition: heat_transfer_and_melt_elements.h:1792
void interpolated_u(const Vector< double > &s, double &u)
Temperature at local coordinate s.
Definition: heat_transfer_and_melt_elements.h:1669
void fill_in_generic_residual_contribution_ust_heat_flux(Vector< double > &residuals)
Generic residuals function.
Definition: heat_transfer_and_melt_elements.h:1838
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function.
Definition: heat_transfer_and_melt_elements.h:1796
UnsteadyHeatBaseFaceElement(FiniteElement *const &bulk_el_pt, const int &face_index)
Constructor.
Definition: heat_transfer_and_melt_elements.h:1526
Definition: unsteady_heat_elements.h:72
virtual unsigned u_index_ust_heat() const
Broken assignment operator.
Definition: unsteady_heat_elements.h:112
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
double melt_flux(const double &t)
Definition: stefan_boltzmann_melt.cc:643
static const unsigned Dim
Problem dimension.
Definition: two_d_tilted_square.cc:62
void flux(const double &time, const Vector< double > &x, double &flux)
Get flux applied along boundary x=0.
Definition: pretend_melt.cc:59
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
void get_flux(const Vector< double > &s, Vector< double > &flux) const
Get flux: .
Definition: gen_axisym_advection_diffusion_elements.h:424
list x
Definition: plotDoE.py:28
Definition: indexed_view.cpp:20
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2