<commit_before>#===============================================================================
# Copyright 2012 <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#===============================================================================

#============= enthought library imports =======================
from traits.api import HasTraits, List, Property, cached_property, Str, Bool, Int, Event
#============= standard library imports ========================
from numpy import array
#============= local library imports  ==========================
from uncertainties import ufloat
# from pychron.processing.analysis import Marker
from pychron.processing.argon_calculations import calculate_plateau_age, age_equation, calculate_isochron
from pychron.pychron_constants import ALPHAS
from pychron.core.stats.core import calculate_mswd, calculate_weighted_mean, validate_mswd


def AGProperty(*depends):
    d = 'dirty,analyses:[status,temp_status]'
    if depends:
        d = '{},{}'.format(','.join(depends), d)

    return Property(depends_on=d)


class AnalysisGroup(HasTraits):
    sample = Str
    analyses = List
    nanalyses = AGProperty()

    arith_age = AGProperty()
    arith_age_error_kind = Str
    # arith_age_error_kind = Enum(*ERROR_TYPES)

    weighted_age = AGProperty()
    # weighted_age_error_kind = Enum(*ERROR_TYPES)
    weighted_age_error_kind = Str  #Enum(*ERROR_TYPES)

    weighted_kca = AGProperty()
    arith_kca = AGProperty()

    mswd = Property

    isochron_age = AGProperty()
    identifier = Property

    j_err = AGProperty()
    include_j_error_in_mean = Bool(True)
    include_j_error_in_individual_analyses = Bool(False)

    dirty = Event

    def get_mswd_tuple(self):
        mswd = self.mswd
        valid_mswd = validate_mswd(mswd, self.nanalyses)
        return mswd, valid_mswd, self.nanalyses

    # @cached_property
    def _get_mswd(self):
        attr = 'uage_wo_j_err'
        if self.include_j_error_in_individual_analyses:
            attr = 'uage'

        return self._calculate_mswd(attr)

    def _calculate_mswd(self, attr):
        m = None
        args = self._get_values(attr)
        if args:
            vs, es = args
            m = calculate_mswd(vs, es)

        return m

    @cached_property
    def _get_j_err(self):
        j = self.analyses[0].j
        e = j.std_dev if j is not None else 0
        return e

    @cached_property
    def _get_isochron_age(self):
        return self._calculate_isochron_age()

    @cached_property
    def _get_identifier(self):
        return self.analyses[0].labnumber

    # @cached_property
    def _get_weighted_age(self):

        if self.include_j_error_in_individual_analyses:
            v, e = self._calculate_weighted_mean('uage', self.weighted_age_error_kind)
        else:
            v, e = self._calculate_weighted_mean('uage_wo_j_err', self.weighted_age_error_kind)

        e = self._modify_error(e, self.weighted_age_error_kind)

        return ufloat(v, e)

    def _modify_error(self, e, kind, mswd=None, include_j_error=None):

        if mswd is None:
            mswd = self.mswd

        if kind == 'SEM, but if MSWD>1 use SEM * sqrt(MSWD)':
            e = e * (mswd ** 0.5 if mswd > 1 else 1)

        if include_j_error is None:
            include_j_error = self.include_j_error_in_mean

        if include_j_error:
            e = (e ** 2 + self.j_err ** 2) ** 0.5
        return e

    # @cached_property
    def _get_weighted_kca(self):
        return ufloat(*self._calculate_weighted_mean('kca'))

    # @cached_property
    def _get_arith_kca(self):
        return ufloat(*self._calculate_arithmetic_mean('kca'))

    # @cached_property
    def _get_arith_age(self):
        if self.include_j_error_in_individual_analyses:
            v, e = self._calculate_arithmetic_mean('uage')
        else:
            v, e = self._calculate_arithmetic_mean('uage_wo_j_err')
        e = self._modify_error(e, self.arith_age_error_kind)
        return ufloat(v, e)

    @cached_property
    def _get_nanalyses(self):
        return len([ai for ai in self.analyses if not ai.is_omitted()])

    def _get_values(self, attr):
        vs = (getattr(ai, attr) for ai in self.analyses
              if not ai.is_omitted())

        vs = [vi for vi in vs if vi is not None]
        if vs:
            vs, es = zip(*[(v.nominal_value, v.std_dev) for v in vs])
            vs, es = array(vs), array(es)
            return vs, es

    def _calculate_mean(self, attr, use_weights=True, error_kind=None):
        args = self._get_values(attr)
        if args:
            vs, es = args
            if use_weights:
                av, werr = calculate_weighted_mean(vs, es)
                if error_kind == 'SD':
                    werr = (sum((av - es) ** 2)) ** 0.5

            else:
                av = vs.mean()
                werr = vs.std(ddof=1)
        else:
            av, werr = 0, 0

        return av, werr

    def _calculate_arithmetic_mean(self, attr):
        return self._calculate_mean(attr, use_weights=False)

    def _calculate_weighted_mean(self, attr, error_kind=None):
        return self._calculate_mean(attr, use_weights=True, error_kind=error_kind)

    def _calculate_isochron_age(self):
        args = calculate_isochron(self.analyses)
        if args:
            return args[0]


class StepHeatAnalysisGroup(AnalysisGroup):
    plateau_age = AGProperty()
    integrated_age = AGProperty()

    include_j_error_in_plateau = Bool(True)
    plateau_steps_str = Str<commit_msg>fixed include_j_error in mean<commit_after>#===============================================================================
# Copyright 2012 <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#===============================================================================

