/* * Copyright (C) 2012 Alexander Wolf * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #include "config.h" #include "Pulsar.hpp" #include "Pulsars.hpp" #include "StelObject.hpp" #include "StelPainter.hpp" #include "StelApp.hpp" #include "StelCore.hpp" #include "StelTexture.hpp" #include "StelUtils.hpp" #include "StelTranslator.hpp" #include "StelModuleMgr.hpp" #include "StelSkyDrawer.hpp" #include "StelProjector.hpp" #include #include #include #include #include #include #define PSR_INERTIA 1.0e45 /* Typical moment of inertia for a pulsar */ StelTextureSP Pulsar::markerTexture; bool Pulsar::distributionMode = false; bool Pulsar::glitchFlag = false; Vec3f Pulsar::markerColor = Vec3f(0.4f,0.5f,1.0f); Vec3f Pulsar::glitchColor = Vec3f(0.2f,0.3f,1.0f); Pulsar::Pulsar(const QVariantMap& map) : initialized(false), designation(""), RA(0.), DE(0.), parallax(0.), period(0.), frequency(0.), pfrequency(0.), pderivative(0.), dmeasure(0.), bperiod(0.), eccentricity(0.), w50(0.), s400(0.), s600(0.), s1400(0.), distance(0.), glitch(-1), notes("") { // return initialized if the mandatory fields are not present if (!map.contains("designation")) return; designation = map.value("designation").toString(); parallax = map.value("parallax").toFloat(); period = map.value("period").toDouble(); bperiod = map.value("bperiod").toDouble(); frequency = map.value("frequency").toDouble(); pfrequency = map.value("pfrequency").toDouble(); pderivative = map.value("pderivative").toDouble(); dmeasure = map.value("dmeasure").toDouble(); eccentricity = map.value("eccentricity").toDouble(); RA = StelUtils::getDecAngle(map.value("RA").toString()); DE = StelUtils::getDecAngle(map.value("DE").toString()); w50 = map.value("w50").toFloat(); s400 = map.value("s400").toFloat(); s600 = map.value("s600").toFloat(); s1400 = map.value("s1400").toFloat(); distance = map.value("distance").toFloat(); glitch = map.value("glitch").toInt(); notes = map.value("notes").toString(); // If barycentric period not set then calculate it if (period==0 && frequency>0) { period = 1/frequency; } // If barycentric period derivative not set then calculate it if (pderivative==0) { pderivative = getP1(period, pfrequency); } initialized = true; } Pulsar::~Pulsar() { // } QVariantMap Pulsar::getMap(void) { QVariantMap map; map["designation"] = designation; map["parallax"] = parallax; map["bperiod"] = bperiod; map["frequency"] = frequency; map["pfrequency"] = pfrequency; map["pderivative"] = pderivative; map["dmeasure"] = dmeasure; map["eccentricity"] = eccentricity; map["RA"] = RA; map["DE"] = DE; map["period"] = period; map["w50"] = w50; map["s400"] = s400; map["s600"] = s600; map["s1400"] = s1400; map["distance"] = distance; map["glitch"] = glitch; map["notes"] = notes; return map; } float Pulsar::getSelectPriority(const StelCore* core) const { return StelObject::getSelectPriority(core)-2.f; } QString Pulsar::getInfoString(const StelCore* core, const InfoStringGroup& flags) const { QString str; QTextStream oss(&str); if (flags&Name) { oss << "

" << designation << "

"; } if (flags&ObjectType) { if (glitch==0) oss << q_("Type: %1").arg(q_("pulsar")) << "
"; else { QString sglitch; if (glitch==1) sglitch = q_("has one registered glitch"); else { // TRANSLATORS: Full phrase is "Has X registered glitches", where X is number sglitch = q_("has %1 registered glitches").arg(glitch); } oss << q_("Type: %1 (%2)").arg(q_("pulsar with glitches")).arg(sglitch) << "
"; } } // Ra/Dec etc. oss << getPositionInfoString(core, flags); if (flags&Extra) { if (period>0) { //TRANSLATORS: Unit of measure for period - seconds oss << q_("Barycentric period: %1 s").arg(QString::number(period, 'f', 16)) << "
"; } if (pderivative>0) { oss << q_("Time derivative of barycentric period: %1").arg(QString::number(pderivative, 'e', 5)) << "
"; } if (dmeasure>0) { oss << QString("%1 %2 %3-3 %4 %5") .arg(q_("Dispersion measure:")) .arg(QString::number(dmeasure, 'f', 3)) //TRANSLATORS: Unit of measure for distance - centimeters .arg(q_("cm")) .arg(QChar(0x00B7)) //TRANSLATORS: Unit of measure for distance - parsecs .arg(q_("pc")); oss << "
"; } double edot = getEdot(period, pderivative); if (edot>0) { oss << q_("Spin down energy loss rate: %1 ergs/s").arg(QString::number(edot, 'e', 2)) << "
"; } if (bperiod>0) { oss << q_("Binary period of pulsar: %1 days").arg(QString::number(bperiod, 'f', 12)) << "
"; } if (eccentricity>0) { oss << q_("Eccentricity: %1").arg(QString::number(eccentricity, 'f', 10)) << "
"; } if (parallax>0) { //TRANSLATORS: Unit of measure for annual parallax - milliarcseconds oss << q_("Annual parallax: %1 mas").arg(parallax) << "
"; } if (distance>0) { oss << q_("Distance based on electron density model: %1 kpc (%2 ly)").arg(distance).arg(distance*3261.563777) << "
"; } if (w50>0) { oss << q_("Profile width at 50% of peak: %1 ms").arg(QString::number(w50, 'f', 2)) << "
"; } if (s400>0) { oss << QString("%1 %2%3: %4 %5") // TRANSLATORS: Full phrase is "Time averaged flux density at XXXMHz" .arg(q_("Time averaged flux density at")) .arg(400) // TRANSLATORS: Unit of measurement of frequency .arg(q_("MHz")) .arg(QString::number(s400, 'f', 2)) // TRANSLATORS: mJy is milliJansky(10-26W/m2/Hz) .arg(q_("mJy")) << "
"; } if (s600>0) { oss << QString("%1 %2%3: %4 %5") // TRANSLATORS: Full phrase is "Time averaged flux density at XXXMHz" .arg(q_("Time averaged flux density at")) .arg(600) // TRANSLATORS: Unit of measurement of frequency .arg(q_("MHz")) .arg(QString::number(s600, 'f', 2)) // TRANSLATORS: mJy is milliJansky(10-26W/m2/Hz) .arg(q_("mJy")) << "
"; } if (s1400>0) { oss << QString("%1 %2%3: %4 %5") // TRANSLATORS: Full phrase is "Time averaged flux density at XXXMHz" .arg(q_("Time averaged flux density at")) .arg(1400) // TRANSLATORS: Unit of measurement of frequency .arg(q_("MHz")) .arg(QString::number(s1400, 'f', 2)) // TRANSLATORS: mJy is milliJansky(10-26W/m2/Hz) .arg(q_("mJy")) << "
"; } if (notes.length()>0) { oss << "
" << q_("Notes: %1").arg(getPulsarTypeInfoString(notes)) << "
"; } } postProcessInfoString(str, flags); return str; } Vec3f Pulsar::getInfoColor(void) const { return Vec3f(1.0, 1.0, 1.0); } float Pulsar::getVMagnitude(const StelCore* core) const { Q_UNUSED(core); // Calculate fake visual magnitude as function by distance - minimal magnitude is 6 float vmag = distance + 6.f; if (distributionMode) { return 3.f; } else { return vmag; } } float Pulsar::getVMagnitudeWithExtinction(const StelCore *core) const { return getVMagnitude(core); } double Pulsar::getEdot(double p0, double p1) const { if (p0>0 && p1!=0) { // Calculate spin down energy loss rate (ergs/s) return 4.0 * M_PI * M_PI * PSR_INERTIA * p1 / pow(p0,3); } else { return 0.0; } } double Pulsar::getP1(double p0, double f1) const { if (p0>0 && f1!=0) { // Calculate derivative of barycentric period return -1.0 * p0 * p0 * f1; } else { return 0.0; } } QString Pulsar::getPulsarTypeInfoString(QString pcode) const { QStringList out; if (pcode.contains("AXP")) { out.append(q_("anomalous X-ray pulsar or soft gamma-ray repeater with detected pulsations")); } if (pcode.contains("BINARY") || bperiod>0) { out.append(q_("has one or more binary companions")); } if (pcode.contains("HE")) { out.append(q_("with pulsed emission from radio to infrared or higher frequencies")); } if (pcode.contains("NRAD")) { out.append(q_("with pulsed emission only at infrared or higher frequencies")); } if (pcode.contains("RADIO")) { out.append(q_("with pulsed emission in the radio band")); } if (pcode.contains("RRAT")) { out.append(q_("with intermittently pulsed radio emission")); } if (pcode.contains("XINS")) { out.append(q_("isolated neutron star with pulsed thermal X-ray emission but no detectable radio emission")); } return out.join(",
"); } double Pulsar::getAngularSize(const StelCore*) const { return 0.00001; } void Pulsar::update(double deltaTime) { labelsFader.update((int)(deltaTime*1000)); } void Pulsar::draw(StelCore* core, StelPainter *painter) { StelSkyDrawer* sd = core->getSkyDrawer(); double mag = getVMagnitudeWithExtinction(core); StelUtils::spheToRect(RA, DE, XYZ); Vec3d win; // Check visibility of pulsar if (!(painter->getProjector()->projectCheck(XYZ, win))) return; glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); if (glitch>0 && glitchFlag) painter->setColor(glitchColor[0], glitchColor[1], glitchColor[2], 1); else painter->setColor(markerColor[0], markerColor[1], markerColor[2], 1); float mlimit = sd->getLimitMagnitude(); if (mag <= mlimit) { Pulsar::markerTexture->bind(); float size = getAngularSize(NULL)*M_PI/180.*painter->getProjector()->getPixelPerRadAtCenter(); float shift = 5.f + size/1.6f; painter->drawSprite2dMode(XYZ, distributionMode ? 4.f : 5.f); if (labelsFader.getInterstate()<=0.f && !distributionMode && (mag+2.f)drawText(XYZ, designation, 0, shift, shift, false); } } }