// Compute and log the measured periods of the moons. void LogPeriods(Ephemeris<KSP> const& ephemeris) { auto const position = [this, &ephemeris]( not_null<MassiveBody const*> body, Instant const& t) { return ephemeris.trajectory(body)->EvaluatePosition(t, nullptr); }; auto const barycentre = [this, &position](Instant const& t) { BarycentreCalculator<Position<KSP>, Mass> result; for (auto const body : jool_system_) { result.Add(position(body, t), body->mass()); } return result.Get(); }; auto const barycentric_position = [this, &barycentre, &ephemeris, &position]( not_null<MassiveBody const*> body, Instant const& t) { return position(body, t) - barycentre(t); }; for (auto const moon : {laythe_, vall_, tylo_}) { auto const moon_y = [this, &barycentric_position, moon](Instant const& t) { return barycentric_position(moon, t).coordinates().y; }; LOG(INFO) << (moon == laythe_ ? "Laythe" : moon == vall_ ? "Vall" : "Tylo"); Sign const s0(moon_y(game_epoch_)); Instant t0 = game_epoch_; Time const Δt = 45 * Minute; while (Sign(moon_y(t0)) == s0) { t0 += Δt; } // The moon crosses the xz plane between t0 and t0 - Δt. Instant t1 = t0; int const orbits = moon == laythe_ ? 8 : moon == vall_ ? 4 : 2; for (int i = 0; i < orbits; ++i) { while (Sign(moon_y(t1)) != s0) { t1 += Δt; } // The crossing of the xz plane halfway through the orbit occurs between // t1 and t1 - Δt. while (Sign(moon_y(t1)) == s0) { t1 += Δt; } // The |i|th orbit ends between t1 and t1 - Δt. } Time const actual_period = (Bisect(moon_y, t1 - Δt, t1) - Bisect(moon_y, t0 - Δt, t0)) / orbits; Time const expected_period = (2 * π * Radian) / *elements_[moon].mean_motion; LOG(INFO) << "actual period : " << actual_period; LOG(INFO) << "expected period : " << expected_period; LOG(INFO) << "error : " << RelativeError(expected_period, actual_period); } }
//---------------------------------------------------------------------- box observer::SIVIA(box& X0,box& Psecours) { int NbissectMax = N_Bissect_0; if (phase==0) NbissectMax=N_Bissect_0; if (phase==1) NbissectMax=N_Bissect_k; int Nbissect=0; Psecours = box(4);Psecours[1] = 5;Psecours[2] = 5;Psecours[3] = 0;Psecours[4] = 0; vector<box> Result; list<box> L; L.push_back(X0); box P; //Form1->R1.image->Refresh(); while (!L.empty()) { P=L.front(); //Form1->R1.DrawCadre(P,clBlue,psSolid,1,2,1); L.pop_front(); bool sortie=false; while (!sortie) { box Pold(P); Contract(P); if (P.IsEmpty()) sortie=true; if (decrease(Pold,P)<0.05) sortie=true; } if (!P.IsEmpty()) { if (Nbissect>NbissectMax) { //Form1->R1.DrawBox(P,clRed,clRed,bsSolid,1,2); //Form1->R2.image->Refresh(); Result.push_back(P); } else { box P1,P2; Bisect(P,P1,P2); Psecours=P; Nbissect++; L.push_back(P1); L.push_back(P2); } } } box R=Union(Result); //Form1->R1.DrawCadre(R,clGreen,psSolid,1,2,1); L.clear(); return R; }
// Solving Δt * Δt == n. TEST_F(RootFindersTest, SquareRoots) { Instant const t_0; Instant const t_max = t_0 + 10 * Second; Length const n_max = Pow<2>(t_max - t_0) * SIUnit<Acceleration>(); for (Length n = 1 * Metre; n < n_max; n += 1 * Metre) { int evaluations = 0; auto const equation = [t_0, n, &evaluations](Instant const& t) { ++evaluations; return Pow<2>(t - t_0) * SIUnit<Acceleration>() - n; }; EXPECT_THAT(Bisect(equation, t_0, t_max) - t_0, AlmostEquals(Sqrt(n / SIUnit<Acceleration>()), 0, 1)); if (n == 25 * Metre) { EXPECT_EQ(3, evaluations); } else { EXPECT_THAT(evaluations, AllOf(Ge(49), Le(58))); } } }
std::unique_ptr<bsp_tree_node> GenerateTreeRecursion(std::vector<pcs_polygon> &polygons, std::vector<int>&contained) { PCS_Model::BSP_CUR_DEPTH++; if(PCS_Model::BSP_MAX_DEPTH < PCS_Model::BSP_CUR_DEPTH) PCS_Model::BSP_MAX_DEPTH = PCS_Model::BSP_CUR_DEPTH; if (PCS_Model::BSP_CUR_DEPTH > 500) { PCS_Model::BSP_COMPILE_ERROR = true; return std::unique_ptr<bsp_tree_node>((bsp_tree_node*)NULL); //WHOA wtf infinite recursion! } std::unique_ptr<bsp_tree_node> node(new bsp_tree_node); MakeBound(node->bound_max, node->bound_min, contained, polygons); if (contained.size() == 1) { //we're a polygon.. w00t node->Type = POLY; node->poly_num = contained; } else { // we're a sortnorm vector3d cmax = polygons[contained[0]].centeroid; vector3d cmin = polygons[contained[0]].centeroid; for (std::vector<int>::iterator it = contained.begin() + 1; it < contained.end(); ++it) { ExpandBoundingBoxes(cmax, cmin, polygons[*it].centeroid); } std::vector<int> front, back; if (!Bisect(cmax, cmin, node->point, node->normal, polygons, contained, front, back)) { node->Type = POLY; node->poly_num = contained; } else { node->Type = SPLIT; node->front = GenerateTreeRecursion(polygons, front); node->back = GenerateTreeRecursion(polygons, back); } } PCS_Model::BSP_CUR_DEPTH--; return node; }
//=========================================================================== int CheckBorders(int *NumNodesUsed, int NumNodes, NODE *Node, int *NumTris, TRI **pTri) { int border; int i, j, k0, k1, N; float angle[3]; TRI *Tri; N = NumNodesUsed[0]; Tri = *pTri; for(i=0; i<NumTris[0]; i++) { EdgeOnSide(Tri[i].v,&k0,&border); if(border < 0) continue; CalcAngles(Node, Tri[i].v, angle); k1 = (k0+1) % 3; if((angle[k0] < SLIVER_ANGLE) || (angle[k1] < SLIVER_ANGLE)) { j = Bisect(Node, border, Tri[i].v[k0], Tri[i].v[k1]); if(j >= 0) { if(!Node[j].used) // Shouldn't be used, but... { NumNodesUsed[0]++; Node[j].used++; } } } } if(NumNodesUsed[0] > N) { free(*pTri); tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY"); Tri = *pTri; } return (NumNodesUsed[0] - N); }
double TTDigest::GetQuantile(const double& Q) const { double Left = Min; double Right = Max; if (TotalSum == 0.0) { return -1.0; } if (Q <= 0) { return Min; } if (Q >= 1) { return Max; } if (Last == 0) { return Mean[0]; } // calculate boundaries, pick centroid via binary search double QSum = Q * TotalSum; int N1 = Last + 1; int N0 = 0; int I = Bisect(MergeMean, QSum, N0, N1); if (I > 0) { Left = Boundary(I-1, I, Mean, Weight); } if (I < Last) { Right = Boundary(I, I+1, Mean, Weight); } return Left + (Right - Left) * (QSum - (MergeMean[I-1])) / Weight[I]; };
inline void NestedDissectionRecursion ( const Graph& graph, const vector<Int>& perm, Separator& sep, NodeInfo& node, Int off, const BisectCtrl& ctrl ) { DEBUG_CSE const Int numSources = graph.NumSources(); const Int* offsetBuf = graph.LockedOffsetBuffer(); const Int* sourceBuf = graph.LockedSourceBuffer(); const Int* targetBuf = graph.LockedTargetBuffer(); if( numSources <= ctrl.cutoff ) { // Filter out the graph of the diagonal block Int numValidEdges = 0; const Int numEdges = graph.NumEdges(); for( Int e=0; e<numEdges; ++e ) if( targetBuf[e] < numSources ) ++numValidEdges; vector<Int> subOffsets(numSources+1), subTargets(Max(numValidEdges,1)); Int sourceOff = 0; Int validCounter = 0; Int prevSource = -1; for( Int e=0; e<numEdges; ++e ) { const Int source = sourceBuf[e]; const Int target = targetBuf[e]; while( source != prevSource ) { subOffsets[sourceOff++] = validCounter; ++prevSource; } if( target < numSources ) subTargets[validCounter++] = target; } while( sourceOff <= numSources ) { subOffsets[sourceOff++] = validCounter; } // Technically, SuiteSparse expects column-major storage, but since // the matrix is structurally symmetric, it's okay to pass in the // row-major representation vector<Int> amdPerm; AMDOrder( subOffsets, subTargets, amdPerm ); // Compute the symbolic factorization of this leaf node using the // reordering just computed node.LOffsets.resize( numSources+1 ); node.LParents.resize( numSources ); vector<Int> LNnz( numSources ), Flag( numSources ), amdPermInv( numSources ); suite_sparse::ldl::Symbolic ( numSources, subOffsets.data(), subTargets.data(), node.LOffsets.data(), node.LParents.data(), LNnz.data(), Flag.data(), amdPerm.data(), amdPermInv.data() ); // Fill in this node of the local separator tree sep.off = off; sep.inds.resize( numSources ); for( Int i=0; i<numSources; ++i ) sep.inds[i] = perm[amdPerm[i]]; // TODO: Replace with better deletion mechanism SwapClear( sep.children ); // Fill in this node of the local elimination tree node.size = numSources; node.off = off; // TODO: Replace with better deletion mechanism SwapClear( node.children ); set<Int> lowerStruct; for( Int s=0; s<node.size; ++s ) { const Int edgeOff = offsetBuf[s]; const Int numConn = offsetBuf[s+1] - edgeOff; for( Int t=0; t<numConn; ++t ) { const Int target = targetBuf[edgeOff+t]; if( target >= numSources ) lowerStruct.insert( off+target ); } } CopySTL( lowerStruct, node.origLowerStruct ); } else { DEBUG_ONLY( if( !IsSymmetric(graph) ) { Print( graph, "graph" ); LogicError("Graph was not symmetric"); } ) // Partition the graph and construct the inverse map Graph leftChild, rightChild; vector<Int> map; const Int sepSize = Bisect( graph, leftChild, rightChild, map, ctrl ); vector<Int> invMap( numSources ); for( Int s=0; s<numSources; ++s ) invMap[map[s]] = s; DEBUG_ONLY( if( !IsSymmetric(leftChild) ) { Print( graph, "graph" ); Print( leftChild, "leftChild" ); LogicError("Left child was not symmetric"); } )
inline void NestedDissectionRecursion ( const DistGraph& graph, const DistMap& perm, DistSeparator& sep, DistNodeInfo& node, Int off, const BisectCtrl& ctrl ) { DEBUG_ONLY(CSE cse("ldl::NestedDissectionRecursion")) mpi::Comm comm = graph.Comm(); const int commSize = mpi::Size(comm); mpi::Dup( comm, sep.comm ); mpi::Dup( comm, node.comm ); if( commSize > 1 ) { const Int numLocalSources = graph.NumLocalSources(); const Int firstLocalSource = graph.FirstLocalSource(); const Int* offsetBuf = graph.LockedOffsetBuffer(); const Int* targetBuf = graph.LockedTargetBuffer(); // Partition the graph and construct the inverse map DistGraph child; bool childIsOnLeft; DistMap map; const Int sepSize = Bisect( graph, child, map, childIsOnLeft, ctrl ); const Int numSources = graph.NumSources(); const Int childSize = child.NumSources(); const Int leftChildSize = ( childIsOnLeft ? childSize : numSources-sepSize-childSize ); DistMap invMap; InvertMap( map, invMap ); // Mostly fill this node of the DistSeparatorTree // (we will finish computing the separator indices at the end) sep.off = off + (numSources-sepSize); sep.inds.resize( sepSize ); for( Int s=0; s<sepSize; ++s ) sep.inds[s] = s + (numSources-sepSize); invMap.Translate( sep.inds ); // Fill in this node of the DistNode node.size = sepSize; node.off = sep.off; set<Int> localLowerStruct; for( Int s=0; s<sepSize; ++s ) { const Int source = sep.inds[s]; if( source >= firstLocalSource && source < firstLocalSource+numLocalSources ) { const Int localSource = source - firstLocalSource; const Int edgeOff = offsetBuf[localSource]; const Int numConn = offsetBuf[localSource+1] - edgeOff; for( Int t=0; t<numConn; ++t ) { const Int target = targetBuf[edgeOff+t]; if( target >= numSources ) localLowerStruct.insert( off+target ); } } } const int numLocalConnected = localLowerStruct.size(); vector<int> localConnectedSizes( commSize ); mpi::AllGather ( &numLocalConnected, 1, localConnectedSizes.data(), 1, comm ); vector<Int> localConnectedVec; CopySTL( localLowerStruct, localConnectedVec ); vector<int> localConnectedOffs; const int sumOfLocalConnectedSizes = Scan( localConnectedSizes, localConnectedOffs ); vector<Int> localConnections( sumOfLocalConnectedSizes ); mpi::AllGather ( localConnectedVec.data(), numLocalConnected, localConnections.data(), localConnectedSizes.data(), localConnectedOffs.data(), comm ); set<Int> lowerStruct ( localConnections.begin(), localConnections.end() ); CopySTL( lowerStruct, node.origLowerStruct ); // Finish computing the separator indices perm.Translate( sep.inds ); // Construct map from child indices to the original ordering DistMap newPerm( child.NumSources(), child.Comm() ); const Int localChildSize = child.NumLocalSources(); const Int firstLocalChildSource = child.FirstLocalSource(); auto& newPermLoc = newPerm.Map(); if( childIsOnLeft ) for( Int s=0; s<localChildSize; ++s ) newPermLoc[s] = s+firstLocalChildSource; else for( Int s=0; s<localChildSize; ++s ) newPermLoc[s] = s+firstLocalChildSource+leftChildSize; invMap.Extend( newPerm ); perm.Extend( newPerm ); // Recurse const Int childOff = ( childIsOnLeft ? off : off+leftChildSize ); sep.child = new DistSeparator(&sep); node.child = new DistNodeInfo(&node); node.child->onLeft = childIsOnLeft; NestedDissectionRecursion ( child, newPerm, *sep.child, *node.child, childOff, ctrl ); } else { Graph seqGraph( graph ); sep.duplicate = new Separator(&sep); node.duplicate = new NodeInfo(&node); NestedDissectionRecursion ( seqGraph, perm.Map(), *sep.duplicate, *node.duplicate, off, ctrl ); // Pull information up from the duplicates sep.off = sep.duplicate->off; sep.inds = sep.duplicate->inds; node.size = node.duplicate->size; node.off = node.duplicate->off; node.origLowerStruct = node.duplicate->origLowerStruct; } }
void Ephemeris<Frame>::ComputeApsides(not_null<MassiveBody const*> const body1, not_null<MassiveBody const*> const body2, DiscreteTrajectory<Frame>& apoapsides1, DiscreteTrajectory<Frame>& periapsides1, DiscreteTrajectory<Frame>& apoapsides2, DiscreteTrajectory<Frame>& periapsides2) { not_null<ContinuousTrajectory<Frame> const*> const body1_trajectory = trajectory(body1); not_null<ContinuousTrajectory<Frame> const*> const body2_trajectory = trajectory(body2); typename ContinuousTrajectory<Frame>::Hint hint1; typename ContinuousTrajectory<Frame>::Hint hint2; // Computes the derivative of the squared distance between |body1| and |body2| // at time |t|. auto const evaluate_square_distance_derivative = [body1_trajectory, body2_trajectory, &hint1, &hint2]( Instant const& t) -> Variation<Square<Length>> { DegreesOfFreedom<Frame> const body1_degrees_of_freedom = body1_trajectory->EvaluateDegreesOfFreedom(t, &hint1); DegreesOfFreedom<Frame> const body2_degrees_of_freedom = body2_trajectory->EvaluateDegreesOfFreedom(t, &hint2); RelativeDegreesOfFreedom<Frame> const relative = body1_degrees_of_freedom - body2_degrees_of_freedom; return 2.0 * InnerProduct(relative.displacement(), relative.velocity()); }; std::experimental::optional<Instant> previous_time; std::experimental::optional<Variation<Square<Length>>> previous_squared_distance_derivative; for (Instant time = t_min(); time <= t_max(); time += parameters_.step()) { Variation<Square<Length>> const squared_distance_derivative = evaluate_square_distance_derivative(time); if (previous_squared_distance_derivative && Sign(squared_distance_derivative) != Sign(*previous_squared_distance_derivative)) { CHECK(previous_time); // The derivative of |squared_distance| changed sign. Find its zero by // bisection, this is the time of the apsis. Then compute the apsis and // append it to one of the output trajectories. Instant const apsis_time = Bisect(evaluate_square_distance_derivative, *previous_time, time); DegreesOfFreedom<Frame> const apsis1_degrees_of_freedom = body1_trajectory->EvaluateDegreesOfFreedom(apsis_time, &hint1); DegreesOfFreedom<Frame> const apsis2_degrees_of_freedom = body2_trajectory->EvaluateDegreesOfFreedom(apsis_time, &hint2); if (Sign(squared_distance_derivative).Negative()) { apoapsides1.Append(apsis_time, apsis1_degrees_of_freedom); apoapsides2.Append(apsis_time, apsis2_degrees_of_freedom); } else { periapsides1.Append(apsis_time, apsis1_degrees_of_freedom); periapsides2.Append(apsis_time, apsis2_degrees_of_freedom); } } previous_time = time; previous_squared_distance_derivative = squared_distance_derivative; } }