int main(int argc, char *argv[]) { int dims = 2; int nr_particles = 5; if (argc > 1) dims = atoi(argv[1]); if (argc > 2) nr_particles = atoi(argv[2]); System *system = init_system(nr_particles, dims); print_system(system); printf("total mass = %lf\n", total_mass(system)); double cms[dims]; center_of_mass(system, cms); print_position(cms, dims); free_system(system); return EXIT_SUCCESS; }
bool game::dump_stats( const std::string &what, dump_mode mode, const std::vector<std::string> &opts ) { try { loading_ui ui( false ); load_core_data( ui ); load_packs( _( "Loading content packs" ), { mod_id( "dda" ) }, ui ); DynamicDataLoader::get_instance().finalize_loaded_data( ui ); } catch( const std::exception &err ) { std::cerr << "Error loading data from json: " << err.what() << std::endl; return false; } std::vector<std::string> header; std::vector<std::vector<std::string>> rows; int scol = 0; // sorting column std::map<std::string, standard_npc> test_npcs; test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8, 10 /* PER 10 */ ); test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" }, 4, 10, 8, 8, 8 /* STAT 10 */ ); test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); std::map<std::string, item> test_items; test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" ); test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" ); test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" ); test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" ); test_items[ "G4" ].emplace_back( "rifle_scope" ); if( what == "AMMO" ) { header = { "Name", "Ammo", "Volume", "Weight", "Stack", "Range", "Dispersion", "Recoil", "Damage", "Pierce" }; auto dump = [&rows]( const item & obj ) { // a common task is comparing ammo by type so ammo has multiple repeat the entry for( const auto &e : obj.type->ammo->type ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( e.str() ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( to_gram( obj.weight() ) ) ); r.push_back( to_string( obj.type->stack_size ) ); r.push_back( to_string( obj.type->ammo->range ) ); r.push_back( to_string( obj.type->ammo->dispersion ) ); r.push_back( to_string( obj.type->ammo->recoil ) ); damage_instance damage = obj.type->ammo->damage; r.push_back( to_string( damage.total_damage() ) ); r.push_back( to_string( damage.empty() ? 0 : ( *damage.begin() ).res_pen ) ); rows.push_back( r ); } }; for( const itype *e : item_controller->all() ) { if( e->ammo ) { dump( item( e, calendar::turn, item::solitary_tag {} ) ); } } } else if( what == "ARMOR" ) { header = { "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire" }; auto dump = [&rows]( const item & obj ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( to_string( obj.get_encumber() ) ); r.push_back( to_string( obj.get_warmth() ) ); r.push_back( to_string( to_gram( obj.weight() ) ) ); r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) ); r.push_back( to_string( obj.get_coverage() ) ); r.push_back( to_string( obj.bash_resist() ) ); r.push_back( to_string( obj.cut_resist() ) ); r.push_back( to_string( obj.acid_resist() ) ); r.push_back( to_string( obj.fire_resist() ) ); rows.push_back( r ); }; body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() ); for( const itype *e : item_controller->all() ) { if( e->armor ) { item obj( e ); if( bp == num_bp || obj.covers( bp ) ) { if( obj.has_flag( "VARSIZE" ) ) { obj.item_tags.insert( "FIT" ); } dump( obj ); } } } } else if( what == "EDIBLE" ) { header = { "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy" }; for( const auto &v : vitamin::all() ) { header.push_back( v.second.name() ); } auto dump = [&rows]( const item & obj ) { std::vector<std::string> r; r.push_back( obj.tname( false ) ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( to_gram( obj.weight() ) ) ); r.push_back( to_string( obj.type->stack_size ) ); r.push_back( to_string( obj.type->comestible->get_calories() ) ); r.push_back( to_string( obj.type->comestible->quench ) ); r.push_back( to_string( obj.type->comestible->healthy ) ); auto vits = g->u.vitamins_from( obj ); for( const auto &v : vitamin::all() ) { r.push_back( to_string( vits[ v.first ] ) ); } rows.push_back( r ); }; for( const itype *e : item_controller->all() ) { item food( e, calendar::turn, item::solitary_tag {} ); if( food.is_food() && g->u.can_eat( food ).success() ) { dump( food ); } } } else if( what == "GUN" ) { header = { "Name", "Ammo", "Volume", "Weight", "Capacity", "Range", "Dispersion", "Effective recoil", "Damage", "Pierce", "Aim time", "Effective range", "Snapshot range", "Max range" }; std::set<std::string> locations; for( const itype *e : item_controller->all() ) { if( e->gun ) { std::transform( e->gun->valid_mod_locations.begin(), e->gun->valid_mod_locations.end(), std::inserter( locations, locations.begin() ), []( const std::pair<gunmod_location, int> &q ) { return q.first.name(); } ); } } for( const auto &e : locations ) { header.push_back( e ); } auto dump = [&rows, &locations]( const standard_npc & who, const item & obj ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( to_gram( obj.weight() ) ) ); r.push_back( to_string( obj.ammo_capacity() ) ); r.push_back( to_string( obj.gun_range() ) ); r.push_back( to_string( obj.gun_dispersion() ) ); r.push_back( to_string( obj.gun_recoil( who ) ) ); damage_instance damage = obj.gun_damage(); r.push_back( to_string( damage.total_damage() ) ); r.push_back( to_string( damage.empty() ? 0 : ( *damage.begin() ).res_pen ) ); r.push_back( to_string( who.gun_engagement_moves( obj ) ) ); for( const auto &e : locations ) { const auto &vml = obj.type->gun->valid_mod_locations; const auto iter = vml.find( e ); r.push_back( to_string( iter != vml.end() ? iter->second : 0 ) ); } rows.push_back( r ); }; for( const itype *e : item_controller->all() ) { if( e->gun ) { item gun( e ); if( !gun.magazine_integral() ) { gun.emplace_back( gun.magazine_default() ); } gun.ammo_set( gun.ammo_type()->default_ammotype(), gun.ammo_capacity() ); dump( test_npcs[ "S1" ], gun ); if( gun.type->gun->barrel_length > 0 ) { gun.emplace_back( "barrel_small" ); dump( test_npcs[ "S1" ], gun ); } } } } else if( what == "RECIPE" ) { // optionally filter recipes to include only those using specified skills recipe_subset dict; for( const auto &r : recipe_dict ) { if( opts.empty() || std::any_of( opts.begin(), opts.end(), [&r]( const std::string & s ) { if( r.second.skill_used == skill_id( s ) && r.second.difficulty > 0 ) { return true; } auto iter = r.second.required_skills.find( skill_id( s ) ); return iter != r.second.required_skills.end() && iter->second > 0; } ) ) { dict.include( &r.second ); } } // only consider skills that are required by at least one recipe std::vector<Skill> sk; std::copy_if( Skill::skills.begin(), Skill::skills.end(), std::back_inserter( sk ), [&dict]( const Skill & s ) { return std::any_of( dict.begin(), dict.end(), [&s]( const recipe * r ) { return r->skill_used == s.ident() || r->required_skills.find( s.ident() ) != r->required_skills.end(); } ); } ); header = { "Result" }; for( const auto &e : sk ) { header.push_back( e.ident().str() ); } for( const recipe *e : dict ) { std::vector<std::string> r; r.push_back( e->result_name() ); for( const auto &s : sk ) { if( e->skill_used == s.ident() ) { r.push_back( to_string( e->difficulty ) ); } else { auto iter = e->required_skills.find( s.ident() ); r.push_back( to_string( iter != e->required_skills.end() ? iter->second : 0 ) ); } } rows.push_back( r ); } } else if( what == "VEHICLE" ) { header = { "Name", "Weight (empty)", "Weight (fueled)", "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)", "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %", "Traction coeff % (grass)" }; auto dump = [&rows]( const vproto_id & obj ) { auto veh_empty = vehicle( obj, 0, 0 ); auto veh_fueled = vehicle( obj, 100, 0 ); std::vector<std::string> r; r.push_back( veh_empty.name ); r.push_back( to_string( to_kilogram( veh_empty.total_mass() ) ) ); r.push_back( to_string( to_kilogram( veh_fueled.total_mass() ) ) ); r.push_back( to_string( veh_fueled.max_velocity() / 100 ) ); r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) ); r.push_back( to_string( veh_fueled.acceleration() / 100 ) ); r.push_back( to_string( ( int )( 100 * veh_fueled.k_mass() ) ) ); r.push_back( to_string( ( int )( 100 * veh_fueled.k_aerodynamics() ) ) ); r.push_back( to_string( ( int )( 100 * veh_fueled.k_friction() ) ) ); r.push_back( to_string( ( int )( 100 * veh_fueled.k_traction( veh_fueled.wheel_area( false ) / 2.0f ) ) ) ); rows.push_back( r ); }; for( auto &e : vehicle_prototype::get_all() ) { dump( e ); } } else if( what == "VPART" ) { header = { "Name", "Location", "Weight", "Size" }; auto dump = [&rows]( const vpart_info & obj ) { std::vector<std::string> r; r.push_back( obj.name() ); r.push_back( obj.location ); r.push_back( to_string( int( ceil( to_gram( item( obj.item ).weight() ) / 1000.0 ) ) ) ); r.push_back( to_string( obj.size / units::legacy_volume_factor ) ); rows.push_back( r ); }; for( const auto &e : vpart_info::all() ) { dump( e.second ); } } else { std::cerr << "unknown argument: " << what << std::endl; return false; } rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string> &e ) { return e.empty(); } ), rows.end() ); if( scol >= 0 ) { std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string> &lhs, const std::vector<std::string> &rhs ) { return lhs[ scol ] < rhs[ scol ]; } ); } rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() ); switch( mode ) { case dump_mode::TSV: rows.insert( rows.begin(), header ); for( const auto &r : rows ) { std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) ); std::cout << r.back() << "\n"; } break; case dump_mode::HTML: std::cout << "<table>"; std::cout << "<thead>"; std::cout << "<tr>"; for( const auto &col : header ) { std::cout << "<th>" << col << "</th>"; } std::cout << "</tr>"; std::cout << "</thead>"; std::cout << "<tdata>"; for( const auto &r : rows ) { std::cout << "<tr>"; for( const auto &col : r ) { std::cout << "<td>" << col << "</td>"; } std::cout << "</tr>"; } std::cout << "</tdata>"; std::cout << "</table>"; break; } return true; }
bool game::dump_stats( const std::string& what, dump_mode mode, const std::vector<std::string> &opts ) { try { load_core_data(); } catch( const std::exception &err ) { std::cerr << "Error loading data from json: " << err.what() << std::endl; return false; } DynamicDataLoader::get_instance().finalize_loaded_data(); std::vector<std::string> header; std::vector<std::vector<std::string>> rows; int scol = 0; // sorting column std::map<std::string, standard_npc> test_npcs; test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8, 10 /* PER 10 */ ); test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" }, 4, 10, 8, 8, 8 /* STAT 10 */ ); test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ ); std::map<std::string, item> test_items; test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" ); test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" ); test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" ); test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" ); test_items[ "G4" ].emplace_back( "rifle_scope" ); if( what == "AMMO" ) { header = { "Name", "Ammo", "Volume", "Weight", "Stack", "Range", "Dispersion", "Recoil", "Damage", "Pierce" }; auto dump = [&rows]( const item& obj ) { // a common task is comparing ammo by type so ammo has multiple repeat the entry for( const auto &e : obj.type->ammo->type ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( e.str() ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( obj.weight() ) ); r.push_back( to_string( obj.type->stack_size ) ); r.push_back( to_string( obj.type->ammo->range ) ); r.push_back( to_string( obj.type->ammo->dispersion ) ); r.push_back( to_string( obj.type->ammo->recoil ) ); r.push_back( to_string( obj.type->ammo->damage ) ); r.push_back( to_string( obj.type->ammo->pierce ) ); rows.push_back( r ); } }; for( auto& e : item_controller->get_all_itypes() ) { if( e.second.ammo ) { dump( item( e.first, calendar::turn, item::solitary_tag {} ) ); } } } else if( what == "ARMOR" ) { header = { "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire" }; auto dump = [&rows]( const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( to_string( obj.get_encumber() ) ); r.push_back( to_string( obj.get_warmth() ) ); r.push_back( to_string( obj.weight() ) ); r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) ); r.push_back( to_string( obj.get_coverage() ) ); r.push_back( to_string( obj.bash_resist() ) ); r.push_back( to_string( obj.cut_resist() ) ); r.push_back( to_string( obj.acid_resist() ) ); r.push_back( to_string( obj.fire_resist() ) ); rows.push_back( r ); }; body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() ); for( auto& e : item_controller->get_all_itypes() ) { if( e.second.armor ) { item obj( e.first ); if( bp == num_bp || obj.covers( bp ) ) { if( obj.has_flag( "VARSIZE" ) ) { obj.item_tags.insert( "FIT" ); } dump( obj ); } } } } else if( what == "EDIBLE" ) { header = { "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy" }; for( const auto& v : vitamin::all() ) { header.push_back( v.second.name() ); } auto dump = [&rows,&test_npcs]( const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( false ) ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( obj.weight() ) ); r.push_back( to_string( obj.type->stack_size ) ); r.push_back( to_string( obj.type->comestible->get_calories() ) ); r.push_back( to_string( obj.type->comestible->quench ) ); r.push_back( to_string( obj.type->comestible->healthy ) ); auto vits = g->u.vitamins_from( obj ); for( const auto& v : vitamin::all() ) { r.push_back( to_string( vits[ v.first ] ) ); } rows.push_back( r ); }; for( auto& e : item_controller->get_all_itypes() ) { if( e.second.comestible && ( e.second.comestible->comesttype == "FOOD" || e.second.comestible->comesttype == "DRINK" ) ) { item food( e.first, calendar::turn, item::solitary_tag {} ); if( g->u.can_eat( food, false, true ) == EDIBLE ) { dump( food ); } } } } else if( what == "GUN" ) { header = { "Name", "Ammo", "Volume", "Weight", "Capacity", "Range", "Dispersion", "Effective recoil", "Damage", "Pierce", "Aim time", "Effective range", "Snapshot range", "Max range" }; std::set<std::string> locations; for( const auto& e : item_controller->get_all_itypes() ) { if( e.second.gun ) { std::transform( e.second.gun->valid_mod_locations.begin(), e.second.gun->valid_mod_locations.end(), std::inserter( locations, locations.begin() ), []( const std::pair<std::string, int>& e ) { return e.first; } ); } } for( const auto &e : locations ) { header.push_back( e ); } auto dump = [&rows,&locations]( const standard_npc &who, const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( 1, false ) ); r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" ); r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) ); r.push_back( to_string( obj.weight() ) ); r.push_back( to_string( obj.ammo_capacity() ) ); r.push_back( to_string( obj.gun_range() ) ); r.push_back( to_string( obj.gun_dispersion() ) ); r.push_back( to_string( obj.gun_recoil( who ) ) ); r.push_back( to_string( obj.gun_damage() ) ); r.push_back( to_string( obj.gun_pierce() ) ); r.push_back( to_string( who.gun_engagement_moves( obj ) ) ); r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::effective ) ) ); r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::snapshot ) ) ); r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::maximum ) ) ); for( const auto &e : locations ) { r.push_back( to_string( obj.type->gun->valid_mod_locations[ e ] ) ); } rows.push_back( r ); }; for( const auto& e : item_controller->get_all_itypes() ) { if( e.second.gun ) { item gun( e.first ); if( !gun.magazine_integral() ) { gun.emplace_back( gun.magazine_default() ); } gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() ); dump( test_npcs[ "S1" ], gun ); if( gun.type->gun->barrel_length > 0 ) { gun.emplace_back( "barrel_small" ); dump( test_npcs[ "S1" ], gun ); } } } } else if( what == "VEHICLE" ) { header = { "Name", "Weight (empty)", "Weight (fueled)", "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)", "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %", "Traction coeff % (grass)" }; auto dump = [&rows]( const vproto_id& obj ) { auto veh_empty = vehicle( obj, 0, 0 ); auto veh_fueled = vehicle( obj, 100, 0 ); std::vector<std::string> r; r.push_back( veh_empty.name ); r.push_back( to_string( veh_empty.total_mass() ) ); r.push_back( to_string( veh_fueled.total_mass() ) ); r.push_back( to_string( veh_fueled.max_velocity() / 100 ) ); r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) ); r.push_back( to_string( veh_fueled.acceleration() / 100 ) ); r.push_back( to_string( (int)( 100 * veh_fueled.k_mass() ) ) ); r.push_back( to_string( (int)( 100 * veh_fueled.k_aerodynamics() ) ) ); r.push_back( to_string( (int)( 100 * veh_fueled.k_friction() ) ) ); r.push_back( to_string( (int)( 100 * veh_fueled.k_traction( veh_fueled.wheel_area( false ) / 2.0f ) ) ) ); rows.push_back( r ); }; for( auto& e : vehicle_prototype::get_all() ) { dump( e ); } } else if( what == "VPART" ) { header = { "Name", "Location", "Weight", "Size" }; auto dump = [&rows]( const vpart_info &obj ) { std::vector<std::string> r; r.push_back( obj.name() ); r.push_back( obj.location ); r.push_back( to_string( int( ceil( item( obj.item ).weight() / 1000.0 ) ) ) ); r.push_back( to_string( obj.size / units::legacy_volume_factor ) ); rows.push_back( r ); }; for( const auto &e : vpart_info::all() ) { dump( e.second ); } } else if( what == "AIMING" ) { scol = -1; // unsorted output so graph columns have predictable ordering const int cycles = 1400; header = { "Name" }; for( int i = 0; i <= cycles; ++i ) { header.push_back( to_string( i ) ); } auto dump = [&rows]( const standard_npc &who, const item &gun) { std::vector<std::string> r( 1, string_format( "%s %s", who.get_name().c_str(), gun.tname().c_str() ) ); double penalty = MIN_RECOIL; for( int i = 0; i <= cycles; ++i ) { penalty -= who.aim_per_move( gun, penalty ); r.push_back( string_format( "%.2f", who.gun_current_range( gun, penalty ) ) ); } rows.push_back( r ); }; if( opts.empty() ) { dump( test_npcs[ "S1" ], test_items[ "G1" ] ); dump( test_npcs[ "S1" ], test_items[ "G2" ] ); dump( test_npcs[ "S1" ], test_items[ "G3" ] ); dump( test_npcs[ "S1" ], test_items[ "G4" ] ); } else { for( const auto &str : opts ) { auto idx = str.find( ':' ); if( idx == std::string::npos ) { std::cerr << "cannot parse test case: " << str << std::endl; return false; } auto test = std::make_pair( test_npcs.find( str.substr( 0, idx ) ), test_items.find( str.substr( idx + 1 ) ) ); if( test.first == test_npcs.end() || test.second == test_items.end() ) { std::cerr << "invalid test case: " << str << std::endl; return false; } dump( test.first->second, test.second->second ); } } } else if( what == "EXPLOSIVE" ) { header = { // @todo Should display more useful data: shrapnel damage, safe range "Name", "Power", "Power at 5 tiles", "Power halves at", "Shrapnel count", "Shrapnel mass" }; auto dump = [&rows]( const std::string &name, const explosion_data &ex ) { std::vector<std::string> r; r.push_back( name ); r.push_back( to_string( ex.power ) ); r.push_back( string_format( "%.1f", ex.power_at_range( 5.0f ) ) ); r.push_back( string_format( "%.1f", ex.expected_range( 0.5f ) ) ); r.push_back( to_string( ex.shrapnel.count ) ); r.push_back( to_string( ex.shrapnel.mass ) ); rows.push_back( r ); }; for( const auto& e : item_controller->get_all_itypes() ) { const auto &itt = e.second; const auto use = itt.get_use( "explosion" ); if( use != nullptr && use->get_actor_ptr() != nullptr ) { const auto actor = dynamic_cast<const explosion_iuse *>( use->get_actor_ptr() ); if( actor != nullptr ) { dump( itt.nname( 1 ), actor->explosion ); } } auto c_ex = dynamic_cast<const explosion_iuse *>( itt.countdown_action.get_actor_ptr() ); if( c_ex != nullptr ) { dump( itt.nname( 1 ), c_ex->explosion ); } } } else { std::cerr << "unknown argument: " << what << std::endl; return false; } rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) { return e.empty(); } ), rows.end() ); if( scol >= 0 ) { std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) { return lhs[ scol ] < rhs[ scol ]; } ); } rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() ); switch( mode ) { case dump_mode::TSV: rows.insert( rows.begin(), header ); for( const auto& r : rows ) { std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) ); std::cout << r.back() << "\n"; } break; case dump_mode::HTML: std::cout << "<table>"; std::cout << "<thead>"; std::cout << "<tr>"; for( const auto& col : header ) { std::cout << "<th>" << col << "</th>"; } std::cout << "</tr>"; std::cout << "</thead>"; std::cout << "<tdata>"; for( const auto& r : rows ) { std::cout << "<tr>"; for( const auto& col : r ) { std::cout << "<td>" << col << "</td>"; } std::cout << "</tr>"; } std::cout << "</tdata>"; std::cout << "</table>"; break; } return true; }
void game::dump_stats( const std::string& what, dump_mode mode ) { load_core_data(); DynamicDataLoader::get_instance().finalize_loaded_data(); std::vector<std::string> header; std::vector<std::vector<std::string>> rows; if( what == "AMMO" ) { header = { "Name", "Ammo", "Volume", "Weight", "Stack", "Range", "Dispersion", "Recoil", "Damage", "Pierce" }; auto dump = [&rows]( const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( false ) ); r.push_back( obj.type->ammo->type ); r.push_back( std::to_string( obj.volume() ) ); r.push_back( std::to_string( obj.weight() ) ); r.push_back( std::to_string( obj.type->stack_size ) ); r.push_back( std::to_string( obj.type->ammo->range ) ); r.push_back( std::to_string( obj.type->ammo->dispersion ) ); r.push_back( std::to_string( obj.type->ammo->recoil ) ); r.push_back( std::to_string( obj.type->ammo->damage ) ); r.push_back( std::to_string( obj.type->ammo->pierce ) ); rows.push_back( r ); }; for( auto& e : item_controller->get_all_itypes() ) { if( e.second->ammo ) { dump( item( e.first, calendar::turn, item::solitary_tag {} ) ); } } } else if( what == "EDIBLE" ) { header = { "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy" }; for( const auto& v : vitamin::all() ) { header.push_back( v.second.name() ); } auto dump = [&rows]( const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( false ) ); r.push_back( std::to_string( obj.volume() ) ); r.push_back( std::to_string( obj.weight() ) ); r.push_back( std::to_string( obj.type->stack_size ) ); r.push_back( std::to_string( obj.type->comestible->get_calories() ) ); r.push_back( std::to_string( obj.type->comestible->quench ) ); r.push_back( std::to_string( obj.type->comestible->healthy ) ); auto vits = g->u.vitamins_from( obj ); for( const auto& v : vitamin::all() ) { r.push_back( std::to_string( vits[ v.first ] ) ); } rows.push_back( r ); }; for( auto& e : item_controller->get_all_itypes() ) { if( e.second->comestible && ( e.second->comestible->comesttype == "FOOD" || e.second->comestible->comesttype == "DRINK" ) ) { item food( e.first, calendar::turn, item::solitary_tag {} ); if( g->u.can_eat( food, false, true ) == EDIBLE ) { dump( food ); } } } } else if( what == "GUN" ) { header = { "Name", "Ammo", "Volume", "Weight", "Capacity", "Range", "Dispersion", "Recoil", "Damage", "Pierce" }; std::set<std::string> locations; for( const auto& e : item_controller->get_all_itypes() ) { if( e.second->gun ) { std::transform( e.second->gun->valid_mod_locations.begin(), e.second->gun->valid_mod_locations.end(), std::inserter( locations, locations.begin() ), []( const std::pair<std::string, int>& e ) { return e.first; } ); } } for( const auto &e : locations ) { header.push_back( e ); } auto dump = [&rows,&locations]( const item& obj ) { std::vector<std::string> r; r.push_back( obj.tname( false ) ); r.push_back( obj.ammo_type() != "NULL" ? obj.ammo_type() : "" ); r.push_back( std::to_string( obj.volume() ) ); r.push_back( std::to_string( obj.weight() ) ); r.push_back( std::to_string( obj.ammo_capacity() ) ); r.push_back( std::to_string( obj.gun_range() ) ); r.push_back( std::to_string( obj.gun_dispersion() ) ); r.push_back( std::to_string( obj.gun_recoil() ) ); r.push_back( std::to_string( obj.gun_damage() ) ); r.push_back( std::to_string( obj.gun_pierce() ) ); for( const auto &e : locations ) { r.push_back( std::to_string( obj.type->gun->valid_mod_locations[ e ] ) ); } rows.push_back( r ); }; for( const auto& e : item_controller->get_all_itypes() ) { if( e.second->gun ) { item gun( e.first ); if( gun.is_reloadable() ) { gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() ); } dump( gun ); if( gun.type->gun->barrel_length > 0 ) { gun.emplace_back( "barrel_small" ); dump( gun ); } } } } else if( what == "VEHICLE" ) { header = { "Name", "Weight (empty)", "Weight (fueled)" }; auto dump = [&rows]( const vproto_id& obj ) { auto veh_empty = vehicle( obj, 0, 0 ); auto veh_fueled = vehicle( obj, 100, 0 ); std::vector<std::string> r; r.push_back( veh_empty.name ); r.push_back( std::to_string( veh_empty.total_mass() ) ); r.push_back( std::to_string( veh_fueled.total_mass() ) ); rows.push_back( r ); }; for( auto& e : vehicle_prototype::get_all() ) { dump( e ); } } else if( what == "VPART" ) { header = { "Name", "Location", "Weight", "Size" }; auto dump = [&rows]( const vpart_info *obj ) { std::vector<std::string> r; r.push_back( obj->name() ); r.push_back( obj->location ); r.push_back( std::to_string( int( ceil( item( obj->item ).weight() / 1000.0 ) ) ) ); r.push_back( std::to_string( obj->size ) ); rows.push_back( r ); }; for( const auto e : vpart_info::get_all() ) { dump( e ); } } rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) { return e.empty(); } ), rows.end() ); std::sort( rows.begin(), rows.end(), []( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) { return lhs[ 0 ] < rhs[ 0 ]; } ); rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() ); switch( mode ) { case dump_mode::TSV: rows.insert( rows.begin(), header ); for( const auto& r : rows ) { std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) ); std::cout << r.back() << "\n"; } break; case dump_mode::HTML: std::cout << "<table>"; std::cout << "<thead>"; std::cout << "<tr>"; for( const auto& col : header ) { std::cout << "<th>" << col << "</th>"; } std::cout << "</tr>"; std::cout << "</thead>"; std::cout << "<tdata>"; for( const auto& r : rows ) { std::cout << "<tr>"; for( const auto& col : r ) { std::cout << "<td>" << col << "</td>"; } std::cout << "</tr>"; } std::cout << "</tdata>"; std::cout << "</table>"; break; } }
ErrorCode Intx2MeshOnSphere::update_tracer_data(EntityHandle out_set, Tag & tagElem, Tag & tagArea) { EntityHandle dum = 0; Tag corrTag; ErrorCode rval = mb->tag_get_handle(CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE, &dum); // it should have been created ERRORR(rval, "can't get correlation tag"); Tag gid; rval = mb->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, gid, MB_TAG_DENSE); ERRORR(rval,"can't get global ID tag" ); // get all polygons out of out_set; then see where are they coming from Range polys; rval = mb->get_entities_by_dimension(out_set, 2, polys); ERRORR(rval, "can't get polygons out"); // rs2 is the red range, arrival; rs1 is blue, departure; // there is a connection between rs1 and rs2, through the corrTag // corrTag is __correlation // basically, mb->tag_get_data(corrTag, &(redPoly), 1, &bluePoly); // also, mb->tag_get_data(corrTag, &(bluePoly), 1, &redPoly); // we start from rs2 existing, then we have to update something // tagElem will have multiple tracers int numTracers = 0; rval = mb->tag_get_length(tagElem, numTracers); ERRORR(rval, "can't get number of tracers in simulation"); if (numTracers < 1) ERRORR(MB_FAILURE, "no tracers data"); std::vector<double> currentVals(rs2.size()*numTracers); rval = mb->tag_get_data(tagElem, rs2, ¤tVals[0]); ERRORR(rval, "can't get existing tracers values"); // create new tuple list for tracers to other processors, from remote_cells #ifdef MOAB_HAVE_MPI if (remote_cells) { int n = remote_cells->get_n(); if (n>0) { remote_cells_with_tracers = new TupleList(); remote_cells_with_tracers->initialize(2, 0, 1, numTracers, n); // tracers are in these tuples remote_cells_with_tracers->enableWriteAccess(); for (int i=0; i<n; i++) { remote_cells_with_tracers->vi_wr[2*i]=remote_cells->vi_wr[2*i]; remote_cells_with_tracers->vi_wr[2*i+1]=remote_cells->vi_wr[2*i+1]; // remote_cells->vr_wr[i] = 0.; will have a different tuple for communication remote_cells_with_tracers->vul_wr[i]= remote_cells->vul_wr[i];// this is the corresponding red cell (arrival) for (int k=0; k<numTracers; k++) remote_cells_with_tracers->vr_wr[numTracers*i+k] = 0; // initialize tracers to be transported remote_cells_with_tracers->inc_n(); } } delete remote_cells; remote_cells = NULL; } #endif // for each polygon, we have 2 indices: red and blue parents // we need index blue to update index red? std::vector<double> newValues(rs2.size()*numTracers, 0.);// initialize with 0 all of them // area of the polygon * conc on red (old) current quantity // finally, divide by the area of the red double check_intx_area=0.; for (Range::iterator it= polys.begin(); it!=polys.end(); ++it) { EntityHandle poly=*it; int blueIndex, redIndex; rval = mb->tag_get_data(blueParentTag, &poly, 1, &blueIndex); ERRORR(rval, "can't get blue tag"); EntityHandle blue = rs1[blueIndex]; rval = mb->tag_get_data(redParentTag, &poly, 1, &redIndex); ERRORR(rval, "can't get red tag"); //EntityHandle red = rs2[redIndex]; // big assumption here, red and blue are "parallel" ;we should have an index from // blue to red (so a deformed blue corresponds to an arrival red) double areap = area_spherical_element(mb, poly, R); check_intx_area+=areap; // so the departure cell at time t (blueIndex) covers a portion of a redCell // that quantity will be transported to the redCell at time t+dt // the blue corresponds to a red arrival EntityHandle redArr; rval = mb->tag_get_data(corrTag, &blue, 1, &redArr); if (0==redArr || MB_TAG_NOT_FOUND==rval) { #ifdef MOAB_HAVE_MPI if (!remote_cells_with_tracers) ERRORR( MB_FAILURE, "no remote cells, failure\n"); // maybe the element is remote, from another processor int global_id_blue; rval = mb->tag_get_data(gid, &blue, 1, &global_id_blue); ERRORR(rval, "can't get arrival red for corresponding blue gid"); // find the int index_in_remote = remote_cells_with_tracers->find(1, global_id_blue); if (index_in_remote==-1) ERRORR( MB_FAILURE, "can't find the global id element in remote cells\n"); for (int k=0; k<numTracers; k++) remote_cells_with_tracers->vr_wr[index_in_remote*numTracers+k] += currentVals[numTracers*redIndex+k]*areap; #endif } else if (MB_SUCCESS==rval) { int arrRedIndex = rs2.index(redArr); if (-1 == arrRedIndex) ERRORR(MB_FAILURE, "can't find the red arrival index"); for (int k=0; k<numTracers; k++) newValues[numTracers*arrRedIndex+k] += currentVals[redIndex*numTracers+k]*areap; } else ERRORR(rval, "can't get arrival red for corresponding "); } // now, send back the remote_cells_with_tracers to the processors they came from, with the updated values for // the tracer mass in a cell #ifdef MOAB_HAVE_MPI if (remote_cells_with_tracers) { // so this means that some cells will be sent back with tracer info to the procs they were sent from (parcomm->proc_config().crystal_router())->gs_transfer(1, *remote_cells_with_tracers, 0); // now, look at the global id, find the proper "red" cell with that index and update its mass //remote_cells->print("remote cells after routing"); int n = remote_cells_with_tracers->get_n(); for (int j=0; j<n; j++) { EntityHandle redCell = remote_cells_with_tracers->vul_rd[j];// entity handle sent back int arrRedIndex = rs2.index(redCell); if (-1 == arrRedIndex) ERRORR(MB_FAILURE, "can't find the red arrival index"); for (int k=0; k<numTracers; k++) newValues[arrRedIndex*numTracers+k] += remote_cells_with_tracers->vr_rd[j*numTracers+k]; } } #endif /* MOAB_HAVE_MPI */ // now divide by red area (current) int j=0; Range::iterator iter = rs2.begin(); void * data=NULL; //used for stored area int count =0; std::vector<double> total_mass_local(numTracers, 0.); while (iter != rs2.end()) { rval = mb->tag_iterate(tagArea, iter, rs2.end(), count, data); ERRORR(rval, "can't tag iterate"); double * ptrArea=(double*)data; for (int i=0; i<count; i++, ++iter, j++, ptrArea++) { for (int k=0; k<numTracers; k++) { total_mass_local[k]+=newValues[j*numTracers+k]; newValues[j*numTracers+k]/= (*ptrArea); } } } rval = mb->tag_set_data(tagElem, rs2, &newValues[0]); ERRORR(rval, "can't set new values tag"); #ifdef MOAB_HAVE_MPI std::vector<double> total_mass(numTracers,0.); double total_intx_area =0; int mpi_err = MPI_Reduce(&total_mass_local[0], &total_mass[0], numTracers, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (MPI_SUCCESS != mpi_err) return MB_FAILURE; // now reduce total area mpi_err = MPI_Reduce(&check_intx_area, &total_intx_area, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (MPI_SUCCESS != mpi_err) return MB_FAILURE; if (my_rank==0) { for (int k=0; k<numTracers; k++) std::cout <<"total mass now tracer k=" << k+1<<" " << total_mass[k] << "\n"; std::cout <<"check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * R*R << " " << total_intx_area << "\n"; } if (remote_cells_with_tracers) { delete remote_cells_with_tracers; remote_cells_with_tracers=NULL; } #else for (int k=0; k<numTracers; k++) std::cout <<"total mass now tracer k=" << k+1<<" " << total_mass_local[k] << "\n"; std::cout <<"check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * R*R << " " << check_intx_area << "\n"; #endif return MB_SUCCESS; }