Exemple #1
0
    def test_amqp_sanity(self):
        """We can talk to ourselves from Python using RabbitMQ"""
        conn, ch, qname = self.setup_queue()

        # now there is a queue, send a test message
        sender = java.AMQPConnection()
        sender.setHost(config.get("amqp", "host"))
        sender.setPort(int(config.get("amqp", "port")))
        sender.setUsername(config.get("amqp", "user"))
        sender.setPassword(config.get("amqp", "password"))
        sender.setVirtualHost(config.get("amqp", "vhost"))
        sender.publish('oq-unittest.topic', 'oq-unittest-log.FOO', 0, 'WARN',
                       'Hi there')
        sender.close()

        # process the messaages
        messages = []

        def consume(msg):
            messages.append(msg)
            ch.basic_cancel(msg.consumer_tag)

        self.consume_messages(conn, ch, qname, consume)

        self.assertEquals(1, len(messages))
        self.assertEquals('Hi there', messages[0].body)
Exemple #2
0
def compute_uhs(the_job, site):
    """Given a `JobContext` and a site of interest, compute UHS. The Java
    `UHSCalculator` is called to do perform the core computation.

    :param the_job:
        :class:`openquake.engine.JobContext` instance.
    :param site:
        :class:`openquake.shapes.Site` instance.
    :returns:
        An `ArrayList` (Java object) of `UHSResult` objects, one per PoE.
    """

    periods = list_to_jdouble_array(the_job["UHS_PERIODS"])
    poes = list_to_jdouble_array(the_job["POES"])
    imls = get_iml_list(the_job["INTENSITY_MEASURE_LEVELS"], the_job["INTENSITY_MEASURE_TYPE"])
    max_distance = the_job["MAXIMUM_DISTANCE"]

    cache = java.jclass("KVS")(config.get("kvs", "host"), int(config.get("kvs", "port")))

    erf = generate_erf(the_job.job_id, cache)
    gmpe_map = generate_gmpe_map(the_job.job_id, cache)
    set_gmpe_params(gmpe_map, the_job.params)

    uhs_calc = java.jclass("UHSCalculator")(periods, poes, imls, erf, gmpe_map, max_distance)

    uhs_results = uhs_calc.computeUHS(
        site.latitude,
        site.longitude,
        the_job["VS30_TYPE"],
        the_job["REFERENCE_VS30_VALUE"],
        the_job["DEPTHTO1PT0KMPERSEC"],
        the_job["REFERENCE_DEPTH_TO_2PT5KM_PER_SEC_PARAM"],
    )

    return uhs_results
Exemple #3
0
    def execute(self):
        """
        Calculation work is parallelized over sources, which means that each
        task will compute hazard for all sites but only with a subset of the
        seismic sources defined in the input model.

        The general workflow is as follows:

        1. Fill the queue with an initial set of tasks. The number of initial
        tasks is configurable using the `concurrent_tasks` parameter in the
        `[hazard]` section of the OpenQuake config file.

        2. Wait for tasks to signal completion (via AMQP message) and enqueue a
        new task each time another completes. Once all of the job work is
        enqueued, we just wait until all of the tasks conclude.
        """
        block_size = int(config.get('hazard', 'block_size'))
        concurrent_tasks = int(config.get('hazard', 'concurrent_tasks'))

        self.progress = dict(total=0, computed=0)
        # The following two counters are in a dict so that we can use them in
        # the closures below.
        # When `self.progress['compute']` becomes equal to
        # `self.progress['total']`, # `execute` can conclude.

        task_gen = self.task_arg_gen(block_size)

        exchange, conn_args = exchange_and_conn_args()

        routing_key = ROUTING_KEY_FMT % dict(job_id=self.job.id)
        task_signal_queue = kombu.Queue(
            'htasks.job.%s' % self.job.id, exchange=exchange,
            routing_key=routing_key, durable=False, auto_delete=True)

        with kombu.BrokerConnection(**conn_args) as conn:
            task_signal_queue(conn.channel()).declare()
            with conn.Consumer(
                task_signal_queue,
                callbacks=[self.get_task_complete_callback(task_gen)]):

                # First: Queue up the initial tasks.
                for _ in xrange(concurrent_tasks):
                    try:
                        self.core_calc_task.apply_async(task_gen.next())
                    except StopIteration:
                        # If we get a `StopIteration` here, that means we have
                        # a number of tasks < concurrent_tasks.
                        # This basically just means that we could be
                        # under-utilizing worker node resources.
                        break

                while (self.progress['computed'] < self.progress['total']):
                    # This blocks until a message is received.
                    # Once we receive a completion signal, enqueue the next
                    # piece of work (if there's anything left to be done).
                    # (The `task_complete_callback` will handle additional
                    # queuing.)
                    conn.drain_events()
        logs.log_progress("hazard calculation 100% complete", 2)
