File: test_mogi.py

package info (click to toggle)
mystic 0.4.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,924 kB
  • sloc: python: 42,022; makefile: 33; sh: 9
file content (167 lines) | stat: -rwxr-xr-x 5,298 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env python
#
# Author: Patrick Hung (patrickh @caltech)
# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
# Copyright (c) 1997-2016 California Institute of Technology.
# Copyright (c) 2016-2026 The Uncertainty Quantification Foundation.
# License: 3-clause BSD.  The full license text is available at:
#  - https://github.com/uqfoundation/mystic/blob/master/LICENSE
"""
Tests a single mogi fitting. 

Script is pretty crude right now.

Requirement: 
   numpy  --- for data-structures and "vectorized" ops on them, like sqrt, pow
   matplotlib for plotting

Computes surface displacements Ux, Uy, Uz in meters from a point spherical
pressure source in an elastic half space [1].

Reference:

[1] Mogi, K. Relations between the eruptions of various
volcanoes and the deformations of the ground surfaces around them, 
Bull. Earthquake. Res. Inst., 36, 99-134, 1958.
"""

import matplotlib.pyplot as plt
from mystic.solvers import DifferentialEvolutionSolver
from mystic.termination import ChangeOverGeneration, VTR
from mystic.monitors import Monitor, VerboseMonitor
from mystic.tools import getch, random_seed

from numpy import pi, sqrt, array, mgrid, random, real, conjugate, arange
from numpy.random import rand
import numpy

random_seed(123)

from mystic.models import mogi; ForwardMogiFactory = mogi.ForwardFactory

# Let the "actual parameters" be :
actual_params = [1234.,-500., 10., .1]
actual_forward = ForwardMogiFactory(actual_params)

# The data to be "fitted" 
xstations = array([random.uniform(-30,30) for i in range(300)])+actual_params[0]
ystations =  0*xstations + actual_params[1]
stations  = array((xstations, ystations))

data = actual_forward(stations)
# noisy data, gaussian distribution with mean 0, sig 0.1e-3
noise =  array([[random.normal(0,0.1e-3) for i in range(data.shape[1])] for j in range(data.shape[0])])

# Here is the "observed data"
data_z = -data[2,:] + noise[2,:]
# the stations are still at : stations

def plot_noisy_data():
    import matplotlib.pyplot as plt
    plt.plot(stations[0,:],data_z,'k.')

# we need a filter for the forward model
def filter_for_zdisp(input):
    return -input[2,:]

# Here is the cost function
def vec_cost_function(params):
    model = ForwardMogiFactory(params)
    zdisp = filter_for_zdisp(model(stations))
    return 100. * (zdisp - data_z)

# Here is the normed version
def cost_function(params):
    x = vec_cost_function(params)
    return numpy.sum(real((conjugate(x)*x)))

# a cost function with parameters "normalized"
def vec_cost_function2(params):
    sca = numpy.array([1000, 100., 10., 0.1])
    return vec_cost_function(sca * params)


ND = 4
NP = 50
MAX_GENERATIONS = 2500

def de_solve():
    solver = DifferentialEvolutionSolver(ND, NP)

    stepmon = Monitor()
    minrange = [-1000., -1000., -100., -10.];
    maxrange = [1000., 1000., 100., 10.];
    solver.SetRandomInitialPoints(min = minrange, max = maxrange)
    solver.SetEvaluationLimits(generations=MAX_GENERATIONS)
    solver.SetGenerationMonitor(stepmon)

   #termination = VTR(0.0000029)
    termination = ChangeOverGeneration(generations=100)

    solver.Solve(cost_function, termination=termination, \
                 CrossProbability=0.5, ScalingFactor=0.5)

    solution = solver.Solution()
  
    return solution, stepmon


def plot_sol(params, linestyle = 'b-'):
    forward_solution = ForwardMogiFactory(params)
    xx = arange(-30,30,0.1)+actual_params[0]
    yy = 0*xx + actual_params[1]
    ss  = array((xx, yy))
    dd = forward_solution(ss)
    plt.plot(ss[0,:],-dd[2,:],'%s'%linestyle,linewidth=2.0)

if __name__ == '__main__':

    from mystic.solvers import NelderMeadSimplexSolver as fmin
    from mystic.termination import CandidateRelativeTolerance as CRT
    try:
        from scipy.optimize import leastsq, fmin_cg
    except ImportError:
        from mystic._scipyoptimize import fmin_cg
        leastsq = None
    #
    desol, dstepmon = de_solve()
    print("desol: %s" % desol)
    print("dstepmon 50: %s" % dstepmon.x[50])
    print("dstepmon 100: %s" % dstepmon.x[100])
    #
    # this will try to use nelder_mean from a relatively "near by" point (very sensitive)
    point = [1234., -500., 10., 0.001] # both cg and nm does fine
    point = [1000,-100,0,1] # cg will do badly on this one
    # this will try nelder-mead from an unconverged DE solution 
    #point = dstepmon.x[-150]
    #
    simplex, esow = Monitor(), Monitor()
    solver = fmin(len(point))
    solver.SetInitialPoints(point)
    solver.SetEvaluationMonitor(esow)
    solver.SetGenerationMonitor(simplex)
    solver.Solve(cost_function, CRT())
    sol = solver.Solution()

    print("\nsimplex solution: %s" % sol)
    #
    solcg = fmin_cg(cost_function, point)
    print("\nConjugate-Gradient (Polak Rubiere) : %s" % solcg)
    #
    if leastsq:
        sollsq = leastsq(vec_cost_function, point)
        sollsq = sollsq[0]
        print("\nLeast Squares (Levenberg Marquardt) : %s" % sollsq)
    #
    legend = ['Noisy data', 'Differential Evolution', 'Nelder Mead', 'Polak Ribiere']
    plot_noisy_data()
    plot_sol(desol,'r-')
    plot_sol(sol,'k--')
    plot_sol(solcg,'b-.')
    if leastsq:
        plot_sol(sollsq,'g-.')
        legend += ['Levenberg Marquardt']
    plt.legend(legend) 
    plt.show()

# end of file