void CRocheLobe_FF::ComputeRadii(const double pot_surface, const double separation, const double q, const double P) { // Compute the radii for the pixels and corners: for(unsigned int i = 0; i < pixel_radii.size(); i++) pixel_radii[i] = ComputeRadius(pot_surface, separation, q, P, pixel_theta[i], pixel_phi[i]); for(unsigned int i = 0; i < corner_radii.size(); i++) corner_radii[i] = ComputeRadius(pot_surface, separation, q, P, corner_theta[i], corner_phi[i]); }
void CRocheLobe_FF::preRender(double & max_flux) { if (!mModelReady) Init(); // See if the user change the tesselation const unsigned int n_sides = pow(2, mParams["n_side_power"].getValue()); if(mParams["n_side_power"].isDirty()) { Init(); } const double T_eff_pole = mParams["T_eff_pole"].getValue(); const double von_zeipel_beta = mParams["von_zeipel_beta"].getValue(); const double separation = mParams["separation"].getValue(); const double q = mParams["q"].getValue(); const double P = mParams["P"].getValue(); const double F = mParams["F"].getValue(); //printf("%lf %lf %lf %lf", q, P, F, separation); // First find the position of L1 point on the axis double r_L1 = separation * ComputeRL1(q, P); // Potential at L1 point double pot_L1, dpot_L1; ComputePotential(pot_L1, dpot_L1, r_L1, PI/2., 0.0, separation, q, P); // Potential at F surface double pot_surface = (pot_L1 + 0.5*q*q/(1.+q))/F - 0.5*q*q/(1.+q); // Compute r_pole double r_pole = ComputeRadius(pot_surface, separation, q, P, 0.0, 0.0); // Compute gravity at pole double g_pole, tempx, tempy, tempz; ComputeGravity(separation, q, P, r_pole, 0.0, 0.0, tempx, tempy, tempz, g_pole); // Compute Radii for all Healpix pixels ComputeRadii(pot_surface, separation, q, P); // Compute Gravity for all Healpix pixels ComputeGravity(separation, q, P); bool feature_dirty = false; for(auto feature: mFeatures) feature_dirty |= feature->isDirty(); if(feature_dirty || mParams["T_eff_pole"].isDirty() || mParams["von_zeipel_beta"].isDirty()) VonZeipelTemperatures(T_eff_pole, g_pole, von_zeipel_beta); for(auto feature: mFeatures) feature->apply(this); TemperatureToFlux(mPixelTemperatures, mFluxTexture, mWavelength, max_flux); GenerateVBO(n_pixels, n_sides, mVBOData); }
/// Computes the geometry of the spherical Healpix surface void CRocheLobe_FF::GenerateModel(vector<vec3> & vbo_data, vector<unsigned int> & elements) { const double T_eff_pole = mParams["T_eff_pole"].getValue(); const double von_zeipel_beta = mParams["von_zeipel_beta"].getValue(); const unsigned int n_sides = pow(2, mParams["n_side_power"].getValue()); const double separation = mParams["separation"].getValue(); const double q = mParams["q"].getValue(); const double P = mParams["P"].getValue(); const double F = mParams["F"].getValue(); // Generate a unit Healpix sphere GenerateHealpixSphere(n_pixels, n_sides); // recomputing the sphereoid is very expensive. Make use of the dirty flags // to only compute that which is absolutely necessary. double r_L1 = separation * ComputeRL1(q, P); // Potential at L1 point double pot_L1, dpot_L1; ComputePotential(pot_L1, dpot_L1, r_L1, PI/2., 0.0, separation, q, P); // Potential at F surface double pot_surface = (pot_L1 + 0.5*q*q/(1.+q))/F - 0.5*q*q/(1.+q); // Compute r_pole double r_pole = ComputeRadius(pot_surface, separation, q, P, 0.0, 0.0); // Compute gravity at pole double g_pole, tempx, tempy, tempz; ComputeGravity(separation, q, P, r_pole, 0.0, 0.0, tempx, tempy, tempz, g_pole); // Compute Radii for all Healpix pixels ComputeRadii(pot_surface, separation, q, P); // Compute Gravity for all Healpix pixels ComputeGravity(separation, q, P); // Compute Temperatures for all Healpix pixels VonZeipelTemperatures(T_eff_pole, g_pole, von_zeipel_beta); for(auto feature: mFeatures) feature->apply(this); // Find the maximum temperature double max_temperature = 0; for(unsigned int i = 0; i < mPixelTemperatures.size(); i++) { if(mPixelTemperatures[i] > max_temperature) max_temperature = mPixelTemperatures[i]; } // Convert temperatures to fluxes. TemperatureToFlux(mPixelTemperatures, mFluxTexture, mWavelength, max_temperature); GenerateVBO(n_pixels, n_sides, vbo_data); // Create the lookup indicies. GenerateHealpixVBOIndicies(n_pixels, elements); }
ConformalMap<Real>::ConformalMap (int numPoints, const Vector3<Real>* points, int numTriangles, const int* indices, int punctureTriangle) { // Construct a vertex-triangle-edge representation of mesh. BasicMesh mesh(numPoints, points, numTriangles, indices); int numEdges = mesh.GetNumEdges(); const BasicMesh::Edge* edges = mesh.GetEdges(); const BasicMesh::Triangle* triangles = mesh.GetTriangles(); mPlanes = new1<Vector2<Real> >(numPoints); mSpheres = new1<Vector3<Real> >(numPoints); // Construct sparse matrix A nondiagonal entries. typename LinearSystem<Real>::SparseMatrix AMat; int i, e, t, v0, v1, v2; Real value = (Real)0; for (e = 0; e < numEdges; ++e) { const BasicMesh::Edge& edge = edges[e]; v0 = edge.V[0]; v1 = edge.V[1]; Vector3<Real> E0, E1; const BasicMesh::Triangle& T0 = triangles[edge.T[0]]; for (i = 0; i < 3; ++i) { v2 = T0.V[i]; if (v2 != v0 && v2 != v1) { E0 = points[v0] - points[v2]; E1 = points[v1] - points[v2]; value = E0.Dot(E1)/E0.Cross(E1).Length(); } } const BasicMesh::Triangle& T1 = triangles[edge.T[1]]; for (i = 0; i < 3; ++i) { v2 = T1.V[i]; if (v2 != v0 && v2 != v1) { E0 = points[v0] - points[v2]; E1 = points[v1] - points[v2]; value += E0.Dot(E1)/E0.Cross(E1).Length(); } } value *= -(Real)0.5; AMat[std::make_pair(v0, v1)] = value; } // Aonstruct sparse matrix A diagonal entries. Real* tmp = new1<Real>(numPoints); memset(tmp, 0, numPoints*sizeof(Real)); typename LinearSystem<Real>::SparseMatrix::iterator iter = AMat.begin(); typename LinearSystem<Real>::SparseMatrix::iterator end = AMat.end(); for (/**/; iter != end; ++iter) { v0 = iter->first.first; v1 = iter->first.second; value = iter->second; assertion(v0 != v1, "Unexpected condition\n"); tmp[v0] -= value; tmp[v1] -= value; } for (int v = 0; v < numPoints; ++v) { AMat[std::make_pair(v, v)] = tmp[v]; } assertion(numPoints + numEdges == (int)AMat.size(), "Mismatch in sizes\n"); // Construct column vector B (happens to be sparse). const BasicMesh::Triangle& tri = triangles[punctureTriangle]; v0 = tri.V[0]; v1 = tri.V[1]; v2 = tri.V[2]; Vector3<Real> V0 = points[v0]; Vector3<Real> V1 = points[v1]; Vector3<Real> V2 = points[v2]; Vector3<Real> E10 = V1 - V0; Vector3<Real> E20 = V2 - V0; Vector3<Real> E12 = V1 - V2; Vector3<Real> cross = E20.Cross(E10); Real len10 = E10.Length(); Real invLen10 = ((Real)1)/len10; Real twoArea = cross.Length(); Real invLenCross = ((Real)1)/twoArea; Real invProd = invLen10*invLenCross; Real re0 = -invLen10; Real im0 = invProd*E12.Dot(E10); Real re1 = invLen10; Real im1 = invProd*E20.Dot(E10); Real re2 = (Real)0; Real im2 = -len10*invLenCross; // Solve sparse system for real parts. memset(tmp, 0, numPoints*sizeof(Real)); tmp[v0] = re0; tmp[v1] = re1; tmp[v2] = re2; Real* result = new1<Real>(numPoints); bool solved = LinearSystem<Real>().SolveSymmetricCG(numPoints, AMat, tmp, result); assertion(solved, "Failed to solve linear system\n"); WM5_UNUSED(solved); for (i = 0; i < numPoints; ++i) { mPlanes[i].X() = result[i]; } // Solve sparse system for imaginary parts. memset(tmp, 0, numPoints*sizeof(Real)); tmp[v0] = -im0; tmp[v1] = -im1; tmp[v2] = -im2; solved = LinearSystem<Real>().SolveSymmetricCG(numPoints, AMat, tmp, result); assertion(solved, "Failed to solve linear system\n"); for (i = 0; i < numPoints; ++i) { mPlanes[i].Y() = result[i]; } delete1(tmp); delete1(result); // Scale to [-1,1]^2 for numerical conditioning in later steps. Real fmin = mPlanes[0].X(), fmax = fmin; for (i = 0; i < numPoints; i++) { if (mPlanes[i].X() < fmin) { fmin = mPlanes[i].X(); } else if (mPlanes[i].X() > fmax) { fmax = mPlanes[i].X(); } if (mPlanes[i].Y() < fmin) { fmin = mPlanes[i].Y(); } else if (mPlanes[i].Y() > fmax) { fmax = mPlanes[i].Y(); } } Real halfRange = ((Real)0.5)*(fmax - fmin); Real invHalfRange = ((Real)1)/halfRange; for (i = 0; i < numPoints; ++i) { mPlanes[i].X() = -(Real)1 + invHalfRange*(mPlanes[i].X() - fmin); mPlanes[i].Y() = -(Real)1 + invHalfRange*(mPlanes[i].Y() - fmin); } // Map plane points to sphere using inverse stereographic projection. // The main issue is selecting a translation in (x,y) and a radius of // the projection sphere. Both factors strongly influence the final // result. // Use the average as the south pole. The points tend to be clustered // approximately in the middle of the conformally mapped punctured // triangle, so the average is a good choice to place the pole. Vector2<Real> origin((Real)0 ,(Real)0 ); for (i = 0; i < numPoints; ++i) { origin += mPlanes[i]; } origin /= (Real)numPoints; for (i = 0; i < numPoints; ++i) { mPlanes[i] -= origin; } mPlaneMin = mPlanes[0]; mPlaneMax = mPlanes[0]; for (i = 1; i < numPoints; ++i) { if (mPlanes[i].X() < mPlaneMin.X()) { mPlaneMin.X() = mPlanes[i].X(); } else if (mPlanes[i].X() > mPlaneMax.X()) { mPlaneMax.X() = mPlanes[i].X(); } if (mPlanes[i].Y() < mPlaneMin.Y()) { mPlaneMin.Y() = mPlanes[i].Y(); } else if (mPlanes[i].Y() > mPlaneMax.Y()) { mPlaneMax.Y() = mPlanes[i].Y(); } } // Select the radius of the sphere so that the projected punctured // triangle has an area whose fraction of total spherical area is the // same fraction as the area of the punctured triangle to the total area // of the original triangle mesh. Real twoTotalArea = (Real)0; for (t = 0; t < numTriangles; ++t) { const BasicMesh::Triangle& T0 = triangles[t]; const Vector3<Real>& V0 = points[T0.V[0]]; const Vector3<Real>& V1 = points[T0.V[1]]; const Vector3<Real>& V2 = points[T0.V[2]]; Vector3<Real> E0 = V1 - V0, E1 = V2 - V0; twoTotalArea += E0.Cross(E1).Length(); } mRadius = ComputeRadius(mPlanes[v0], mPlanes[v1], mPlanes[v2], twoArea/twoTotalArea); Real radiusSqr = mRadius*mRadius; // Inverse stereographic projection to obtain sphere coordinates. The // sphere is centered at the origin and has radius 1. for (i = 0; i < numPoints; i++) { Real rSqr = mPlanes[i].SquaredLength(); Real mult = ((Real)1)/(rSqr + radiusSqr); Real x = ((Real)2)*mult*radiusSqr*mPlanes[i].X(); Real y = ((Real)2)*mult*radiusSqr*mPlanes[i].Y(); Real z = mult*mRadius*(rSqr - radiusSqr); mSpheres[i] = Vector3<Real>(x,y,z)/mRadius; } }