Exemple #4
0
 def connect(self, *args, **kwargs):
     host = config.get("kvs", "host")
     port = config.get("kvs", "port")
     port = int(port) if port else 6379
     stats_db = config.get("kvs", "stats_db")
     stats_db = int(stats_db) if stats_db else 15
     args = {"host": host, "port": port, "db": stats_db}
     return redis.Redis(**args)
Exemple #5
0
 def connect(self, *args, **kwargs):
     host = config.get("kvs", "host")
     port = config.get("kvs", "port")
     port = int(port) if port else 6379
     stats_db = config.get("kvs", "stats_db")
     stats_db = int(stats_db) if stats_db else 15
     args = {"host": host, "port": port, "db": stats_db}
     return redis.Redis(**args)
Exemple #6
0
    def __init__(self, host=config.get("kvs", "host"),
                       port=int(config.get("kvs", "port")),
                       **kwargs):
        if not self.__dict__:
            args = {"host": host,
                    "port": port,
                    "db": kwargs.get('db', 0)}

            self.conn = redis.Redis(**args)
Exemple #7
0
def _redis():
    """Return a connection to the redis store."""
    host = config.get("kvs", "host")
    port = config.get("kvs", "port")
    port = int(port) if port else 6379
    stats_db = config.get("kvs", "stats_db")
    stats_db = int(stats_db) if stats_db else 15
    args = {"host": host, "port": port, "db": stats_db}
    return redis.Redis(**args)
Exemple #8
0
def _redis():
    """Return a connection to the redis store."""
    host = config.get("kvs", "host")
    port = config.get("kvs", "port")
    port = int(port) if port else 6379
    stats_db = config.get("kvs", "stats_db")
    stats_db = int(stats_db) if stats_db else DEFAULT_STATS_DB
    args = {"host": host, "port": port, "db": stats_db}
    return redis.Redis(**args)
Exemple #9
0
def compute_disagg_matrix(job_id, site, poe, result_dir):
    """ Compute a complete 5D Disaggregation matrix. This task leans heavily
    on the DisaggregationCalculator (in the OpenQuake Java lib) to handle this
    computation.

    The 5D matrix returned from the java calculator will be saved to a file in
    HDF5 format.

    :param job_id: id of the job record in the KVS
    :type job_id: `str`
    :param site: a single site of interest
    :type site: :class:`openquake.shapes.Site` instance`
    :param poe: Probability of Exceedence
    :type poe: `float`
    :param result_dir: location for the Java code to write the matrix in an
        HDF5 file (in a distributed environment, this should be the path of a
        mounted NFS)

    :returns: 2-tuple of (ground_motion_value, path_to_h5_matrix_file)
    """
    the_job = job.Job.from_kvs(job_id)

    lat_bin_lims = the_job[job_cfg.LAT_BIN_LIMITS]
    lon_bin_lims = the_job[job_cfg.LON_BIN_LIMITS]
    mag_bin_lims = the_job[job_cfg.MAG_BIN_LIMITS]
    eps_bin_lims = the_job[job_cfg.EPS_BIN_LIMITS]

    jd = list_to_jdouble_array

    disagg_calc = java.jclass('DisaggregationCalculator')(
        jd(lat_bin_lims), jd(lon_bin_lims),
        jd(mag_bin_lims), jd(eps_bin_lims))

    cache = java.jclass('KVS')(
        config.get('kvs', 'host'),
        int(config.get('kvs', 'port')))

    erf = generate_erf(job_id, cache)
    gmpe_map = generate_gmpe_map(job_id, cache)
    set_gmpe_params(gmpe_map, the_job.params)

    imls = get_iml_list(the_job['INTENSITY_MEASURE_LEVELS'],
                        the_job['INTENSITY_MEASURE_TYPE'])
    vs30_type = the_job['VS30_TYPE']
    vs30_value = the_job['REFERENCE_VS30_VALUE']
    depth_to_1pt0 = the_job['DEPTHTO1PT0KMPERSEC']
    depth_to_2pt5 = the_job['REFERENCE_DEPTH_TO_2PT5KM_PER_SEC_PARAM']

    matrix_result = disagg_calc.computeMatrix(
        site.latitude, site.longitude, erf, gmpe_map, poe, imls,
        vs30_type, vs30_value, depth_to_1pt0, depth_to_2pt5)

    matrix_path = save_5d_matrix_to_h5(result_dir,
                                       numpy.array(matrix_result.getMatrix()))

    return (matrix_result.getGMV(), matrix_path)
Exemple #10
0
 def preloader(self, *args, **kwargs):
     """Validate job"""
     self.cache = java.jclass("KVS")(
             config.get("kvs", "host"),
             int(config.get("kvs", "port")))
     self.calc = java.jclass("LogicTreeProcessor")(
             self.cache, self.key)
     java.jvm().java.lang.System.setProperty("openquake.nrml.schema",
                                             xml.nrml_schema_file())
     return fn(self, *args, **kwargs)
