| Total Complexity | 41 |
| Total Lines | 317 |
| Duplicated Lines | 0 % |
Complex classes like sync_network often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | """! |
||
| 302 | class sync_network(network): |
||
| 303 | """! |
||
| 304 | @brief Model of oscillatory network that is based on the Kuramoto model of synchronization. |
||
| 305 | |||
| 306 | """ |
||
| 307 | |||
| 308 | # Protected members: |
||
| 309 | _name = 'Phase Sync Network' |
||
| 310 | _phases = None; # Current phases of oscillators. |
||
| 311 | _freq = None; # Own frequencies of oscillators. |
||
| 312 | _weight = 0; # Strength of connections between oscillators. |
||
| 313 | |||
| 314 | _ccore_network_pointer = None; # Pointer to CCORE Sync implementation of the network. |
||
| 315 | |||
| 316 | |||
| 317 | def __init__(self, num_osc, weight = 1, frequency = 0, type_conn = conn_type.ALL_TO_ALL, conn_represent = conn_represent.MATRIX, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore = False): |
||
| 318 | """! |
||
| 319 | @brief Constructor of oscillatory network is based on Kuramoto model. |
||
| 320 | |||
| 321 | @param[in] num_osc (uint): Number of oscillators in the network. |
||
| 322 | @param[in] weight (double): Coupling strength of the links between oscillators. |
||
| 323 | @param[in] frequency (double): Multiplier of internal frequency of the oscillators. |
||
| 324 | @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.). |
||
| 325 | @param[in] conn_represent (conn_represent): Internal representation of connection in the network: matrix or list. |
||
| 326 | @param[in] initial_phases (initial_type): Type of initialization of initial phases of oscillators (random, uniformly distributed, etc.). |
||
| 327 | @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering). |
||
| 328 | |||
| 329 | """ |
||
| 330 | |||
| 331 | if (ccore is True): |
||
| 332 | self._ccore_network_pointer = wrapper.sync_create_network(num_osc, weight, frequency, type_conn, initial_phases); |
||
| 333 | else: |
||
| 334 | super().__init__(num_osc, type_conn, conn_represent); |
||
| 335 | |||
| 336 | self._weight = weight; |
||
| 337 | |||
| 338 | self._phases = list(); |
||
| 339 | self._freq = list(); |
||
| 340 | |||
| 341 | for index in range(0, num_osc, 1): |
||
| 342 | if (initial_phases == initial_type.RANDOM_GAUSSIAN): |
||
| 343 | self._phases.append(random.random() * 2.0 * pi); |
||
| 344 | elif (initial_phases == initial_type.EQUIPARTITION): |
||
| 345 | self._phases.append( pi / num_osc * index); |
||
| 346 | |||
| 347 | self._freq.append(random.random() * frequency); |
||
| 348 | |||
| 349 | |||
| 350 | def __del__(self): |
||
| 351 | """! |
||
| 352 | @brief Destructor of oscillatory network is based on Kuramoto model. |
||
| 353 | |||
| 354 | """ |
||
| 355 | |||
| 356 | if (self._ccore_network_pointer is not None): |
||
| 357 | wrapper.sync_destroy_network(self._ccore_network_pointer); |
||
| 358 | self._ccore_network_pointer = None; |
||
| 359 | |||
| 360 | |||
| 361 | def sync_order(self): |
||
| 362 | """! |
||
| 363 | @brief Calculates level of global synchorization in the network. |
||
| 364 | |||
| 365 | @return (double) Level of global synchronization. |
||
| 366 | |||
| 367 | @see sync_local_order() |
||
| 368 | |||
| 369 | """ |
||
| 370 | |||
| 371 | if (self._ccore_network_pointer is not None): |
||
| 372 | return wrapper.sync_order(self._ccore_network_pointer); |
||
| 373 | |||
| 374 | exp_amount = 0; |
||
| 375 | average_phase = 0; |
||
| 376 | |||
| 377 | for index in range(0, self._num_osc, 1): |
||
| 378 | exp_amount += math.expm1( abs(1j * self._phases[index]) ); |
||
| 379 | average_phase += self._phases[index]; |
||
| 380 | |||
| 381 | exp_amount /= self._num_osc; |
||
| 382 | average_phase = math.expm1( abs(1j * (average_phase / self._num_osc)) ); |
||
| 383 | |||
| 384 | return abs(average_phase) / abs(exp_amount); |
||
| 385 | |||
| 386 | |||
| 387 | def sync_local_order(self): |
||
| 388 | """! |
||
| 389 | @brief Calculates level of local (partial) synchronization in the network. |
||
| 390 | |||
| 391 | @return (double) Level of local (partial) synchronization. |
||
| 392 | |||
| 393 | @see sync_order() |
||
| 394 | |||
| 395 | """ |
||
| 396 | |||
| 397 | if (self._ccore_network_pointer is not None): |
||
| 398 | return wrapper.sync_local_order(self._ccore_network_pointer); |
||
| 399 | |||
| 400 | exp_amount = 0.0; |
||
| 401 | num_neigh = 0; |
||
| 402 | |||
| 403 | for i in range(0, self._num_osc, 1): |
||
| 404 | for j in range(0, self._num_osc, 1): |
||
| 405 | if (self.has_connection(i, j) == True): |
||
| 406 | exp_amount += math.exp(-abs(self._phases[j] - self._phases[i])); |
||
| 407 | num_neigh += 1; |
||
| 408 | |||
| 409 | if (num_neigh == 0): |
||
| 410 | num_neigh = 1; |
||
| 411 | |||
| 412 | return exp_amount / num_neigh; |
||
| 413 | |||
| 414 | |||
| 415 | def _phase_kuramoto(self, teta, t, argv): |
||
| 416 | """! |
||
| 417 | @brief Returns result of phase calculation for specified oscillator in the network. |
||
| 418 | |||
| 419 | @param[in] teta (double): Phase of the oscillator that is differentiated. |
||
| 420 | @param[in] t (double): Current time of simulation. |
||
| 421 | @param[in] argv (tuple): Index of the oscillator in the list. |
||
| 422 | |||
| 423 | @return (double) New phase for specified oscillator (don't assign here). |
||
| 424 | |||
| 425 | """ |
||
| 426 | |||
| 427 | index = argv; |
||
| 428 | phase = 0; |
||
| 429 | for k in range(0, self._num_osc): |
||
| 430 | if (self.has_connection(index, k) == True): |
||
| 431 | phase += math.sin(self._phases[k] - teta); |
||
| 432 | |||
| 433 | return ( self._freq[index] + (phase * self._weight / self._num_osc) ); |
||
| 434 | |||
| 435 | |||
| 436 | def simulate(self, steps, time, solution = solve_type.FAST, collect_dynamic = True): |
||
| 437 | """! |
||
| 438 | @brief Performs static simulation of Sync oscillatory network. |
||
| 439 | |||
| 440 | @param[in] steps (uint): Number steps of simulations during simulation. |
||
| 441 | @param[in] time (double): Time of simulation. |
||
| 442 | @param[in] solution (solve_type): Type of solution (solving). |
||
| 443 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 444 | |||
| 445 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 446 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 447 | |||
| 448 | @see simulate_dynamic() |
||
| 449 | @see simulate_static() |
||
| 450 | |||
| 451 | """ |
||
| 452 | |||
| 453 | return self.simulate_static(steps, time, solution, collect_dynamic); |
||
| 454 | |||
| 455 | |||
| 456 | def simulate_dynamic(self, order = 0.998, solution = solve_type.FAST, collect_dynamic = False, step = 0.1, int_step = 0.01, threshold_changes = 0.0000001): |
||
| 457 | """! |
||
| 458 | @brief Performs dynamic simulation of the network until stop condition is not reached. Stop condition is defined by input argument 'order'. |
||
| 459 | |||
| 460 | @param[in] order (double): Order of process synchronization, distributed 0..1. |
||
| 461 | @param[in] solution (solve_type): Type of solution. |
||
| 462 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 463 | @param[in] step (double): Time step of one iteration of simulation. |
||
| 464 | @param[in] int_step (double): Integration step, should be less than step. |
||
| 465 | @param[in] threshold_changes (double): Additional stop condition that helps prevent infinite simulation, defines limit of changes of oscillators between current and previous steps. |
||
| 466 | |||
| 467 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 468 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 469 | |||
| 470 | @see simulate() |
||
| 471 | @see simulate_static() |
||
| 472 | |||
| 473 | """ |
||
| 474 | |||
| 475 | if (self._ccore_network_pointer is not None): |
||
| 476 | ccore_instance_dynamic = wrapper.sync_simulate_dynamic(self._ccore_network_pointer, order, solution, collect_dynamic, step, int_step, threshold_changes); |
||
| 477 | return sync_dynamic(None, None, ccore_instance_dynamic); |
||
| 478 | |||
| 479 | # For statistics and integration |
||
| 480 | time_counter = 0; |
||
| 481 | |||
| 482 | # Prevent infinite loop. It's possible when required state cannot be reached. |
||
| 483 | previous_order = 0; |
||
| 484 | current_order = self.sync_local_order(); |
||
| 485 | |||
| 486 | # If requested input dynamics |
||
| 487 | dyn_phase = []; |
||
| 488 | dyn_time = []; |
||
| 489 | if (collect_dynamic == True): |
||
| 490 | dyn_phase.append(self._phases); |
||
| 491 | dyn_time.append(0); |
||
| 492 | |||
| 493 | # Execute until sync state will be reached |
||
| 494 | while (current_order < order): |
||
| 495 | # update states of oscillators |
||
| 496 | self._phases = self._calculate_phases(solution, time_counter, step, int_step); |
||
| 497 | |||
| 498 | # update time |
||
| 499 | time_counter += step; |
||
| 500 | |||
| 501 | # if requested input dynamic |
||
| 502 | if (collect_dynamic == True): |
||
| 503 | dyn_phase.append(self._phases); |
||
| 504 | dyn_time.append(time_counter); |
||
| 505 | |||
| 506 | # update orders |
||
| 507 | previous_order = current_order; |
||
| 508 | current_order = self.sync_local_order(); |
||
| 509 | |||
| 510 | # hang prevention |
||
| 511 | if (abs(current_order - previous_order) < threshold_changes): |
||
| 512 | # print("Warning: sync_network::simulate_dynamic - simulation is aborted due to low level of convergence rate (order = " + str(current_order) + ").");
|
||
| 513 | break; |
||
| 514 | |||
| 515 | if (collect_dynamic != True): |
||
| 516 | dyn_phase.append(self._phases); |
||
| 517 | dyn_time.append(time_counter); |
||
| 518 | |||
| 519 | output_sync_dynamic = sync_dynamic(dyn_phase, dyn_time, None); |
||
| 520 | return output_sync_dynamic; |
||
| 521 | |||
| 522 | |||
| 523 | def simulate_static(self, steps, time, solution = solve_type.FAST, collect_dynamic = False): |
||
| 524 | """! |
||
| 525 | @brief Performs static simulation of oscillatory network. |
||
| 526 | |||
| 527 | @param[in] steps (uint): Number steps of simulations during simulation. |
||
| 528 | @param[in] time (double): Time of simulation. |
||
| 529 | @param[in] solution (solve_type): Type of solution. |
||
| 530 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 531 | |||
| 532 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 533 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 534 | |||
| 535 | @see simulate() |
||
| 536 | @see simulate_dynamic() |
||
| 537 | |||
| 538 | """ |
||
| 539 | |||
| 540 | if (self._ccore_network_pointer is not None): |
||
| 541 | ccore_instance_dynamic = wrapper.sync_simulate_static(self._ccore_network_pointer, steps, time, solution, collect_dynamic); |
||
| 542 | return sync_dynamic(None, None, ccore_instance_dynamic); |
||
| 543 | |||
| 544 | dyn_phase = []; |
||
| 545 | dyn_time = []; |
||
| 546 | |||
| 547 | if (collect_dynamic == True): |
||
| 548 | dyn_phase.append(self._phases); |
||
| 549 | dyn_time.append(0); |
||
| 550 | |||
| 551 | step = time / steps; |
||
| 552 | int_step = step / 10.0; |
||
| 553 | |||
| 554 | for t in numpy.arange(step, time + step, step): |
||
| 555 | # update states of oscillators |
||
| 556 | self._phases = self._calculate_phases(solution, t, step, int_step); |
||
| 557 | |||
| 558 | # update states of oscillators |
||
| 559 | if (collect_dynamic == True): |
||
| 560 | dyn_phase.append(self._phases); |
||
| 561 | dyn_time.append(t); |
||
| 562 | |||
| 563 | if (collect_dynamic != True): |
||
| 564 | dyn_phase.append(self._phases); |
||
| 565 | dyn_time.append(t); |
||
| 566 | |||
| 567 | output_sync_dynamic = sync_dynamic(dyn_phase, dyn_time); |
||
| 568 | return output_sync_dynamic; |
||
| 569 | |||
| 570 | |||
| 571 | def _calculate_phases(self, solution, t, step, int_step): |
||
| 572 | """! |
||
| 573 | @brief Calculates new phases for oscillators in the network in line with current step. |
||
| 574 | |||
| 575 | @param[in] solution (solve_type): Type solver of the differential equation. |
||
| 576 | @param[in] t (double): Time of simulation. |
||
| 577 | @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated. |
||
| 578 | @param[in] int_step (double): Step differentiation that is used for solving differential equation. |
||
| 579 | |||
| 580 | @return (list) New states (phases) for oscillators. |
||
| 581 | |||
| 582 | """ |
||
| 583 | |||
| 584 | next_phases = [0] * self._num_osc; # new oscillator _phases |
||
| 585 | |||
| 586 | for index in range (0, self._num_osc, 1): |
||
| 587 | if (solution == solve_type.FAST): |
||
| 588 | result = self._phases[index] + self._phase_kuramoto(self._phases[index], 0, index); |
||
| 589 | next_phases[index] = self._phase_normalization(result); |
||
| 590 | |||
| 591 | elif (solution == solve_type.RK4): |
||
| 592 | result = odeint(self._phase_kuramoto, self._phases[index], numpy.arange(t - step, t, int_step), (index , )); |
||
| 593 | next_phases[index] = self._phase_normalization(result[len(result) - 1][0]); |
||
| 594 | |||
| 595 | else: |
||
| 596 | raise NameError("Solver '" + solution + "' is not supported");
|
||
| 597 | |||
| 598 | return next_phases; |
||
| 599 | |||
| 600 | |||
| 601 | def _phase_normalization(self, teta): |
||
| 602 | """! |
||
| 603 | @brief Normalization of phase of oscillator that should be placed between [0; 2 * pi]. |
||
| 604 | |||
| 605 | @param[in] teta (double): phase of oscillator. |
||
| 606 | |||
| 607 | @return (double) Normalized phase. |
||
| 608 | |||
| 609 | """ |
||
| 610 | |||
| 611 | norm_teta = teta; |
||
| 612 | while (norm_teta > (2.0 * pi)) or (norm_teta < 0): |
||
| 613 | if (norm_teta > (2.0 * pi)): |
||
| 614 | norm_teta -= 2.0 * pi; |
||
| 615 | else: |
||
| 616 | norm_teta += 2.0 * pi; |
||
| 617 | |||
| 618 | return norm_teta; |
||
| 619 |
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.pyfiles in your module folders. Make sure that you place one file in each sub-folder.