#ifndef NOTCL #include #include #include #include #include #include #include namespace netgen { // extern shared_ptr mesh; RKStepper :: ~RKStepper() { delete a; } RKStepper :: RKStepper(int type) : a(NULL), tolerance(1e100) { notrestarted = 0; if (type == 0) // explicit Euler { c.SetSize(1); c[0] = 0; b.SetSize(1); b[0] = 1; steps = order = 1; } else if (type == 1) // Euler-Cauchy { c.SetSize(2); c[0] = 0; c[1] = 0.5; b.SetSize(2); b[0] = 0; b[1] = 1; NgArray size(2); size[0] = 0; size[1] = 1; a = new TABLE(size); a->Set(2,1,0.5); // Set, Get: 1-based! steps = order = 2; } else if (type == 2) // Simpson { c.SetSize(3); c[0] = 0; c[1] = 1; c[2] = 0.5; b.SetSize(3); b[0] = b[1] = 1./6.; b[2] = 2./3.; NgArray size(3); size[0] = 0; size[1] = 1; size[2] = 2; a = new TABLE(size); a->Set(2,1,1); a->Set(3,1,0.25); a->Set(3,2,0.25); steps = order = 3; } else if (type == 3) // classical Runge-Kutta { c.SetSize(4); c[0] = 0; c[1] = c[2] = 0.5; c[3] = 1; b.SetSize(4); b[0] = b[3] = 1./6.; b[1] = b[2] = 1./3.; NgArray size(4); size[0] = 0; size[1] = 1; size[2] = 2; size[3] = 3; a = new TABLE(size); a->Set(2,1,0.5); a->Set(3,1,0); a->Set(3,2,0.5); a->Set(4,1,0); a->Set(4,2,0); a->Set(4,3,1); steps = order = 4; } K.SetSize(steps); } void RKStepper :: StartNextValCalc(const Point<3> & astartval, const double astartt, const double ah, const bool aadaptive) { //cout << "Starting RK-Step with h=" << ah << endl; stepcount = 0; h = ah; startt = astartt; startval = astartval; adaptive = aadaptive; adrun = 0; } bool RKStepper :: GetNextData(Point<3> & val, double & t, double & ah) { bool finished = false; if(stepcount <= steps) { t = startt + c[stepcount-1]*h; val = startval; for(int i=0; iGet(stepcount,i+1) * K[i]; } if(stepcount == steps) { val = startval; for(int i=0; i valh2 = val; val = valh2 + 1./(pow(2.,order)-1.) * (valh2 - valh); auto errvec = val - valh; double err = errvec.Length(); double fac = 0.7 * pow(tolerance/err,1./(order+1.)); if(fac > 1.3) fac = 1.3; if(fac < 1 || notrestarted >= 2) ah = 2.*h * fac; if(err < tolerance) { finished = true; notrestarted++; //(*testout) << "finished RK-Step, new h=" << ah << " tolerance " << tolerance << " err " << err << endl; } else { //ah *= 0.9; notrestarted = 0; //(*testout) << "restarting h " << 2.*h << " ah " << ah << " tolerance " << tolerance << " err " << err << endl; StartNextValCalc(startval_bak,startt_bak, ah, adaptive); } } } else { t = startt + h; finished = true; } } if(stepcount == 0) { t = startt + c[stepcount]*h; val = startval; for(int i=0; iGet(stepcount,i) * K[i]; } return finished; } bool RKStepper :: FeedNextF(const Vec<3> & f) { K[stepcount] = f; stepcount++; return true; } void FieldLineCalc :: GenerateFieldLines(Array> & potential_startpoints, const int numlines) { Array> line_points; Array line_values; Array drawelems; Array dirstart; pstart.SetSize0(); pend.SetSize0(); values.SetSize0(); double crit = 1.0; if(randomized) { double sum = 0; double lami[3]; Vec<3> v; for(int i=0; i= numlines) break; Calc(potential_startpoints[i],line_points,line_values,drawelems,dirstart); bool usable = false; for(int j=1; j 0) ? rel_length : 0.5; maxlength *= 2.*rad; thickness = (rel_thickness > 0) ? rel_thickness : 0.0015; thickness *= 2.*rad; double auxtolerance = (rel_tolerance > 0) ? rel_tolerance : 1.5e-3; auxtolerance *= 2.*rad; stepper.SetTolerance(auxtolerance); direction = adirection; maxpoints = amaxpoints; if(direction == 0) { maxlength *= 0.5; maxpoints /= 2; } critical_value = -1; randomized = false; } void FieldLineCalc :: Calc(const Point<3> & startpoint, Array> & points, Array & vals, Array & drawelems, Array & dirstart) { Vec<3> v = 0.0; double startlami[3] = {0.0, 0.0, 0.0}; points.SetSize(0); vals.SetSize(0); drawelems.SetSize(0); dirstart.SetSize(0); dirstart.Append(0); int startelnr = mesh.GetElementOfPoint(startpoint,startlami,true) - 1; (*testout) << "p = " << startpoint << "; elnr = " << startelnr << endl; if (startelnr == -1) return; mesh.SetPointSearchStartElement(startelnr); Vec<3> startv; bool startdraw = func(startelnr, startlami, startv); double startval = startv.Length(); if(critical_value > 0 && fabs(startval) < critical_value) return; //cout << "p = " << startpoint << "; elnr = " << startelnr << endl; for(int dir = 1; dir >= -1; dir -= 2) { if(dir*direction < 0) continue; points.Append(startpoint); vals.Append(startval); drawelems.Append(startdraw); double h = 0.001*rad/startval; // otherwise no nice lines; should be made accessible from outside v = startv; if(dir == -1) v *= -1.; int elnr = startelnr; double lami[3] = { startlami[0], startlami[1], startlami[2]}; for(double length = 0; length < maxlength; length += h*vals.Last()) { if(v.Length() < 1e-12*rad) { (*testout) << "Current fieldlinecalculation came to a stillstand at " << points.Last() << endl; break; } double dummyt; stepper.StartNextValCalc(points.Last(),dummyt,h,true); stepper.FeedNextF(v); bool drawelem = false; Point<3> newp; while(!stepper.GetNextData(newp,dummyt,h) && elnr != -1) { elnr = mesh.GetElementOfPoint(newp,lami,true) - 1; if(elnr != -1) { mesh.SetPointSearchStartElement(elnr); drawelem = func(elnr, lami, v); if(dir == -1) v *= -1.; stepper.FeedNextF(v); } } if (elnr == -1) { //cout << "direction " < 1) (*testout) << "Points in current fieldline: " << points.Size() << ", current position: " << newp << endl; if(maxpoints > 0 && points.Size() >= maxpoints) { break; } //cout << "length " << length << " h " << h << " vals.Last() " << vals.Last() << " maxlength " << maxlength << endl; } dirstart.Append(points.Size()); } } void VisualSceneSolution :: BuildFieldLinesFromBox(Array> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; if(fieldlines_startarea_parameter[0] > fieldlines_startarea_parameter[3] || fieldlines_startarea_parameter[1] > fieldlines_startarea_parameter[4] || fieldlines_startarea_parameter[2] > fieldlines_startarea_parameter[5]) { Point3d pmin, pmax; mesh->GetBox (pmin, pmax); fieldlines_startarea_parameter[0] = pmin.X(); fieldlines_startarea_parameter[1] = pmin.Y(); fieldlines_startarea_parameter[2] = pmin.Z(); fieldlines_startarea_parameter[3] = pmax.X(); fieldlines_startarea_parameter[4] = pmax.Y(); fieldlines_startarea_parameter[5] = pmax.Z(); } for (int i = 1; i <= startpoints.Size(); i++) { Point<3> p (fieldlines_startarea_parameter[0] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[3]-fieldlines_startarea_parameter[0]), fieldlines_startarea_parameter[1] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[4]-fieldlines_startarea_parameter[1]), fieldlines_startarea_parameter[2] + double (rand()) / RAND_MAX * (fieldlines_startarea_parameter[5]-fieldlines_startarea_parameter[2])); startpoints[i-1] = p; } } void VisualSceneSolution :: BuildFieldLinesFromLine(Array> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; for (int i = 1; i <= startpoints.Size(); i++) { double s = double (rand()) / RAND_MAX; Point<3> p (fieldlines_startarea_parameter[0] + s * (fieldlines_startarea_parameter[3]-fieldlines_startarea_parameter[0]), fieldlines_startarea_parameter[1] + s * (fieldlines_startarea_parameter[4]-fieldlines_startarea_parameter[1]), fieldlines_startarea_parameter[2] + s * (fieldlines_startarea_parameter[5]-fieldlines_startarea_parameter[2])); startpoints[i-1] = p; } } void VisualSceneSolution :: BuildFieldLinesFromFile(Array> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; ifstream * infile; infile = new ifstream(fieldlines_filename.c_str()); //cout << "reading from file " << fieldlines_filename << endl; int numpoints = 0; string keyword; double dparam; int iparam; while(infile->good()) { (*infile) >> keyword; if(keyword == "point") numpoints++; else if(keyword == "line" || keyword == "box") { for(int i=0; i<6; i++) (*infile) >> dparam; (*infile) >> iparam; numpoints += iparam; } } delete infile; //cout << numpoints << " startpoints" << endl; startpoints.SetSize(numpoints); infile = new ifstream(fieldlines_filename.c_str()); numpoints = 0; while(infile->good()) { (*infile) >> keyword; if (keyword == "point") { (*infile) >> startpoints[numpoints][0]; (*infile) >> startpoints[numpoints][1]; (*infile) >> startpoints[numpoints][2]; numpoints++; } else if (keyword == "line" || keyword == "box") { for(int i=0; i<6; i++) (*infile) >> fieldlines_startarea_parameter[i]; (*infile) >> iparam; Array> auxpoints(iparam); if (keyword == "box") BuildFieldLinesFromBox(auxpoints); else if (keyword == "line") BuildFieldLinesFromLine(auxpoints); for(int i=0; i> & startpoints) { shared_ptr mesh = GetMesh(); if (!mesh) return; Array elements_2d; //cout << "fieldlines_startface " << fieldlines_startface << endl; mesh->GetSurfaceElementsOfFace(fieldlines_startface,elements_2d); if(elements_2d.Size() == 0) { cerr << "No Elements on selected face (?)" << endl; return; } Vec3d v1,v2,cross; double area = 0; int i; for(i=0; iPoint(elem[1]) - mesh->Point(elem[0]); v2 = mesh->Point(elem[2]) - mesh->Point(elem[0]); cross = Cross(v1,v2); area += cross.Length(); if(elem.GetNV() == 4) { v1 = mesh->Point(elem[2]) - mesh->Point(elem[0]); v2 = mesh->Point(elem[3]) - mesh->Point(elem[0]); cross = Cross(v1,v2); area += cross.Length(); } } int startpointsp = 0; i = 0; while(startpointsp < startpoints.Size()) { const Element2d & elem = (*mesh)[elements_2d[i]]; int numtri = (elem.GetNV() == 3) ? 1 : 2; for(int tri = 0; startpointsp < startpoints.Size() && triPoint(elem[1]) - mesh->Point(elem[0]); v2 = mesh->Point(elem[2]) - mesh->Point(elem[0]); cross = Cross(v1,v2); } else if(tri == 1) { v1 = mesh->Point(elem[2]) - mesh->Point(elem[0]); v2 = mesh->Point(elem[3]) - mesh->Point(elem[0]); cross = Cross(v1,v2); } double thisarea = cross.Length(); int numloc = int(startpoints.Size()*thisarea/area); if(double (rand()) / RAND_MAX < startpoints.Size()*thisarea/area - numloc) numloc++; for(int j=0; startpointsp < startpoints.Size() && j 1) { s = 1.-s; t = 1.-t; } startpoints[startpointsp] = mesh->Point(elem[0]) + s*v1 +t*v2; startpointsp++; } } i++; if(i == elements_2d.Size()) i = 0; } } void VisualSceneSolution :: BuildFieldLinesPlot () { shared_ptr mesh = GetMesh(); if (!mesh) return; if (fieldlinestimestamp >= solutiontimestamp) return; fieldlinestimestamp = solutiontimestamp; if (fieldlineslist) glDeleteLists (fieldlineslist, num_fieldlineslists); if (vecfunction == -1) return; const SolData * vsol = soldata[fieldlines_vecfunction]; num_fieldlineslists = (vsol -> iscomplex && !fieldlines_fixedphase) ? 100 : 1; double phaser=1.0; double phasei=0.0; std::function eval_func = [&](int elnr, const double * lami, Vec<3> & vec) { double values[6] = {0., 0., 0., 0., 0., 0.}; bool drawelem; auto mesh = GetMesh(); if (mesh->GetDimension()==3) drawelem = GetValues (vsol, elnr, lami[0], lami[1], lami[2], values); else drawelem = GetSurfValues (vsol, elnr, -1, lami[0], lami[1], values); Vec3d v; RealVec3d (values, v, vsol->iscomplex, phaser, phasei); vec = v; return drawelem; }; FieldLineCalc linecalc(*mesh, eval_func, fieldlines_rellength,fieldlines_maxpoints,fieldlines_relthickness,fieldlines_reltolerance,fieldlines_rktype); if(fieldlines_randomstart) linecalc.Randomized(); fieldlineslist = glGenLists (num_fieldlineslists); int num_startpoints = num_fieldlines / num_fieldlineslists; if (num_fieldlines % num_fieldlineslists != 0) num_startpoints++; if(fieldlines_randomstart) num_startpoints *= 10; Array> startpoints(num_startpoints); for (int ln = 0; ln < num_fieldlineslists; ln++) { if(fieldlines_startarea == 0) BuildFieldLinesFromBox(startpoints); else if(fieldlines_startarea == 1) BuildFieldLinesFromFile(startpoints); else if(fieldlines_startarea == 2) BuildFieldLinesFromFace(startpoints); double phi; if(vsol -> iscomplex) { if(fieldlines_fixedphase) phi = fieldlines_phase; else phi = 2*M_PI*ln / num_fieldlineslists; } else phi = 0; cout << "phi = " << phi << endl; phaser = cos(phi); phasei = sin(phi); linecalc.GenerateFieldLines(startpoints,num_fieldlines / num_fieldlineslists+1); auto & pstart = linecalc.GetPStart(); auto & pend = linecalc.GetPEnd(); auto & values = linecalc.GetValues(); auto nlines = values.Size(); glNewList(fieldlineslist+ln, GL_COMPILE); SetTextureMode (usetexture); for(auto i : Range(nlines)) { SetOpenGlColor (values[i]); DrawCylinder (pstart[i], pend[i], fieldlines_relthickness); } glEndList (); } } } #endif // NOTCL