Exemple #11
0
    def decorated(self, *args, **kwargs):  # pylint: disable=C0111
        kvs_data = (config.get("kvs", "host"), int(config.get("kvs", "port")))

        if kvs.cache_connections():
            key = hashlib.md5(repr(kvs_data)).hexdigest()
            if key not in __KVS_CONN_CACHE:
                __KVS_CONN_CACHE[key] = java.jclass("KVS")(*kvs_data)
            self.cache = __KVS_CONN_CACHE[key]
        else:
            self.cache = java.jclass("KVS")(*kvs_data)

        return fn(self, *args, **kwargs)
Exemple #12
0
    def decorated(self, *args, **kwargs):  # pylint: disable=C0111
        kvs_data = (config.get("kvs", "host"), int(config.get("kvs", "port")))

        if kvs.cache_connections():
            key = hashlib.md5(repr(kvs_data)).hexdigest()
            if key not in __KVS_CONN_CACHE:
                __KVS_CONN_CACHE[key] = java.jclass("KVS")(*kvs_data)
            self.cache = __KVS_CONN_CACHE[key]
        else:
            self.cache = java.jclass("KVS")(*kvs_data)

        return fn(self, *args, **kwargs)
Exemple #13
0
    def setUp(self):
        self.amqp = logs.AMQPHandler(
            host=config.get("amqp", "host"),
            username=config.get("amqp", "user"),
            password=config.get("amqp", "password"),
            virtual_host=config.get("amqp", "vhost"),
            exchange='oq-unittest.topic',
            routing_key='oq-unittest-log.%(levelname)s',
            level=logging.DEBUG)

        self.log = logging.getLogger('tests.PythonAMQPLogTestCase')
        self.log.setLevel(logging.DEBUG)
        self.log.addHandler(self.amqp)
Exemple #14
0
    def setup_queue(self):
        # connect to localhost and bind to a queue
        conn = amqp.Connection(host=config.get("amqp", "host"),
                               userid=config.get("amqp", "user"),
                               password=config.get("amqp", "password"),
                               virtual_host=config.get("amqp", "vhost"))
        ch = conn.channel()
        ch.access_request(config.get("amqp", "vhost"), active=False, read=True)
        ch.exchange_declare(self.TOPIC, 'topic', auto_delete=True)
        qname, _, _ = ch.queue_declare()
        ch.queue_bind(qname, self.TOPIC, routing_key=self.ROUTING_KEY)

        return conn, ch, qname
Exemple #15
0
    def setUp(self):
        # starting the jvm...
        print "About to start the jvm..."
        jpype = java.jvm()
        java_class = jpype.JClass("org.gem.engine.hazard.redis.Cache")
        print "Not dead yet, and found the class..."
        self.java_client = java_class(config.get("kvs", "host"),
                                      int(config.get("kvs", "port")))

        self.python_client = kvs.get_client()
        self.python_client.flushdb()

        self._delete_test_file()
    def setUp(self):
        # starting the jvm...
        print "About to start the jvm..."
        jpype = java.jvm()
        java_class = jpype.JClass("org.gem.engine.hazard.redis.Cache")
        print "Not dead yet, and found the class..."
        self.java_client = java_class(
            config.get("kvs", "host"), int(config.get("kvs", "port")))

        self.python_client = kvs.get_client()
        self.python_client.flushdb()

        self._delete_test_file()
Exemple #17
0
def compute_uhs(the_job, site):
    """Given a `JobContext` and a site of interest, compute UHS. The Java
    `UHSCalculator` is called to do perform the core computation.

    :param the_job:
        :class:`openquake.engine.JobContext` instance.
    :param site:
        :class:`openquake.shapes.Site` instance.
    :returns:
        An `ArrayList` (Java object) of `UHSResult` objects, one per PoE.
    """

    periods = list_to_jdouble_array(the_job['UHS_PERIODS'])
    poes = list_to_jdouble_array(the_job['POES'])
    imls = general.get_iml_list(the_job['INTENSITY_MEASURE_LEVELS'],
                                the_job['INTENSITY_MEASURE_TYPE'])
    max_distance = the_job['MAXIMUM_DISTANCE']

    cache = java.jclass('KVS')(
        config.get('kvs', 'host'),
        int(config.get('kvs', 'port')))

    erf = general.generate_erf(the_job.job_id, cache)
    gmpe_map = general.generate_gmpe_map(the_job.job_id, cache)
    general.set_gmpe_params(gmpe_map, the_job.params)

    uhs_calc = java.jclass('UHSCalculator')(periods, poes, imls, erf, gmpe_map,
                                            max_distance)

    site_model = general.get_site_model(the_job.oq_job.id)

    if site_model is not None:
        sm_data = general.get_closest_site_model_data(site_model, site)
        vs30_type = sm_data.vs30_type.capitalize()
        vs30 = sm_data.vs30
        z1pt0 = sm_data.z1pt0
        z2pt5 = sm_data.z2pt5
    else:
        jp = the_job.oq_job_profile

        vs30_type = jp.vs30_type.capitalize()
        vs30 = jp.reference_vs30_value
        z1pt0 = jp.depth_to_1pt_0km_per_sec
        z2pt5 = jp.reference_depth_to_2pt5km_per_sec_param

    uhs_results = _compute_uhs(
        uhs_calc, site.latitude, site.longitude, vs30_type, vs30, z1pt0, z2pt5
    )

    return uhs_results
