示例#1
0
int main (int argc, char* argv[])
{
    /** We create a command line parser. */
    OptionsParser parser ("GraphStats");
    parser.push_back (new OptionOneParam (STR_URI_GRAPH, "graph input",  true));

    try
    {
        /** We parse the user options. */
        IProperties* options = parser.parse (argc, argv);

        // We load the graph
        Graph graph = Graph::load (options->getStr(STR_URI_GRAPH));

        // We create a graph marker.
        GraphMarker marker (graph);

        // We create an object for Breadth First Search for the de Bruijn graph.
        BFS bfs (graph);

        // We want to compute the distribution of connected components of the branching nodes.
        //    - key is a connected component class (for a given number of branching nodes for this component)
        //    - value is the number of times this component class occurs in the branching sub graph
        map<size_t,size_t> distrib;

        // We get an iterator for all nodes of the graph. We use a progress iterator to get some progress feedback
        ProgressGraphIterator<BranchingNode,ProgressTimer>  itBranching (graph.iteratorBranching(), "statistics");

        // We want time duration of the iteration
        TimeInfo ti;
        ti.start ("compute");

        // We need to keep each connected component.
        list<set<BranchingNode> > components;

        // We loop the branching nodes
        for (itBranching.first(); !itBranching.isDone(); itBranching.next())
        {
            // We skip already visited nodes.
            if (marker.isMarked (*itBranching))  { continue; }

            // We launch the breadth first search; we get as a result the set of branching nodes in this component
            const set<BranchingNode>& component = bfs.run (*itBranching);

            // We memorize the component
            components.push_back (component);

            // We mark the nodes for this connected component
            marker.mark (component);

            // We update our distribution
            distrib[component.size()] ++;
        }

        ti.stop ("compute");

        // We compute the total number of branching nodes in all connected components.
        size_t sum = 0;   for (map<size_t,size_t>::iterator it = distrib.begin(); it != distrib.end(); it++)  {  sum += it->first*it->second; }

        // Note: it must be equal to the number of branching nodes of the graph
        assert (sum == itBranching.size());

        size_t idx1=0;
        size_t cc=0;
        // We check that each component has no intersection with all other components.
        // Note: this check may take a long time since we have N^2 intersections to compute.
        for (list<set<BranchingNode> >::iterator it1 = components.begin(); it1 != components.end(); it1++, idx1++)
        {
            size_t idx2=0;

            for (list<set<BranchingNode> >::iterator it2 = components.begin(); it2 != components.end(); it2++, idx2++)
            {
                if (it1 != it2)
                {
                    set<BranchingNode> inter;
                    set_intersection (it1->begin(),it1->end(),it2->begin(),it2->end(), std::inserter(inter,inter.begin()));
                    if (inter.size()!=0)  { printf ("ERROR, intersection should be empty...\n");  exit(EXIT_FAILURE); }
                }

                if (++cc % 50 == 0)
                {
                    cc = 0;
                    printf ("[check] %.1f  %.1f\r", 100.0*(float)idx1/(float)components.size(), 100.0*(float)idx2/(float)components.size());
                    fflush (stdout);
                }
            }
        }
        printf ("\n");

        // We aggregate the computed information
        Properties props ("connected_components");
        props.add (1, "graph_name",              "%s", graph.getName().c_str());
        props.add (1, "nb_branching_nodes",      "%d", sum);
        props.add (1, "nb_connected_components", "%d", distrib.size());
        for (map<size_t,size_t>::iterator it = distrib.begin(); it!=distrib.end(); it++)
        {
            props.add (2, "component");
            props.add (3, "nb_nodes",    "%d", it->first);
            props.add (3, "nb_occurs",   "%d", it->second);
            props.add (3, "freq_nodes",  "%f", 100.0*(float)(it->first*it->second) / (float)sum);
            props.add (3, "freq_occurs", "%f", 100.0*(float)it->second / (float)sum);
        }
        props.add (1, ti.getProperties("time"));

        // We dump the results in a XML file in the current directory
        XmlDumpPropertiesVisitor v (graph.getName() + ".xml", false);
        props.accept (&v);
    }
    catch (OptionFailure& e)
    {
        return e.displayErrors (std::cout);
    }
    catch (Exception& e)
    {
        std::cerr << "EXCEPTION: " << e.getMessage() << std::endl;
    }

    return EXIT_SUCCESS;
}
示例#2
0
int main (int argc, char* argv[])
{
    /** We create a command line parser. */
    OptionsParser parser;
    parser.push_back (new OptionOneParam (STR_URI_INPUT,  "graph file", true));

    IProperties* params = 0;

    try  {
        /** We parse the user options. */
        params = parser.parse (argc, argv);
    }
    catch (OptionFailure& e)
    {
        e.getParser().displayErrors (stdout);
        e.getParser().displayHelp   (stdout);
        return EXIT_FAILURE;
    }

    // We create the graph with the bank and other options
    Graph graph = Graph::load (params->getStr(STR_URI_INPUT));

    // We create a graph marker.
    GraphMarker<BranchingNode> marker (graph);

    // We create an object for Breadth First Search for the de Bruijn graph.
    BFS<BranchingNode> bfs (graph);

    // We want to compute the distribution of connected components of the branching nodes.
    //    - key is a connected component class (for a given number of branching nodes for this component)
    //    - value is the number of times this component class occurs in the branching sub graph
    map<size_t,Entry> distrib;

    // We get an iterator for all nodes of the graph. We use a progress iterator to get some progress feedback
    ProgressGraphIterator<BranchingNode,ProgressTimer>  itBranching (graph.iterator<BranchingNode>(), "statistics");

    // We want to know the number of connected components
    size_t nbConnectedComponents = 0;

    // We define some kind of unique identifier for a couple (indegree,outdegree)
    map <InOut_t, size_t> topology;

    size_t simplePathSizeMin = ~0;
    size_t simplePathSizeMax =  0;


    // We want time duration of the iteration
    TimeInfo ti;
    ti.start ("compute");

    // We loop the branching nodes
    for (itBranching.first(); !itBranching.isDone(); itBranching.next())
    {
        // We get branching nodes neighbors for the current branching node.
        Graph::Vector<BranchingEdge> successors   = graph.successors  <BranchingEdge> (*itBranching);
        Graph::Vector<BranchingEdge> predecessors = graph.predecessors<BranchingEdge> (*itBranching);

        // We increase the occurrences number for the current couple (in/out) neighbors
        topology [make_pair(predecessors.size(), successors.size())] ++;

        // We loop the in/out neighbors and update min/max simple path size
        for (size_t i=0; i<successors.size(); i++)
        {
            simplePathSizeMax = std::max (simplePathSizeMax, successors[i].distance);
            simplePathSizeMin = std::min (simplePathSizeMin, successors[i].distance);
        }
        for (size_t i=0; i<predecessors.size(); i++)
        {
            simplePathSizeMax = std::max (simplePathSizeMax, predecessors[i].distance);
            simplePathSizeMin = std::min (simplePathSizeMin, predecessors[i].distance);
        }

        // We skip already visited nodes.
        if (marker.isMarked (*itBranching))  {
            continue;
        }

        // We launch the breadth first search; we get as a result the set of branching nodes in this component
        const set<BranchingNode>& component = bfs.run (*itBranching);

        // We mark the nodes for this connected component
        marker.mark (component);

        // We update our distribution
        distrib[component.size()].nbOccurs += 1;

        // We update the number of connected components.
        nbConnectedComponents++;
    }

    ti.stop ("compute");

    // We compute the total number of branching nodes in all connected components.
    size_t sumOccurs = 0;
    size_t sumKmers = 0;
    for (map<size_t,Entry>::iterator it = distrib.begin(); it != distrib.end(); it++)
    {
        sumOccurs += it->first*it->second.nbOccurs;
        sumKmers  += it->second.nbKmers;
    }

    // We sort the statistics by decreasing occurrence numbers. Since map have its own ordering, we need to put all
    // the data into a vector and sort it with our own sorting criteria.
    vector < pair<InOut_t,size_t> >  stats;
    for (map <InOut_t, size_t>::iterator it = topology.begin(); it != topology.end(); it++)  {
        stats.push_back (*it);
    }

    sort (stats.begin(), stats.end(), CompareFct);

    // Note: it must be equal to the number of branching nodes of the graph
    assert (sumOccurs == itBranching.size());

    // We aggregate the computed information
    Properties props ("topology");

    props.add (1, "graph");
    props.add (2, "name",                    "%s", graph.getName().c_str());
    props.add (2, "db_input",                "%s", graph.getInfo().getStr("input").c_str());
    props.add (2, "db_nb_seq",               "%d", graph.getInfo().getInt("sequences_number"));
    props.add (2, "db_size",                 "%d", graph.getInfo().getInt("sequences_size"));
    props.add (2, "kmer_size",               "%d", graph.getInfo().getInt("kmer_size"));
    props.add (2, "kmer_nks",                "%d", graph.getInfo().getInt("nks"));
    props.add (2, "nb_nodes",                "%d", graph.getInfo().getInt("kmers_nb_solid"));
    props.add (2, "nb_branching_nodes",      "%d", graph.getInfo().getInt("nb_branching"));
    props.add (2, "percent_branching_nodes", "%.1f",
               graph.getInfo().getInt("kmers_nb_solid") > 0 ?
               100.0 * (float)graph.getInfo().getInt("nb_branching") / (float) graph.getInfo().getInt("kmers_nb_solid") : 0
              );

    props.add (1, "branching_nodes");

    props.add (2, "simple_path");
    props.add (3, "size_min", "%d", simplePathSizeMin);
    props.add (3, "size_max", "%d", simplePathSizeMax);

    props.add (2, "neighborhoods");
    for (size_t i=0; i<stats.size(); i++)
    {
        props.add (3, "neighborhood", "in=%d out=%d", stats[i].first.first, stats[i].first.second);
        props.add (4, "nb_bnodes",     "%d",    stats[i].second);
        props.add (4, "percentage",   "%5.2f", itBranching.size() > 0 ?
                   100.0*(float)stats[i].second / (float)itBranching.size() : 0
                  );
    }

    props.add (2, "connected_components");
    props.add (3, "nb_classes",    "%d", distrib.size());
    props.add (3, "nb_components", "%d", nbConnectedComponents);
    for (map<size_t,Entry>::iterator it = distrib.begin(); it!=distrib.end(); it++)
    {
        props.add (3, "component_class");
        props.add (4, "nb_occurs",    "%d", it->second.nbOccurs);
        props.add (4, "nb_bnodes",    "%d", it->first);
        props.add (4, "freq_bnodes",  "%f", sumOccurs > 0 ?
                   100.0*(float)(it->first*it->second.nbOccurs) / (float)sumOccurs : 0
                  );
    }
    props.add (1, ti.getProperties("time"));

    // We dump the results in a XML file in the current directory
    XmlDumpPropertiesVisitor v (graph.getName() + ".xml", false);
    props.accept (&v);

    return EXIT_SUCCESS;
}
void BpDocument::composeFireCharacteristicsDiagram( void )
{
    // Surface Module must be active and using fuel model inputs
    PropertyDict *prop = m_eqTree->m_propDict;
    if ( ! prop->boolean( "surfaceModuleActive" )
      || ! prop->boolean( "surfaceCalcFireCharacteristicsDiagram" ) )
    {
        return;
    }

    // Graph fonts.
    QFont  textFont( property()->string( "graphTextFontFamily" ),
                     property()->integer( "graphTextFontSize" ) );
    QColor textColor( property()->color( "graphTextFontColor" ) );
    QPen   textPen( textColor );
    QFont  subTitleFont( property()->string( "graphSubtitleFontFamily" ),
                    property()->integer( "graphSubtitleFontSize" ) );
    QColor subTitleColor( property()->color( "graphSubtitleFontColor" ) );

    // Open the result file
    QString resultFile = m_eqTree->m_resultFile;
    FILE *fptr = 0;
    if ( ! ( fptr = fopen( resultFile.latin1(), "r" ) ) )
    // This code block should never be executed!
    {
        QString text("");
        translate( text, "BpDocument:FireCharacteristicsDiagram:NoLogOpen",
            resultFile );
        error( text );
        return;
    }
    // Allocate ros and hpua data arrays
    int rows  = tableRows();
    int cols  = tableCols();
    int cells = rows * cols;
    double *hpua = new double[ cells ];
    checkmem( __FILE__, __LINE__, hpua, "double hpua", cells );
    double *ros = new double[ cells ];
    checkmem( __FILE__, __LINE__, ros, "double ros", cells );
    // Set the variable names we're looking for
    const char* hpuaName = "vSurfaceFireHeatPerUnitArea";
    const char* rosName = "vSurfaceFireSpreadAtHead";
    if ( prop->boolean( "surfaceConfSpreadDirInput" ) )
    {
        rosName = "vSurfaceFireSpreadAtVector";
    }
    // Read and store the ros and hpua values
    char   buffer[1024], varName[128], varUnits[128];
    int    row, col, cell;
    double value;
    double rosMax = 0.0;
    double hpuaMax = 0.0;
    while ( fgets( buffer, sizeof(buffer), fptr ) )
    {
        if ( strncmp( buffer, "CELL", 4 ) == 0 )
        {
            if ( strstr( buffer, hpuaName ) )
            {
                sscanf( buffer, "CELL %d %d %s cont %lf %s",
                    &row, &col, varName, &value, varUnits );
                cell = ( col - 1 ) + ( cols * ( row - 1) );
                if ( ( hpua[ cell ] = value ) > hpuaMax )
                {
                    hpuaMax = value;
                }
            }
            else if ( strstr( buffer, rosName ) )
            {
                sscanf( buffer, "CELL %d %d %s cont %lf %s",
                    &row, &col, varName, &value, varUnits );
                cell = ( col - 1 ) + ( cols * ( row - 1) );
                if ( ( ros[ cell ] = value ) > rosMax )
                {
                    rosMax = value;
                }
            }
        }
    }
    fclose( fptr );

    // Get variable pointers
    EqVar *hpuaVar = m_eqTree->m_varDict->find( "vSurfaceFireHeatPerUnitArea" );
    EqVar *rosVar = m_eqTree->m_varDict->find( "vSurfaceFireSpreadAtHead" );
    EqVar *fliVar = m_eqTree->m_varDict->find( "vSurfaceFireLineIntAtHead" );
    EqVar *flVar = m_eqTree->m_varDict->find( "vSurfaceFireFlameLengAtHead" );

    // Conversion factor
    double flFactor, fliFactor, rosFactor, hpuaFactor, offset;
    appSiUnits()->conversionFactorOffset(
        flVar->m_nativeUnits, flVar->m_displayUnits, &flFactor, &offset );
    appSiUnits()->conversionFactorOffset(
        fliVar->m_nativeUnits, fliVar->m_displayUnits, &fliFactor, &offset );
    appSiUnits()->conversionFactorOffset(
        hpuaVar->m_nativeUnits, hpuaVar->m_displayUnits, &hpuaFactor, &offset );
    appSiUnits()->conversionFactorOffset(
        rosVar->m_nativeUnits, rosVar->m_displayUnits, &rosFactor, &offset );

    // Determine which of four different chart scales to use
    static const int Scales = 4;
    static double RosScale[Scales] = { 100., 200., 400., 800. };        // ft/min
    static double HpuaScale[Scales] = { 2000., 4000., 8000., 16000. };  // Btu/ft2
    double rosScale = 0.;       // Max y-axis ros
    double hpuaScale = 0.;      // Max x-axis hpua
    int scale;
    for ( scale=0; scale<Scales; scale++ )
    {
        if ( rosMax < ( rosScale = RosScale[ scale ] ) )
        {
            break;
        }
    }
    for ( scale=0; scale<Scales; scale++ )
    {
        if ( hpuaMax < ( hpuaScale = HpuaScale[scale] ) )
        {
            break;
        }
    }
    // Set axis maximums to appropriate predefined scale in display units
    rosMax  = rosFactor * rosScale;
    hpuaMax = hpuaFactor * hpuaScale;
    double ratio = rosMax / hpuaMax;

    // Create the graph
    Graph  graph;
    GraphLine *graphLine;
    GraphMarker *graphMarker;
    static const int Points = 100;
    double l_x[Points];
    double l_y[Points];

    // Draw the four standard hauling chart fli-fl levels
    static const int Lines = 4;
    static const double Fli[Lines] = { 100., 500., 1000., 2000. };  // Btu/ft/s
    static const double Fl[Lines] = { 4., 8., 11., 15. };           // ft

    // Create the hauling chart lines
    // Put Fireline Int label 65% of the way along the HPUA axis (display units)
    double  xPosFli = 0.65 * hpuaMax;
    // Put Flame Length label 85% of the way along the HPUA axis (display units)
    double  xPosFl  = 0.85 * hpuaMax;
    // Fireline Int and Flame Length label Y positions (display units)
    double  yPosFl[Lines], yPosFli[Lines];
    // Icon locations (in display units)
    double xIcon[Lines+1], yIcon[Lines+1];
    double diff, minDiff;
    QString label;
    QPen    redPen( "red", 1 );
    QColor  blackColor( "black" );
    int     alignCenter = Qt::AlignHCenter | Qt::AlignVCenter;
    // Fireline intensity - flame length curves
    int     line, point;
    for ( line = 0; line < Lines; line++ )
    {
        minDiff = 999999999.;
        for ( point = 0; point < Points; point++ )
        {
            // Hpua value in native units (Btu/ft2)
            l_x[point] = ( (point+1) * hpuaScale ) / (double) Points;
            // Ros value in native units (ft/min)
            l_y[point] = 60. * Fli[line] / l_x[point];
            // Convert to display units
            l_x[point] *= hpuaFactor;
            l_y[point] *= rosFactor;
            // Check for curve inflection point (for icon placement)
            if ( ( diff = fabs( l_y[point]/l_x[point] - ratio ) ) < minDiff )
            {
                minDiff = diff;
                xIcon[line+1] = l_x[point];
                yIcon[line+1] = l_y[point];
            }
        }
        // Create a graph line (with its own copy of the data).
        graphLine = graph.addGraphLine( Points, l_x, l_y, redPen );

        // Fireline intensity label
        label = QString( "%1" ).arg( ( Fli[line] * fliFactor ), 0, 'f', 0 );
        yPosFli[line] = rosFactor * ( 60. * Fli[line] / ( xPosFli / hpuaFactor ) );
        graph.addGraphMarker( xPosFli, yPosFli[line], label, textFont,
            blackColor, alignCenter );

        // Flame length label
        label = QString( "%1" ).arg( ( Fl[line] * flFactor ), 0, 'f', 0 );
        yPosFl[line] = rosFactor * ( 60. * Fli[line] / ( xPosFl / hpuaFactor ) );
        graph.addGraphMarker( xPosFl, yPosFl[line], label, textFont,
            blackColor, alignCenter );
    } // Next line

    // Fireline intensity label and units
    translate( label, "BpDocument:FireCharacteristicsDiagram:FLI" );
    graph.addGraphMarker( xPosFli, ( yPosFli[Lines-1] + 0.10 * rosMax ),
        label, textFont, blackColor, alignCenter );
    graph.addGraphMarker( xPosFli, ( yPosFli[Lines-1] + 0.05 * rosMax ),
        fliVar->m_displayUnits, textFont, blackColor, alignCenter );

    // Flame length label and units
    translate( label, "BpDocument:FireCharacteristicsDiagram:FL" );
    graph.addGraphMarker( xPosFl, ( yPosFl[Lines-1] + 0.10 * rosMax ),
        label, textFont, blackColor, alignCenter );
    graph.addGraphMarker( xPosFl, ( yPosFl[Lines-1] + 0.05 * rosMax ),
        flVar->m_displayUnits, textFont, blackColor, alignCenter );

    // Add icons
    QPixmap pixmap[Lines];
    pixmap[0] = QPixmap( fireman_xpm );
    pixmap[1] = QPixmap( dozer_xpm );
    pixmap[2] = QPixmap( torchtree_xpm );
    pixmap[3] = QPixmap( mtnfire_xpm );
    xIcon[0] = yIcon[0] = 0.0;
    for ( line=0; line<Lines; line++ )
    {
        graphMarker = graph.addGraphMarker(
            xIcon[line] + ( 0.5 * ( xIcon[line+1] - xIcon[line] ) ),
            yIcon[line] + ( 0.5 * ( yIcon[line+1] - yIcon[line] ) ),
            "", textFont, blackColor, alignCenter );
        graphMarker->setGraphMarkerPixmap( pixmap[line] );
    }

    // Finally, add a marker for each output result
    QColor  bluePen( "blue" );
    for ( cell=0; cell<cells; cell++ )
    {
        //fprintf( stderr, "%02d: %3.2f  %3.2f\n", i, hpua[i], ros[i] );
        graph.addGraphMarker( hpua[cell], ros[cell],
            QString( "%1" ).arg( cell + 1 ), textFont, bluePen, alignCenter );
    }
    // Compose the graph
    EqVar *zVar = 0;
    GraphAxleParms xParms( 0.0, hpuaMax, 11 );
    GraphAxleParms yParms( 0.0, rosMax, 11 );
    composeGraphBasics( &graph, true, hpuaVar, rosVar, zVar, Lines,
        &xParms, &yParms );

    // Create a separate page for this graph.
    translate( label, "BpDocument:FireCharacteristicsDiagram:Caption" );
    graph.setSubTitle( label, subTitleFont, subTitleColor );
    startNewPage( label, TocHaulChart );

    // This is how we save the graph and its composer.
    m_composer->graph( graph,
        m_pageSize->m_marginLeft
            + m_pageSize->m_bodyWd * property()->real( "graphXOffset" ),
        m_pageSize->m_marginTop
            + m_pageSize->m_bodyHt * property()->real( "graphYOffset" ),
        m_pageSize->m_bodyWd * property()->real( "graphScaleWidth" ),
        m_pageSize->m_bodyHt * property()->real( "graphScaleHeight" )
    );
    // Be polite and stop the composer.
    m_composer->end();
    delete[] ros;   ros  = 0;
    delete[] hpua;  hpua = 0;
    return;
}