#============= enthought library imports =======================
from traits.api import HasTraits, List, Property, cached_property, Str, Bool, Int, Event
#============= standard library imports ========================
from numpy import array
#============= local library imports  ==========================
from uncertainties import ufloat
# from pychron.processing.analysis import Marker
from pychron.processing.argon_calculations import calculate_plateau_age, age_equation, calculate_isochron
from pychron.pychron_constants import ALPHAS
from pychron.core.stats.core import calculate_mswd, calculate_weighted_mean, validate_mswd


def AGProperty(*depends):
    d = 'dirty,analyses:[status,temp_status]'
    if depends:
        d = '{},{}'.format(','.join(depends), d)

    return Property(depends_on=d)


class AnalysisGroup(HasTraits):
    sample = Str
    analyses = List
    nanalyses = AGProperty()

    arith_age = AGProperty()
    arith_age_error_kind = Str
    # arith_age_error_kind = Enum(*ERROR_TYPES)

    weighted_age = AGProperty()
    # weighted_age_error_kind = Enum(*ERROR_TYPES)
    weighted_age_error_kind = Str  #Enum(*ERROR_TYPES)

    weighted_kca = AGProperty()
    arith_kca = AGProperty()

    mswd = Property

    isochron_age = AGProperty()
    identifier = Property

    j_err = AGProperty()
    include_j_error_in_mean = Bool(True)
    include_j_error_in_individual_analyses = Bool(False)

    dirty = Event

    def get_mswd_tuple(self):
        mswd = self.mswd
        valid_mswd = validate_mswd(mswd, self.nanalyses)
        return mswd, valid_mswd, self.nanalyses

    # @cached_property
    def _get_mswd(self):
        attr = 'uage_wo_j_err'
        if self.include_j_error_in_individual_analyses:
            attr = 'uage'

        return self._calculate_mswd(attr)

    def _calculate_mswd(self, attr):
        m = None
        args = self._get_values(attr)
        if args:
            vs, es = args
            m = calculate_mswd(vs, es)

        return m

    @cached_property
    def _get_j_err(self):
        j = self.analyses[0].j
        e = (j.std_dev/j.nominal_value) if j is not None else 0
        return e

    @cached_property
    def _get_isochron_age(self):
        return self._calculate_isochron_age()

    @cached_property
    def _get_identifier(self):
        return self.analyses[0].labnumber

    # @cached_property
    def _get_weighted_age(self):

        if self.include_j_error_in_individual_analyses:
            v, e = self._calculate_weighted_mean('uage', self.weighted_age_error_kind)
        else:
            v, e = self._calculate_weighted_mean('uage_wo_j_err', self.weighted_age_error_kind)

        e = self._modify_error(v, e, self.weighted_age_error_kind)

        return ufloat(v, e)

    def _modify_error(self, v, e, kind, mswd=None, include_j_error=None):

        if mswd is None:
            mswd = self.mswd

        if kind == 'SEM, but if MSWD>1 use SEM * sqrt(MSWD)':
            e = e * (mswd ** 0.5 if mswd > 1 else 1)

        if include_j_error is None:
            include_j_error = self.include_j_error_in_mean

        if include_j_error:
            e = ((e/v) ** 2 + self.j_err ** 2) ** 0.5 * v
        return e

    # @cached_property
    def _get_weighted_kca(self):
        return ufloat(*self._calculate_weighted_mean('kca'))

    # @cached_property
    def _get_arith_kca(self):
        return ufloat(*self._calculate_arithmetic_mean('kca'))

    # @cached_property
    def _get_arith_age(self):
        if self.include_j_error_in_individual_analyses:
            v, e = self._calculate_arithmetic_mean('uage')
        else:
            v, e = self._calculate_arithmetic_mean('uage_wo_j_err')
        e = self._modify_error(v, e, self.arith_age_error_kind)
        return ufloat(v, e)

    @cached_property
    def _get_nanalyses(self):
        return len([ai for ai in self.analyses if not ai.is_omitted()])

    def _get_values(self, attr):
        vs = (getattr(ai, attr) for ai in self.analyses
              if not ai.is_omitted())

        vs = [vi for vi in vs if vi is not None]
        if vs:
            vs, es = zip(*[(v.nominal_value, v.std_dev) for v in vs])
            vs, es = array(vs), array(es)
            return vs, es

    def _calculate_mean(self, attr, use_weights=True, error_kind=None):
        args = self._get_values(attr)
        if args:
            vs, es = args
            if use_weights:
                av, werr = calculate_weighted_mean(vs, es)
                if error_kind == 'SD':
                    n=len(vs)
                    werr = (sum((av - vs) ** 2)/(n-1)) ** 0.5

            else:
                av = vs.mean()
                werr = vs.std(ddof=1)
        else:
            av, werr = 0, 0

        return av, werr

    def _calculate_arithmetic_mean(self, attr):
        return self._calculate_mean(attr, use_weights=False)

    def _calculate_weighted_mean(self, attr, error_kind=None):
        return self._calculate_mean(attr, use_weights=True, error_kind=error_kind)

    def _calculate_isochron_age(self):
        args = calculate_isochron(self.analyses)
        if args:
            return args[0]


class StepHeatAnalysisGroup(AnalysisGroup):
    plateau_age = AGProperty()
    integrated_age = AGProperty()

    include_j_error_in_plateau = Bool(True)
    plateau_steps_str = Str
{'fraction_non_alphanumeric': 0.13011611628098493, 'fraction_numerical': 0.004529358478135551, 'mean_word_length': 2.873684210526316, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5554491', 'n_tokens_mistral': 3994, 'n_tokens_neox': 3715, 'n_words': 933}