Exemple #18
0
    def execute(self):
        """Main execution point for the Disaggregation calculator.

        The workflow is structured like so:
        1) Store source and GMPE models in the KVS (so the workers can rapidly
            access that data).
        2) Create a result dir (on the NFS) for storing matrices.
        3) Distribute full disaggregation matrix computation to workers.
        4) Distribute matrix subset extraction (using full disagg. results as
            input.
        5) Finally, write an NRML/XML wrapper around the disagg. results.
        """
        # matrix results for this job will go here:
        result_dir = DisaggHazardCalculator.create_result_dir(
            config.get('nfs', 'base_dir'), self.job_ctxt.job_id)

        realizations = self.job_ctxt['NUMBER_OF_LOGIC_TREE_SAMPLES']
        poes = self.job_ctxt['POES']
        sites = self.job_ctxt.sites_to_compute()

        log_msg = ("Computing disaggregation for job_id=%s,  %s sites, "
                   "%s realizations, and PoEs=%s")
        log_msg %= (self.job_ctxt.job_id, len(sites), realizations, poes)
        LOG.info(log_msg)

        full_disagg_results = self.distribute_disagg(sites, realizations, poes,
                                                     result_dir)

        subset_types = self.job_ctxt['DISAGGREGATION_RESULTS']

        subset_results = self.distribute_subsets(full_disagg_results,
                                                 subset_types, result_dir)

        DisaggHazardCalculator.serialize_nrml(self.job_ctxt, subset_types,
                                              subset_results)
Exemple #19
0
 def test_get_with_empty_section_data(self):
     """config.get() returns `None` if the section data dict is empty."""
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict()
         self.assertTrue(config.get("whatever", "key") is None)
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("whatever", ), {}], mock.call_args)
Exemple #20
0
    def execute(self):
        """Main execution point for the Disaggregation calculator.

        The workflow is structured like so:
        1) Store source and GMPE models in the KVS (so the workers can rapidly
            access that data).
        2) Create a result dir (on the NFS) for storing matrices.
        3) Distribute full disaggregation matrix computation to workers.
        4) Distribute matrix subset extraction (using full disagg. results as
            input.
        5) Finally, write an NRML/XML wrapper around the disagg. results.
        """
        # matrix results for this job will go here:
        result_dir = DisaggHazardCalculator.create_result_dir(
            config.get('nfs', 'base_dir'), self.calc_proxy.job_id)

        realizations = self.calc_proxy['NUMBER_OF_LOGIC_TREE_SAMPLES']
        poes = self.calc_proxy['POES']
        sites = self.calc_proxy.sites_to_compute()

        log_msg = ("Computing disaggregation for job_id=%s,  %s sites, "
            "%s realizations, and PoEs=%s")
        log_msg %= (self.calc_proxy.job_id, len(sites), realizations, poes)
        LOG.info(log_msg)

        full_disagg_results = self.distribute_disagg(sites, realizations, poes,
                                                     result_dir)

        subset_types = self.calc_proxy['DISAGGREGATION_RESULTS']

        subset_results = self.distribute_subsets(full_disagg_results,
                                                 subset_types, result_dir)

        DisaggHazardCalculator.serialize_nrml(self.calc_proxy, subset_types,
                                              subset_results)
Exemple #21
0
 def test_get_with_empty_section_data(self):
     """config.get() returns `None` if the section data dict is empty."""
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict()
         self.assertTrue(config.get("whatever", "key") is None)
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("whatever",), {}], mock.call_args)
Exemple #22
0
 def test_get_with_unknown_key(self):
     """config.get() returns `None` if the `key` is not known."""
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict(b=1)
         self.assertTrue(config.get("arghh", "c") is None)
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("arghh",), {}], mock.call_args)
Exemple #23
0
    def record_init_stats(self):
        """
        Record some basic job stats, including the number of sites,
        realizations (end branches), and total number of tasks for the job.

        This should be run between the `pre-execute` and `execute` phases, once
        the job has been fully initialized.
        """
        # Record num sites, num realizations, and num tasks.
        num_sites = len(self.hc.points_to_compute())
        realizations = models.LtRealization.objects.filter(
            hazard_calculation=self.hc.id)
        num_rlzs = realizations.count()

        # Compute the number of tasks.
        block_size = int(config.get('hazard', 'block_size'))
        num_tasks = 0
        for lt_rlz in realizations:
            # Each realization has the potential to choose a random source
            # model, and thus there may be a variable number of tasks for each
            # realization (depending on the number of the sources in the model
            # which was chosen for the realization).
            num_sources = models.SourceProgress.objects.filter(
                lt_realization=lt_rlz).count()
            num_tasks += math.ceil(float(num_sources) / block_size)

        models.JobStats.objects.filter(oq_job=self.job.id).update(
            num_sites=num_sites, num_tasks=num_tasks,
            num_realizations=num_rlzs)
Exemple #24
0
 def test_get_with_unknown_key(self):
     """config.get() returns `None` if the `key` is not known."""
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict(b=1)
         self.assertTrue(config.get("arghh", "c") is None)
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("arghh", ), {}], mock.call_args)
Exemple #25
0
 def test_get_with_nonempty_section_data_and_known_key(self):
     """
     config.get() correctly returns the configuration datum for known
     sections/keys.
     """
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict(a=11)
         self.assertEqual(11, config.get("hmmm", "a"))
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("hmmm", ), {}], mock.call_args)
Exemple #26
0
    def from_kvs(job_id):
        """Return the job in the underlying kvs system with the given id."""

        logs.init_logs(
            level=FLAGS.debug, log_type=oq_config.get("logging", "backend"))

        params = kvs.get_value_json_decoded(
            kvs.tokens.generate_job_key(job_id))
        job = Job(params, job_id)
        return job
Exemple #27
0
 def test_get_with_nonempty_section_data_and_known_key(self):
     """
     config.get() correctly returns the configuration datum for known
     sections/keys.
     """
     with patch('openquake.utils.config.get_section') as mock:
         mock.return_value = dict(a=11)
         self.assertEqual(11, config.get("hmmm", "a"))
         self.assertEqual(1, mock.call_count)
         self.assertEqual([("hmmm",), {}], mock.call_args)
Exemple #28
0
    def setUp(self):
        jvm = java.jvm()

        props = jvm.JClass("java.util.Properties")()
        props.setProperty('log4j.rootLogger', 'DEBUG, rabbit')

        for key, value in [
            ('', 'org.gem.log.AMQPAppender'),
            ('.host', config.get("amqp", "host")),
            ('.port', config.get("amqp", "port")),
            ('.username', config.get("amqp", "user")),
            ('.password', config.get("amqp", "password")),
            ('.virtualHost', config.get("amqp", "vhost")),
            ('.routingKeyPattern', 'oq-unittest-log.%p'),
            ('.exchange', 'oq-unittest.topic'),
            ('.layout', 'org.apache.log4j.PatternLayout'),
            ('.layout.ConversionPattern', '%p - %m')]:
            props.setProperty('log4j.appender.rabbit' + key, value)

        jvm.JClass("org.apache.log4j.BasicConfigurator").resetConfiguration()
        jvm.JClass("org.apache.log4j.PropertyConfigurator").configure(props)
Exemple #29
0
def compute_uhs(the_job, site):
    """Given a `CalculationProxy` and a site of interest, compute UHS. The Java
    `UHSCalculator` is called to do perform the core computation.

    :param the_job:
        :class:`openquake.engine.CalculationProxy` instance.
    :param site:
        :class:`openquake.shapes.Site` instance.
    :returns:
        An `ArrayList` (Java object) of `UHSResult` objects, one per PoE.
    """

    periods = list_to_jdouble_array(the_job['UHS_PERIODS'])
    poes = list_to_jdouble_array(the_job['POES'])
    imls = get_iml_list(the_job['INTENSITY_MEASURE_LEVELS'],
                        the_job['INTENSITY_MEASURE_TYPE'])
    max_distance = the_job['MAXIMUM_DISTANCE']

    cache = java.jclass('KVS')(
        config.get('kvs', 'host'),
        int(config.get('kvs', 'port')))

    erf = generate_erf(the_job.job_id, cache)
    gmpe_map = generate_gmpe_map(the_job.job_id, cache)
    set_gmpe_params(gmpe_map, the_job.params)

    uhs_calc = java.jclass('UHSCalculator')(periods, poes, imls, erf, gmpe_map,
                                            max_distance)

    uhs_results = uhs_calc.computeUHS(
        site.latitude,
        site.longitude,
        the_job['VS30_TYPE'],
        the_job['REFERENCE_VS30_VALUE'],
        the_job['DEPTHTO1PT0KMPERSEC'],
        the_job['REFERENCE_DEPTH_TO_2PT5KM_PER_SEC_PARAM'])

    return uhs_results
Exemple #30
0
def spawn_job_supervisor(job_id, pid):
    """
    Spawn a supervisor process as configured in openquake.cfg.

    :param int job_id: the id of the job to be supervised
    :param int pid: the process id of the job to be supervised
    :return: the id of the supervisor process or None if no supervisor was
             configured
    :rtype: int or None
    """
    exe = oq_config.get('supervisor', 'exe')

    if exe:
        if oq_config.get('logging', 'backend') != 'amqp':
            LOG.warn('If you want to run supervised jobs it\'s better '
                     'to set [logging] backend=amqp in openquake.cfg')

        if not os.path.isabs(exe):
            exe = os.path.join(OPENQUAKE_ROOT, exe)

        cmd = [exe, str(job_id), str(pid)]

        supervisor_pid = subprocess.Popen(cmd, env=os.environ).pid

        job = OqJob.objects.get(id=job_id)
        job.supervisor_pid = supervisor_pid
        job.job_pid = pid
        job.save()

        # Ensure the supervisor amqp queue exists
        supervisor.bind_supervisor_queue(job_id)

        return supervisor_pid
    else:
        LOG.warn('This job won\'t be supervised, '
                 'because no supervisor is configured in openquake.cfg')
Exemple #31
0
def get_client(**kwargs):
    """
    Return a redis kvs client connection for general OpenQuake engine
    calculation usage..

    PLEASE NOTE: The 'db' argument is automatically read from the openquake.cfg
    and set. If specified in ``kwargs``, it will be overridden with the setting
    in openquake.cfg.
    """
    global __KVS_CONN_POOL
    if __KVS_CONN_POOL is None:
        cfg = config.get_section("kvs")
        # get the default db from the openquake.cfg:
        db = int(config.get('kvs', 'redis_db'))
        __KVS_CONN_POOL = redis.ConnectionPool(
            max_connections=1, host=cfg["host"], port=int(cfg["port"]), db=db)
    kwargs.update({"connection_pool": __KVS_CONN_POOL})
    return redis.Redis(**kwargs)
Exemple #32
0
def jvm():
    """Return the jpype module, after guaranteeing the JVM is running and
    the classpath has been loaded properly."""
    jarpaths = (os.path.abspath(
                    os.path.join(os.path.dirname(__file__), "../dist")),
                '/usr/share/java')

    if not jpype.isJVMStarted():
        jpype.startJVM(jpype.getDefaultJVMPath(),
            "-Djava.ext.dirs=%s:%s" % jarpaths,
            # force the default Xerces parser configuration, otherwise
            # some random system-installed JAR might override it
            "-Dorg.apache.xerces.xni.parser.XMLParserConfiguration=" \
                "org.apache.xerces.parsers.XIncludeAwareParserConfiguration")

        init_logs(level=FLAGS.debug, log_type=config.get("logging", "backend"))

    return jpype
Exemple #33
0
def do_hazard_map_post_process(job):
    """
    Create and distribute tasks for processing hazard curves into hazard maps.

    :param job:
        A :class:`openquake.db.models.OqJob` which has some hazard curves
        associated with it.
    """
    logs.LOG.debug('> Post-processing - Hazard Maps')
    block_size = int(config.get('hazard', 'concurrent_tasks'))

    poes = job.hazard_calculation.poes_hazard_maps

    # Stats for debug logging:
    hazard_curve_ids = models.HazardCurve.objects.filter(
        output__oq_job=job).values_list('id', flat=True)
    logs.LOG.debug('num haz curves: %s' % len(hazard_curve_ids))

    # Limit the number of concurrent tasks to the configured concurrency level:
    block_gen = block_splitter(hazard_curve_ids, block_size)
    total_blocks = int(math.ceil(len(hazard_curve_ids) / float(block_size)))

    for i, block in enumerate(block_gen):
        logs.LOG.debug('> Hazard post-processing block, %s of %s'
                       % (i + 1, total_blocks))

        tasks = []
        for hazard_curve_id in block:
            tasks.append(hazard_curves_to_hazard_map_task.subtask(
                (job.id, hazard_curve_id, poes)))
        results = TaskSet(tasks=tasks).apply_async()

        utils_tasks._check_exception(results)

        logs.LOG.debug('< Done Hazard Map post-processing block, %s of %s'
                       % (i + 1, total_blocks))
    logs.LOG.debug('< Done post-processing - Hazard Maps')
def compute_disagg_matrix(job_ctxt, site, poe, result_dir):
    """ Compute a complete 5D Disaggregation matrix. This task leans heavily
    on the DisaggregationCalculator (in the OpenQuake Java lib) to handle this
    computation.

    The 5D matrix returned from the java calculator will be saved to a file in
    HDF5 format.

    :param job_ctxt:
        A :class:`openquake.engine.JobContext` which holds all of the
        data we need to run this computation.
    :param site: a single site of interest
    :type site: :class:`openquake.shapes.Site` instance`
    :param poe: Probability of Exceedence
    :type poe: `float`
    :param result_dir: location for the Java code to write the matrix in an
        HDF5 file (in a distributed environment, this should be the path of a
        mounted NFS)

    :returns: 2-tuple of (ground_motion_value, path_to_h5_matrix_file)
    """
    lat_bin_lims = job_ctxt[job_cfg.LAT_BIN_LIMITS]
    lon_bin_lims = job_ctxt[job_cfg.LON_BIN_LIMITS]
    mag_bin_lims = job_ctxt[job_cfg.MAG_BIN_LIMITS]
    eps_bin_lims = job_ctxt[job_cfg.EPS_BIN_LIMITS]

    jd = list_to_jdouble_array

    disagg_calc = java.jclass('DisaggregationCalculator')(
        jd(lat_bin_lims), jd(lon_bin_lims),
        jd(mag_bin_lims), jd(eps_bin_lims))

    cache = java.jclass('KVS')(
        config.get('kvs', 'host'),
        int(config.get('kvs', 'port')))

    erf = general.generate_erf(job_ctxt.job_id, cache)
    gmpe_map = general.generate_gmpe_map(job_ctxt.job_id, cache)
    general.set_gmpe_params(gmpe_map, job_ctxt.params)

    imls = general.get_iml_list(job_ctxt['INTENSITY_MEASURE_LEVELS'],
                                job_ctxt['INTENSITY_MEASURE_TYPE'])

    site_model = general.get_site_model(job_ctxt.oq_job.id)

    if site_model is not None:
        sm_data = general.get_closest_site_model_data(site_model, site)
        vs30_type = sm_data.vs30_type.capitalize()
        vs30 = sm_data.vs30
        z1pt0 = sm_data.z1pt0
        z2pt5 = sm_data.z2pt5
    else:
        jp = job_ctxt.oq_job_profile

        vs30_type = jp.vs30_type.capitalize()
        vs30 = jp.reference_vs30_value
        z1pt0 = jp.depth_to_1pt_0km_per_sec
        z2pt5 = jp.reference_depth_to_2pt5km_per_sec_param

    matrix_result = _compute_matrix(
        disagg_calc, site.latitude, site.longitude, erf, gmpe_map, poe, imls,
        vs30_type, vs30, z1pt0, z2pt5)

    matrix_path = save_5d_matrix_to_h5(result_dir,
                                       numpy.array(matrix_result.getMatrix()))

    return (matrix_result.getGMV(), matrix_path)
Exemple #35
0
 def __new__(cls, host=config.get("kvs", "host"),
                  port=int(config.get("kvs", "port")),
                  **kwargs):  # pylint: disable=W0613
     self = object.__new__(cls)
     self.__dict__ = cls.__shared_state
     return self
Exemple #36
0
    def execute(self):
        """
        Calculation work is parallelized over sources, which means that each
        task will compute hazard for all sites but only with a subset of the
        seismic sources defined in the input model.

        The general workflow is as follows:

        1. Fill the queue with an initial set of tasks. The number of initial
        tasks is configurable using the `concurrent_tasks` parameter in the
        `[hazard]` section of the OpenQuake config file.

        2. Wait for tasks to signal completion (via AMQP message) and enqueue a
        new task each time another completes. Once all of the job work is
        enqueued, we just wait until all of the tasks conclude.
        """
        job = self.job
        hc = job.hazard_calculation
        sources_per_task = int(config.get('hazard', 'block_size'))
        concurrent_tasks = int(config.get('hazard', 'concurrent_tasks'))

        progress = dict(total=0, computed=0)
        # The following two counters are in a dict so that we can use them in
        # the closures below.
        # When `progress['compute']` becomes equal to `progress['total']`,
        # `execute` can conclude.

        task_gen = self.task_arg_gen(hc, job, sources_per_task, progress)

        def task_complete_callback(body, message):
            """
            :param dict body:
                ``body`` is the message sent by the task. The dict should
                contain 2 keys: `job_id` and `num_sources` (to indicate the
                number of sources computed).

                Both values are `int`.
            :param message:
                A :class:`kombu.transport.pyamqplib.Message`, which contains
                metadata about the message (including content type, channel,
                etc.). See kombu docs for more details.
            """
            job_id = body['job_id']
            num_sources = body['num_sources']

            assert job_id == job.id
            progress['computed'] += num_sources

            logs.log_percent_complete(job_id, "hazard")

            # Once we receive a completion signal, enqueue the next
            # piece of work (if there's anything left to be done).
            try:
                self.core_calc_task.apply_async(task_gen.next())
            except StopIteration:
                # There are no more tasks to dispatch; now we just need
                # to wait until all tasks signal completion.
                pass

            message.ack()

        exchange, conn_args = exchange_and_conn_args()

        routing_key = ROUTING_KEY_FMT % dict(job_id=job.id)
        task_signal_queue = kombu.Queue(
            'htasks.job.%s' % job.id, exchange=exchange,
            routing_key=routing_key, durable=False, auto_delete=True)

        with kombu.BrokerConnection(**conn_args) as conn:
            task_signal_queue(conn.channel()).declare()
            with conn.Consumer(task_signal_queue,
                               callbacks=[task_complete_callback]):
                # First: Queue up the initial tasks.
                for _ in xrange(concurrent_tasks):
                    try:
                        self.core_calc_task.apply_async(task_gen.next())
                    except StopIteration:
                        # If we get a `StopIteration` here, that means we have
                        # a number of tasks < concurrent_tasks.
                        # This basically just means that we could be
                        # under-utilizing worker node resources.
                        break

                while (progress['computed'] < progress['total']):
                    # This blocks until a message is received.
                    # Once we receive a completion signal, enqueue the next
                    # piece of work (if there's anything left to be done).
                    # (The `task_complete_callback` will handle additional
                    # queuing.)
                    conn.drain_events()
        logs.log_progress("hazard calculation 100% complete", 2)
Exemple #37
0
 def open():
     """Initialize the test store."""
     if TestStore._conn is not None:
         return
     TestStore._conn = redis.Redis(db=int(config.get("kvs", "test_db")))
Exemple #38
0
def compute_disagg_matrix(job_ctxt, site, poe, result_dir):
    """ Compute a complete 5D Disaggregation matrix. This task leans heavily
    on the DisaggregationCalculator (in the OpenQuake Java lib) to handle this
    computation.

    The 5D matrix returned from the java calculator will be saved to a file in
    HDF5 format.

    :param job_ctxt:
        A :class:`openquake.engine.JobContext` which holds all of the
        data we need to run this computation.
    :param site: a single site of interest
    :type site: :class:`openquake.shapes.Site` instance`
    :param poe: Probability of Exceedence
    :type poe: `float`
    :param result_dir: location for the Java code to write the matrix in an
        HDF5 file (in a distributed environment, this should be the path of a
        mounted NFS)

    :returns: 2-tuple of (ground_motion_value, path_to_h5_matrix_file)
    """
    lat_bin_lims = job_ctxt[job_cfg.LAT_BIN_LIMITS]
    lon_bin_lims = job_ctxt[job_cfg.LON_BIN_LIMITS]
    mag_bin_lims = job_ctxt[job_cfg.MAG_BIN_LIMITS]
    eps_bin_lims = job_ctxt[job_cfg.EPS_BIN_LIMITS]

    jd = list_to_jdouble_array

    disagg_calc = java.jclass('DisaggregationCalculator')(jd(lat_bin_lims),
                                                          jd(lon_bin_lims),
                                                          jd(mag_bin_lims),
                                                          jd(eps_bin_lims))

    cache = java.jclass('KVS')(config.get('kvs', 'host'),
                               int(config.get('kvs', 'port')))

    erf = general.generate_erf(job_ctxt.job_id, cache)
    gmpe_map = general.generate_gmpe_map(job_ctxt.job_id, cache)
    general.set_gmpe_params(gmpe_map, job_ctxt.params)

    imls = general.get_iml_list(job_ctxt['INTENSITY_MEASURE_LEVELS'],
                                job_ctxt['INTENSITY_MEASURE_TYPE'])

    site_model = general.get_site_model(job_ctxt.oq_job.id)

    if site_model is not None:
        sm_data = general.get_closest_site_model_data(site_model, site)
        vs30_type = sm_data.vs30_type.capitalize()
        vs30 = sm_data.vs30
        z1pt0 = sm_data.z1pt0
        z2pt5 = sm_data.z2pt5
    else:
        jp = job_ctxt.oq_job_profile

        vs30_type = jp.vs30_type.capitalize()
        vs30 = jp.reference_vs30_value
        z1pt0 = jp.depth_to_1pt_0km_per_sec
        z2pt5 = jp.reference_depth_to_2pt5km_per_sec_param

    matrix_result = _compute_matrix(disagg_calc, site.latitude, site.longitude,
                                    erf, gmpe_map, poe, imls, vs30_type, vs30,
                                    z1pt0, z2pt5)

    matrix_path = save_5d_matrix_to_h5(result_dir,
                                       numpy.array(matrix_result.getMatrix()))

    return (matrix_result.getGMV(), matrix_path)
Exemple #39
0
LOG4J_STDOUT_FORMAT = '%-5p %X{processName} [%c] - Job %X{job_id} - %m%n'

LOG4J_STDOUT_SETTINGS = {
    'log4j.rootLogger': '%(level)s, stdout',

    'log4j.appender.stdout': 'org.apache.log4j.ConsoleAppender',
    'log4j.appender.stdout.follow': 'true',
    'log4j.appender.stdout.layout': 'org.apache.log4j.PatternLayout',
    'log4j.appender.stdout.layout.ConversionPattern': LOG4J_STDOUT_FORMAT,
}

LOG4J_AMQP_SETTINGS = {
    'log4j.rootLogger': '%(level)s, amqp',

    'log4j.appender.amqp': 'org.gem.log.AMQPAppender',
    'log4j.appender.amqp.host': config.get("amqp", "host"),
    'log4j.appender.amqp.port': config.get("amqp", "port"),
    'log4j.appender.amqp.username': config.get("amqp", "user"),
    'log4j.appender.amqp.password': config.get("amqp", "password"),
    'log4j.appender.amqp.virtualHost': config.get("amqp", "vhost"),
    'log4j.appender.amqp.routingKeyPattern': 'log.%p.%X{job_id}',
    'log4j.appender.amqp.exchange': config.get("amqp", "exchange"),
    'log4j.appender.amqp.layout': 'org.apache.log4j.PatternLayout',
    'log4j.appender.amqp.layout.ConversionPattern': LOG4J_AMQP_FORMAT,
}


def init_logs(log_type='console', level='warn'):
    """
    Initialize Python logging.
Exemple #40
0
 def open():
     """Initialize the test store."""
     if TestStore._conn is not None:
         return
     TestStore._conn = redis.Redis(db=int(config.get("kvs", "test_db")))